text: /**
   * A component to show indication of an active item.
   */
  Ext.define('Ext.Indicator', {
      extend: 'Ext.Component',
      xtype: 'indicator',
  
      config: {
          /**
           * @cfg {Number} activeIndex The index of the active indicator
           * dot.
           */
          activeIndex: null,
  
          /**
           * @cfg {Number} count The number of indicator dots to show.
           */
          count: null,
  
          /**
           * @cfg {String} [direction=horizontal] The direction the indicator
           * will be shown. Can be `horizontal` to have the dots be shown
           * in a row or `vertical` to have the dots be shown in a column.
           */
          direction: 'horizontal',
  
          /**
           * @cfg {String} [tapMode=direction] Controls what happens when clicked
           * on. The following are valid options:
           *
           * - **`direction`** Depending where the click happened, if on the right
           * half of the indicator, the next item will be made active else the
           * previous item will be made active.
           * - **`item`** If the click was on an indicator dot, the associated item
           * to that dot will be made active. If the click was not on an indicator
           * dot, then `direction` mode will be used.
           */
          tapMode: 'direction'
      },
  
      /**
       * @property {String} [activeCls=active] The CSS class name that will
       * be added to the active indicator dot.
       * @protected
       */
      activeCls: Ext.baseCSSPrefix + 'indicator-active',
  
      baseCls: Ext.baseCSSPrefix + 'indicator',
  
      /**
       * @property {String} [itemCls=x-indicator-item] The CSS class name
       * that will be added to the indicator dots.
       * @protected
       */
      itemCls: Ext.baseCSSPrefix + 'indicator-item',
  
      defaultBindProperty: 'activeIndex',
  
      twoWayBindable: [
          'activeIndex'
      ],
  
      /**
       * @private
       */
      isIndicator: true,
  
      /**
       * @property {Array} indicators An array of indicator dot
       * elements.
       * @private
       */
  
      /**
       * @event indicatortap
       * Fires when an indicator dot has been tapped and {@link #tapMode}
       * is set to `item`.
       * @param {Ext.Indicator} this
       * @param {Number} index The index of the indicator dot.
       * @param {Ext.dom.Elemnet} item The indicator dot item.
       */
  
      /**
       * @event next
       * Fires when this indicator is tapped on the right half
       * @param {Ext.Indicator} this
       */
  
      /**
       * @event previous
       * Fires when this indicator is tapped on the left half
       * @param {Ext.Indicator} this
       */
  
      constructor: function (config) {
          this.indicators = [];
  
          this.callParent([config]);
      },
  
      initialize: function () {
          this.callParent();
  
          this.element.on({
              tap: 'onTap',
              scope: this
          });
      },
  
      doDestroy: function () {
          Ext.destroy(this.indicators);
  
          this.callParent();
      },
  
      //<debug>
      applyActiveIndex: function (index) {
          var indicators = this.indicators,
              max = indicators.length - 1;
  
          if (index > max) {
              Ext.raise('Cannot set the active index greater than the number of indicators');
          }
  
          return index;
      },
      //</debug>
  
      updateActiveIndex: function (index, oldIndex) {
          var activeCls = this.activeCls,
              baseCls = this.baseCls,
              indicators = this.indicators,
              currentActiveItem = indicators[oldIndex],
              activeItem = indicators[index];
  
          if (currentActiveItem) {
              currentActiveItem.removeCls(activeCls);
          }
  
          if (activeItem) {
              activeItem.addCls(activeCls);
          }
      },
  
      updateCount: function (count) {
          var indicators = this.indicators;
  
          while (indicators.length < count) {
               this.doAdd()
          }
  
          while (indicators.length > count) {
              this.doRemove();
          }
      },
  
      //<debug>
      applyDirection: function (direction) {
          if (direction !== 'vertical' && direction !== 'horizontal') {
              Ext.raise('Invalid indicator direction provided: ' + direction);
  
              direction = 'horizontal';
          }
  
          return direction;
      },
      //</debug>
  
      updateDirection: function (newDirection, oldDirection) {
          this.element.replaceCls(oldDirection, newDirection, this.baseCls);
      },
  
      /**
       * Syncs the number of indicators and sets the active index.
       * @param {Number} count The number of indicators that needs to be shown. If `null`,
       * will skip syncing the number of indicators
       * @param {Number} activeIndex If specified, will set the {@link #activeIndex}.
       * @return {Ext.Indicator} this
       */
      sync: function (count, activeIndex) {
          if (Ext.isNumber(count)) {
              this.setCount(count);
          }
  
          if (Ext.isNumber(activeIndex)) {
              this.setActiveIndex(activeIndex);
          }
  
          return this;
      },
  
      /**
       * Adds an indicator dot at the end.
       * @return {Ext.Indicator} this
       */
      add: function () {
          var count = this.getCount();
  
          return this.setCount(++count);
      },
  
      /**
       * Removes all indicator dots.
       * @return {Ext.Indicator} this
       */
      removeAll: function () {
          return this.setCount(0);
      },
  
      /**
       * Removes the last indicator dot.
       * @return {Ext.Indicator} this
       */
      remove: function () {
          var count = this.getCount();
  
          return this.setCount(--count);
      },
  
      /**
       * Creates an indicator dot and addes it to {@link #indicators}.
       * @private
       * @return {Ext.Indicator} this
       */
      doAdd: function () {
          var indicators = this.indicators;
  
          indicators.push(this.element.createChild({
              tag: 'span',
              cls: this.itemCls
          }));
  
          return this;
      },
  
      /**
       * Removes and destroys the last indicator dot.
       * @private
       * @return {Ext.Indicator} this
       */
      doRemove: function () {
          var indicators = this.indicators,
              indicator = indicators.pop();
  
          if (indicator) {
              indicator.destroy();
          }
  
          return this;
      },
  
      /**
       * @private
       */
      onTap: function (e) {
          var mode = this.getTapMode();
  
          if (mode === 'item') {
              this.onTapItem(e);
          } else {
              this.onTapDirection(e);
          }
      },
  
      /**
       * Handles the tap when {@link #tapMode} is set to `item`.
       * @private
       */
      onTapItem: function (e) {
          var me = this,
              item = e.getTarget('.' + me.itemCls, 1, true),
              index;
  
          if (item) {
              index = me.indicators.indexOf(item);
  
              if (index !== -1) {
                  me.fireEvent('indicatortap', me, index, item);
              }
          } else {
              //tap wasn't on a dot, go with direction
              me.onTapDirection(e);
          }
      },
  
      /**
       * Handles the tap when {@link #tapMode} is set to `direction`.
       * @private
       */
      onTapDirection: function (e) {
          var me = this,
              direction = me.getDirection(),
              touch = e.touch,
              box = me.element.getBox(),
              centerX = box.left + (box.width / 2),
              centerY = box.top + (box.height / 2),
              event = (direction === 'horizontal' && touch.pageX >= centerX) ||
                      (direction === 'vertical' && touch.pageY >= centerY) ? 'next' : 'previous';
  
          me.fireEvent(event, me);
      }
  });
  