text: Ext.define('Ext.rtl.dom.Element', {
      override: 'Ext.dom.Element',
  
      requires: [
          "Ext.CompositeElementLite"
      ],
      
      rtlXAnchors: {
          l: 'r',
          r: 'l'
      },
  
      _positionTopRight: ['position', 'top', 'right'],
  
      pxRe: /^\d+(?:\.\d*)?px$/i,
     
      statics: { 
          rtlParseBox: function (box) {
              var ret = Ext.Element.parseBox(box),
                  temp;
                 
              temp = ret.left;
              ret.left = ret.right;
              ret.right = temp;
              
              return ret;
          },
  
          rtlUnitizeBox: function(box, units){
              var Element = Ext.Element,
                  a = Element.addUnits,
                  b = Element.parseBox(box);
  
              // Usual order is trbl, so reverse it
              // to return tlbr
              return a(b.top, units) + ' ' +
                     a(b.left, units) + ' ' +
                     a(b.bottom, units) + ' ' +
                     a(b.right, units);
          }
      },
  
      anchorAnimX: function(anchor) {
          if (Ext.rootInheritedState.rtl) {
              anchor = this.rtlXAnchors[anchor];
          }
          this.callParent(arguments);
      },
  
      getPositioning: function(autoPx){
          var xStyle = Ext.rootInheritedState.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;
      },
  
      getXY: function() {
          var doc = document,
              round = Math.round,
              dom = this.dom,
              body = doc.body,
              x = 0,
              y = 0,
              bodyRect, rect;
  
          if(dom !== doc && dom !== body){
              // IE (including IE10) throws an error when getBoundingClientRect
              // is called on an element not attached to dom
              try {
                  bodyRect = body.getBoundingClientRect();
                  rect = dom.getBoundingClientRect();
  
                  x = rect.left - bodyRect.left;
                  y = rect.top - bodyRect.top;
  
                  if (Ext.rootInheritedState.rtl) {
                      x = body.scrollWidth - rect.right;
                  }
              } catch (ex) {}
          }
  
          return [round(x), round(y)];
      },
  
      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, '_internal').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, '_internal').getX();
              }
          }
  
          if (!y || y === 'auto') {
              y = 0;
          } else if (me.pxRe.test(y)) {
              y = parseFloat(y);
          } else {
              y = me.getY();
              if (offsetParent) {
                  y -= Ext.fly(offsetParent, '_internal').getY();
              }
          }
  
          return [x, y];
      },
  
      rtlGetScroll: function() {
          var me = this,
              dom = me.dom,
              doc = document,
              body = doc.body,
              scroll = me.getScroll(),
              left = scroll.left,
              isDocOrBody = (dom === doc || dom === body);
  
          if (isDocOrBody ? (3 & me._rtlDocScrollFlag) : (me._rtlScrollFlag === 1)) { // jshint ignore:line
              // If the browser reports scrollLeft as the number of pixels from left
              // (same as ltr) we need to convert it to a rtl position by subtracting it
              // from scrollWidth
              if (isDocOrBody) {
                  dom = body;
              }
              
              left = dom.scrollWidth - left -
                  (isDocOrBody ? Ext.Element.getViewportWidth() : dom.clientWidth);
          }
          scroll.left = left;
  
          return scroll;
      },
      
      rtlGetScrollLeft: function() {
          return this.rtlGetScroll().left;
      },
  
      rtlNormalizeScrollLeft: function(left){
          var dom = this.dom,
              flag = this._rtlScrollFlag;
              
          if (flag === 0) {
              left = -left;
          } else if (flag === 1) {
              left = dom.scrollWidth - left - dom.clientWidth;
          }
          return left;
      },
  
      rtlScrollBy: function(deltaX, deltaY, animate) {
          var me = this,
              dom = me.dom,
              left;
  
          // Extract args if deltas were passed as an Array.
          if (deltaX.length) {
              animate = deltaY;
              deltaY = deltaX[1];
              deltaX = deltaX[0];
          } else if (typeof deltaX !== 'number') { // or an object
              animate = deltaY;
              deltaY = deltaX.y;
              deltaX = deltaX.x;
          }
         
          if (deltaX) {
              left = me.rtlNormalizeScrollLeft(
                  me.constrainScrollLeft(me.rtlGetScrollLeft() + deltaX)
              ); 
   
              me.scrollTo('left', left, animate);
          }
          if (deltaY) {
              me.scrollTo('top', me.constrainScrollTop(dom.scrollTop + deltaY), animate);
          }
  
          return me;
      },
  
      rtlScrollIntoView: function(container, hscroll, animate, highlight) {
          container = Ext.getDom(container) || Ext.getBody().dom;
  
          return this.doScrollIntoView(
              container,
              hscroll,
              animate,
              highlight,
              'rtlGetScrollLeft',
              'rtlScrollTo'
          );
      },
  
      rtlScrollTo: function(side, value, animate) {
          if (side === 'left') {
              value = this.rtlNormalizeScrollLeft(value);
          }
  
          return this.scrollTo(side, value, animate);
      },
  
      rtlSetLocalX: function(x) {
          var me = this,
              style = me.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';
  
          if (me.shadow || me.shim) {
              me.syncUnderlays();
          }
  
          return me;
      },
  
      rtlSetLocalXY: function(x, y) {
          var me = this,
              style = me.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';
          }
  
          if (me.shadow || me.shim) {
              me.syncUnderlays();
          }
  
          return me;
      },
  
      rtlSetScrollLeft: function(left){
          var me = this;
  
          me.dom.scrollLeft = me.rtlNormalizeScrollLeft(left);
          return me;
      },
  
      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
          };
      },
  
      translatePoints: function(x, y) {
          return Ext.rootInheritedState.rtl ? this.rtlTranslatePoints(x, y) :
              this.callParent(arguments);
      },
  
      translateXY: function(x, y) {
          return Ext.rootInheritedState.rtl ? this.rtlTranslateXY(x, y) :
              this.callParent(arguments);
      },
  
      wrap: function() {
          var parent = this.parent(),
              rtlCls = Ext.baseCSSPrefix + 'rtl',
              ltrCls = Ext.baseCSSPrefix + 'ltr',
              wrapEl = this.callParent(arguments),
              cls;
  
          // if the parentNode of the element being wrapped has the "x-rtl" or "x-ltr" css
          // class, then add that class to the wrapper as well.  This ensures that descendant
          // and child selectors still apply e.g. ".x-rtl > .x-foo" or ".x-ltr .x-foo"
          if (parent.hasCls(rtlCls)) {
              cls = rtlCls;
          } else if (parent.hasCls(ltrCls)) {
              cls = ltrCls;
          }
  
          if (cls) {
              // superclass method may return dom, so use fly() to access the wrap el
              Ext.fly(wrapEl, '_internal').addCls(cls);
          }
  
          return wrapEl;
      }
  
  }, function() {
      var Element = this;
  
      // ensure that any methods added by this override are also added to Ext.CompositeElementLite
      Ext.CompositeElementLite.importElementMethods();
  
      /*
       * Sets a _rtlScrollFlag property on the Element class prototype indicating how the
       * browser reports scrollLeft on overflowing rtl elements.  This method cannot be used
       * reliably on the documentElement or document.body because the behavior of these
       * elements can be different from other elements in some browsers.
       * 
       * 0: offset from right (negative number) - Firefox & Safari
       * 1: offset from left (positive number) - Webkit
       * 2: offset from right (positive number) - IE8 - IE10
       */
      function cacheRtlScrollFlag() {
          var el = Ext.getBody().createChild({
              tag: 'div',
              style: 'direction:rtl;position:absolute;overflow:auto;height:100px;width:100px;background-color:yellow',
              children: [{
                  tag: 'div',
                  style: 'height:30px;width:150px;background-color:red'
              }]
          }),
          dom = el.dom,
          inner = dom.firstChild,
          flag = 2;
  
          if (dom.scrollLeft === 50) {
              flag = 1;
          } else {
              dom.scrollLeft = -1;
              if (dom.scrollLeft) {
                  flag = 0;
              }
          }
  
          // Make content overflow vertically to see where the vertical scsrollbar is
          inner.style.width = '30px';
          inner.style.height = '150px';
  
          // Scrollbar is erroneously on right in RTL mode if the inner element is not flush against the right egde of the outer.
          // Safaris suffers from this bug.
          Element.prototype._rtlScrollbarOnRight = inner.getBoundingClientRect().right < dom.getBoundingClientRect().right;
  
          el.destroy();
          Element.prototype._rtlScrollFlag = flag;
      }
  
      /*
       * scrollLeft on the document/body is reported differently from ordinary
       * overflowing elements in many browsers (see getRtlScrollFlag).There are 2
       * separate things we have to detect:
       * 1. The element that overflows - when the document overflows some browsers
       * set scrollLeft on the document body (webkit), while other browsers set scrollLeft
       * on the documentElement (all other supported browsers at the time of this writing).
       * 2. The scrollLeft of the overflowing document/body can be one of the
       * following:
       *    a. number of pixels offset from right expressed as a negative number
       *       (Webkit, Firefox)
       *    b. number of pixels offset from right expressed as a positive number
       *       (IE8 - IE10)
       *
       * The following logic feture detects the handling of scrollLeft and sets the 
       * _rtlDocScrollFlag property on this class' prototype as a bit flag which has 
       * the following values:
       * 
       * 0 - docEl, negative right
       * 1 - docEl, positive left
       * 2 - docEl, positive right
       * 4 - body, negative right
       */
      function cacheRtlDocScrollFlag() {
          var doc = document,
              docEl = doc.documentElement,
              body = doc.body,
              // flag defaults to body, negative right (webkit) so no detection needed
              // is needed for this scenario
              flag = 4,
              bodyStyle = body.style,
              // save the direction property so we can set it back when we are done.
              direction = bodyStyle.direction,
              el = Ext.getBody().createChild(
                  '<div style="height:20000px;width:20000px;"></div>'
              );
  
          bodyStyle.direction = 'rtl';
  
          // First, check if scrollLeft is a non-zero value on the documentElement or
          // body. This means scrollLeft is a positive number offset from the left.
          if (docEl.scrollLeft > 0) {
              flag = 1;
          } else {
              // The next step is to attempt to set scrollLeft values, This allows us to
              // test for non-zero values to see if the value was valid (scrollLeft
              // resets to 0 when a non-valid value is set).
              // attempt to set the documentElement's scrollLeft to a negative number
              docEl.scrollLeft = -1;
              if (docEl.scrollLeft) {
                  // it worked! we were able to set a negative scroll left on the
                  // documentElement (firefox)
                  flag = 0;
              } else {
                  // attempt to set the documentElement's scrollLeft to a positive number
                  docEl.scrollLeft = 1;
                  if (docEl.scrollLeft) {
                      // success setting scroll left to a positive number on
                      // documentElement (IE8 & IE9)
                      flag = 2;
                  }
              }
          }
  
          el.destroy();
          if (!direction) {
              // if direction is an empty string, we set it back to "ltr", because once
              // the direction style on the body element is changed to "rtl" in webkit,
              // it becomes permanent, even after it is set back to "", unless it is first
              // explicitly set back to "ltr"
              bodyStyle.direction = 'ltr';
              // read the scroll width before setting the direction back to "".
              // This forces webkit to update its computed direction style to ltr
              body.scrollWidth; // jshint ignore:line
          }
          // set direction back to its original value
          bodyStyle.direction = direction;
          Element.prototype._rtlDocScrollFlag = flag;
      }
  
      Ext.onInternalReady(function () {
          // This function attaches to onReady with a priority of 1000 so that we can
          // detect how the browser reports scrollLeft by manipulating the document/body
          // before any components have been rendered to the page.  
          cacheRtlDocScrollFlag();
          cacheRtlScrollFlag();
      });
  });
  