dropdown.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. /**
  4. * --------------------------------------------------------------------------
  5. * Bootstrap (v4.0.0-alpha.4): dropdown.js
  6. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  7. * --------------------------------------------------------------------------
  8. */
  9. var Dropdown = function ($) {
  10. /**
  11. * ------------------------------------------------------------------------
  12. * Constants
  13. * ------------------------------------------------------------------------
  14. */
  15. var NAME = 'dropdown';
  16. var VERSION = '4.0.0-alpha.4';
  17. var DATA_KEY = 'bs.dropdown';
  18. var EVENT_KEY = '.' + DATA_KEY;
  19. var DATA_API_KEY = '.data-api';
  20. var JQUERY_NO_CONFLICT = $.fn[NAME];
  21. var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
  22. var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
  23. var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
  24. var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
  25. var Event = {
  26. HIDE: 'hide' + EVENT_KEY,
  27. HIDDEN: 'hidden' + EVENT_KEY,
  28. SHOW: 'show' + EVENT_KEY,
  29. SHOWN: 'shown' + EVENT_KEY,
  30. CLICK: 'click' + EVENT_KEY,
  31. CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY,
  32. KEYDOWN_DATA_API: 'keydown' + EVENT_KEY + DATA_API_KEY
  33. };
  34. var ClassName = {
  35. BACKDROP: 'dropdown-backdrop',
  36. DISABLED: 'disabled',
  37. OPEN: 'open'
  38. };
  39. var Selector = {
  40. BACKDROP: '.dropdown-backdrop',
  41. DATA_TOGGLE: '[data-toggle="dropdown"]',
  42. FORM_CHILD: '.dropdown form',
  43. ROLE_MENU: '[role="menu"]',
  44. ROLE_LISTBOX: '[role="listbox"]',
  45. NAVBAR_NAV: '.navbar-nav',
  46. VISIBLE_ITEMS: '[role="menu"] li:not(.disabled) a, ' + '[role="listbox"] li:not(.disabled) a'
  47. };
  48. /**
  49. * ------------------------------------------------------------------------
  50. * Class Definition
  51. * ------------------------------------------------------------------------
  52. */
  53. var Dropdown = function () {
  54. function Dropdown(element) {
  55. _classCallCheck(this, Dropdown);
  56. this._element = element;
  57. this._addEventListeners();
  58. }
  59. // getters
  60. // public
  61. Dropdown.prototype.toggle = function toggle() {
  62. if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
  63. return false;
  64. }
  65. var parent = Dropdown._getParentFromElement(this);
  66. var isActive = $(parent).hasClass(ClassName.OPEN);
  67. Dropdown._clearMenus();
  68. if (isActive) {
  69. return false;
  70. }
  71. if ('ontouchstart' in document.documentElement && !$(parent).closest(Selector.NAVBAR_NAV).length) {
  72. // if mobile we use a backdrop because click events don't delegate
  73. var dropdown = document.createElement('div');
  74. dropdown.className = ClassName.BACKDROP;
  75. $(dropdown).insertBefore(this);
  76. $(dropdown).on('click', Dropdown._clearMenus);
  77. }
  78. var relatedTarget = { relatedTarget: this };
  79. var showEvent = $.Event(Event.SHOW, relatedTarget);
  80. $(parent).trigger(showEvent);
  81. if (showEvent.isDefaultPrevented()) {
  82. return false;
  83. }
  84. this.focus();
  85. this.setAttribute('aria-expanded', 'true');
  86. $(parent).toggleClass(ClassName.OPEN);
  87. $(parent).trigger($.Event(Event.SHOWN, relatedTarget));
  88. return false;
  89. };
  90. Dropdown.prototype.dispose = function dispose() {
  91. $.removeData(this._element, DATA_KEY);
  92. $(this._element).off(EVENT_KEY);
  93. this._element = null;
  94. };
  95. // private
  96. Dropdown.prototype._addEventListeners = function _addEventListeners() {
  97. $(this._element).on(Event.CLICK, this.toggle);
  98. };
  99. // static
  100. Dropdown._jQueryInterface = function _jQueryInterface(config) {
  101. return this.each(function () {
  102. var data = $(this).data(DATA_KEY);
  103. if (!data) {
  104. $(this).data(DATA_KEY, data = new Dropdown(this));
  105. }
  106. if (typeof config === 'string') {
  107. if (data[config] === undefined) {
  108. throw new Error('No method named "' + config + '"');
  109. }
  110. data[config].call(this);
  111. }
  112. });
  113. };
  114. Dropdown._clearMenus = function _clearMenus(event) {
  115. if (event && event.which === RIGHT_MOUSE_BUTTON_WHICH) {
  116. return;
  117. }
  118. var backdrop = $(Selector.BACKDROP)[0];
  119. if (backdrop) {
  120. backdrop.parentNode.removeChild(backdrop);
  121. }
  122. var toggles = $.makeArray($(Selector.DATA_TOGGLE));
  123. for (var i = 0; i < toggles.length; i++) {
  124. var parent = Dropdown._getParentFromElement(toggles[i]);
  125. var relatedTarget = { relatedTarget: toggles[i] };
  126. if (!$(parent).hasClass(ClassName.OPEN)) {
  127. continue;
  128. }
  129. if (event && event.type === 'click' && /input|textarea/i.test(event.target.tagName) && $.contains(parent, event.target)) {
  130. continue;
  131. }
  132. var hideEvent = $.Event(Event.HIDE, relatedTarget);
  133. $(parent).trigger(hideEvent);
  134. if (hideEvent.isDefaultPrevented()) {
  135. continue;
  136. }
  137. toggles[i].setAttribute('aria-expanded', 'false');
  138. $(parent).removeClass(ClassName.OPEN).trigger($.Event(Event.HIDDEN, relatedTarget));
  139. }
  140. };
  141. Dropdown._getParentFromElement = function _getParentFromElement(element) {
  142. var parent = void 0;
  143. var selector = Util.getSelectorFromElement(element);
  144. if (selector) {
  145. parent = $(selector)[0];
  146. }
  147. return parent || element.parentNode;
  148. };
  149. Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
  150. if (!/(38|40|27|32)/.test(event.which) || /input|textarea/i.test(event.target.tagName)) {
  151. return;
  152. }
  153. event.preventDefault();
  154. event.stopPropagation();
  155. if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
  156. return;
  157. }
  158. var parent = Dropdown._getParentFromElement(this);
  159. var isActive = $(parent).hasClass(ClassName.OPEN);
  160. if (!isActive && event.which !== ESCAPE_KEYCODE || isActive && event.which === ESCAPE_KEYCODE) {
  161. if (event.which === ESCAPE_KEYCODE) {
  162. var toggle = $(parent).find(Selector.DATA_TOGGLE)[0];
  163. $(toggle).trigger('focus');
  164. }
  165. $(this).trigger('click');
  166. return;
  167. }
  168. var items = $.makeArray($(Selector.VISIBLE_ITEMS));
  169. items = items.filter(function (item) {
  170. return item.offsetWidth || item.offsetHeight;
  171. });
  172. if (!items.length) {
  173. return;
  174. }
  175. var index = items.indexOf(event.target);
  176. if (event.which === ARROW_UP_KEYCODE && index > 0) {
  177. // up
  178. index--;
  179. }
  180. if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
  181. // down
  182. index++;
  183. }
  184. if (index < 0) {
  185. index = 0;
  186. }
  187. items[index].focus();
  188. };
  189. _createClass(Dropdown, null, [{
  190. key: 'VERSION',
  191. get: function get() {
  192. return VERSION;
  193. }
  194. }]);
  195. return Dropdown;
  196. }();
  197. /**
  198. * ------------------------------------------------------------------------
  199. * Data Api implementation
  200. * ------------------------------------------------------------------------
  201. */
  202. $(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.ROLE_MENU, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.ROLE_LISTBOX, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, Dropdown.prototype.toggle).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
  203. e.stopPropagation();
  204. });
  205. /**
  206. * ------------------------------------------------------------------------
  207. * jQuery
  208. * ------------------------------------------------------------------------
  209. */
  210. $.fn[NAME] = Dropdown._jQueryInterface;
  211. $.fn[NAME].Constructor = Dropdown;
  212. $.fn[NAME].noConflict = function () {
  213. $.fn[NAME] = JQUERY_NO_CONFLICT;
  214. return Dropdown._jQueryInterface;
  215. };
  216. return Dropdown;
  217. }(jQuery);
  218. //# sourceMappingURL=dropdown.js.map