/**
 * @class Ext.core.Element
 */
(function(){

var ELEMENT = Ext.core.Element,
    LEFT = "left",
    RIGHT = "right",
    TOP = "top",
    BOTTOM = "bottom",
    POSITION = "position",
    STATIC = "static",
    RELATIVE = "relative",
    AUTO = "auto",
    ZINDEX = "z-index";

Ext.override(Ext.core.Element, {
    
/** * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @return {Number} The X position of the element */ getX : function(){ return ELEMENT.getX(this.dom); },
/** * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @return {Number} The Y position of the element */ getY : function(){ return ELEMENT.getY(this.dom); },
/** * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @return {Array} The XY position of the element */ getXY : function(){ return ELEMENT.getXY(this.dom); },
/** * Returns the offsets of this element from the passed element. Both element must be part of the DOM tree and not have display:none to have page coordinates. * @param {Mixed} element The element to get the offsets from. * @return {Array} The XY page offsets (e.g. [100, -200]) */ getOffsetsTo : function(el){ var o = this.getXY(), e = Ext.fly(el, '_internal').getXY(); return [o[0]-e[0],o[1]-e[1]]; },
/** * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @param {Number} The X position of the element * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object * @return {Ext.core.Element} this */ setX : function(x, animate){ return this.setXY([x, this.getY()], animate); },
/** * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @param {Number} The Y position of the element * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object * @return {Ext.core.Element} this */ setY : function(y, animate){ return this.setXY([this.getX(), y], animate); },
/** * Sets the element's left position directly using CSS style (instead of {@link #setX}). * @param {String} left The left CSS property value * @return {Ext.core.Element} this */ setLeft : function(left){ this.setStyle(LEFT, this.addUnits(left)); return this; },
/** * Sets the element's top position directly using CSS style (instead of {@link #setY}). * @param {String} top The top CSS property value * @return {Ext.core.Element} this */ setTop : function(top){ this.setStyle(TOP, this.addUnits(top)); return this; },
/** * Sets the element's CSS right style. * @param {String} right The right CSS property value * @return {Ext.core.Element} this */ setRight : function(right){ this.setStyle(RIGHT, this.addUnits(right)); return this; },
/** * Sets the element's CSS bottom style. * @param {String} bottom The bottom CSS property value * @return {Ext.core.Element} this */ setBottom : function(bottom){ this.setStyle(BOTTOM, this.addUnits(bottom)); return this; },
/** * Sets the position of the element in page coordinates, regardless of how the element is positioned. * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based) * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object * @return {Ext.core.Element} this */ setXY: function(pos, animate) { var me = this; if (!animate || !me.anim) { ELEMENT.setXY(me.dom, pos); } else { if (!Ext.isObject(animate)) { animate = {}; } me.animate(Ext.applyIf({ to: { x: pos[0], y: pos[1] } }, animate)); } return me; },
/** * Sets the position of the element in page coordinates, regardless of how the element is positioned. * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @param {Number} x X value for new position (coordinates are page-based) * @param {Number} y Y value for new position (coordinates are page-based) * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object * @return {Ext.core.Element} this */ setLocation : function(x, y, animate){ return this.setXY([x, y], animate); },
/** * Sets the position of the element in page coordinates, regardless of how the element is positioned. * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false). * @param {Number} x X value for new position (coordinates are page-based) * @param {Number} y Y value for new position (coordinates are page-based) * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object * @return {Ext.core.Element} this */ moveTo : function(x, y, animate){ return this.setXY([x, y], animate); },
/** * Gets the left X coordinate * @param {Boolean} local True to get the local css position instead of page coordinate * @return {Number} */ getLeft : function(local){ return !local ? this.getX() : parseInt(this.getStyle(LEFT), 10) || 0; },
/** * Gets the right X coordinate of the element (element X position + element width) * @param {Boolean} local True to get the local css position instead of page coordinate * @return {Number} */ getRight : function(local){ var me = this; return !local ? me.getX() + me.getWidth() : (me.getLeft(true) + me.getWidth()) || 0; },
/** * Gets the top Y coordinate * @param {Boolean} local True to get the local css position instead of page coordinate * @return {Number} */ getTop : function(local) { return !local ? this.getY() : parseInt(this.getStyle(TOP), 10) || 0; },
/** * Gets the bottom Y coordinate of the element (element Y position + element height) * @param {Boolean} local True to get the local css position instead of page coordinate * @return {Number} */ getBottom : function(local){ var me = this; return !local ? me.getY() + me.getHeight() : (me.getTop(true) + me.getHeight()) || 0; },
/** * Initializes positioning on this element. If a desired position is not passed, it will make the * the element positioned relative IF it is not already positioned. * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed" * @param {Number} zIndex (optional) The zIndex to apply * @param {Number} x (optional) Set the page X position * @param {Number} y (optional) Set the page Y position */ position : function(pos, zIndex, x, y) { var me = this; if (!pos && me.isStyle(POSITION, STATIC)){ me.setStyle(POSITION, RELATIVE); } else if(pos) { me.setStyle(POSITION, pos); } if (zIndex){ me.setStyle(ZINDEX, zIndex); } if (x || y) { me.setXY([x || false, y || false]); } },
/** * Clear positioning back to the default when the document was loaded * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'. * @return {Ext.core.Element} this */ clearPositioning : function(value){ value = value || ''; this.setStyle({ left : value, right : value, top : value, bottom : value, "z-index" : "", position : STATIC }); return this; },
/** * Gets an object with all CSS positioning properties. Useful along with setPostioning to get * snapshot before performing an update and then restoring the element. * @return {Object} */ getPositioning : function(){ var l = this.getStyle(LEFT); var t = this.getStyle(TOP); return { "position" : this.getStyle(POSITION), "left" : l, "right" : l ? "" : this.getStyle(RIGHT), "top" : t, "bottom" : t ? "" : this.getStyle(BOTTOM), "z-index" : this.getStyle(ZINDEX) }; },
/** * Set positioning with an object returned by getPositioning(). * @param {Object} posCfg * @return {Ext.core.Element} this */ setPositioning : function(pc){ var me = this, style = me.dom.style; me.setStyle(pc); if(pc.right == AUTO){ style.right = ""; } if(pc.bottom == AUTO){ style.bottom = ""; } return me; },
/** * Translates the passed page coordinates into left/top css values for this element * @param {Number/Array} x The page x or an array containing [x, y] * @param {Number} y (optional) The page y, required if x is not an array * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)} */ translatePoints : function(x, y){ y = isNaN(x[1]) ? y : x[1]; x = isNaN(x[0]) ? x : x[0]; var me = this, relative = me.isStyle(POSITION, RELATIVE), o = me.getXY(), l = parseInt(me.getStyle(LEFT), 10), t = parseInt(me.getStyle(TOP), 10); l = !isNaN(l) ? l : (relative ? 0 : me.dom.offsetLeft); t = !isNaN(t) ? t : (relative ? 0 : me.dom.offsetTop); return {left: (x - o[0] + l), top: (y - o[1] + t)}; },
/** * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently. * @param {Object} box The box to fill {x, y, width, height} * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object * @return {Ext.core.Element} this */ setBox: function(box, adjust, animate) { var me = this, w = box.width, h = box.height; if ((adjust && !me.autoBoxAdjust) && !me.isBorderBox()) { w -= (me.getBorderWidth("lr") + me.getPadding("lr")); h -= (me.getBorderWidth("tb") + me.getPadding("tb")); } me.setBounds(box.x, box.y, w, h, animate); return me; },
/** * Return an object defining the area of this Element which can be passed to {@link #setBox} to * set another Element's size/location to match this element. * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned. * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y. * @return {Object} box An object in the format

{
    x: <Element's X position>,
    y: <Element's Y position>,
    width: <Element's width>,
    height: <Element's height>,
    bottom: <Element's lower bound>,
    right: <Element's rightmost bound>
}
* The returned object may also be addressed as an Array where index 0 contains the X position * and index 1 contains the Y position. So the result may also be used for {@link #setXY} */ getBox: function(contentBox, local) { var me = this, xy, left, top, getBorderWidth = me.getBorderWidth, getPadding = me.getPadding, l, r, t, b; if (!local) { xy = me.getXY(); } else { left = parseInt(me.getStyle("left"), 10) || 0; top = parseInt(me.getStyle("top"), 10) || 0; xy = [left, top]; } var el = me.dom, w = el.offsetWidth, h = el.offsetHeight, bx; if (!contentBox) { bx = { x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h }; } else { l = getBorderWidth.call(me, "l") + getPadding.call(me, "l"); r = getBorderWidth.call(me, "r") + getPadding.call(me, "r"); t = getBorderWidth.call(me, "t") + getPadding.call(me, "t"); b = getBorderWidth.call(me, "b") + getPadding.call(me, "b"); bx = { x: xy[0] + l, y: xy[1] + t, 0: xy[0] + l, 1: xy[1] + t, width: w - (l + r), height: h - (t + b) }; } bx.right = bx.x + bx.width; bx.bottom = bx.y + bx.height; return bx; },
/** * Move this element relative to its current position. * @param {String} direction Possible values are: "l" (or "left"), "r" (or "right"), "t" (or "top", or "up"), "b" (or "bottom", or "down"). * @param {Number} distance How far to move the element in pixels * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object * @return {Ext.core.Element} this */ move: function(direction, distance, animate) { var me = this, xy = me.getXY(), x = xy[0], y = xy[1], left = [x - distance, y], right = [x + distance, y], top = [x, y - distance], bottom = [x, y + distance], hash = { l: left, left: left, r: right, right: right, t: top, top: top, up: top, b: bottom, bottom: bottom, down: bottom }; direction = direction.toLowerCase(); me.moveTo(hash[direction][0], hash[direction][1], animate); },
/** * Quick set left and top adding default units * @param {String} left The left CSS property value * @param {String} top The top CSS property value * @return {Ext.core.Element} this */ setLeftTop: function(left, top) { var me = this, style = me.dom.style; style.left = me.addUnits(left); style.top = me.addUnits(top); return me; },
/** * Returns the region of this element. * The element must be part of the DOM tree to have a region (display:none or elements not appended return false). * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data. */ getRegion: function() { return this.getPageBox(true); },
/** * Returns the content region of this element. That is the region within the borders and padding. * @return {Region} A Ext.util.Region containing "top, left, bottom, right" member data. */ getViewRegion: function() { var pos = this.getXY(), top = pos[1] + this.getBorderWidth('t') + this.getPadding('t'), left = pos[0] + this.getBorderWidth('l') + this.getPadding('l'), size = this.getViewSize(); return new Ext.util.Region(top, left + size.width - 1 - this.getPadding('lr'), top + size.height - 1 - this.getPadding('tb'), left); },
/** * Return an object defining the area of this Element which can be passed to {@link #setBox} to * set another Element's size/location to match this element. * @param {Boolean} asRegion(optional) If true an Ext.util.Region will be returned * @return {Object} box An object in the format

{
    x: <Element's X position>,
    y: <Element's Y position>,
    width: <Element's width>,
    height: <Element's height>,
    bottom: <Element's lower bound>,
    right: <Element's rightmost bound>
}
* The returned object may also be addressed as an Array where index 0 contains the X position * and index 1 contains the Y position. So the result may also be used for {@link #setXY} */ getPageBox : function(getRegion) { var me = this, el = me.dom, isDoc = el === document.body, w = isDoc ? Ext.core.Element.getViewWidth() : el.offsetWidth, h = isDoc ? Ext.core.Element.getViewHeight() : el.offsetHeight, xy = me.getXY(), t = xy[1], r = xy[0] + w - 1, b = xy[1] + h - 1, l = xy[0]; if (getRegion) { return new Ext.util.Region(t, r, b, l); } else { return { left: l, top: t, width: w, height: h, right: r, bottom: b }; } },
/** * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently. * @param {Number} x X value for new position (coordinates are page-based) * @param {Number} y Y value for new position (coordinates are page-based) * @param {Mixed} width The new width. This may be one of:
* @param {Mixed} height The new height. This may be one of:
* @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object * @return {Ext.core.Element} this */ setBounds: function(x, y, width, height, animate) { var me = this; if (!animate || !me.anim) { me.setSize(width, height); me.setLocation(x, y); } else { if (!Ext.isObject(animate)) { animate = {}; } me.animate(Ext.applyIf({ to: { x: x, y: y, width: me.adjustWidth(width), height: me.adjustHeight(height) } }, animate)); } return me; },
/** * Sets the element's position and size the specified region. If animation is true then width, height, x and y will be animated concurrently. * @param {Ext.util.Region} region The region to fill * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object * @return {Ext.core.Element} this */ setRegion: function(region, animate) { return this.setBounds(region.left, region.top, region.right - region.left, region.bottom - region.top, animate); } }); })();