API Docs 0.11.3.33c7ec07

import Ember from 'ember';
import toggleButton from 'ember-bootstrap/components/bs-dropdown-button';
import ComponentParent from 'ember-bootstrap/mixins/component-parent';

const { computed, observer } = Ember;

/**
 Bootstrap style dropdown menus, consisting of a toggle element, and the dropdown menu itself.
 See http://getbootstrap.com/components/#dropdowns

 Use this component together with two sub components, a dropdown toggle (`Components.DropdownToggle` or
 `Components.DropdownButton` component) and a dropdown menu (`Components.DropdownMenu`) component:

 ```hbs
 <nav class="navbar navbar-default navbar-static">
   <div class="container-fluid">
     <ul class="nav navbar-nav">
       {{#bs-dropdown tagName="li"}}
         {{#bs-dropdown-toggle}}Dropdown <span class="caret"></span>{{/bs-dropdown-toggle}}
         {{#bs-dropdown-menu}}
           <li>{{#link-to "index"}}Something{{/link-to}}</li>
           <li>{{#link-to "index"}}Something different{{/link-to}}</li>
         {{/bs-dropdown-menu}}
       {{/bs-dropdown}}
     </ul>
   </div>
 </nav>
 ```

 ### Button dropdowns

 To use a button as the dropdown toggle element (see http://getbootstrap.com/components/#btn-dropdowns), use the
 `Components.DropdownButton` component as the toggle:

 ```hbs
 {{#bs-dropdown}}
   {{#bs-dropdown-button}}Dropdown <span class="caret"></span>{{/bs-dropdown-button}}
   {{#bs-dropdown-menu}}
     <li>{{#link-to "index"}}Something{{/link-to}}</li>
     <li>{{#link-to "index"}}Something different{{/link-to}}</li>
   {{/bs-dropdown-menu}}
 {{/bs-dropdown}}
 ```

 It has all the functionality of a `Components.Button` with additional dropdown support.

 ### Split button dropdowns

 To have a regular button with a dropdown button as in http://getbootstrap.com/components/#btn-dropdowns-split, use a
 `Components.Button` component and a `Components.DropdownButton`:

 ```hbs
 {{#bs-dropdown}}
   {{#bs-button}}Dropdown{{/bs-button}}
   {{#bs-dropdown-button}}Dropdown <span class="caret"></span>{{/bs-dropdown-button}}
   {{#bs-dropdown-menu}}
     <li>{{#link-to "index"}}Something{{/link-to}}</li>
     <li>{{#link-to "index"}}Something different{{/link-to}}</li>
   {{/bs-dropdown-menu}}
 {{/bs-dropdown}}
 ```

 ### Dropup style

 Set the `direction` property to "up" to switch to a "dropup" style:

 ```hbs
 {{#bs-dropdown direction="up"}}
   ...
 {{/bs-dropdown}}
 ```

 @class Dropdown
 @namespace Components
 @extends Ember.Component
 @public
 */
export default Ember.Component.extend(ComponentParent, {
  classNameBindings: ['open', 'containerClass'],

  /**
   * This property reflects the state of the dropdown, whether it is open or closed.
   *
   * @property open
   * @default false
   * @type boolean
   * @public
   */
  open: false,

  /**
   * By default clicking on an open dropdown menu will close it. Set this property to false for the menu to stay open.
   *
   * @property closeOnMenuClick
   * @default true
   * @type boolean
   * @public
   */
  closeOnMenuClick: true,

  /**
   * jQuery click event name, namespaced to this component's instance to prevent interference between multiple dropdowns.
   *
   * @property clickEventName
   * @type string
   * @private
   */
  clickEventName: undefined,

  /**
   * By default the dropdown menu will expand downwards. Set to 'up' to expand upwards.
   *
   * @property direction
   * @type string
   * @default 'down'
   * @public
   */
  direction: 'down',

  /**
   * A computed property to generate the suiting class for the dropdown container, either "dropdown", "dropup" or "btn-group".
   *
   * @property containerClass
   * @type string
   * @readonly
   * @private
   */
  containerClass: computed('toggleType', 'direction', function() {
    if (this.get('toggleType') === 'button') {
      return this.get('direction') === 'up' ? 'btn-group dropup' : 'btn-group';
    } else {
      return this.get('direction') === 'up' ? 'dropup' : 'dropdown';
    }
  }),

  /**
   * This property is "button" if the toggle element is an instance of [Components.DropdownButton](Components.DropdownButton.html), otherwise "toggle".
   *
   * @property toggleType
   * @type string
   * @readonly
   * @protected
   */
  toggleType: computed('children.[]', function() {
    if (this.get('children').any(function(view) {
        return view instanceof toggleButton;
      })) {
      return 'button';
    }
    return 'toggle';
  }),

  actions: {
    toggleDropdown() {
      this.toggleProperty('open');
    },

    openDropdown() {
      this.set('open', true);
    },

    closeDropdown() {
      this.set('open', false);
    }
  },

  handleClickEvents: observer('open', function() {
    if (this.get('open')) {
      Ember.$(document).on(this.clickEventName, Ember.run.bind(this, this.closeOnClickHandler));
    } else {
      Ember.$(document).off(this.clickEventName);
    }
  }),

  willDestroyElement() {
    this._super();
    Ember.$(document).off(this.clickEventName);
  },

  init() {
    this._super();
    // click event name that is namespaced to our component instance, so multiple dropdowns do not interfere
    // with each other
    this.clickEventName = `click.${this.get('elementId')}`;
  },

  /**
   * Handler for click events to close the dropdown
   *
   * @method closeOnClickHandler
   * @param e
   * @protected
   */
  closeOnClickHandler(e) {
    let $target = Ember.$(e.target);
    if (!this.get('isDestroyed') &&
      $target.closest(this.$().find('.dropdown-toggle')).length === 0 &&
      ($target.closest(this.$().find('.dropdown-menu')).length === 0 || this.get('closeOnMenuClick'))) {
      this.set('open', false);
    }
  }
});