text: define([
    'jquery',
    '../utils',
    '../keys'
  ], function ($, Utils, KEYS) {
    function BaseSelection ($element, options) {
      this.$element = $element;
      this.options = options;
      BaseSelection.__super__.constructor.call(this);
    }
    Utils.Extend(BaseSelection, Utils.Observable);
    BaseSelection.prototype.render = function () {
      var $selection = $(
        '<span class="select2-selection" role="combobox" ' +
        ' aria-haspopup="true" aria-expanded="false">' +
        '</span>'
      );
      this._tabindex = 0;
      if (this.$element.data('old-tabindex') != null) {
        this._tabindex = this.$element.data('old-tabindex');
      } else if (this.$element.attr('tabindex') != null) {
        this._tabindex = this.$element.attr('tabindex');
      }
      $selection.attr('title', this.$element.attr('title'));
      $selection.attr('tabindex', this._tabindex);
      this.$selection = $selection;
      return $selection;
    };
    BaseSelection.prototype.bind = function (container, $container) {
      var self = this;
      var id = container.id + '-container';
      var resultsId = container.id + '-results';
      this.container = container;
      this.$selection.on('focus', function (evt) {
        self.trigger('focus', evt);
      });
      this.$selection.on('blur', function (evt) {
        self._handleBlur(evt);
      });
      this.$selection.on('keydown', function (evt) {
        self.trigger('keypress', evt);
        if (evt.which === KEYS.SPACE) {
          evt.preventDefault();
        }
      });
      container.on('results:focus', function (params) {
        self.$selection.attr('aria-activedescendant', params.data._resultId);
      });
      container.on('selection:update', function (params) {
        self.update(params.data);
      });
      container.on('open', function () {
        // When the dropdown is open, aria-expanded="true"
        self.$selection.attr('aria-expanded', 'true');
        self.$selection.attr('aria-owns', resultsId);
        self._attachCloseHandler(container);
      });
      container.on('close', function () {
        // When the dropdown is closed, aria-expanded="false"
        self.$selection.attr('aria-expanded', 'false');
        self.$selection.removeAttr('aria-activedescendant');
        self.$selection.removeAttr('aria-owns');
        self.$selection.focus();
        self._detachCloseHandler(container);
      });
      container.on('enable', function () {
        self.$selection.attr('tabindex', self._tabindex);
      });
      container.on('disable', function () {
        self.$selection.attr('tabindex', '-1');
      });
    };
    BaseSelection.prototype._handleBlur = function (evt) {
      var self = this;
      // This needs to be delayed as the active element is the body when the tab
      // key is pressed, possibly along with others.
      window.setTimeout(function () {
        // Don't trigger `blur` if the focus is still in the selection
        if (
          (document.activeElement == self.$selection[0]) ||
          ($.contains(self.$selection[0], document.activeElement))
        ) {
          return;
        }
        self.trigger('blur', evt);
      }, 1);
    };
    BaseSelection.prototype._attachCloseHandler = function (container) {
      var self = this;
      $(document.body).on('mousedown.select2.' + container.id, function (e) {
        var $target = $(e.target);
        var $select = $target.closest('.select2');
        var $all = $('.select2.select2-container--open');
        $all.each(function () {
          var $this = $(this);
          if (this == $select[0]) {
            return;
          }
          var $element = $this.data('element');
          $element.select2('close');
        });
      });
    };
    BaseSelection.prototype._detachCloseHandler = function (container) {
      $(document.body).off('mousedown.select2.' + container.id);
    };
    BaseSelection.prototype.position = function ($selection, $container) {
      var $selectionContainer = $container.find('.selection');
      $selectionContainer.append($selection);
    };
    BaseSelection.prototype.destroy = function () {
      this._detachCloseHandler(this.container);
    };
    BaseSelection.prototype.update = function (data) {
      throw new Error('The `update` method must be defined in child classes.');
    };
    return BaseSelection;
  });
  