/** * This override adds RTL positioning methods to Ext.dom.Element. */ Ext.define('Ext.rtl.dom.Element_position', { override: 'Ext.dom.Element', _positionTopRight: ['position', 'top', 'right'], statics: { getXY: function(el) { var doc = document, bd = doc.body, docEl = doc.documentElement, leftBorder = 0, topBorder = 0, ret = [0,0], x, box, scroll; el = Ext.getDom(el); if(el !== doc && el !== bd){ // IE has the potential to throw when getBoundingClientRect // is called on an element not attached to dom if (Ext.isIE) { try { box = el.getBoundingClientRect(); // In some versions of IE, the documentElement (HTML element) // will have a 2px border that gets included, so subtract it off topBorder = docEl.clientTop || bd.clientTop; leftBorder = docEl.clientLeft || bd.clientLeft; } catch (ex) { box = { left: 0, top: 0 }; } } else { box = el.getBoundingClientRect(); } doc = Ext.fly(document, '_getXY'); if (Ext.rootHierarchyState.rtl) { scroll = doc.rtlGetScroll(); x = Ext.Element.getViewportWidth() - box.right + scroll.left; } else { scroll = doc.getScroll(); x = box.left + scroll.left; } ret = [ Math.round(x - leftBorder), Math.round(box.top + scroll.top - topBorder) ]; } return ret; }, setXY: function(el, xy) { (el = Ext.fly(el, '_setXY')).position(); var pts = el.translatePoints(xy), style = el.dom.style, pos; style[Ext.rootHierarchyState.rtl ? 'left' : 'right'] = 'auto'; for (pos in pts) { if (!isNaN(pts[pos])) { style[pos] = pts[pos] + 'px'; } } } }, getPositioning: function(autoPx){ var xStyle = Ext.rootHierarchyState.rtl ? 'right' : 'left', styles = this.getStyle([xStyle, 'top', 'position', 'z-index']), dom = this.dom; if(autoPx) { if(styles[xStyle] === 'auto') { styles[xStyle] = (xStyle === 'left') ? (dom.offsetLeft + 'px') : (dom.offsetParent.offsetWidth - dom.offsetLeft - dom.offsetWidth); } if(styles.top === 'auto') { styles.top = dom.offsetTop + 'px'; } } return styles; }, rtlGetLocalX: function() { var me = this, offsetParent = me.dom.offsetParent, x = me.getStyle('right'); if (!x || x === 'auto') { x = 0; } else if (me.pxRe.test(x)) { x = parseFloat(x); } else { x = me.getX(); if (offsetParent) { x -= Ext.fly(offsetParent, '_rtlGetLocalX').getX(); } } return x; }, rtlGetLocalXY: function() { var me = this, offsetParent = me.dom.offsetParent, style = me.getStyle(['right', 'top']), x = style.right, y = style.top; if (!x || x === 'auto') { x = 0; } else if (me.pxRe.test(x)) { x = parseFloat(x); } else { x = me.getX(); if (offsetParent) { x -= Ext.fly(offsetParent, '_rtlGetLocalXY').getX(); } } if (!y || y === 'auto') { y = 0; } else if (me.pxRe.test(y)) { y = parseFloat(y); } else { y = me.getY(); if (offsetParent) { y -= Ext.Element.getY(offsetParent); } } return [x, y]; }, rtlSetLocalX: function(x) { var style = this.dom.style; // clear left style just in case it was previously set by setXY/setLocalXY style.left = 'auto'; style.right = (x === null) ? 'auto' : x + 'px'; }, rtlSetLocalXY: function(x, y) { var style = this.dom.style; // clear left style just in case it was previously set by setXY/setLocalXY style.left = 'auto'; if (x && x.length) { y = x[1]; x = x[0]; } if (x === null) { style.right = 'auto'; } else if (x !== undefined) { style.right = x + 'px'; } if (y === null) { style.top = 'auto'; } else if (y !== undefined) { style.top = y + 'px'; } }, rtlSetX: function(x, animate) { return this.rtlSetXY([x, this.getY()], animate); }, rtlSetXY: function(xy, animate) { var me = this, pts, style, pos; if (!animate || !me.anim) { pts = me.rtlTranslatePoints(xy); style = me.dom.style; // left position may have been previously set by setXY or setLocalXY // so clear it here just in case. style.left = 'auto'; for (pos in pts) { if (!isNaN(pts[pos])) { style[pos] = pts[pos] + "px"; } } } else { if (!Ext.isObject(animate)) { animate = {}; } me.animate(Ext.applyIf({ to: { x: xy[0], y: xy[1] } }, animate)); } return me; }, rtlSetY: function(y, animate) { return this.rtlSetXY([this.getX(), y], animate); }, rtlTranslatePoints: function(x, y) { var pos = this.rtlTranslateXY(x, y); return { right: pos.x, top: pos.y }; }, rtlTranslateXY: function(x, y) { var me = this, styles = me.getStyle(me._positionTopRight), relative = styles.position == 'relative', right = parseFloat(styles.right), top = parseFloat(styles.top), xy = me.getXY(), dom = me.dom, doc, body, offsetParentWidth, offsetParent; if (x && x.length) { y = x[1]; x = x[0]; } if (isNaN(right)) { doc = document; body = doc.body; if (dom === body) { // translateXY can sometimes be called on the body element. // e.g. in Renderable#afterFirstLayout if the "container" is a viewport right = 0; } else { offsetParent = dom.offsetParent; offsetParentWidth = (offsetParent && offsetParent !== body && offsetParent !== doc.documentElement) ? offsetParent.scrollWidth : Ext.Element.getViewportWidth(); right = offsetParentWidth - dom.offsetLeft - me.getWidth(); } } if (isNaN(top)) { top = relative ? 0 : me.dom.offsetTop; } right = (typeof x == 'number') ? x - xy[0] + right : undefined; top = (typeof y == 'number') ? y - xy[1] + top : undefined; return { x: right, y: top }; }, setX: function(x, animate) { return Ext.rootHierarchyState.rtl ? this.rtlSetX(x, animate) : this.callParent(arguments); }, setXY: function(xy, animate) { return Ext.rootHierarchyState.rtl ? this.rtlSetXY(xy, animate) : this.callParent(arguments); }, setY: function(y, animate) { return Ext.rootHierarchyState.rtl ? this.rtlSetY(y, animate) : this.callParent(arguments); }, translatePoints: function(x, y) { return Ext.rootHierarchyState.rtl ? this.rtlTranslatePoints(x, y) : this.callParent(arguments); }, translateXY: function(x, y) { return Ext.rootHierarchyState.rtl ? this.rtlTranslateXY(x, y) : this.callParent(arguments); } });