// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.client.editor;
import com.google.collide.client.util.Elements;
import com.google.collide.shared.document.Line;
import com.google.collide.shared.document.LineInfo;
import com.google.collide.shared.document.anchor.Anchor;
import com.google.collide.shared.util.SortedList;
import elemental.css.CSSStyleDeclaration;
import elemental.events.Event;
import elemental.events.EventListener;
import elemental.html.Element;
/*
* TODO: Knowledge about what lines the spacer is logically linked
* to which could make the system scroll intelligently, see comments in CL
* 26294787
*/
/**
* A spacer allows a client to insert UI inbetween lines in an editor without
* affecting the backing document.
*
*/
public class Spacer {
/**
* Comparator for sorting spacers.
*/
public static class Comparator implements SortedList.Comparator<Spacer> {
@Override
public int compare(Spacer a, Spacer b) {
return a.getLineNumber() - b.getLineNumber();
}
}
/**
* One way comparator for sorting spacers.
*/
public static class OneWaySpacerComparator extends SortedList.OneWayIntComparator<Spacer> {
@Override
public int compareTo(Spacer s) {
return value - s.getLineNumber();
}
}
/** A spacer's anchor is always attached to the line that follows the spacer */
private final Anchor anchor;
private final Buffer buffer;
private final CoordinateMap coordinateMap;
/** Always use {@link #getElement()} */
private Element element;
private int height;
private String cssClass;
Spacer(Anchor anchor, int height, CoordinateMap coordinateMap, Buffer buffer, String cssClass) {
this.anchor = anchor;
this.height = height;
this.coordinateMap = coordinateMap;
this.buffer = buffer;
this.cssClass = cssClass;
}
/**
* Return the line number this spacer is attached above.
*/
public int getLineNumber() {
return anchor.getLineNumber();
}
public Line getLine() {
return anchor.getLine();
}
public LineInfo getLineInfo() {
return anchor.getLineInfo();
}
public Anchor getAnchor() {
return anchor;
}
/**
* Return the height of this spacer, not including the line it is attached
* to below.
*/
public int getHeight() {
return height;
}
public void setHeight(int newHeight) {
int oldHeight = height;
height = newHeight;
coordinateMap.handleSpacerHeightChanged(this, oldHeight);
element.getStyle().setHeight(height, CSSStyleDeclaration.Unit.PX);
element.getStyle().setMarginTop(-height, CSSStyleDeclaration.Unit.PX);
}
public void addElement(Element addElement) {
getElement().appendChild(addElement);
}
public boolean isAttached() {
return anchor.isAttached();
}
@Override
public String toString() {
return "Spacer, height: " + height + ", line number: " + anchor.getLineNumber();
}
private Element getElement() {
if (element != null) {
return element;
}
// Create div area for clients to draw inside
element = Elements.createDivElement();
element.addClassName(cssClass);
element.getStyle().setLeft("0px");
element.getStyle().setRight("0px");
element.getStyle().setHeight(height, CSSStyleDeclaration.Unit.PX);
element.getStyle().setPosition(CSSStyleDeclaration.Position.ABSOLUTE);
element.getStyle().setMarginTop(-height, CSSStyleDeclaration.Unit.PX);
EventListener bubblePreventionListener = new EventListener() {
@Override
public void handleEvent(Event e) {
e.stopPropagation();
}
};
element.setOnMouseDown(bubblePreventionListener);
element.setOnMouseMove(bubblePreventionListener);
element.setOnMouseUp(bubblePreventionListener);
buffer.addAnchoredElement(anchor, element);
return element;
}
}