/*
* MyGWT Widget Library
* Copyright(c) 2007, MyGWT.
* licensing@mygwt.net
*
* http://mygwt.net/license
*/
package net.mygwt.ui.client;
import net.mygwt.ui.client.MyGWT;
import net.mygwt.ui.client.Style;
import net.mygwt.ui.client.impl.MyDOMImpl;
import net.mygwt.ui.client.util.Point;
import net.mygwt.ui.client.util.Rectangle;
import net.mygwt.ui.client.util.Region;
import net.mygwt.ui.client.util.Size;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;
/**
* Provides additional static methods that allow you to manipulate the browser's
* Document Object Model (DOM).
*
* @see DOM
*/
public class MyDOM {
private static final MyDOMImpl impl = (MyDOMImpl) GWT.create(MyDOMImpl.class);
private static boolean isVisibleBox;
private static int AUTO_ID = 0;
private static int Z_INDEX = 1000;
static {
MyGWT.init();
isVisibleBox = isVisibleBoxInternal();
}
/**
* Adds the event type to the element's sunk events.
*
* @param elem the element
* @param event the events to add
*/
public static void addEventsSunk(Element elem, int event) {
int bits = DOM.getEventsSunk(elem);
DOM.sinkEvents(elem, bits | event);
}
/**
* Adds a style name to the element.
*
* @param elem the element
* @param style the style to be added
*/
public static void addStyleName(Element elem, String style) {
setStyleName(elem, style, true);
}
/**
* Aligns the element with another element relative to the specified anchor
* points. Two values from the table below should be passed separated by a
* dash, the first value is used as the element's anchor point, and the second
* value is used as the target's anchor point.
* <p>
* In addition to the anchor points, the position parameter also supports the
* "?" character. If "?" is passed at the end of the position string, the
* element will attempt to align as specified, but the position will be
* adjusted to constrain to the viewport if necessary. Note that the element
* being aligned might be swapped to align to a different position than that
* specified in order to enforce the viewport constraints.
* </p>
* <dl>
* <dt>Following are all of the supported anchor positions:</dt>
* </dl>
* <code><pre>
* Value Description
* ----- -----------------------------
* tl The top left corner (default)
* t The center of the top edge
* tr The top right corner
* l The center of the left edge
* c In the center of the element
* r The center of the right edge
* bl The bottom left corner
* b The center of the bottom edge
* br The bottom right corner
* </code></pre>
*
* @param elem the element to be aligned
* @param align the element to align to
* @param pos the position to align to
* @param offsets the offsets or <code>null</code>
*/
public static void alignTo(Element elem, Element align, String pos, int[] offsets) {
Point p = getAlignToXY(elem, align, pos, offsets);
setXY(elem, p);
}
/**
* Centers the element.
*
* @param elem the element
*/
public static void center(Element elem) {
int width = Window.getClientWidth();
int height = Window.getClientHeight();
int w = getWidth(elem);
int h = getHeight(elem);
int left = (width / 2) - (w / 2);
int top = (height / 2) - (h / 2);
setLeft(elem, left);
setTop(elem, top);
}
/**
* Clips overflow on the element.
*/
public static void clip(Element elem) {
DOM.setStyleAttribute(elem, "overflow", "hidden");
DOM.setStyleAttribute(elem, "overflowX", "hidden");
DOM.setStyleAttribute(elem, "overflowY", "hidden");
}
/**
* Creates an element form the given markup.
*
* @param html the markup
* @return the new element
*/
public static Element create(String html) {
Element div = DOM.createDiv();
DOM.setInnerHTML(div, html);
div = DOM.getFirstChild(div);
return div;
}
/**
* Disable the element.
*/
public native static void disable(Element elem) /*-{
elem.disabled = true;
}-*/;
/**
* Disables the browsers default context menu for the specified element.
*
* @param elem the element whos context menu will be disabled
*/
public static native void disableContextMenu(Element elem) /*-{
elem.oncontextmenu=function() { return false};
}-*/;
/**
* Disables text selection.
*
* @param elem the element
*/
public static void disableTextSelection(Element elem) {
setStyleName(elem, "my-no-selection", true);
nativeSetTextSelect(elem, false);
}
/**
* Enable the element.
*
* @param elem the element
*/
public native static void enable(Element elem) /*-{
elem.disabled = false;
}-*/;
/**
* Returns the first child with a matching style name.
*
* @param style the style
* @param elem the element
* @return the matching element or <code>null</code>
*/
public static Element findChild(String style, Element elem) {
String cls = DOM.getElementProperty(elem, "className");
if (style.equals(cls)) {
return elem;
}
int count = DOM.getChildCount(elem);
for (int i = 0; i < count; i++) {
Element child = findChild(style, DOM.getChild(elem, i));
if (child != null) {
return child;
}
}
return null;
}
/**
* Finds the first parent element with the given style name.
*
* @param style the style name
* @param elem the start element
* @param maxDepth the max amount of parent to search
* @return the matching element
*/
public static Element findParent(String style, Element elem, int maxDepth) {
Element p = elem;
int depth = 0;
while (p != null && depth < maxDepth) {
String cls = DOM.getElementProperty(p, "className");
String[] classes = cls.split(" ");
for (int i = 0; i < classes.length; i++) {
if (style.equals(classes[i])) {
return p;
}
}
depth++;
p = DOM.getParent(p);
}
return null;
}
/**
* Returns the x,y coordinates to align this element with another element. See
* {@link #alignTo} for more info on the supported position values.
*
* @param elem the align to be aligned
* @param align the element to align to
* @param pos the position, see alignTo
* @param offsets the optional offsets
* @return the the point
*/
public static Point getAlignToXY(Element elem, Element align, String pos, int[] offsets) {
if (pos == null) {
pos = "tl-bl";
}
String[] m = pos.split("-");
String p1 = m[0];
String p2 = m[1];
Point a1 = getAnchorXY(elem, p1, true);
Point a2 = getAnchorXY(align, p2, false);
if (offsets == null) {
offsets = new int[] {0, 0};
}
int x = a2.x - a1.x + offsets[0];
int y = a2.y - a1.y + offsets[1];
if (m.length == 3) {
int w = getComputedWidth(elem);
int h = getHeight(elem);
int dw = Window.getClientWidth() - 5;
int dh = Window.getClientHeight() - 5;
Region r = getRegion(elem);
char p1y = p1.charAt(0), p1x = p1.charAt(p1.length() - 1);
char p2y = p2.charAt(0), p2x = p2.charAt(p2.length() - 1);
boolean swapY = ((p1y == 't' && p2y == 'b') || (p1y == 'b' && p2y == 't'));
boolean swapX = ((p1x == 'r' && p2x == 'l') || (p1x == 'l' && p2x == 'r'));
int scrollX = getBodyScrollLeft();
int scrollY = getBodyScrollTop();
if ((x + w) > dw + scrollX) {
x = swapX ? r.left - w : dw + scrollX - w;
}
if (x < scrollX) {
x = swapX ? r.right : scrollX;
}
if ((y + h) > dh + scrollY) {
y = swapY ? r.top - h : dh + scrollY - h;
}
if (y < scrollY) {
y = swapY ? r.bottom : scrollY;
}
}
return new Point(x, y);
}
/**
* Returns the x,y coordinates specified by the anchor position on the
* element.
*
* @param elem the element
* @param anchor the specified anchor position (defaults to "c"). See
* {@link #alignTo} for details on supported anchor positions.
* @param local <code>true</code> to get the local (element
* top/left-relative) anchor position instead of page coordinates
* @return the position
*/
public static Point getAnchorXY(Element elem, String anchor, boolean local) {
int w = getWidth(elem);
int h = getHeight(elem);
int x = 0;
int y = 0;
if (anchor == null) {
anchor = "c";
}
if (anchor.equalsIgnoreCase("c")) {
x = (int) Math.round(x * .5);
y = (int) Math.round(h * .5);
} else if (anchor.equalsIgnoreCase("t")) {
x = (int) Math.round(x * .5);
y = 0;
} else if (anchor.equalsIgnoreCase("l")) {
x = 0;
y = (int) Math.round(h * .5);
} else if (anchor.equalsIgnoreCase("r")) {
x = w;
y = (int) Math.round(h * .5);
} else if (anchor.equalsIgnoreCase("b")) {
x = (int) Math.round(x * .5);
y = h;
} else if (anchor.equalsIgnoreCase("tl")) {
x = 0;
y = 0;
} else if (anchor.equalsIgnoreCase("bl")) {
x = 0;
y = h;
} else if (anchor.equalsIgnoreCase("br")) {
x = w;
y = h;
} else if (anchor.equalsIgnoreCase("tr")) {
x = w;
y = 0;
}
if (local) {
return new Point(x, y);
}
Point p = getXY(elem);
p.x += x;
p.y += y;
return p;
}
/**
* Returns the body element.
*
* @return the body
*/
public static native Element getBody() /*-{
return $doc.body;
}-*/;
/**
* Returns the body elements horizontal scroll.
*
* @return the scroll amount in pixels
*/
public static native int getBodyScrollLeft() /*-{
return $doc.body.scrollLeft;
}-*/;
/**
* Return the body elements vertical scroll.
*
* @return the scroll amount in pixels
*/
public static native int getBodyScrollTop() /*-{
return $doc.body.scrollTop;
}-*/;
/**
* Returns the total border width of the specified sides.
*
* @param elem the element
* @param sides can be any combination of LEFT, RIGHT, TOP, BOTTOM
* @return the width of the sides passed added together
*/
public static int getBorderWidth(Element elem, int sides) {
int width = 0;
if ((sides & Style.LEFT) != 0) {
width += getIntStyleAttribute(elem, "borderLeftWidth");
}
if ((sides & Style.RIGHT) != 0) {
width += getIntStyleAttribute(elem, "borderRightWidth");
}
if ((sides & Style.TOP) != 0) {
width += getIntStyleAttribute(elem, "borderTopWidth");
}
if ((sides & Style.BOTTOM) != 0) {
width += getIntStyleAttribute(elem, "borderBottomWidth");
}
return width;
}
/**
* Returns the bottom Y coordinate of the element (element Y position +
* element height).
*
* @param elem the element
* @param local <code>true</code> to get the local css position instead of
* page coordinate
* @return the bottom value
*/
public static int getBottom(Element elem, boolean local) {
if (!local) {
return getY(elem) + getHeight(elem);
} else {
return getTop(elem) + getHeight(elem);
}
}
/**
* Returns the element's bounds.
*
* @param elem the element
* @return the elements bounds
*/
public static Rectangle getBounds(Element elem) {
return getBounds(elem, false);
}
/**
* Returns the element's bounds.
*
* @param elem the element
* @param content <code>true</code> to adjust for box model issues
* @return the elements bounds
*/
public static Rectangle getBounds(Element elem, boolean content) {
int x = DOM.getAbsoluteLeft(elem);
int y = DOM.getAbsoluteTop(elem);
int width = getWidth(elem);
int height = getHeight(elem);
if (content) {
x += getBorderWidth(elem, Style.LEFT);
y += getBorderWidth(elem, Style.TOP);
width -= getDecorationWidth(elem, Style.LEFT | Style.RIGHT);
height -= getDecorationWidth(elem, Style.TOP | Style.BOTTOM);
}
width = Math.max(0, width);
height = Math.max(0, height);
return new Rectangle(x, y, width, height);
}
/**
* Returns either the offsetHeight or the height of this element based on it's
* CSS height.
*
* @param elem the element
* @return the height
*/
public static int getComputedHeight(Element elem) {
int h = getHeight(elem);
if (h == 0) {
h = DOM.getIntStyleAttribute(elem, "height");
}
return h;
}
/**
* Returns either the offsetWidth or the width of this element based on it's
* CSS width.
*
* @param elem the element
* @return the width
*/
public static int getComputedWidth(Element elem) {
int w = getWidth(elem);
if (w == 0) {
w = DOM.getIntStyleAttribute(elem, "width");
}
return w;
}
/**
* Returns the total width of borders and padding for the specified sides.
*
* @param elem the element
* @param sides can be any combination of LEFT, RIGHT, TOP, BOTTOM
* @return the width in pixels
*/
public static int getDecorationWidth(Element elem, int sides) {
int width = 0;
width += getBorderWidth(elem, sides);
width += getPaddingWidth(elem, sides);
return width;
}
/**
* Returns the document element.
*
* @return the docuemnt
*/
public static native Element getDocument() /*-{
return $doc;
}-*/;
public static native Element getHead() /*-{
return $doc.getElementsByTagName('head')[0];
}-*/;
/**
* Returns the element's offset height in pixels. This is the total height of
* the object, including decorations such as border, margin, and padding.
*
* @param elem the element
* @return the element's offset height
*/
public static int getHeight(Element elem) {
return DOM.getElementPropertyInt(elem, "offsetHeight");
}
/**
* Returns the element's height.
*
* @param elem the element
* @param contentHeight <code>true</code> to get the height minus borders
* and padding
* @return the element's height
*/
public static int getHeight(Element elem, boolean contentHeight) {
int h = DOM.getElementPropertyInt(elem, "offsetHeight");
if (contentHeight & !isVisibleBox) {
h -= getDecorationWidth(elem, Style.TOP | Style.BOTTOM);
}
return h;
}
/**
* Returns the element's style attribute value.
*
* @param elem the element
* @param attr the attribute name
* @return the attribute value
*/
public static int getIntStyleAttribute(Element elem, String attr) {
String s = impl.getStyle(elem, attr);
try {
if (s.indexOf("px") != -1) {
s = s.substring(0, s.indexOf("px"));
}
int i = Integer.parseInt(s);
return i;
} catch (Exception e) {
}
return 0;
}
/**
* Returns the left X coordinate.
*
* @param elem the element
* @return the left value
*/
public static int getLeft(Element elem) {
return DOM.getIntStyleAttribute(elem, "left");
}
/**
* Returns the total padding width of the given sides.
*
* @param elem the element
* @param sides can be any combination of LEFT, RIGHT, TOP, BOTTOM
* @return the padding
*/
public static int getPaddingWidth(Element elem, int sides) {
int width = 0;
if ((sides & Style.LEFT) != 0) {
width += DOM.getIntStyleAttribute(elem, "paddingTop");
}
if ((sides & Style.RIGHT) != 0) {
width += DOM.getIntStyleAttribute(elem, "paddingRight");
}
if ((sides & Style.TOP) != 0) {
width += DOM.getIntStyleAttribute(elem, "paddingTop");
}
if ((sides & Style.BOTTOM) != 0) {
width += DOM.getIntStyleAttribute(elem, "paddingBottom");
}
return width;
}
/**
* Returns the region of the given element. The element must be part of the
* DOM tree to have a region.
*
* @param elem the element
* @return a region containing top, left, bottom, right
*/
public static Region getRegion(Element elem) {
Rectangle bounds = getBounds(elem, false);
Region r = new Region();
r.left = bounds.x;
r.top = bounds.y;
r.right = r.left + bounds.width;
r.bottom = r.top + bounds.height;
return r;
}
/**
* Returns the right X coordinate of the element (element X position + element
* width).
*
* @param elem the element
* @param local <code>true</code> to get the local css position instead of
* page coordinate
* @return the right value
*/
public static int getRight(Element elem, boolean local) {
if (!local) {
return getX(elem) + getWidth(elem);
} else {
return getLeft(elem) + getWidth(elem);
}
}
/**
* Returns the element's horizontal scroll position.
*
* @param elem the element
* @return the scroll amount in pixels
*/
public static int getScrollLeft(Element elem) {
return DOM.getElementPropertyInt(elem, "scrollLeft");
}
/**
* Returns the element's vertical scroll position.
*
* @param elem the element
* @return the scroll amount in pixel
*/
public static int getScrollTop(Element elem) {
return DOM.getElementPropertyInt(elem, "scrollTop");
}
/**
* Returns the elements size.
*
* @param elem the element
* @return the size
*/
public static Size getSize(Element elem) {
return new Size(getWidth(elem), getHeight(elem));
}
public static String getStyleName(Element elem) {
return DOM.getElementProperty(elem, "className");
}
/**
* Returns the element's sub child.
*
* @param elem the element
* @param depth the child node depth
* @return the child element
*/
public static Element getSubChild(Element elem, int depth) {
Element child = elem;
while (depth-- > 0) {
child = DOM.getChild(child, 0);
}
return child;
}
/**
* Returns the top Y coordinate.
*
* @param elem the element
* @return the top value
*/
public static int getTop(Element elem) {
return DOM.getIntStyleAttribute(elem, "top");
}
/**
* Returns an unique id.
*
* @return the id
*/
public static String getUniqueID() {
return "my-" + AUTO_ID++;
}
/**
* Returns the element's offset width in pixels. This is the total width of
* the element, including decorations such as border, margin, and padding.
*
* @param elem the element
* @return the element's offset width
*/
public static int getWidth(Element elem) {
return DOM.getElementPropertyInt(elem, "offsetWidth");
}
/**
* Returns the element's width.
*
* @param elem the element
* @param contentWidth <code>true</code> to get the width minus borders and
* padding
* @return the element's width
*/
public static int getWidth(Element elem, boolean contentWidth) {
int w = getWidth(elem);
if (contentWidth) {
w -= getDecorationWidth(elem, Style.LEFT | Style.RIGHT);
}
return w;
}
/**
* Gets the current X position of the element based on page coordinates.
* Element must be part of the DOM tree to have page coordinates.
*
* @param elem the element
* @return the x coordinate
*/
public static int getX(Element elem) {
return DOM.getAbsoluteLeft(elem);
}
/**
* Returns the current position of the element based on page coordinates.
* Element must be part of the DOM tree to have page coordinates.
*
* @param elem the element
* @return the current location
*/
public static Point getXY(Element elem) {
return new Point(getX(elem), getY(elem));
}
/**
* Returns the current Y position of the element based on page coordinates.
* Element must be part of the DOM tree to have page coordinates.
*
* @param elem the element
* @return the y coordinate
*/
public static int getY(Element elem) {
return DOM.getAbsoluteTop(elem);
}
/**
* Returns the current max z-index.
*
* @return the z-index
*/
public static int getZIndex() {
return ++Z_INDEX;
}
/**
* Checks if the specified CSS class exists on this element's DOM node.
*
* @param elem the element
* @param className the CSS class to check for
* @return <code>true</code> if the class exists, else <code>false</code>
*/
public static boolean hasClass(Element elem, String className) {
String[] classes = getStyleName(elem).split(" ");
for (int i = 0; i < classes.length; i++) {
if (className.equals(classes[i])) {
return true;
}
}
return false;
}
/**
* Inserts this element after the passed element in the DOM.
*
* @param elem the element
* @param after the element to insert after
*/
public native static void insertAfter(Element elem, Element after) /*-{
after.parentNode.insertBefore(elem, after.nextSibling);
}-*/;
/**
* Inserts the element before the passed element in the DOM.
*
* @param elem the element to be inserted
* @param before the element to insert before
*/
public native static void insertBefore(Element elem, Element before) /*-{
before.parentNode.insertBefore(elem, before);
}-*/;
/**
* Returns <code>true</code> if the horizontal scroll bar is present
*
* @param container the container element
* @return the vertical scroll bar state
*/
public static boolean isHScrollBarShowing(Element container) {
int orig = MyDOM.getScrollTop(container);
if (orig > 0) {
return true;
}
setScrollLeft(container, 10);
if (MyDOM.getScrollLeft(container) > 0) {
setScrollLeft(container, orig);
return true;
}
setScrollLeft(container, orig);
return false;
}
/**
* Returns <code>true</code> if the element is visible using the css
* 'visibiliy' attribute.
*
* @param elem the element
* @return the visible state
*/
public static boolean isVisibility(Element elem) {
return !DOM.getStyleAttribute(elem, "visibility").equals("hidden");
}
/**
* Checks whether the element is currently visible using both visibility and
* display properties.
*
* @return <code>true</code> if the element is currently visible, else
* <code>false</code>
*/
public static boolean isVisible(Element elem) {
if (DOM.getStyleAttribute(elem, "visibility").equals("hidden")) {
return false;
} else if (DOM.getStyleAttribute(elem, "display").equals("none")) {
return false;
} else {
return true;
}
}
/**
* Determines if the visible box or content area is set when sizing elements.
*
* @return <code>true</code> for visible box sizing
*/
public static boolean isVisibleBox() {
return isVisibleBox;
}
/**
* Returns <code>true</code> if the vertical scroll bar is present
*
* @param container the container element
* @return the vertical scroll bar state
*/
public static boolean isVScrollBarShowing(Element container) {
int orig = MyDOM.getScrollLeft(container);
if (orig > 0) {
return true;
}
setScrollLeft(container, 10);
if (MyDOM.getScrollLeft(container) > 0) {
setScrollLeft(container, orig);
return true;
}
setScrollLeft(container, orig);
return false;
}
/**
* Makes an element positionable.
*
* @param elem the element
*/
public static void makePositionable(Element elem) {
String position = DOM.getStyleAttribute(elem, "position");
if (position.equals("") || position.equals("static")) {
DOM.setStyleAttribute(elem, "position", "relative");
}
}
/**
* Returns the offsets between two elements. Both element must be part of the
* DOM tree and not have display:none to have page coordinates.
*
* @param elem the element
* @param to the to element
* @return the xy page offsets
*/
public static Point offsetsTo(Element elem, Element to) {
Point o = getXY(elem);
Point e = getXY(to);
return new Point(o.x - e.x, o.y - e.y);
}
/**
* Removes all the elements children.
*
* @param elem the element
*/
public static void removeChildren(Element elem) {
while (DOM.getChildCount(elem) > 0) {
DOM.removeChild(elem, DOM.getChild(elem, 0));
}
}
public static void removeStyleName(Element elem, String style) {
setStyleName(elem, style, false);
}
/**
* Scrolls the element into view.
*
* @param elem the element to scroll
* @param container the container element
* @param hscroll <code>false</code> to disable horizontal scrolling.
*/
public static native void scrollIntoView(Element elem, Element container,
boolean hscroll) /*-{
var c = container || $doc.body;
var o = @net.mygwt.ui.client.MyDOM::offsetsTo(Lcom/google/gwt/user/client/Element;Lcom/google/gwt/user/client/Element;)(elem, container);
var l = o.@net.mygwt.ui.client.util.Point::x;
var t = o.@net.mygwt.ui.client.util.Point::y;
l = l + c.scrollLeft;
t = t + c.scrollTop;
var b = t + elem.offsetHeight;
var r = l + elem.offsetWidth;
var ch = c.clientHeight;
var ct = parseInt(c.scrollTop, 10);
var cl = parseInt(c.scrollLeft, 10);
var cb = ct + ch;
var cr = cl + c.clientWidth;
if (t < ct){
c.scrollTop = t;
}else if(b > cb){
c.scrollTop = b-ch;
}
c.scrollTop = c.scrollTop;
if(hscroll !== false){
if(l < cl){
c.scrollLeft = l;
} else if(r > cr){
c.scrollLeft = r-c.clientWidth;
}
c.scrollLeft = c.scrollLeft;
}
}-*/;
public static void setBounds(Element elem, int x, int y, int width, int height) {
setBounds(elem, x, y, width, height, false);
}
/**
* Sets the widgets size and location to the rectangular area specified by the
* arguments.
*
* @param elem the element
* @param x the x coordinate
* @param y the y coordinate
* @param width the width
* @param height the height
* @param adjust <code>true</code> to adjust for box model issues
*/
public static void setBounds(Element elem, int x, int y, int width, int height,
boolean adjust) {
Rectangle rect = new Rectangle(x, y, width, height);
setBounds(elem, rect, adjust);
}
/**
* Sets the elements size and location to the specified rectangle.
*
* @param elem the element
* @param rect the rectangle
*/
public static void setBounds(Element elem, Rectangle rect) {
setLocation(elem, rect.x, rect.y);
setSize(elem, rect.width, rect.height);
}
/**
* Sets the widgets size and location to the specified rectangle.
*
* @param elem the element
* @param adjust <code>true</code> to adjust for box model issues
* @param rect the rectangle
*/
public static void setBounds(Element elem, Rectangle rect, boolean adjust) {
setLocation(elem, rect.x, rect.y);
setSize(elem, rect.width, rect.height, adjust);
}
/**
* Sets the elements style attribute.
*
* @param elem the element
* @param style the style
* @param value the new double value
*/
public static void setDoubleStyleAttribute(Element elem, String style, double value) {
setStyleAttribute(elem, style, "" + value);
}
/**
* Sets the focus state of the element.
*
* @param focused the new focus state
*/
public native static void setFocus(Element elem, boolean focused) /*-{
try {
if (focused)
elem.focus();
else
elem.blur();
}
catch(err) {
}
}-*/;
/**
* Sets the element's height.
*
* @param elem the element
* @param height the new height
*/
public static void setHeight(Element elem, int height) {
setHeight(elem, height, false);
}
/**
* Sets the element's height.
*
* @param elem the element
* @param height the new height
* @param adjust <code>true</code> to adjust for box model issue
*/
public static void setHeight(Element elem, int height, boolean adjust) {
height = Math.max(0, height);
if (adjust && !isVisibleBox) {
height -= getDecorationWidth(elem, Style.TOP | Style.BOTTOM);
}
DOM.setIntStyleAttribute(elem, "height", height);
}
/**
* Sets the element's left position directly using CSS style (instead of
* {@link #setX}).
*
* @param elem the element
* @param left the left value
*/
public static void setLeft(Element elem, int left) {
DOM.setIntStyleAttribute(elem, "left", left);
}
/**
* Sets the element's left position directly using CSS style.
*
* @param elem the element
* @param left the left value
* @param top the top value
*/
public static void setLeftTop(Element elem, int left, int top) {
setLeft(elem, left);
setTop(elem, top);
}
/**
* Sets the element position using page coordinates.
*
* @param elem the element
* @param x the x coordinate value
* @param y the y coordinate value
*/
public static void setLocation(Element elem, int x, int y) {
setX(elem, x);
setY(elem, y);
}
/**
* Sets the element's scroll left value.
*
* @param elem the element
* @param top the value
*/
public static void setScrollLeft(Element elem, int left) {
DOM.setElementPropertyInt(elem, "scrollLeft", left);
}
/**
* Sets the element's scroll top value.
*
* @param elem the element
* @param top the value
*/
public static void setScrollTop(Element elem, int top) {
DOM.setElementPropertyInt(elem, "scrollTop", top);
}
/**
* Set the size of the element. Values equal to My.DEFAULT are ignored.
*
* @param elem the element
* @param width the new width
* @param height the new height
*/
public static void setSize(Element elem, int width, int height) {
setSize(elem, width, height, false);
}
/**
* Set the size of the element. Values equal to My.DEFAULT are ignored.
*
* @param elem the element
* @param width the new width
* @param height the new height
* @param adjust <code>true</code> to adjust for box model issues
*/
public static void setSize(Element elem, int width, int height, boolean adjust) {
if (width != Style.DEFAULT) {
setWidth(elem, width, adjust);
}
if (height != Style.DEFAULT) {
setHeight(elem, height, adjust);
}
}
/**
* Sets the element's style attribute.
*
* @param elem the element
* @param attr the attribute
* @param value the value
*/
public static void setStyleAttribute(Element elem, String attr, String value) {
impl.setStyle(elem, attr, value);
}
/**
* Sets the element's style name.
*
* @param elem the element
* @param style the style name
*/
public static void setStyleName(Element elem, String style) {
DOM.setElementProperty(elem, "className", style);
}
/**
* This convenience method adds or removes a style name for a given element.
* This method is typically used to add and remove secondary style names, but
* it can be used to remove primary stylenames as well, but that is not
* recommended.
*
* @param elem the element whose style is to be modified
* @param style the secondary style name to be added or removed
* @param add <code>true</code> to add the given style, <code>false</code>
* to remove it
*/
public static void setStyleName(Element elem, String style, boolean add) {
style = style.trim();
if (style.length() == 0) {
throw new IllegalArgumentException("EMPTY STRING");
}
// Get the current style string.
String oldStyle = DOM.getElementProperty(elem, "className");
int idx = oldStyle.indexOf(style);
// Calculate matching index.
while (idx != -1) {
if (idx == 0 || oldStyle.charAt(idx - 1) == ' ') {
int last = idx + style.length();
int lastPos = oldStyle.length();
if ((last == lastPos) || ((last < lastPos) && (oldStyle.charAt(last) == ' '))) {
break;
}
}
idx = oldStyle.indexOf(style, idx + 1);
}
if (add) {
// Only add the style if it's not already present.
if (idx == -1) {
if (oldStyle.length() > 0) {
oldStyle += " ";
}
DOM.setElementProperty(elem, "className", oldStyle + style);
}
} else {
// Don't try to remove the style if it's not there.
if (idx != -1) {
// Get the leading and trailing parts, without the removed name.
String begin = oldStyle.substring(0, idx).trim();
String end = oldStyle.substring(idx + style.length()).trim();
// Some contortions to make sure we don't leave extra spaces.
String newClassName;
if (begin.length() == 0) {
newClassName = end;
} else if (end.length() == 0) {
newClassName = begin;
} else {
newClassName = begin + " " + end;
}
DOM.setElementProperty(elem, "className", newClassName);
}
}
}
/**
* Sets the element's top position directly using CSS style (instead of
* {@link #setY}).
*
* @param elem the element
* @param top the top value
*/
public static void setTop(Element elem, int top) {
DOM.setIntStyleAttribute(elem, "top", top);
}
/**
* Sets the elements css 'visibility' property. Behavior is different than
* using the 'display' property.
*
* @param elem the element
* @param visible <code>true</code> to show, <code>false</code> to hide
*/
public static void setVisibility(Element elem, boolean visible) {
String value = visible ? "" : "hidden";
DOM.setStyleAttribute(elem, "visibility", value);
}
/**
* Sets the element's css 'display' property.
*
* @param elem the element
* @param visible <code>true</code> to show, <code>false</code> to hide
*/
public static void setVisible(Element elem, boolean visible) {
String value = visible ? "" : "none";
DOM.setStyleAttribute(elem, "display", value);
}
/**
* Sets the element's width.
*
* @param elem the element
* @param width the new width value
*/
public static void setWidth(Element elem, int width) {
setWidth(elem, width, false);
}
/**
* Sets the element's width.
*
* @param elem the element
* @param adjust <code>true</code> to adjust for box model issues
* @param width the new width value
*/
public static void setWidth(Element elem, int width, boolean adjust) {
width = Math.max(0, width);
if (adjust && !isVisibleBox) {
width -= getDecorationWidth(elem, Style.LEFT | Style.RIGHT);
}
DOM.setIntStyleAttribute(elem, "width", width);
}
/**
* Set the x position of the element.
*
* @param elem the element
* @param x the x coordinate
*/
public static void setX(Element elem, int x) {
makePositionable(elem);
int l = DOM.getIntStyleAttribute(elem, "left");
x = x - DOM.getAbsoluteLeft(elem) + l;
if (!isVisibleBox()) {
if (x == 1) x = 0;
x -= getScrollLeft(elem);
}
DOM.setStyleAttribute(elem, "left", x + "px");
}
/**
* Sets the position of the element.
*
* @param elem the element
* @param point the position
*/
public static void setXY(Element elem, Point point) {
setX(elem, point.x);
setY(elem, point.y);
}
/**
* Set the y position of an html element in page coordinates, regardless of
* how the element is positioned. The element must be part of the DOM tree to
* have page coordinates.
*
* @param elem the element
* @param y the y coordinate
*/
public static void setY(Element elem, int y) {
makePositionable(elem);
int t = DOM.getIntStyleAttribute(elem, "top");
y = y - DOM.getAbsoluteTop(elem) + t;
if (!isVisibleBox()) {
if (y == 1) y = 0;
y -= getScrollTop(elem);
}
DOM.setStyleAttribute(elem, "top", y + "px");
}
/**
* Unwraps the child element.
*
* @param bounds the original bounds
*/
public static void unwrap(Element wrapper, Element child, Rectangle bounds) {
MyDOM.setTop(child, bounds.y);
MyDOM.setLeft(child, bounds.x);
Element p = DOM.getParent(wrapper);
DOM.removeChild(p, wrapper);
DOM.appendChild(p, child);
}
/**
* Wraps the element with the specified wrapper. The wrapper will have the
* same size and position of the element. The original bounds can be used to
* 'unwrap' the element.
*
* @param wrapper the wrapper element
* @return the original bounds
*/
public static Rectangle wrap(Element elem, Element wrapper) {
MyDOM.setVisible(wrapper, false);
String pos = DOM.getStyleAttribute(elem, "position");
MyDOM.setStyleAttribute(wrapper, "position", pos);
int l = MyDOM.getLeft(elem);
int t = MyDOM.getTop(elem);
MyDOM.setLeft(elem, 5000);
MyDOM.setVisible(elem, true);
int h = getComputedHeight(elem);
int w = getComputedWidth(elem);
MyDOM.setLeft(elem, 1);
MyDOM.setStyleAttribute(elem, "overflow", "hidden");
MyDOM.setVisible(elem, false);
MyDOM.insertBefore(wrapper, elem);
DOM.appendChild(wrapper, elem);
MyDOM.setStyleAttribute(wrapper, "overflow", "hidden");
MyDOM.setLeft(wrapper, l);
MyDOM.setTop(wrapper, t);
MyDOM.setTop(elem, 0);
MyDOM.setLeft(elem, 0);
return new Rectangle(l, t, w, h);
}
private static native boolean isVisibleBoxInternal() /*-{
if (!$wnd.isVisibleBox) {
var d = $wnd.document;
var test = d.createElement('div');
d.body.appendChild(test);
test.style.position = "absolute";
test.style.border = "2px solid";
test.style.height = "50";
$wnd.isVisibleValue = test.offsetHeight == 50 ? true : false;
$wnd.isVisibleBox = true;
d.body.removeChild(test);
}
return $wnd.isVisibleValue;
}-*/;
private native static void nativeSetTextSelect(Element e, boolean select)/*-{
if (!select) {
e.ondrag = function () { return false; };
e.onselectstart = function () { return false; };
} else {
e.ondrag = null;
e.onselectstart = null;
}
}-*/;
private MyDOM() {
}
}