View Javadoc

1   /*
2    * Ext GWT 2.2.5 - Ext for GWT
3    * Copyright(c) 2007-2010, Ext JS, LLC.
4    * licensing@extjs.com
5    * 
6    * http://extjs.com/license
7    */
8   package com.extjs.gxt.ui.client.core;
9   
10  import java.util.ArrayList;
11  import java.util.Arrays;
12  import java.util.List;
13  import java.util.Map;
14  import java.util.Set;
15  
16  import com.extjs.gxt.ui.client.GXT;
17  import com.extjs.gxt.ui.client.Style;
18  import com.extjs.gxt.ui.client.Style.Direction;
19  import com.extjs.gxt.ui.client.Style.ScrollDir;
20  import com.extjs.gxt.ui.client.core.impl.ComputedStyleImpl;
21  import com.extjs.gxt.ui.client.fx.BaseEffect;
22  import com.extjs.gxt.ui.client.fx.Fx;
23  import com.extjs.gxt.ui.client.fx.FxConfig;
24  import com.extjs.gxt.ui.client.fx.Move;
25  import com.extjs.gxt.ui.client.util.Format;
26  import com.extjs.gxt.ui.client.util.Margins;
27  import com.extjs.gxt.ui.client.util.Markup;
28  import com.extjs.gxt.ui.client.util.Padding;
29  import com.extjs.gxt.ui.client.util.Point;
30  import com.extjs.gxt.ui.client.util.Rectangle;
31  import com.extjs.gxt.ui.client.util.Region;
32  import com.extjs.gxt.ui.client.util.Scroll;
33  import com.extjs.gxt.ui.client.util.Size;
34  import com.extjs.gxt.ui.client.util.TextMetrics;
35  import com.extjs.gxt.ui.client.util.Util;
36  import com.google.gwt.core.client.GWT;
37  import com.google.gwt.core.client.JavaScriptObject;
38  import com.google.gwt.dom.client.Document;
39  import com.google.gwt.dom.client.NodeList;
40  import com.google.gwt.http.client.Request;
41  import com.google.gwt.http.client.RequestBuilder;
42  import com.google.gwt.http.client.RequestCallback;
43  import com.google.gwt.http.client.Response;
44  import com.google.gwt.user.client.Command;
45  import com.google.gwt.user.client.DOM;
46  import com.google.gwt.user.client.DeferredCommand;
47  import com.google.gwt.user.client.Element;
48  
49  /**
50   * Represents an Element in the DOM.
51   */
52  @SuppressWarnings("deprecation")
53  public class El {
54  
55    /**
56     * VisMode enumeration. Specifies the the element should hidden using the CSS
57     * display or visibility style.
58     * 
59     */
60    public enum VisMode {
61      DISPLAY, VISIBILITY
62    }
63  
64    private static Map<String, Boolean> borderBoxMap = new FastMap<Boolean>();
65  
66    /**
67     * The globally shared El instance.
68     */
69    private static Map<String, El> flyweights = new FastMap<El>();
70  
71    private static ComputedStyleImpl computedStyle = GWT.create(ComputedStyleImpl.class);
72    private static JavaScriptObject leftRightTest;
73    private static JavaScriptObject removeStyleNameReCache;
74  
75    static {
76      GXT.init();
77    }
78  
79    /**
80     * Tests to see if the value has units, otherwise appends the default (px).
81     * 
82     * @param v the value
83     * @return the value with units
84     */
85    public native static String addUnits(String v, String defaultUnit) /*-{
86  		if (v === "" || v == "auto") {
87  			return v;
88  		}
89  		if (v === undefined) {
90  			return '';
91  		}
92  		if (typeof v == "number"
93  				|| !/\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i.test(v)) {
94  			return v + (defaultUnit || 'px');
95  		}
96  		return v;
97    }-*/;
98  
99    public static El fly(com.google.gwt.dom.client.Element element) {
100     return fly(element, "_global");
101   }
102 
103   /**
104    * Gets the globally shared flyweight El, with the passed node as the active
105    * element. Do not store a reference to this element - the dom node can be
106    * overwritten by other code.
107    * 
108    * @param element the element
109    * @return the el instance
110    */
111   public static El fly(com.google.gwt.dom.client.Element element, String s) {
112     assert element != null : "Element my not be null";
113     El g = flyweights.get(s);
114     if (g == null) {
115       g = new El(DOM.createDiv());
116       flyweights.put(s, g);
117     }
118     g.dom = (Element) element;
119     return g;
120   }
121 
122   public static El fly(Element element) {
123     return fly(element, "_global");
124   }
125 
126   /**
127    * Gets the globally shared flyweight El, with the passed node as the active
128    * element. Do not store a reference to this element - the dom node can be
129    * overwritten by other code.
130    * 
131    * @param element the element to be wrapped
132    * @return the global El object
133    */
134   public static El fly(Element element, String s) {
135     assert element != null : "Element my not be null";
136     El g = flyweights.get(s);
137     if (g == null) {
138       g = new El(DOM.createDiv());
139       flyweights.put(s, g);
140     }
141     g.dom = (Element) element;
142     return g;
143   }
144 
145   /**
146    * Returns true if the passed element has a border box.
147    * 
148    * @param element the element to test
149    * @return true if the passed element has a border box
150    */
151   public static boolean isBorderBox(Element element) {
152     assert element != null : "Element may not be null";
153     String tag = element.getTagName().toLowerCase();
154     Boolean r = borderBoxMap.get(tag);
155     if (r == null) {
156       Element testElement = (Element) Document.get().createElement(tag);
157       testElement.getStyle().setPropertyPx("padding", 1);
158       testElement.getStyle().setPropertyPx("width", 100);
159       testElement.getStyle().setProperty("visibility", "hidden");
160       testElement.getStyle().setProperty("position", "absolute");
161       XDOM.getBody().appendChild(testElement);
162       r = testElement.getOffsetWidth() == 100;
163       XDOM.getBody().removeChild(testElement);
164       borderBoxMap.put(tag, r);
165     }
166     return r;
167   }
168 
169   private native static void disableTextSelectInternal(Element e, boolean disable)/*-{
170 		if (disable) {
171 			e.ondrag = function(evt) {
172 				var targ;
173 				if (!evt)
174 					evt = $wnd.event;
175 				if (evt.target)
176 					targ = evt.target;
177 				else if (evt.srcElement)
178 					targ = evt.srcElement;
179 				if (targ.nodeType == 3) // defeat Safari bug
180 					targ = targ.parentNode;
181 				if (targ.tagName == 'INPUT' || targ.tagName == 'TEXTAREA') {
182 					return true;
183 				}
184 				return false;
185 			};
186 			e.onselectstart = function(evt) {
187 				var targ;
188 				if (!evt)
189 					evt = $wnd.event;
190 				if (evt.target)
191 					targ = evt.target;
192 				else if (evt.srcElement)
193 					targ = evt.srcElement;
194 				if (targ.nodeType == 3) // defeat Safari bug
195 					targ = targ.parentNode;
196 				if (targ.tagName == 'INPUT' || targ.tagName == 'TEXTAREA') {
197 					return true;
198 				}
199 				return false;
200 			};
201 		} else {
202 			e.ondrag = null;
203 			e.onselectstart = null;
204 		}
205   }-*/;
206 
207   /**
208    * The wrapped dom element.
209    */
210   public Element dom;
211 
212   private VisMode visiblityMode = VisMode.DISPLAY;
213 
214   private String originalDisplay = "block";
215   private El _mask;
216   private El _maskMsg;
217   private boolean isClipped;
218   private String[] originalClipped;
219 
220   /**
221    * Creates a new el instance.
222    * 
223    * @param element the element to be wrapped
224    */
225   public El(Element element) {
226     assert element != null : "The element may not be null";
227     this.dom = element;
228   }
229 
230   /**
231    * Creates a new El instance from the HTML fragment.
232    * 
233    * @param html the html
234    */
235   public El(String html) {
236     this(XDOM.create(html));
237   }
238 
239   /**
240    * Adds the event type to the element's sunk events.
241    * 
242    * @param event the events to add
243    * @return this
244    */
245   public El addEventsSunk(int event) {
246     int bits = DOM.getEventsSunk(dom);
247     DOM.sinkEvents(dom, bits | event);
248     return this;
249   }
250 
251   /**
252    * Adds the style name to the element. Duplicate styles are automatically
253    * filtered out.
254    * 
255    * @param styleNames the new style names
256    * @return this
257    */
258   public El addStyleName(String... styleNames) {
259     if (styleNames != null) {
260       for (String styleName : styleNames) {
261         if (styleName != null && !hasStyleName(styleName)) {
262           styleName = styleName.trim();
263           /* begin laaglu */
264 //        dom.setClassName(dom.getClassName() + " " + styleName);
265           setClassName(dom, getClassName(dom) + " " + styleName);
266           /* end laaglu */        }
267       }
268     }
269     return this;
270   }
271 
272   /**
273    * Toggles the given style name, adding if not already present, removing if
274    * present.
275    * 
276    * @param styleName the style name to toggle
277    * @return this
278    */
279   public El toggleStyleName(String styleName) {
280     if (hasStyleName(styleName)) {
281       removeStyleName(styleName);
282     } else {
283       addStyleName(styleName);
284     }
285     return this;
286   }
287 
288   /**
289    * Ensures the element is within the browser viewport.
290    * 
291    * @param p the target destination
292    * @return the new location
293    */
294   public Point adjustForConstraints(Point p) {
295     return getConstrainToXY(XDOM.getBody(), p);
296   }
297 
298   /**
299    * Aligns the element with another element relative to the specified anchor
300    * points. Two values from the table below should be passed separated by a
301    * dash, the first value is used as the element's anchor point, and the second
302    * value is used as the target's anchor point.
303    * <p>
304    * In addition to the anchor points, the position parameter also supports the
305    * "?" character. If "?" is passed at the end of the position string, the
306    * element will attempt to align as specified, but the position will be
307    * adjusted to constrain to the viewport if necessary. Note that the element
308    * being aligned might be swapped to align to a different position than that
309    * specified in order to enforce the viewport constraints. Following are all
310    * of the supported anchor positions:
311    * </p>
312    * <dl>
313    * <dt>Following are all of the supported anchor positions:</dt>
314    * </dl>
315    * <code><pre>
316    *  Value  Description
317    *  -----  -----------------------------
318    *  tl     The top left corner (default)
319    *  t      The center of the top edge
320    *  tr     The top right corner
321    *  l      The center of the left edge
322    *  c      In the center of the element
323    *  r      The center of the right edge
324    *  bl     The bottom left corner
325    *  b      The center of the bottom edge
326    *  br     The bottom right corner
327    * </code></pre>
328    * 
329    * @param align the element to align to
330    * @param pos the position to align to
331    * @param offsets the offsets or <code>null</code>
332    * @return this
333    */
334   public El alignTo(Element align, String pos, int[] offsets) {
335     if (offsets == null) {
336       offsets = new int[] {0, 0};
337     }
338     Point p = getAlignToXY(align, pos, offsets);
339     setXY(p);
340     return this;
341   }
342 
343   /**
344    * Appends a element.
345    * 
346    * @param child the element to add
347    * @return the child element
348    */
349   public El appendChild(Element child) {
350     dom.appendChild(child);
351     return new El(child);
352   }
353 
354   /**
355    * More flexible version of {@link #setStyleAttribute} for setting style
356    * properties. Style attribute names must be in lower camel case, e.g.
357    * "backgroundColor:white"
358    * 
359    * @param styles a style specification string
360    * @return this
361    */
362   public native El applyStyles(String styles) /*-{
363 		var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
364 		var matches;
365 		while ((matches = re.exec(styles)) != null) {
366 			this.@com.extjs.gxt.ui.client.core.El::setStyleAttribute(Ljava/lang/String;Ljava/lang/Object;)(matches[1], matches[2]);
367 		}
368 		return this;
369   }-*/;
370 
371   /**
372    * Blinks the element.
373    * 
374    * @param config the fx config
375    * @return this
376    */
377   public El blink(FxConfig config) {
378     BaseEffect.blink(this, config, 50);
379     return this;
380   }
381 
382   /**
383    * Removes focus.
384    * 
385    * @return this
386    */
387   public El blur() {
388     return setFocus(false);
389   }
390 
391   /**
392    * Wraps the specified element with a special markup/CSS block.
393    * 
394    * @param style a base CSS class to apply to the containing wrapper element
395    *          (defaults to 'x-box').
396    * @return this
397    */
398   public El boxWrap(String style) {
399     String s = style != null ? style : "x-box";
400     El temp = insertHtml("beforeBegin", Format.substitute("<div class={0}>" + Markup.BBOX, s) + "</div>");
401     temp.child("." + s + "-mc").appendChild(dom);
402     return temp;
403   }
404 
405   /**
406    * Centers the element in the viewport.
407    * 
408    * @return this
409    */
410   public El center() {
411     return center(null);
412   }
413 
414   /**
415    * Centers the element.
416    * 
417    * @param constrainViewport true to constrain the element position to the
418    *          viewport.
419    * @return this
420    */
421   public El center(boolean constrainViewport) {
422     return alignTo(XDOM.getBody(), "c-c" + (constrainViewport ? "?" : ""), null);
423   }
424 
425   /**
426    * Centers an element.
427    * 
428    * @param container the container element
429    * @return this
430    */
431   public El center(Element container) {
432     if (container == null) {
433       container = XDOM.getBody();
434     }
435     return alignTo(container, "c-c", null);
436   }
437 
438   /**
439    * Selects a single child at any depth below this element based on the passed
440    * CSS selector.
441    * 
442    * @param selector the css selector
443    * @return the child element
444    */
445   public El child(String selector) {
446     Element child = childElement(selector);
447     return child == null ? null : new El(child);
448   }
449 
450   /**
451    * Selects a single child at any depth below this element based on the passed
452    * CSS selector.
453    * 
454    * @param selector the css selector
455    * @return the child element
456    */
457   public Element childElement(String selector) {
458     return DomQuery.selectNode(selector, dom);
459   }
460 
461   /**
462    * Returns the element's child.
463    * 
464    * @param index the index of the child element
465    * @return the child element
466    */
467   public El childNode(int index) {
468     Element e = DOM.getChild(dom, index);
469     return e == null ? null : new El(e);
470   }
471 
472   /**
473    * Clears the set opacity correctly. This is mostly needed only on IE.
474    * 
475    * @return this
476    */
477   public native El clearOpacity() /*-{
478 		var dom = this.@com.extjs.gxt.ui.client.core.El::dom;
479 		var style = dom.style;
480 		if (@com.extjs.gxt.ui.client.GXT::isIE) {
481 			dom.style.filter = (dom.style.filter || '').replace(
482 					/alpha\([^\)]*\)/gi, "");
483 		} else {
484 			style.opacity = style['-moz-opacity'] = style['-khtml-opacity'] = '';
485 		}
486 		return this;
487   }-*/;
488 
489   /**
490    * Generators a native dom click on the element.
491    * 
492    * @return this
493    */
494   public native El click() /*-{
495 		var dom = this.@com.extjs.gxt.ui.client.core.El::dom;
496 		if (dom.click) {
497 			dom.click();
498 		} else {
499 			var event = $doc.createEvent("MouseEvents");
500 			event.initEvent('click', true, true, $wnd, 0, 0, 0, 0, 0, false,
501 					false, false, false, 1, dom);
502 			dom.dispatchEvent(event);
503 		}
504 		return this;
505   }-*/;
506 
507   /**
508    * Clips overflow on the element.
509    * 
510    * @return this
511    */
512   public El clip() {
513     if (!isClipped) {
514       isClipped = true;
515       originalClipped = new String[3];
516       originalClipped[0] = getStyleAttribute("overflow");
517       originalClipped[1] = getStyleAttribute("overflowX");
518       originalClipped[2] = getStyleAttribute("overflowY");
519       setStyleAttribute("overflow", "hidden");
520       setStyleAttribute("overflowX", "hidden");
521       setStyleAttribute("overflowY", "hidden");
522     }
523     return this;
524   }
525 
526   /**
527    * Clones the element.
528    * 
529    * @param deep true to clone children
530    * @return the new element
531    */
532   public Element cloneNode(boolean deep) {
533     return (Element) dom.cloneNode(deep);
534   }
535 
536   /**
537    * Creates and adds a child using the HTML fragment.
538    * 
539    * @param html the html fragment
540    * @return the new child
541    */
542   public El createChild(String html) {
543     return appendChild(XDOM.create(html));
544   }
545 
546   /**
547    * Creates and inserts a child using the HTML fragment.
548    * 
549    * @param html the html fragment
550    * @param insertBefore a child element of this element
551    * @return the new child
552    */
553   public El createChild(String html, Element insertBefore) {
554     Element element = XDOM.create(html);
555     int idx = DOM.getChildIndex(dom, insertBefore);
556     insertChild(element, idx);
557     return new El(element);
558   }
559 
560   /**
561    * Disables the element.
562    * 
563    * @return this
564    */
565   public El disable() {
566     dom.setPropertyBoolean("disabled", true);
567     return this;
568   }
569 
570   /**
571    * Enables and disables the browsers default context menu for the specified
572    * element.A circular reference will be created when disabling text selection.
573    * Disabling should be cleared when the element is detached. See the
574    * <code>Component</code> source for an example.
575    * 
576    * @param disable true to disable, false to enable
577    * @return this
578    */
579   public native El disableContextMenu(boolean disable) /*-{
580 		var e = this.@com.extjs.gxt.ui.client.core.El::dom;
581 		e.oncontextmenu = disable ? function() {
582 			return false
583 		} : null;
584 		return this;
585   }-*/;
586 
587   /**
588    * Enables or disables text selection for the element. A circular reference
589    * will be created when disabling text selection. Disabling should be cleared
590    * when the element is detached. See the <code>Component</code> source for an
591    * example.
592    * 
593    * @param disable true to disable, false to enable
594    * @return this
595    */
596   public El disableTextSelection(boolean disable) {
597     setStyleName("x-unselectable", disable);
598     setElementAttribute("unselectable", disable ? "on" : "");
599     disableTextSelectInternal(dom, disable);
600     return this;
601   }
602 
603   /**
604    * Selects a single *direct* child based on the passed CSS selector (the
605    * selector should not contain an id).
606    * 
607    * @param selector the CSS selector
608    * @return the child element
609    */
610   public El down(String selector) {
611     Element elem = DomQuery.selectNode(" > " + selector, dom);
612     if (elem != null) {
613       return new El(elem);
614     }
615     return null;
616   }
617 
618   /**
619    * Enables the element.
620    * 
621    * @return this
622    */
623   public El enable() {
624     dom.setPropertyBoolean("disabled", false);
625     return this;
626   }
627 
628   /**
629    * Convenience method for setVisibilityMode(VisibilityMode.DISPLAY).
630    * 
631    * @param display what to set display to when visible
632    * @return this
633    */
634   public El enableDisplayMode(String display) {
635     setVisibilityMode(VisMode.DISPLAY);
636     if (display != null) {
637       originalDisplay = display;
638     }
639     return this;
640   }
641 
642   @Override
643   public boolean equals(Object obj) {
644     if (obj instanceof El) {
645       return getId().equals(((El) obj).getId());
646     }
647     return super.equals(obj);
648   }
649 
650   /**
651    * Fades in the element.
652    * 
653    * @param config the fx config
654    * @return this
655    */
656   public El fadeIn(FxConfig config) {
657     BaseEffect.fadeIn(this, config);
658     return this;
659   }
660 
661   /**
662    * Fades out the element.
663    * 
664    * @param config the fx config
665    * @return this
666    */
667   public El fadeOut(FxConfig config) {
668     BaseEffect.fadeOut(this, config);
669     return this;
670   }
671 
672   /**
673    * Toggles the element visibility using a fade effect.
674    * 
675    * @param config the fx config
676    * @return this
677    */
678   public El fadeToggle(FxConfig config) {
679     if (!isVisible()) {
680       BaseEffect.fadeIn(this, config);
681     } else {
682       BaseEffect.fadeOut(this, config);
683     }
684     return this;
685   }
686 
687   /**
688    * Looks at this node and then at parent nodes for a match of the passed
689    * simple selector (e.g. div.some-class or span:first-child).
690    * 
691    * @param selector the simple selector to test
692    * @return the matching element
693    */
694   public El findParent(String selector, int maxDepth) {
695     Element elem = findParentElement(selector, maxDepth);
696     if (elem == null) {
697       return null;
698     }
699     return new El(elem);
700   }
701 
702   /**
703    * Looks at this node and then at parent nodes for a match of the passed
704    * simple selector (e.g. div.some-class or span:first-child).
705    * 
706    * @param selector the simple selector to test
707    * @param maxDepth the max depth
708    * @return the matching element
709    */
710   public Element findParentElement(String selector, int maxDepth) {
711     Element p = dom;
712     Element b = XDOM.getBody();
713     int depth = 0;
714     while (p != null && p.getNodeType() == 1 && (maxDepth == -1 || depth < maxDepth) && p != b) {
715       if (DomQuery.is(p, selector)) {
716         return p;
717       }
718       depth++;
719       p = (Element) p.getParentElement();
720     }
721     return null;
722   }
723 
724   /**
725    * Returns the element's first child.
726    * 
727    * @return the first child
728    */
729   public El firstChild() {
730     Element firstChild = DOM.getFirstChild(dom);
731     return firstChild == null ? null : new El(firstChild);
732   }
733 
734   /**
735    * Tries to focus the element.
736    * 
737    * @return this
738    */
739   public El focus() {
740     return setFocus(true);
741   }
742 
743   public Point getAlignToXY(Element elem, String p, int ox, int oy) {
744     El el = new El(elem);
745 
746     if (p == null) {
747       p = "tl-bl";
748     } else if (p.equals("?")) {
749       p = "tl-bl?";
750     } else if (p.indexOf("-") == -1) {
751       p = "tl-" + p;
752     }
753     p = p.toLowerCase();
754     boolean c = false;
755     String p1 = p.substring(0, p.indexOf("-"));
756     String p2 = p.substring(p.indexOf("-") + 1, ((c = p.contains("?")) ? p.indexOf("?") : p.length()));
757     // Subtract the aligned el's internal xy from the target's offset xy
758     // plus custom offset to get the aligned el's new offset xy
759     Point a1 = getAnchorXY(p1, true);
760     Point a2 = el.getAnchorXY(p2, false);
761 
762     int x = a2.x - a1.x + ox;
763     int y = a2.y - a1.y + oy;
764 
765     if (c) {
766       // constrain the aligned el to viewport if necessary
767       int w = getWidth();
768       int h = getHeight();
769       Region r = el.getRegion();
770       // 5px of margin for ie
771       int dw = XDOM.getViewWidth(false) - 10;
772       int dh = XDOM.getViewHeight(false) - 10;
773 
774       // If we are at a viewport boundary and the aligned el is anchored on a
775       // target border that is
776       // perpendicular to the vp border, allow the aligned el to slide on that
777       // border,
778       // otherwise swap the aligned el to the opposite border of the target.
779       char p1y = p1.charAt(0), p1x = p1.charAt(p1.length() - 1);
780       char p2y = p2.charAt(0), p2x = p2.charAt(p2.length() - 1);
781 
782       boolean swapY = ((p1y == 't' && p2y == 'b') || (p1y == 'b' && p2y == 't'));
783       boolean swapX = ((p1x == 'r' && p2x == 'l') || (p1x == 'l' && p2x == 'r'));
784 
785       int scrollX = XDOM.getBodyScrollLeft() + 5;
786       int scrollY = XDOM.getBodyScrollTop() + 5;
787 
788       if ((x + w) > dw + scrollX) {
789         x = swapX ? r.left - w : dw + scrollX - w;
790       }
791       if (x < scrollX) {
792         x = swapX ? r.right : scrollX;
793       }
794 
795       if ((y + h) > (dh + scrollY)) {
796         y = swapY ? r.top - h : dh + scrollY - h;
797       }
798       if (y < scrollY) {
799         y = swapY ? r.bottom : scrollY;
800       }
801     }
802 
803     return new Point(x, y);
804   }
805 
806   /**
807    * Gets the x,y coordinates to align this element with another element. See
808    * {@link #alignTo} for more info on the supported position values.
809    * 
810    * @param align the element to align to
811    * @param pos the position to align to
812    * @param offsets the offsets or <code>null</code>
813    * @return the point
814    */
815   public Point getAlignToXY(Element align, String pos, int[] offsets) {
816     if (offsets == null) {
817       offsets = new int[] {0, 0};
818     }
819     return getAlignToXY(align, pos, offsets[0], offsets[1]);
820   }
821 
822   /**
823    * Returns the x,y coordinates specified by the anchor position on the
824    * element.
825    * 
826    * @param anchor the specified anchor position (defaults to "c"). See
827    *          {@link #alignTo} for details on supported anchor positions.
828    * @param local <code>true</code> to get the local (element top/left-relative)
829    *          anchor position instead of page coordinates
830    * @return the position
831    */
832   public Point getAnchorXY(String anchor, boolean local) {
833     if (anchor == null) {
834       return null;
835     }
836     boolean vp = false;
837     int w;
838     int h;
839     if (dom == XDOM.getBody() || dom == XDOM.getDocument()) {
840       vp = true;
841       w = XDOM.getViewWidth(false);
842       h = XDOM.getViewHeight(false);
843     } else {
844       w = getWidth();
845       h = getHeight();
846     }
847 
848     int x = 0, y = 0;
849     if (anchor.length() == 1) {
850       if ("c".equalsIgnoreCase(anchor)) {
851         x = (int) Math.round(w * .5);
852         y = (int) Math.round(h * .5);
853       } else if ("t".equalsIgnoreCase(anchor)) {
854         x = (int) Math.round(w * .5);
855         y = 0;
856       } else if ("l".equalsIgnoreCase(anchor)) {
857         x = 0;
858         y = (int) Math.round(h * .5);
859       } else if ("r".equalsIgnoreCase(anchor)) {
860         x = w;
861         y = (int) Math.round(h * .5);
862       } else if ("b".equalsIgnoreCase(anchor)) {
863         x = (int) Math.round(w * .5);
864         y = h;
865       }
866     } else {
867       if ("tl".equalsIgnoreCase(anchor)) {
868         x = 0;
869         y = 0;
870       } else if ("bl".equalsIgnoreCase(anchor)) {
871         x = 0;
872         y = h;
873       } else if ("br".equalsIgnoreCase(anchor)) {
874         x = w;
875         y = h;
876       } else if ("tr".equalsIgnoreCase(anchor)) {
877         x = w;
878         y = 0;
879       }
880     }
881 
882     if (local) {
883       return new Point(x, y);
884     }
885     if (vp) {
886       Scroll sc = getScroll();
887       return new Point(x + sc.getScrollLeft(), y + sc.getScrollTop());
888     }
889     // Add the element's offset xy
890 
891     Point o = getXY();
892     return new Point(x + o.x, y + o.y);
893   }
894 
895   /**
896    * Returns the width of the border(s) for the specified side(s).
897    * 
898    * @param sides can be t, l, r, b or any combination of those to add multiple
899    *          values. For example, passing lr would get the border (l)eft width
900    *          + the border (r)ight width.
901    * @return the width of the sides passed added together
902    */
903   public int getBorderWidth(String sides) {
904     double borderWidth = 0;
905     List<String> list = new ArrayList<String>();
906     if (sides.contains("l")) {
907       list.add("borderLeftWidth");
908     }
909     if (sides.contains("r")) {
910       list.add("borderRightWidth");
911     }
912     if (sides.contains("t")) {
913       list.add("borderTopWidth");
914     }
915     if (sides.contains("b")) {
916       list.add("borderBottomWidth");
917     }
918     FastMap<String> map = getStyleAttribute(list);
919     for (String s : map.keySet()) {
920       borderWidth += Util.parseFloat(map.get(s), 0);
921     }
922     return (int) Math.round(borderWidth);
923   }
924 
925   /**
926    * Returns the bottom Y coordinate of the element (element Y position +
927    * element height).
928    * 
929    * @param local
930    * @return the bottom value
931    */
932   public int getBottom(boolean local) {
933     return getHeight() + (local ? getTop() : getY());
934   }
935 
936   /**
937    * Returns the elements bounds in page coordinates.
938    * 
939    * @return the bounds
940    */
941   public Rectangle getBounds() {
942     return getBounds(false, false);
943   }
944 
945   /**
946    * Returns the elements bounds in page coordinates.
947    * 
948    * @param local if true the element's left and top are returned instead of
949    *          page coordinates
950    * 
951    * @return the bounds
952    */
953   public Rectangle getBounds(boolean local) {
954     return getBounds(local, false);
955   }
956 
957   /**
958    * Returns the element's bounds in page coordinates.
959    * 
960    * @param local if true the element's left and top are returned instead of
961    *          page coordinates
962    * @param adjust if true sizes get adjusted
963    * 
964    * @return the element's bounds
965    */
966   public Rectangle getBounds(boolean local, boolean adjust) {
967     Size s = getSize(adjust);
968     Rectangle rect = new Rectangle();
969     rect.width = s.width;
970     rect.height = s.height;
971     if (local) {
972       rect.x = getLeft(true);
973       rect.y = getTop(true);
974     } else {
975       Point p = getXY();
976       rect.x = p.x;
977       rect.y = p.y;
978     }
979     return rect;
980   }
981 
982   /**
983    * Returns a child element.
984    * 
985    * @param index the child index
986    * @return the child
987    */
988   public El getChild(int index) {
989     Element child = getChildElement(index);
990     return child == null ? null : new El(child);
991   }
992 
993   /**
994    * Returns a child element.
995    * 
996    * @param index the child index
997    * @return the child
998    */
999   public Element getChildElement(int index) {
1000     return DOM.getChild(dom, index);
1001   }
1002 
1003   /**
1004    * Returns the index of the child element.
1005    * 
1006    * @return the index
1007    */
1008   public int getChildIndex(Element child) {
1009     return DOM.getChildIndex(dom, child);
1010   }
1011 
1012   /**
1013    * Returns the element's client height property.
1014    * 
1015    * @return the client width value
1016    */
1017   public int getClientHeight() {
1018     return DOM.getElementPropertyInt(dom, "clientHeight");
1019   }
1020 
1021   /**
1022    * Returns the element's client width property.
1023    * 
1024    * @return the client width value
1025    */
1026   public int getClientWidth() {
1027     return DOM.getElementPropertyInt(dom, "clientWidth");
1028   }
1029 
1030   /**
1031    * Returns either the offsetHeight or the height of this element based on it's
1032    * CSS height.
1033    * 
1034    * @return the height
1035    */
1036   public int getComputedHeight() {
1037     int h = getHeight();
1038     if (h == 0) {
1039       h = getIntStyleAttribute("height");
1040     }
1041     return h;
1042   }
1043 
1044   /**
1045    * Returns either the offsetWidth or the width of this element based on it's
1046    * CSS width.
1047    * 
1048    * @return the width
1049    */
1050   public int getComputedWidth() {
1051     int w = getWidth();
1052     if (w == 0) {
1053       w = getIntStyleAttribute("width");
1054     }
1055     return w;
1056   }
1057 
1058   /**
1059    * Returns the sum width of the padding and borders for all "sides". See
1060    * #getBorderWidth() for more information about the sides.
1061    * 
1062    * @return the frame size
1063    */
1064   public Size getFrameSize() {
1065     double width = 0;
1066     double height = 0;
1067     List<String> list = new ArrayList<String>();
1068     list.add("paddingLeft");
1069     list.add("borderLeftWidth");
1070 
1071     list.add("paddingRight");
1072     list.add("borderRightWidth");
1073 
1074     list.add("paddingTop");
1075     list.add("borderTopWidth");
1076 
1077     list.add("paddingBottom");
1078     list.add("borderBottomWidth");
1079 
1080     FastMap<String> map = getStyleAttribute(list);
1081     for (String s : map.keySet()) {
1082       if (isLeftorRight(s)) {
1083         width += Util.parseFloat(map.get(s), 0);
1084       } else {
1085         height += Util.parseFloat(map.get(s), 0);
1086       }
1087     }
1088     return new Size((int) Math.round(width), (int) Math.round(height));
1089   }
1090 
1091   /**
1092    * Returns the sum width of the padding and borders for the passed "sides".
1093    * See #getBorderWidth() for more information about the sides.
1094    * 
1095    * @param sides sides
1096    * @return the width
1097    */
1098   public int getFrameWidth(String sides) {
1099     double frameWidth = 0;
1100     List<String> list = new ArrayList<String>();
1101     if (sides.contains("l")) {
1102       list.add("paddingLeft");
1103       list.add("borderLeftWidth");
1104     }
1105     if (sides.contains("r")) {
1106       list.add("paddingRight");
1107       list.add("borderRightWidth");
1108     }
1109     if (sides.contains("t")) {
1110       list.add("paddingTop");
1111       list.add("borderTopWidth");
1112     }
1113     if (sides.contains("b")) {
1114       list.add("paddingBottom");
1115       list.add("borderBottomWidth");
1116     }
1117     FastMap<String> map = getStyleAttribute(list);
1118     for (String s : map.keySet()) {
1119       frameWidth += Util.parseFloat(map.get(s), 0);
1120     }
1121     return (int) Math.round(frameWidth);
1122   }
1123 
1124   /**
1125    * Returns the offset height of the element.
1126    * 
1127    * @return the height
1128    */
1129   public int getHeight() {
1130     return dom.getOffsetHeight();
1131   }
1132 
1133   /**
1134    * Returns the element's height.
1135    * 
1136    * @param content true to get the height minus borders and padding
1137    * @return the element's height
1138    */
1139   public int getHeight(boolean content) {
1140     int h = getHeight();
1141     if (content) {
1142       h -= getFrameWidth("tb");
1143     }
1144     return Math.max(0, h);
1145   }
1146 
1147   /**
1148    * Returns the element's id.
1149    * 
1150    * @return the id
1151    */
1152   public String getId() {
1153     String id = DOM.getElementProperty(dom, "id");
1154     if (id == null || (id != null && id.length() == 0)) {
1155       id = XDOM.getUniqueId();
1156       setId(id);
1157     }
1158     return id;
1159   }
1160 
1161   /**
1162    * Returns the element's inner HTML.
1163    * 
1164    * @return the inner html
1165    */
1166   public String getInnerHtml() {
1167     return DOM.getInnerHTML(dom);
1168   }
1169 
1170   /**
1171    * Returns the element's style value.
1172    * 
1173    * @param attr the attribute name
1174    * @return the value
1175    */
1176   public int getIntStyleAttribute(String attr) {
1177     String v = DOM.getStyleAttribute(dom, attr);
1178     if (v == null || v.equals("")) {
1179       return 0;
1180     }
1181     return Util.parseInt(v, 0);
1182   }
1183 
1184   /**
1185    * Returns the element's content area bounds.
1186    * 
1187    * @return the bounds
1188    */
1189   public Rectangle getLayoutBounds() {
1190     Rectangle r = getBounds();
1191     r.width -= getFrameWidth("lr");
1192     r.height -= getFrameWidth("tb");
1193     return r;
1194   }
1195 
1196   /**
1197    * Returns the top Y coordinate.
1198    * 
1199    * @return the top value
1200    */
1201   public int getLeft() {
1202     return getLeft(true);
1203   }
1204 
1205   /**
1206    * Gets the left X coordinate.
1207    * 
1208    * @param local true to get the local css position instead of page coordinate
1209    * @return the left value
1210    */
1211   public int getLeft(boolean local) {
1212     return local ? Util.parseInt(getStyleAttribute("left"), 0) : getX();
1213   }
1214 
1215   /**
1216    * Returns an object with properties top, left, right and bottom representing
1217    * the margins of this element unless sides is passed, then it returns the
1218    * calculated width of the sides (see #getPadding).
1219    * 
1220    * @param sides any combination of l, r, t, b to get the sum of those sides
1221    * @return the margins
1222    */
1223   public int getMargins(String sides) {
1224     double margin = 0;
1225     List<String> list = new ArrayList<String>();
1226     if (sides.contains("l")) {
1227       list.add("marginLeft");
1228     }
1229     if (sides.contains("r")) {
1230       list.add("marginRight");
1231     }
1232     if (sides.contains("t")) {
1233       list.add("marginTop");
1234     }
1235     if (sides.contains("b")) {
1236       list.add("marginBottom");
1237     }
1238     FastMap<String> map = getStyleAttribute(list);
1239     for (String s : map.keySet()) {
1240       margin += Util.parseFloat(map.get(s), 0);
1241     }
1242     return (int) Math.round(margin);
1243   }
1244 
1245   /**
1246    * Returns the offsets between two elements. Both element must be part of the
1247    * DOM tree and not have display:none to have page coordinates.
1248    * 
1249    * @param to the to element
1250    * @return the xy page offsets
1251    */
1252   public Point getOffsetsTo(Element to) {
1253     Point o = getXY();
1254     Point e = El.fly(to, "_internal").getXY();
1255     return new Point(o.x - e.x, o.y - e.y);
1256   }
1257 
1258   /**
1259    * Returns the element's outer HTML.
1260    * 
1261    * @return the inner html
1262    */
1263   public String getOuterHtml() {
1264     return dom.getAttribute("outerHTML");
1265   }
1266 
1267   /**
1268    * Gets the width of the padding(s) for the specified side(s).
1269    * 
1270    * @param sides can be t, l, r, b or any combination of those to add multiple
1271    *          values. For example, passing lr would get the border (l)eft width
1272    *          + the border (r)ight width.
1273    * @return the width of the sides passed added together
1274    */
1275   public int getPadding(String sides) {
1276     double padding = 0;
1277     List<String> list = new ArrayList<String>();
1278     if (sides.contains("l")) {
1279       list.add("paddingLeft");
1280     }
1281     if (sides.contains("r")) {
1282       list.add("paddingRight");
1283     }
1284     if (sides.contains("t")) {
1285       list.add("paddingTop");
1286     }
1287     if (sides.contains("b")) {
1288       list.add("paddingBottom");
1289     }
1290     FastMap<String> map = getStyleAttribute(list);
1291     for (String s : map.keySet()) {
1292       padding += Util.parseFloat(map.get(s), 0);
1293     }
1294     return (int) Math.round(padding);
1295   }
1296 
1297   /**
1298    * Returns the element's parent.
1299    * 
1300    * @return the parent
1301    */
1302   public El getParent() {
1303     Element e = DOM.getParent(dom);
1304     return e == null ? null : new El(e);
1305   }
1306 
1307   /**
1308    * Returns the region of the given element. The element must be part of the
1309    * DOM tree to have a region.
1310    * 
1311    * @return a region containing top, left, bottom, right
1312    */
1313   public Region getRegion() {
1314     Rectangle bounds = getBounds();
1315     Region r = new Region();
1316     r.left = bounds.x;
1317     r.top = bounds.y;
1318     r.right = r.left + bounds.width;
1319     r.bottom = r.top + bounds.height;
1320     return r;
1321   }
1322 
1323   /**
1324    * Returns the right X coordinate of the element (element X position + element
1325    * width).
1326    * 
1327    * @param local <code>true</code> to get the local css position instead of
1328    *          page coordinate
1329    * @return the right value
1330    */
1331   public int getRight(boolean local) {
1332     return getWidth() + (local ? getLeft(true) : getX());
1333   }
1334 
1335   /**
1336    * Returns the body elements current scroll position.
1337    * 
1338    * @return the scroll position
1339    */
1340   public Scroll getScroll() {
1341     if (dom == XDOM.getBody() || dom == XDOM.getDocument()) {
1342       return new Scroll(XDOM.getBodyScrollLeft(), XDOM.getBodyScrollTop());
1343     } else {
1344       return new Scroll(getScrollLeft(), getScrollTop());
1345     }
1346   }
1347 
1348   /**
1349    * Returns the horizontal scroll position.
1350    * 
1351    * @return the scroll position
1352    */
1353   public int getScrollLeft() {
1354     return DOM.getElementPropertyInt(dom, "scrollLeft");
1355   }
1356 
1357   /**
1358    * Returns the current vertical scroll position.
1359    * 
1360    * @return the scroll position
1361    */
1362   public int getScrollTop() {
1363     return DOM.getElementPropertyInt(dom, "scrollTop");
1364   }
1365 
1366   /**
1367    * Returns the size of the element.
1368    * 
1369    * @return the size
1370    */
1371   public Size getSize() {
1372     return getSize(false);
1373   }
1374 
1375   /**
1376    * Returns the element's size.
1377    * 
1378    * @param content true to get the size minus borders and padding
1379    * @return the size
1380    */
1381   public Size getSize(boolean content) {
1382     int w = getWidth();
1383     int h = getHeight();
1384     if (content) {
1385       Size frameWidth = getFrameSize();
1386       w -= frameWidth.width;
1387       h -= frameWidth.height;
1388     }
1389     return new Size(Math.max(0, w), Math.max(0, h));
1390   }
1391 
1392   public FastMap<String> getStyleAttribute(List<String> attr) {
1393     return computedStyle.getStyleAttribute(dom, attr);
1394   }
1395 
1396   /**
1397    * Normalizes currentStyle and computedStyle.
1398    * 
1399    * @param attr the style attribute whose value is returned.
1400    * @return the current value of the style attribute for this element.
1401    */
1402   public String getStyleAttribute(String attr) {
1403     return getStyleAttribute(Arrays.asList(attr)).get(attr);
1404   }
1405 
1406   /**
1407    * Returns the style width.
1408    * 
1409    * @return the style width
1410    */
1411   public int getStyleHeight() {
1412     String h = dom.getStyle().getProperty("height");
1413     if (h == null || h.equals("")) return 0;
1414     if (h.matches("(auto|em|%|en|ex|pt|in|cm|mm|pc)")) {
1415       return 0;
1416     }
1417     return Util.parseInt(h, 0);
1418   }
1419 
1420   /**
1421    * Returns the element's style name.
1422    * 
1423    * @return the style name
1424    */
1425   public String getStyleName() {
1426 	  /* begin laaglu */
1427 //    return dom.getClassName();
1428 	  return getClassName(dom);
1429 	  /* end laaglu */
1430   }
1431 
1432   public Size getStyleSize() {
1433     return getStyleSize(true);
1434   }
1435 
1436   /**
1437    * Returns the element's size, using style attribute before offsets.
1438    * 
1439    * @return the size
1440    */
1441   public Size getStyleSize(boolean contentOnly) {
1442     int h = Util.parseInt(dom.getStyle().getProperty("height"), Style.DEFAULT);
1443     int w = Util.parseInt(dom.getStyle().getProperty("width"), Style.DEFAULT);
1444 
1445     boolean isBorderBox = isBorderBox();
1446 
1447     if (isBorderBox && contentOnly && w != Style.DEFAULT) {
1448       w -= getFrameWidth("lr");
1449       if (w < 0) {
1450         w = Style.DEFAULT;
1451       }
1452     } else if (!isBorderBox && !contentOnly && w != Style.DEFAULT) {
1453       w += getFrameWidth("lr");
1454     }
1455     if (isBorderBox && contentOnly && h != Style.DEFAULT) {
1456       h -= getFrameWidth("tb");
1457       if (h < 0) {
1458         h = Style.DEFAULT;
1459       }
1460     } else if (!isBorderBox && !contentOnly && h != Style.DEFAULT) {
1461       h += getFrameWidth("tb");
1462     }
1463 
1464     int offsetWidth = Style.DEFAULT;
1465     int offsetHeight = Style.DEFAULT;
1466     if (w == Style.DEFAULT && h == Style.DEFAULT) {
1467       Size s = getSize(contentOnly);
1468       offsetWidth = s.width;
1469       offsetHeight = s.height;
1470       if (s.width > 0) {
1471         w = s.width;
1472       }
1473       if (s.height > 0) {
1474         h = s.height;
1475       }
1476     } else if (w == Style.DEFAULT) {
1477       offsetWidth = getWidth(contentOnly);
1478       if (offsetWidth > 0) {
1479         w = offsetWidth;
1480       }
1481     } else if (h == Style.DEFAULT) {
1482       offsetHeight = getHeight(contentOnly);
1483       if (offsetHeight > 0) {
1484         h = offsetHeight;
1485       }
1486     }
1487 
1488     List<String> l = new ArrayList<String>();
1489     if (w == Style.DEFAULT) {
1490       l.add("width");
1491     }
1492     if (h == Style.DEFAULT) {
1493       l.add("height");
1494     }
1495     Map<String, String> map = getStyleAttribute(l);
1496     if (map != null) {
1497       String wid = map.get("width");
1498       if (wid != null) {
1499         w = Util.parseInt(wid, Style.DEFAULT);
1500         if (offsetWidth == 0 && isBorderBox && contentOnly && w != Style.DEFAULT && !GXT.isIE) {
1501           w -= getFrameWidth("lr");
1502         } else if (GXT.isIE && isBorderBox && w != Style.DEFAULT && contentOnly) {
1503           w -= getFrameWidth("lr");
1504         } else if (offsetWidth == 0 && !isBorderBox && !contentOnly && w != Style.DEFAULT) {
1505           w += getFrameWidth("lr");
1506         }
1507       }
1508       String hei = map.get("height");
1509       if (hei != null) {
1510         h = Util.parseInt(hei, Style.DEFAULT);
1511         if (offsetHeight == 0 && isBorderBox && contentOnly && h != Style.DEFAULT && !GXT.isIE) {
1512           h -= getFrameWidth("tb");
1513         } else if (GXT.isIE && isBorderBox && h != Style.DEFAULT && contentOnly) {
1514           h -= getFrameWidth("tb");
1515         } else if (offsetHeight == 0 && !isBorderBox && !contentOnly && h != Style.DEFAULT) {
1516           h += getFrameWidth("tb");
1517         }
1518       }
1519     }
1520     if (w == Style.DEFAULT && h == Style.DEFAULT) {
1521       return new Size(offsetWidth, offsetHeight);
1522     }
1523     return new Size(w != Style.DEFAULT ? w : offsetWidth, h != Style.DEFAULT ? h : offsetHeight);
1524   }
1525 
1526   /**
1527    * Returns the style width. A value is only returned if the specified style is
1528    * in pixels.
1529    * 
1530    * @return the style width
1531    */
1532   public int getStyleWidth() {
1533     String w = dom.getStyle().getProperty("width");
1534     if (w == null || w.equals("")) return 0;
1535     if (w.matches("(auto|em|%|en|ex|pt|in|cm|mm|pc)")) {
1536       return 0;
1537     }
1538     return Util.parseInt(w, 0);
1539   }
1540 
1541   /**
1542    * Returns the element's sub child.
1543    * 
1544    * @param depth the child node depth
1545    * @return the child element
1546    */
1547   public Element getSubChild(int depth) {
1548     Element child = dom;
1549     while (depth-- > 0) {
1550       child = DOM.getChild(child, 0);
1551     }
1552     return child;
1553   }
1554 
1555   /**
1556    * Returns the measured width of the element's text.
1557    * 
1558    * @return the width
1559    */
1560   public int getTextWidth() {
1561     String html = getInnerHtml();
1562     TextMetrics metrics = TextMetrics.get();
1563     metrics.bind(dom);
1564     return metrics.getWidth(html);
1565   }
1566 
1567   /**
1568    * Returns the top Y coordinate.
1569    * 
1570    * @return the top value
1571    */
1572   public int getTop() {
1573     return getTop(true);
1574   }
1575 
1576   /**
1577    * Gets the top Y coordinate.
1578    * 
1579    * @param local true to get the local css position instead of page coordinate
1580    * @return the top value
1581    */
1582   public int getTop(boolean local) {
1583     return local ? Util.parseInt(getStyleAttribute("top"), 0) : getY();
1584   }
1585 
1586   /**
1587    * Returns the the "value" attribute.
1588    * 
1589    * @return the value
1590    */
1591   public String getValue() {
1592     return DOM.getElementProperty(dom, "value");
1593   }
1594 
1595   /**
1596    * Returns the offset width.
1597    * 
1598    * @return the width
1599    */
1600   public int getWidth() {
1601     return dom.getOffsetWidth();
1602   }
1603 
1604   /**
1605    * Returns the element's width.
1606    * 
1607    * @param content true to get the width minus borders and padding
1608    * @return the width
1609    */
1610   public int getWidth(boolean content) {
1611     int w = getWidth();
1612     if (content) {
1613       w -= getFrameWidth("lr");
1614     }
1615     return Math.max(0, w);
1616   }
1617 
1618   /**
1619    * Gets the current X position of the element based on page coordinates.
1620    * Element must be part of the DOM tree to have page coordinates.
1621    * 
1622    * @return the x position of the element
1623    */
1624   public int getX() {
1625     return dom.getAbsoluteLeft();
1626   }
1627 
1628   /**
1629    * Gets the current position of the element based on page coordinates. Element
1630    * must be part of the DOM tree to have page coordinates.
1631    * 
1632    * @return the location
1633    */
1634   public Point getXY() {
1635     return new Point(getX(), getY());
1636   }
1637 
1638   /**
1639    * Gets the current Y position of the element based on page coordinates.
1640    * 
1641    * @return the y position of the element
1642    */
1643   public int getY() {
1644     return dom.getAbsoluteTop();
1645   }
1646 
1647   /**
1648    * Returns the element's z-index.
1649    * 
1650    * @return the z-index
1651    */
1652   public int getZIndex() {
1653     return Util.parseInt(getStyleAttribute("zIndex"), 0);
1654   }
1655 
1656   /**
1657    * Checks if the specified CSS style name exists on this element's DOM node.
1658    * 
1659    * @param style the style name
1660    * @return true if the style name exists, else false
1661    */
1662   public boolean hasStyleName(String style) {
1663 	  /* begin laaglu */
1664 //	  String cls = dom.getClassName();
1665 	  String cls = getClassName(dom);
1666 	  /* end laaglu */    
1667 	  return (" " + cls + " ").indexOf(" " + style + " ") != -1 ? true : false;
1668   }
1669 
1670   /**
1671    * Hides this element
1672    * 
1673    * @return this
1674    */
1675   public El hide() {
1676     return setVisible(false);
1677   }
1678 
1679   /**
1680    * Inserts this element before the passed element.
1681    * 
1682    * @param before the element to insert before
1683    * @return this
1684    */
1685   public El insertBefore(Element before) {
1686     before.getParentElement().insertBefore(dom, before);
1687     return this;
1688   }
1689 
1690   /**
1691    * Inserts the element as a child before the given element.
1692    * 
1693    * @param child the element to insert
1694    * @param before the element the child will be inserted before
1695    * @return this
1696    */
1697   public El insertBefore(Element child, Element before) {
1698     dom.insertBefore(child, before);
1699     return this;
1700   }
1701 
1702   /**
1703    * Inserts the elements as a child before the given element.
1704    * 
1705    * @param elements the elements to insert
1706    * @param before the element the children will be inserted before
1707    * @return this
1708    */
1709   public El insertBefore(Element[] elements, Element before) {
1710     for (int i = 0; i < elements.length; i++) {
1711       insertBefore(elements[i], before);
1712     }
1713     return this;
1714   }
1715 
1716   /**
1717    * Inserts an element at the specified index.
1718    * 
1719    * @param child the child element
1720    * @param index the insert location
1721    * @return this
1722    */
1723   public El insertChild(Element child, int index) {
1724     DOM.insertChild(dom, child, index);
1725     return this;
1726   }
1727 
1728   /**
1729    * Inserts the children at the specified index.
1730    * 
1731    * @param children the children to add
1732    * @param index the insert location
1733    * @return this
1734    */
1735   public El insertChild(Element[] children, int index) {
1736     for (int i = children.length - 1; i >= 0; i--) {
1737       DOM.insertChild(dom, children[i], index);
1738     }
1739     return this;
1740   }
1741 
1742   /**
1743    * Inserts an element as the first child.
1744    * 
1745    * @param element the child element
1746    * @return this
1747    */
1748   public El insertFirst(Element element) {
1749     DOM.insertChild(dom, element, 0);
1750     return this;
1751   }
1752 
1753   /**
1754    * Inserts the children.
1755    * 
1756    * @param elems the child elements
1757    * @return this
1758    */
1759   public El insertFirst(Element[] elems) {
1760     for (int i = 0; i < elems.length; i++) {
1761       DOM.appendChild(dom, elems[i]);
1762     }
1763     return this;
1764   }
1765 
1766   /**
1767    * Creates and inserts a child element.
1768    * 
1769    * @param html the HTML fragment
1770    * @return the new child
1771    */
1772   public El insertFirst(String html) {
1773     return new El(DomHelper.insertFirst(dom, html));
1774   }
1775 
1776   /**
1777    * Inserts an html fragment into this element
1778    * 
1779    * @param where where to insert the html in relation to el - beforeBegin,
1780    *          afterBegin, beforeEnd, afterEnd.
1781    * @param html the HTML fragment
1782    * @return the inserted node (or nearest related if more than 1 inserted)
1783    */
1784   public El insertHtml(String where, String html) {
1785     return new El(DomHelper.insertHtml(where, dom, html));
1786   }
1787 
1788   /**
1789    * Inserts the element into the given parent.
1790    * 
1791    * @param parent the parent element
1792    * @return this
1793    */
1794   public El insertInto(Element parent) {
1795     fly(parent, "_internal").appendChild(dom);
1796     return this;
1797   }
1798 
1799   /**
1800    * Inserts a element.
1801    * 
1802    * @param parent the parent element
1803    * @param index the insert index
1804    * @return this
1805    */
1806   public El insertInto(Element parent, int index) {
1807     fly(parent, "_internal").insertChild(dom, index);
1808     return this;
1809   }
1810 
1811   /**
1812    * Inserts the child element as the last child.
1813    * 
1814    * @param child the element to insert
1815    * @return this
1816    */
1817   public El insertLast(Element child) {
1818     int idx = dom.getChildNodes().getLength();
1819     insertChild(child, idx);
1820     return this;
1821   }
1822 
1823   /**
1824    * Inserts the passed element as a sibling of this element.
1825    * 
1826    * @param elem the element to insert
1827    * @param where 'before' or 'after'
1828    * @return the inserted element
1829    */
1830   public Element insertSibling(Element elem, String where) {
1831     Element refNode = where.equals("before") ? dom : nextSibling();
1832     if (refNode == null) {
1833       DOM.appendChild(DOM.getParent(dom), elem);
1834     } else {
1835       DOM.insertBefore(getParent().dom, elem, refNode);
1836     }
1837     return elem;
1838   }
1839 
1840   /**
1841    * Inserts the passed elements as a sibling of this element.
1842    * 
1843    * @param elems the elements to insert
1844    * @param where where 'before' or 'after'
1845    * @return this
1846    */
1847   public El insertSibling(Element[] elems, String where) {
1848     for (int i = 0; i < elems.length; i++) {
1849       insertSibling(elems[i], where);
1850     }
1851     return this;
1852   }
1853 
1854   /**
1855    * Returns true if this element matches the passed simple selector (e.g.
1856    * div.some-class or span:first-child).
1857    * 
1858    * @param selector selector
1859    * @return true if the element matches the selector, else false
1860    */
1861   public boolean is(String selector) {
1862     return DomQuery.is(dom, selector);
1863   }
1864 
1865   /**
1866    * Returns true if the element is a border box.
1867    * 
1868    * @return true for border box
1869    */
1870   public boolean isBorderBox() {
1871     return isBorderBox(dom);
1872   }
1873 
1874   /**
1875    * Returns true if the element is part of the browser's DOM.
1876    * 
1877    * @return the dom state
1878    */
1879   public boolean isConnected() {
1880     return Document.get().getBody().isOrHasChild(dom);
1881   }
1882 
1883   /**
1884    * Returns true if this element is masked.
1885    * 
1886    * @return the masked state
1887    */
1888   public boolean isMasked() {
1889     return _mask != null && _mask.isVisible();
1890   }
1891 
1892   /**
1893    * Returns true if the child element is or a child of this element.
1894    * 
1895    * @param child the child element
1896    * @return true if is or child of element
1897    */
1898   public boolean isOrHasChild(Element child) {
1899     return DOM.isOrHasChild(dom, child);
1900   }
1901 
1902   /**
1903    * Returns whether the element is scrollable (x or y).
1904    * 
1905    * @return true if scrollable
1906    */
1907   public boolean isScrollable() {
1908     return isScrollableX() || isScrollableY();
1909   }
1910 
1911   /**
1912    * Returns whether the element is scrollable on the x-axis.
1913    * 
1914    * @return true if scrollable on the x-axis
1915    */
1916   public boolean isScrollableX() {
1917     return dom.getScrollWidth() > dom.getClientWidth();
1918   }
1919 
1920   /**
1921    * Returns whether the element is scrollable on the y-axis.
1922    * 
1923    * @return true if scrollable on the y-axis
1924    */
1925   public boolean isScrollableY() {
1926     return dom.getScrollHeight() > dom.getClientHeight();
1927   }
1928 
1929   public boolean isStyleAttribute(Map<String, String> map, boolean matchAll) {
1930     Set<String> collection = map.keySet();
1931     FastMap<String> a = getStyleAttribute(new ArrayList<String>(collection));
1932     for (String s : collection) {
1933       if (map.get(s).equals(a.get(s))) {
1934         if (!matchAll) {
1935           return true;
1936         }
1937       } else {
1938         if (matchAll) {
1939           return false;
1940         }
1941       }
1942     }
1943     return false;
1944   }
1945 
1946   public boolean isStyleAttribute(String attr, String value) {
1947     String a = getStyleAttribute(attr);
1948     return a != null && a.equals(value);
1949   }
1950 
1951   /**
1952    * Returns <code>true</code> if the element is visible using the css
1953    * 'visibiliy' attribute.
1954    * 
1955    * @return the visible state
1956    */
1957   public boolean isVisibility() {
1958     return isStyleAttribute("visibility", "hidden");
1959   }
1960 
1961   /**
1962    * Returns whether the element is currently visible.
1963    * 
1964    * @return true if visible
1965    */
1966   public boolean isVisible() {
1967     return isVisible(false);
1968   }
1969 
1970   /**
1971    * Returns whether the element is currently visible.
1972    * 
1973    * @param deep true to deep test
1974    * 
1975    * @return true if visible
1976    */
1977   public boolean isVisible(boolean deep) {
1978     Map<String, String> map = new FastMap<String>();
1979     map.put("visibility", "hidden");
1980     map.put("display", "none");
1981     boolean vis = !isStyleAttribute(map, false);
1982     El parent = getParent();
1983     Element p = parent != null ? parent.dom : null;
1984     if (p == null) {
1985       return false;
1986     }
1987     if (!deep || !vis) {
1988       return vis;
1989     }
1990     while (p != null && p != XDOM.getBody()) {
1991       if (!fly(p, "_isVisible").isVisible()) {
1992         return false;
1993       }
1994       p = (Element) p.getParentElement();
1995     }
1996 
1997     return true;
1998 
1999   }
2000 
2001   /**
2002    * Returns the element's last child.
2003    * 
2004    * @return the last child
2005    */
2006   public El lastChild() {
2007     Element e = DOM.getChild(dom, DOM.getChildCount(dom) - 1);
2008     return e == null ? null : new El(e);
2009   }
2010 
2011   /**
2012    * Retrieves the data using the request builder and updates the element'c
2013    * contents.
2014    * <p>
2015    * This method is subject to change.
2016    * 
2017    * @param builder the request builder
2018    */
2019   public Request load(RequestBuilder builder) {
2020     try {
2021       builder.setCallback(new RequestCallback() {
2022 
2023         public void onError(Request request, Throwable exception) {
2024           setInnerHtml(exception.getMessage());
2025         }
2026 
2027         public void onResponseReceived(Request request, Response response) {
2028           setInnerHtml(response.getText());
2029         }
2030 
2031       });
2032       return builder.send();
2033     } catch (Exception e) {
2034       setInnerHtml(e.getMessage());
2035       return null;
2036     }
2037   }
2038 
2039   /**
2040    * Makes an element positionable.
2041    */
2042   public El makePositionable() {
2043     return makePositionable(false);
2044   }
2045 
2046   /**
2047    * Makes an element positionable.
2048    * 
2049    * @param absolute <code>true</code> to position absolutely
2050    * @return this
2051    */
2052   public El makePositionable(boolean absolute) {
2053     if (absolute) {
2054       setStyleAttribute("position", "absolute");
2055     } else if ("static".equals(getStyleAttribute("position"))) {
2056       setStyleAttribute("position", "relative");
2057     }
2058     return this;
2059   }
2060 
2061   /**
2062    * Puts a mask over this element to disable user interaction.
2063    * 
2064    * @return the mask element
2065    */
2066   public El mask() {
2067     return mask(null, null);
2068   }
2069 
2070   /**
2071    * Puts a mask over this element to disable user interaction.
2072    * 
2073    * @param message a message to display in the mask
2074    * @return the mask element
2075    */
2076   public El mask(String message) {
2077     return mask(message, null);
2078   }
2079 
2080   /**
2081    * Puts a mask over this element to disable user interaction.
2082    * 
2083    * @param message a message to display in the mask
2084    * @param messageStyleName a CSS style name to be applied to the message text
2085    * @return the mask element
2086    */
2087   public El mask(String message, String messageStyleName) {
2088     if ("static".equals(getStyleAttribute("position"))) {
2089       addStyleName("x-masked-relative");
2090     }
2091     if (_maskMsg != null) {
2092       _maskMsg.remove();
2093     }
2094     if (_mask != null) {
2095       _mask.remove();
2096     }
2097 
2098     _mask = new El("<div class='ext-el-mask'></div>");
2099 
2100     addStyleName("x-masked");
2101     _mask.setDisplayed(true);
2102 
2103     appendChild(_mask.dom);
2104     if (message != null) {
2105       _maskMsg = new El("<div class='ext-el-mask-msg'><div></div></div>");
2106       if (messageStyleName != null) {
2107         _maskMsg.addStyleName(messageStyleName);
2108       }
2109       _maskMsg.firstChild().setInnerHtml(message);
2110       _maskMsg.setDisplayed(true);
2111 
2112       appendChild(_maskMsg.dom);
2113       _maskMsg.center(dom);
2114     }
2115     if (GXT.isIE && !(GXT.isIE7 && GXT.isStrict) && "auto".equals(getStyleAttribute("height"))) {
2116       _mask.setSize(getWidth(), getHeight());
2117     }
2118 
2119     return _mask;
2120   }
2121 
2122   /**
2123    * Returns the elements next sibling.
2124    * 
2125    * @return the sibling element
2126    */
2127   public Element nextSibling() {
2128     return DOM.getNextSibling(dom);
2129   }
2130 
2131   /**
2132    * Returns the elements previous sibling.
2133    * 
2134    * @return the previous sibling
2135    */
2136   public Element previousSibling() {
2137     return dom.getPreviousSibling().cast();
2138   }
2139 
2140   /**
2141    * Removes this element from the DOM
2142    */
2143   public El remove() {
2144     return removeFromParent();
2145   }
2146 
2147   /**
2148    * Removes a child.
2149    * 
2150    * @param child the child to remove
2151    * @return this
2152    */
2153   public El removeChild(Element child) {
2154     dom.removeChild(child);
2155     return this;
2156   }
2157 
2158   /**
2159    * Removes all the elements children.
2160    */
2161   public El removeChildren() {
2162     El child = null;
2163     while ((child = firstChild()) != null) {
2164       dom.removeChild(child.dom);
2165     }
2166     setInnerHtml("");
2167     return this;
2168   }
2169 
2170   /**
2171    * Removes the element from it's parent.
2172    */
2173   public El removeFromParent() {
2174     com.google.gwt.dom.client.Element p = dom.getParentElement();
2175     if (p != null) {
2176       p.removeChild(dom);
2177     }
2178     return this;
2179   }
2180 
2181   /**
2182    * Removes the style names(s) from the element.
2183    * 
2184    * @param styleNames the style names
2185    * @return this
2186    */
2187   public El removeStyleName(String... styleNames) {
2188     for (String s : styleNames) {
2189       removeStyleName(s);
2190     }
2191     return this;
2192   }
2193 
2194   /**
2195    * Removes a style name.
2196    * 
2197    * @param styleName the style names to remove
2198    * @return this
2199    */
2200   public native El removeStyleName(String styleName) /*-{
2201 		var dom = this.@com.extjs.gxt.ui.client.core.El::dom;
2202 		if (!@com.extjs.gxt.ui.client.core.El::removeStyleNameReCache) {
2203 			@com.extjs.gxt.ui.client.core.El::removeStyleNameReCache = {};
2204 		}
2205 		if (styleName && dom.className) {
2206 			var s = @com.extjs.gxt.ui.client.core.El::removeStyleNameReCache[styleName] = @com.extjs.gxt.ui.client.core.El::removeStyleNameReCache[styleName]
2207 					|| new RegExp('(?:^|\\s+)' + styleName + '(?:\\s+|$)', "g");
2208 			dom.className = dom.className.replace(s, " ");
2209 		}
2210 		return this;
2211   }-*/;
2212 
2213   /**
2214    * Forces the Browser to repaint this element.
2215    * 
2216    * @return this
2217    */
2218   public El repaint() {
2219     addStyleName("x-repaint");
2220     DeferredCommand.addCommand(new Command() {
2221       public void execute() {
2222         removeStyleName("x-repaint");
2223       }
2224     });
2225     return this;
2226   }
2227 
2228   /**
2229    * Replaces a style name on the element with another. If the old name does not
2230    * exist, the new name will simply be added.
2231    * 
2232    * @param oldStyle the style to replace
2233    * @param newStyle the new style
2234    * @return this
2235    */
2236   public El replaceStyleName(String oldStyle, String newStyle) {
2237     return removeStyleName(oldStyle).addStyleName(newStyle);
2238   }
2239 
2240   public El scrollIntoView(Element container, boolean hscroll) {
2241     return scrollIntoView(container, hscroll, null);
2242   }
2243 
2244   /**
2245    * Scrolls the element into view.
2246    * 
2247    * @param container the container element
2248    * @param hscroll <code>false</code> to disable horizontal scrolling.
2249    */
2250   public El scrollIntoView(Element container, boolean hscroll, int[] offsets) {
2251     if (offsets == null) {
2252       offsets = new int[] {0, 0};
2253     }
2254     Element c = container != null ? container : XDOM.getBody();
2255 
2256     Point o = getOffsetsTo(c);
2257     int l = o.x;
2258     int t = o.y;
2259     l = l + c.getScrollLeft();
2260     t = t + c.getScrollTop();
2261     int b = t + getHeight() + offsets[0];
2262     int r = l + getWidth() + offsets[1];
2263 
2264     int ch = c.getClientHeight();
2265     int ct = c.getScrollTop();
2266     int cb = ct + ch;
2267 
2268     if (getHeight() > ch || t < ct) {
2269       c.setScrollTop(t);
2270     } else if (b > cb) {
2271       c.setScrollTop(b - ch);
2272     }
2273 
2274     if (hscroll) {
2275       int cl = c.getScrollLeft();
2276       int cw = c.getClientWidth();
2277       int cr = cl + cw;
2278 
2279       if (getWidth() > cw || l < cl) {
2280         c.setScrollLeft(l);
2281       } else if (r > cr) {
2282         c.setScrollLeft(r - cw);
2283       }
2284     }
2285     return this;
2286   }
2287 
2288   /**
2289    * Scrolls this element the specified scroll point.
2290    * 
2291    * @param side either "left" for scrollLeft values or "top" for scrollTop
2292    *          values.
2293    * @param value the new scroll value
2294    * @return this
2295    */
2296   public El scrollTo(String side, int value) {
2297     if ("left".equalsIgnoreCase(side)) {
2298       setScrollLeft(value);
2299     } else if ("top".equalsIgnoreCase(side)) {
2300       setScrollTop(value);
2301     }
2302     return this;
2303   }
2304 
2305   /**
2306    * Scrolls this element the specified scroll point.
2307    * 
2308    * @param side side either "left" for scrollLeft values or "top" for scrollTop
2309    *          values.
2310    * @param value the new scroll value
2311    * @param config the fx config
2312    * @return this
2313    */
2314   public El scrollTo(String side, int value, FxConfig config) {
2315     ScrollDir dir = ScrollDir.VERTICAL;
2316     if (side.equalsIgnoreCase("left")) {
2317       dir = ScrollDir.HORIZONTAL;
2318     }
2319     BaseEffect.scroll(this, config, dir, value);
2320     return this;
2321   }
2322 
2323   /**
2324    * Selects child nodes based on the passed CSS selector (the selector should
2325    * not contain an id).
2326    * 
2327    * @param selector the selector/xpath query
2328    * @return the matching elements
2329    */
2330   public NodeList<Element> select(String selector) {
2331     return DomQuery.select(selector, dom);
2332   }
2333 
2334   /**
2335    * Selects a single element.
2336    * 
2337    * @param selector the CSS selector
2338    * @return the matching element
2339    */
2340   public El selectNode(String selector) {
2341     Element el = DomQuery.selectNode(selector, dom);
2342     if (el != null) {
2343       return new El(el);
2344     }
2345     return null;
2346   }
2347 
2348   /**
2349    * Adds or removes a border. The style name 'x-border' is added to the widget
2350    * to display a border.
2351    * 
2352    * @param show the show state
2353    * @return this
2354    */
2355   public El setBorders(boolean show) {
2356     if (show) {
2357       addStyleName("x-border");
2358       setStyleAttribute("borderWidth", "1px");
2359     } else {
2360       removeStyleName("x-border");
2361       setStyleAttribute("borderWidth", "0px");
2362     }
2363     return this;
2364   }
2365 
2366   /**
2367    * Sets the element's bounds.
2368    * 
2369    * @param x the x coordinate
2370    * @param y the y coordinate
2371    * @param width the new width
2372    * @param height the new height
2373    * @return this
2374    */
2375   public El setBounds(int x, int y, int width, int height) {
2376     return setBounds(x, y, width, height, false);
2377   }
2378 
2379   /**
2380    * Sets the element's bounds.
2381    * 
2382    * @param x the x coordinate
2383    * @param y the y coordinate
2384    * @param width the new width
2385    * @param height the new height
2386    * @param adjust true to adjust for box model issues
2387    * @return this
2388    */
2389   public El setBounds(int x, int y, int width, int height, boolean adjust) {
2390     setPagePosition(x, y);
2391     setSize(width, height, adjust);
2392     return this;
2393   }
2394 
2395   /**
2396    * Sets the element's bounds.
2397    * 
2398    * @param bounds the new bounds
2399    * @return this
2400    */
2401   public El setBounds(Rectangle bounds) {
2402     setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
2403     return this;
2404   }
2405 
2406   /**
2407    * Sets the element's bounds.
2408    * 
2409    * @param bounds the new bounds
2410    * @param content <code>true</code> to adjust for box model issues
2411    * @return this
2412    */
2413   public El setBounds(Rectangle bounds, boolean content) {
2414     setBounds(bounds.x, bounds.y, bounds.width, bounds.height, content);
2415     return this;
2416   }
2417 
2418   /**
2419    * Sets the CSS display property.
2420    * 
2421    * @param display true to display the element using its default display
2422    * @return this
2423    */
2424   public El setDisplayed(boolean display) {
2425     String value = display ? originalDisplay : "none";
2426     setStyleAttribute("display", value);
2427     return this;
2428   }
2429 
2430   /**
2431    * Sets the CSS display property.
2432    * 
2433    * @param display the display value
2434    * @return this
2435    */
2436   public El setDisplayed(String display) {
2437     setStyleAttribute("display", display);
2438     return this;
2439   }
2440 
2441   /**
2442    * Sets an element's attribute.
2443    * 
2444    * @param attr the attribute name
2445    * @param value the value
2446    * @return this
2447    */
2448   public El setElementAttribute(String attr, boolean value) {
2449     DOM.setElementPropertyBoolean(dom, attr, value);
2450     return this;
2451   }
2452 
2453   /**
2454    * Sets an element's attribute.
2455    * 
2456    * @param attr the attribute name
2457    * @param value the value
2458    * @return this
2459    */
2460   public El setElementAttribute(String attr, int value) {
2461     return setElementAttribute(attr, "" + value);
2462   }
2463 
2464   /**
2465    * Sets an element's attribute.
2466    * 
2467    * @param attr the attribute name
2468    * @param value the value
2469    * @return this
2470    */
2471   public El setElementAttribute(String attr, String value) {
2472     DOM.setElementAttribute(dom, attr, value);
2473     return this;
2474   }
2475 
2476   /**
2477    * Convenience function for setting disabled/enabled by boolean.
2478    * 
2479    * @param enabled the enabled state
2480    */
2481   public void setEnabled(boolean enabled) {
2482     if (!enabled) {
2483       disable();
2484     } else {
2485       enable();
2486     }
2487   }
2488 
2489   /**
2490    * True to focus, false to blur.
2491    * 
2492    * @param focus the new focus state
2493    */
2494   public native El setFocus(boolean focus) /*-{
2495 		var dom = this.@com.extjs.gxt.ui.client.core.El::dom;
2496 		try {
2497 			if (focus) {
2498 				dom.focus();
2499 			} else {
2500 				dom.blur();
2501 			}
2502 		} catch (err) {
2503 		}
2504 		return this;
2505   }-*/;
2506 
2507   /**
2508    * Sets the elements height.
2509    * 
2510    * @param height the height
2511    * @return this
2512    */
2513   public El setHeight(int height) {
2514     return setHeight(height, false);
2515   }
2516 
2517   /**
2518    * Sets the elements height.
2519    * 
2520    * @param height the height
2521    * @param adjust <code>true</code> to adjust for box model issues
2522    * @return this
2523    */
2524   public El setHeight(int height, boolean adjust) {
2525     if (adjust && !isBorderBox()) {
2526       height -= getFrameWidth("tb");
2527     }
2528     if (height >= 0) {
2529       dom.getStyle().setPropertyPx("height", height);
2530     }
2531     return this;
2532   }
2533 
2534   /**
2535    * Sets the elements height.
2536    * 
2537    * @param height the height
2538    * @return this
2539    */
2540   public El setHeight(String height) {
2541     DOM.setStyleAttribute(dom, "height", addUnits(height, "px"));
2542     return this;
2543   }
2544 
2545   /**
2546    * Sets the the icon for an element either as a CSS style name or image path.
2547    * 
2548    * @param style the style are image path
2549    */
2550   public El setIconStyle(String style) {
2551     if (Util.isImagePath(style)) {
2552       setStyleAttribute("backgroundImage", "url(" + style + ")");
2553     } else {
2554       dom.setClassName(style);
2555     }
2556     return this;
2557   }
2558 
2559   /**
2560    * Sets the element's id.
2561    * 
2562    * @param id the new id
2563    * @return this
2564    */
2565   public El setId(String id) {
2566     if (id == null) {
2567       id = XDOM.getUniqueId();
2568     }
2569     dom.setId(id);
2570     return this;
2571   }
2572 
2573   /**
2574    * Sets the element's inner html.
2575    * 
2576    * @param html the new HTML
2577    * @return this
2578    */
2579   public El setInnerHtml(String html) {
2580     DOM.setInnerHTML(dom, html);
2581     return this;
2582   }
2583 
2584   /**
2585    * Sets an element's property.
2586    * 
2587    * @param property the property name
2588    * @param value the value
2589    * @return this
2590    */
2591   public El setIntElementProperty(String property, int value) {
2592     DOM.setElementPropertyInt(dom, property, value);
2593     return this;
2594   }
2595 
2596   /**
2597    * Sets the element's left position directly using CSS style (instead of
2598    * {@link #setX}).
2599    * 
2600    * @param left the left value
2601    * @return this
2602    */
2603   public El setLeft(int left) {
2604     dom.getStyle().setPropertyPx("left", left);
2605     return this;
2606   }
2607 
2608   /**
2609    * Quick set left and top adding default units.
2610    * 
2611    * @param left the left value
2612    * @param top the top value
2613    * @return this
2614    */
2615   public El setLeftTop(int left, int top) {
2616     setLeft(left);
2617     setTop(top);
2618     return this;
2619   }
2620 
2621   /**
2622    * Sets the elements's margin.
2623    * 
2624    * @param margin the margin
2625    * @return this
2626    */
2627   public El setMargins(Margins margin) {
2628     if (margin != null) {
2629       setStyleAttribute("marginLeft", margin.left + "px");
2630       setStyleAttribute("marginTop", margin.top + "px");
2631       setStyleAttribute("marginRight", margin.right + "px");
2632       setStyleAttribute("marginBottom", margin.bottom + "px");
2633     }
2634     return this;
2635   }
2636 
2637   /**
2638    * Sets the elements's padding.
2639    * 
2640    * @param padding the padding
2641    * @return this
2642    */
2643   public El setPadding(Padding padding) {
2644     if (padding != null) {
2645       setStyleAttribute("paddingLeft", padding.left + "px");
2646       setStyleAttribute("paddingTop", padding.top + "px");
2647       setStyleAttribute("paddingRight", padding.right + "px");
2648       setStyleAttribute("paddingBottom", padding.bottom + "px");
2649     }
2650     return this;
2651   }
2652 
2653   /**
2654    * Sets the element's position in page coordinates.
2655    * 
2656    * @param x the x coordinate
2657    * @param y the y coordinate
2658    * @return this
2659    */
2660   public El setPagePosition(int x, int y) {
2661     setX(x);
2662     setY(y);
2663     return this;
2664   }
2665 
2666   /**
2667    * Sets the element's horizontal scroll position.
2668    * 
2669    * @param left the left value
2670    * @return this
2671    */
2672   public El setScrollLeft(int left) {
2673     DOM.setElementPropertyInt(dom, "scrollLeft", left);
2674     return this;
2675   }
2676 
2677   /**
2678    * Sets the element's vertical scroll position.
2679    * 
2680    * @param top the top value
2681    * @return this
2682    */
2683   public El setScrollTop(int top) {
2684     DOM.setElementPropertyInt(dom, "scrollTop", top);
2685     return this;
2686   }
2687 
2688   /**
2689    * Sets the element's size.
2690    * 
2691    * @param width the new width
2692    * @param height the new height
2693    * @return this
2694    */
2695   public El setSize(int width, int height) {
2696     setSize(width, height, false);
2697     return this;
2698   }
2699 
2700   /**
2701    * Set the size of the element.
2702    * 
2703    * @param width the new width
2704    * @param height the new height
2705    * @param adjust <code>true</code> to adjust for box model issues
2706    * @return this
2707    */
2708   public El setSize(int width, int height, boolean adjust) {
2709     if (adjust && !isBorderBox()) {
2710       Size frameWidth = getFrameSize();
2711       width -= frameWidth.width;
2712       height -= frameWidth.height;
2713     }
2714     if (width >= 0) {
2715       dom.getStyle().setPropertyPx("width", width);
2716     }
2717     if (height >= 0) {
2718       dom.getStyle().setPropertyPx("height", height);
2719     }
2720     return this;
2721   }
2722 
2723   /**
2724    * Sets the element's size.
2725    * 
2726    * @param size the size
2727    * @return this
2728    */
2729   public El setSize(Size size) {
2730     setSize(size.width, size.height);
2731     return this;
2732   }
2733 
2734   /**
2735    * Sets the element's size.
2736    * 
2737    * @param width the new size
2738    * @param height the new height
2739    * @return this
2740    */
2741   public El setSize(String width, String height) {
2742     setWidth(width);
2743     setHeight(height);
2744     return this;
2745   }
2746 
2747   /**
2748    * Sets a style attribute.
2749    * 
2750    * @param attr the attribute name
2751    * @param value the int value
2752    * @return this
2753    */
2754   public El setStyleAttribute(String attr, Object value) {
2755     computedStyle.setStyleAttribute(dom, attr, value);
2756     return this;
2757   }
2758 
2759   /**
2760    * Sets the element's style name.
2761    * 
2762    * @param style the style name
2763    * @return this
2764    */
2765   public El setStyleName(String style) {
2766     dom.setClassName(style);
2767     return this;
2768   }
2769 
2770   /**
2771    * Adds or removes the style name.
2772    * 
2773    * @param style the style name
2774    * @param add true to add, false to remove
2775    * @return this
2776    */
2777   public El setStyleName(String style, boolean add) {
2778     if (add) {
2779       addStyleName(style);
2780     } else {
2781       removeStyleName(style);
2782     }
2783     return this;
2784   }
2785 
2786   /**
2787    * Sets the element's size using style attributes.
2788    * 
2789    * @param width the width
2790    * @param height the height
2791    * @return this
2792    */
2793   public El setStyleSize(int width, int height) {
2794     setStyleAttribute("width", width);
2795     setStyleAttribute("height", height);
2796     return this;
2797   }
2798 
2799   /**
2800    * Sets the element's tab index.
2801    * 
2802    * @param index the tab index
2803    * @return this
2804    */
2805   public El setTabIndex(int index) {
2806     DOM.setElementPropertyInt(dom, "tabIndex", index);
2807     return null;
2808   }
2809 
2810   /**
2811    * Sets the element's title property.
2812    * 
2813    * @param title the new title
2814    * @return this
2815    */
2816   public El setTitle(String title) {
2817     dom.setTitle(title);
2818     return this;
2819   }
2820 
2821   /**
2822    * Sets the element's top position directly using CSS style (instead of
2823    * {@link #setY}).
2824    * 
2825    * @param top the top value
2826    * @return this
2827    */
2828   public El setTop(int top) {
2829     dom.getStyle().setPropertyPx("top", top);
2830     return this;
2831   }
2832 
2833   /**
2834    * Sets the element's value property.
2835    * 
2836    * @param value the value
2837    */
2838   public El setValue(String value) {
2839     dom.setPropertyString("value", value);
2840     return this;
2841   }
2842 
2843   /**
2844    * Sets the elements css 'visibility' property. Behavior is different than
2845    * using the 'display' property.
2846    * 
2847    * @param visible <code>true</code> to show, <code>false</code> to hide
2848    * @return this
2849    */
2850   public El setVisibility(boolean visible) {
2851     setStyleAttribute("visibility", visible ? "visible" : "hidden");
2852     return this;
2853   }
2854 
2855   /**
2856    * Sets the element's visibility mode. When setVisible() is called it will use
2857    * this to determine whether to set the visibility or the display property.
2858    * 
2859    * @param visMode value {link VisMode#VISIBILITY}} or {@link VisMode#DISPLAY}
2860    * @return this
2861    */
2862   public El setVisibilityMode(VisMode visMode) {
2863     visiblityMode = visMode;
2864     return this;
2865   }
2866 
2867   /**
2868    * Sets the visibility of the element (see details). If the vis mode is set to
2869    * DISPLAY, it will use the display property to hide the element, otherwise it
2870    * uses visibility. The default is to hide and show using the DISPLAY
2871    * property.
2872    * 
2873    * @param visible whether the element is visible
2874    * @return this
2875    */
2876   public El setVisible(boolean visible) {
2877     if (visiblityMode == VisMode.DISPLAY) {
2878       return setDisplayed(visible);
2879     } else {
2880       return setVisibility(visible);
2881     }
2882   }
2883 
2884   /**
2885    * Sets the element's width.
2886    * 
2887    * @param width the new width
2888    * @return this
2889    */
2890   public El setWidth(int width) {
2891     return setWidth(width, false);
2892   }
2893 
2894   /**
2895    * Sets the elements's width.
2896    * 
2897    * @param width the new width
2898    * @param adjust <code>true</code> to adjust for box model issues
2899    * @return this
2900    */
2901   public El setWidth(int width, boolean adjust) {
2902     if (adjust && !isBorderBox()) {
2903       width -= getFrameWidth("lr");
2904     }
2905     if (width >= 0) {
2906       dom.getStyle().setPropertyPx("width", width);
2907     }
2908     return this;
2909   }
2910 
2911   /**
2912    * Sets the element's width.
2913    * 
2914    * @param width the new width
2915    * @return this
2916    */
2917   public El setWidth(String width) {
2918     DOM.setStyleAttribute(dom, "width", addUnits(width, "px"));
2919     return this;
2920   }
2921 
2922   /**
2923    * Sets the X position of the element based on page coordinates. Element must
2924    * be part of the DOM tree to have page coordinates.
2925    * 
2926    * @param x the x coordinate
2927    * @return this
2928    */
2929   public El setX(int x) {
2930     return setXY(x, Style.DEFAULT);
2931   }
2932 
2933   /**
2934    * Sets the elements position in page coordinates.
2935    * 
2936    * @param x the x coordinate
2937    * @param y the y coordinate
2938    * @return this
2939    */
2940   public El setXY(int x, int y) {
2941     return setXY(new Point(x, y));
2942   }
2943 
2944   /**
2945    * Sets the elements position in page coordinates.
2946    * 
2947    * @param x the x coordinate
2948    * @param y the y coordinate
2949    * @return this
2950    */
2951   public El setXY(int x, int y, FxConfig config) {
2952     if (config == null) {
2953       setXY(x, y);
2954     } else {
2955       Fx fx = new Fx(config);
2956       fx.run(new Move(this, x, y));
2957     }
2958     return this;
2959   }
2960 
2961   /**
2962    * Sets the element's position in page coordinates.
2963    * 
2964    * @param p the position
2965    * @return this
2966    */
2967   public El setXY(Point p) {
2968     makePositionable();
2969     Point pts = translatePoints(p);
2970     if (p.x != Style.DEFAULT) {
2971       setLeft(pts.x);
2972     }
2973     if (p.y != Style.DEFAULT) {
2974       setTop(pts.y);
2975     }
2976     return this;
2977   }
2978 
2979   /**
2980    * Sets the Y position of the element based on page coordinates. Element must
2981    * be part of the DOM tree to have page coordinates.
2982    * 
2983    * @param y the y coordinate
2984    * @return this
2985    */
2986   public El setY(int y) {
2987     return setXY(Style.DEFAULT, y);
2988   }
2989 
2990   /**
2991    * Sets the element's z-index.
2992    * 
2993    * @param zIndex the z-index value
2994    * @return this
2995    */
2996   public El setZIndex(int zIndex) {
2997     DOM.setIntStyleAttribute(dom, "zIndex", Math.max(0, zIndex));
2998     return this;
2999   }
3000 
3001   /**
3002    * Shows this element
3003    * 
3004    * @return this
3005    */
3006   public El show() {
3007     return setVisible(true);
3008   }
3009 
3010   /**
3011    * Slides the element in.
3012    * 
3013    * @param direction the direction
3014    * @param config the fx config
3015    * @return this
3016    */
3017   public El slideIn(Direction direction, FxConfig config) {
3018     BaseEffect.slideIn(this, config, direction);
3019     return this;
3020   }
3021 
3022   /**
3023    * Slides the element out.
3024    * 
3025    * @param direction the direction
3026    * @param config the fx config
3027    * @return this
3028    */
3029   public El slideOut(Direction direction, FxConfig config) {
3030     BaseEffect.slideOut(this, config, direction);
3031     return this;
3032   }
3033 
3034   /**
3035    * Returns the element's sub child.
3036    * 
3037    * @param depth the child node depth
3038    * @return the child element
3039    */
3040   public El subChild(int depth) {
3041     Element child = dom;
3042     while (depth-- > 0) {
3043       child = DOM.getChild(child, 0);
3044     }
3045     return new El(child);
3046   }
3047 
3048   /**
3049    * Synchronizes the layer.
3050    * 
3051    * @param show true to show
3052    */
3053   public El sync(boolean show) {
3054     return this;
3055   }
3056 
3057   public String toString() {
3058     return getOuterHtml();
3059   }
3060 
3061   public Point translatePoints(Point p) {
3062     List<String> list = new ArrayList<String>(3);
3063     list.add("position");
3064     list.add("left");
3065     list.add("top");
3066 
3067     Map<String, String> map = getStyleAttribute(list);
3068     boolean relative = "relative".equals(map.get("position"));
3069     int l = Util.parseInt(map.get("left"), -11234);
3070     int t = Util.parseInt(map.get("top"), -11234);
3071 
3072     l = l != -11234 ? l : (relative ? 0 : dom.getOffsetLeft());
3073     t = t != -11234 ? t : (relative ? 0 : dom.getOffsetTop());
3074 
3075     Point o = getXY();
3076     return new Point(p.x - o.x + l, p.y - o.y + t);
3077   }
3078 
3079   /**
3080    * Return clipping (overflow) to original clipping before clip() was called.
3081    * 
3082    * @return this
3083    */
3084   public El unclip() {
3085     if (isClipped) {
3086       isClipped = false;
3087       setStyleAttribute("overflow", originalClipped[0]);
3088       setStyleAttribute("overflowX", originalClipped[1]);
3089       setStyleAttribute("overflowY", originalClipped[2]);
3090     }
3091     return this;
3092   }
3093 
3094   /**
3095    * Removes a previously applied mask.
3096    * 
3097    * return this
3098    */
3099   public El unmask() {
3100     if (_mask != null) {
3101       if (_maskMsg != null) {
3102         _maskMsg.remove();
3103         _maskMsg = null;
3104       }
3105       _mask.setVisible(false);
3106       _mask.remove();
3107       _mask = null;
3108       removeStyleName("x-masked", "x-masked-relative");
3109     }
3110     return this;
3111   }
3112 
3113   /**
3114    * Unwraps the child element.
3115    * 
3116    * @param bounds the original bounds
3117    */
3118   public El unwrap(Element child, Rectangle bounds) {
3119     El.fly(child, "_internal").setLeftTop(bounds.x, bounds.y);
3120     Element p = dom.getParentElement().cast();
3121     int pos = DOM.getChildIndex(p, dom);
3122     p.removeChild(dom);
3123     DOM.insertChild(p, child, pos);
3124     return this;
3125   }
3126 
3127   /**
3128    * Sets the innerHTML to the given markup.
3129    * 
3130    * @param html the html
3131    * @return this
3132    */
3133   public El update(String html) {
3134     DOM.setInnerHTML(dom, html);
3135     return this;
3136   }
3137 
3138   /**
3139    * Sets the element's z-index using {@link XDOM#getTopZIndex()} to ensure it
3140    * has the highest values.
3141    * 
3142    * @param adj the adjustment to be applied to the z-index value
3143    * 
3144    * @return this
3145    */
3146   public El updateZIndex(int adj) {
3147     setZIndex(XDOM.getTopZIndex() + adj);
3148     return this;
3149   }
3150 
3151   /**
3152    * Wraps the element with the specified wrapper. The wrapper will have the
3153    * same size and position of the element. The original bounds can be used to
3154    * 'unwrap' the element.
3155    * 
3156    * @param wrapper the wrapper element
3157    * @return the original bounds
3158    */
3159   public Rectangle wrap(Element wrapper) {
3160     El wrap = new El(wrapper);
3161     wrap.setVisible(false);
3162 
3163     String pos = getStyleAttribute("position");
3164     wrap.setStyleAttribute("position", pos);
3165 
3166     int l = getLeft();
3167     int t = getTop();
3168 
3169     setLeft(5000);
3170     setVisible(true);
3171 
3172     int h = getComputedHeight();
3173     int w = getComputedWidth();
3174 
3175     setLeft(1);
3176     setStyleAttribute("overflow", "hidden");
3177     setVisible(false);
3178 
3179     wrap.insertBefore(dom);
3180     wrap.appendChild(dom);
3181 
3182     wrap.setStyleAttribute("overflow", "hidden");
3183 
3184     wrap.setLeft(l);
3185     wrap.setTop(t);
3186 
3187     setTop(0);
3188     setLeft(0);
3189 
3190     return new Rectangle(l, t, w, h);
3191   }
3192 
3193   protected Point getConstrainToXY(Element elem, Point proposedXY) {
3194     int vw, vh, vx = 0, vy = 0;
3195     if (elem == XDOM.getBody()) {
3196       vw = XDOM.getViewportSize().width;
3197       vh = XDOM.getViewportSize().height;
3198 
3199       if (!GXT.isIE && !fly(elem.getParentElement(), "_internal").isStyleAttribute("overflowY", "hidden")
3200           && fly(elem.getParentElement(), "_internal").isScrollableY()) {
3201         vw -= (XDOM.getScrollBarWidth());
3202       }
3203       if (!GXT.isIE && !fly(elem.getParentElement(), "_internal").isStyleAttribute("overflowX", "hidden")
3204           && fly(elem.getParentElement(), "_internal").isScrollableX()) {
3205         vh -= (XDOM.getScrollBarWidth());
3206       }
3207 
3208     } else {
3209       vw = fly(elem, "_internal").getWidth();
3210       vh = fly(elem, "_internal").getHeight();
3211     }
3212 
3213     Point xy = proposedXY;
3214     int x = xy.x;
3215     int y = xy.y;
3216 
3217     int vr = vx + vw;
3218     int vb = vy + vh;
3219 
3220     int w = getWidth();
3221     int h = getHeight();
3222 
3223     if ((x + w) > vr) {
3224       x = vr - w;
3225     }
3226     if ((y + h) > vb) {
3227       y = vb - h;
3228     }
3229 
3230     // then make sure top/left isn't negative
3231     if (x < vx) {
3232       x = vx;
3233     }
3234     if (y < vy) {
3235       y = vy;
3236     }
3237 
3238     return new Point(x, y);
3239   }
3240 
3241   private native boolean isLeftorRight(String s) /*-{
3242 		if (@com.extjs.gxt.ui.client.core.El::leftRightTest == null) {
3243 			@com.extjs.gxt.ui.client.core.El::leftRightTest = new RegExp(
3244 					"Left|Right");
3245 		}
3246 		return @com.extjs.gxt.ui.client.core.El::leftRightTest.test(s);
3247   }-*/;
3248   /* begin laaglu */
3249   public static native String getClassName(Element dom) /*-{
3250      var cn = dom.className;
3251 	 //@com.google.gwt.core.client.GWT::log(Ljava/lang/String;)(typeof(cn));
3252      if ("object" == typeof(cn)) {
3253        return cn.baseVal;
3254      }
3255 	 return cn;
3256   }-*/;
3257   
3258 
3259   private static native void setClassName(Element dom, String value) /*-{
3260      var cn = dom.className;
3261      if ("object" == typeof(cn)) {
3262        dom.className.baseVal = value;
3263        return;
3264      }
3265      dom.className = value;
3266   }-*/;
3267 
3268 
3269   /* end laaglu */
3270 }