    /**
     * @class Ext.dom.AbstractElement
     */
    (function(){

    var Element = Ext.dom.AbstractElement;

    Element.override({

        /**
         * 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(el) {
            return this.getXY(el)[0];
        },

        /**
         * 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(el) {
            return this.getXY(el)[1];
        },

        /**
         * 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() {
            // @FEATUREDETECT
            var point = window.webkitConvertPointFromNodeToPage(this.dom, new WebKitPoint(0, 0));
            return [point.x, point.y];
        },

        /**
         * 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 {Ext.Element/HTMLElement/String} 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] True for the default animation, or a standard Element
         * animation config object
         * @return {Ext.dom.AbstractElement} this
         */
        setX: function(x){
            return this.setXY([x, this.getY()]);
        },

        /**
         * 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] True for the default animation, or a standard Element
         * animation config object
         * @return {Ext.dom.AbstractElement} this
         */
        setY: function(y) {
            return this.setXY([this.getX(), y]);
        },

        /**
         * Sets the element's left position directly using CSS style (instead of {@link #setX}).
         * @param {String} left The left CSS property value
         * @return {Ext.dom.AbstractElement} this
         */
        setLeft: function(left) {
            this.setStyle('left', Element.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.dom.AbstractElement} this
         */
        setTop: function(top) {
            this.setStyle('top', Element.addUnits(top));
            return this;
        },

        /**
         * Sets the element's CSS right style.
         * @param {String} right The right CSS property value
         * @return {Ext.dom.AbstractElement} this
         */
        setRight: function(right) {
            this.setStyle('right', Element.addUnits(right));
            return this;
        },

        /**
         * Sets the element's CSS bottom style.
         * @param {String} bottom The bottom CSS property value
         * @return {Ext.dom.AbstractElement} this
         */
        setBottom: function(bottom) {
            this.setStyle('bottom', Element.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] True for the default animation, or a standard Element animation config object
         * @return {Ext.dom.AbstractElement} this
         */
        setXY: function(pos) {
            var me = this,
                pts,
                style,
                pt;

            if (arguments.length > 1) {
                pos = [pos, arguments[1]];
            }

            // me.position();
            pts = me.translatePoints(pos);
            style = me.dom.style;

            for (pt in pts) {
                if (!pts.hasOwnProperty(pt)) {
                    continue;
                }
                if (!isNaN(pts[pt])) {
                    style[pt] = pts[pt] + "px";
                }
            }
            return me;
        },

        /**
         * 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 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) {
            return parseInt(this.getStyle('right'), 10) || 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 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) {
            return parseInt(this.getStyle('bottom'), 10) || 0;
        },

        /**
         * 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] 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] Whether to adjust for box-model issues automatically
         * @param {Boolean/Object} [animate] true for the default animation or a standard
         * Element animation config object
         * @return {Ext.dom.AbstractElement} this
         */
        setBox: function(box) {
            var me = this,
                width = box.width,
                height = box.height,
                top = box.top,
                left = box.left;

            if (left !== undefined) {
                me.setLeft(left);
            }
            if (top !== undefined) {
                me.setTop(top);
            }
            if (width !== undefined) {
                me.setWidth(width);
            }
            if (height !== undefined) {
                me.setHeight(height);
            }

            return this;
        },

        /**
         * 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] If true a box for the content of the element is returned.
         * @param {Boolean} [local] 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,
                dom = me.dom,
                width = dom.offsetWidth,
                height = dom.offsetHeight,
                xy, box, l, r, t, b;

            if (!local) {
                xy = me.getXY();
            }
            else if (contentBox) {
                xy = [0,0];
            }
            else {
                xy = [parseInt(me.getStyle("left"), 10) || 0, parseInt(me.getStyle("top"), 10) || 0];
            }

            if (!contentBox) {
                box = {
                    x: xy[0],
                    y: xy[1],
                    0: xy[0],
                    1: xy[1],
                    width: width,
                    height: height
                };
            }
            else {
                l = me.getBorderWidth.call(me, "l") + me.getPadding.call(me, "l");
                r = me.getBorderWidth.call(me, "r") + me.getPadding.call(me, "r");
                t = me.getBorderWidth.call(me, "t") + me.getPadding.call(me, "t");
                b = me.getBorderWidth.call(me, "b") + me.getPadding.call(me, "b");
                box = {
                    x: xy[0] + l,
                    y: xy[1] + t,
                    0: xy[0] + l,
                    1: xy[1] + t,
                    width: width - (l + r),
                    height: height - (t + b)
                };
            }

            box.left = box.x;
            box.top = box.y;
            box.right = box.x + box.width;
            box.bottom = box.y + box.height;

            return box;
        },

        /**
         * 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] 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,
                w = el.offsetWidth,
                h = el.offsetHeight,
                xy = me.getXY(),
                t = xy[1],
                r = xy[0] + w,
                b = xy[1] + h,
                l = xy[0];

            if (!el) {
                return new Ext.util.Region();
            }

            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
                };
            }
        }
    });

    }());