dropdown.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
  2. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  3. 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); } }
  4. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  5. /**
  6. * --------------------------------------------------------------------------
  7. * Bootstrap (v4.1.1): dropdown.js
  8. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  9. * --------------------------------------------------------------------------
  10. */
  11. var Dropdown = function ($) {
  12. /**
  13. * ------------------------------------------------------------------------
  14. * Constants
  15. * ------------------------------------------------------------------------
  16. */
  17. var NAME = 'dropdown';
  18. var VERSION = '4.1.1';
  19. var DATA_KEY = 'bs.dropdown';
  20. var EVENT_KEY = "." + DATA_KEY;
  21. var DATA_API_KEY = '.data-api';
  22. var JQUERY_NO_CONFLICT = $.fn[NAME];
  23. var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
  24. var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key
  25. var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key
  26. var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
  27. var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
  28. var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
  29. var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE);
  30. var Event = {
  31. HIDE: "hide" + EVENT_KEY,
  32. HIDDEN: "hidden" + EVENT_KEY,
  33. SHOW: "show" + EVENT_KEY,
  34. SHOWN: "shown" + EVENT_KEY,
  35. CLICK: "click" + EVENT_KEY,
  36. CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY,
  37. KEYDOWN_DATA_API: "keydown" + EVENT_KEY + DATA_API_KEY,
  38. KEYUP_DATA_API: "keyup" + EVENT_KEY + DATA_API_KEY
  39. };
  40. var ClassName = {
  41. DISABLED: 'disabled',
  42. SHOW: 'show',
  43. DROPUP: 'dropup',
  44. DROPRIGHT: 'dropright',
  45. DROPLEFT: 'dropleft',
  46. MENURIGHT: 'dropdown-menu-right',
  47. MENULEFT: 'dropdown-menu-left',
  48. POSITION_STATIC: 'position-static'
  49. };
  50. var Selector = {
  51. DATA_TOGGLE: '[data-toggle="dropdown"]',
  52. FORM_CHILD: '.dropdown form',
  53. MENU: '.dropdown-menu',
  54. NAVBAR_NAV: '.navbar-nav',
  55. VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
  56. };
  57. var AttachmentMap = {
  58. TOP: 'top-start',
  59. TOPEND: 'top-end',
  60. BOTTOM: 'bottom-start',
  61. BOTTOMEND: 'bottom-end',
  62. RIGHT: 'right-start',
  63. RIGHTEND: 'right-end',
  64. LEFT: 'left-start',
  65. LEFTEND: 'left-end'
  66. };
  67. var Default = {
  68. offset: 0,
  69. flip: true,
  70. boundary: 'scrollParent',
  71. reference: 'toggle',
  72. display: 'dynamic'
  73. };
  74. var DefaultType = {
  75. offset: '(number|string|function)',
  76. flip: 'boolean',
  77. boundary: '(string|element)',
  78. reference: '(string|element)',
  79. display: 'string'
  80. /**
  81. * ------------------------------------------------------------------------
  82. * Class Definition
  83. * ------------------------------------------------------------------------
  84. */
  85. };
  86. var Dropdown =
  87. /*#__PURE__*/
  88. function () {
  89. function Dropdown(element, config) {
  90. this._element = element;
  91. this._popper = null;
  92. this._config = this._getConfig(config);
  93. this._menu = this._getMenuElement();
  94. this._inNavbar = this._detectNavbar();
  95. this._addEventListeners();
  96. } // Getters
  97. var _proto = Dropdown.prototype;
  98. // Public
  99. _proto.toggle = function toggle() {
  100. if (this._element.disabled || $(this._element).hasClass(ClassName.DISABLED)) {
  101. return;
  102. }
  103. var parent = Dropdown._getParentFromElement(this._element);
  104. var isActive = $(this._menu).hasClass(ClassName.SHOW);
  105. Dropdown._clearMenus();
  106. if (isActive) {
  107. return;
  108. }
  109. var relatedTarget = {
  110. relatedTarget: this._element
  111. };
  112. var showEvent = $.Event(Event.SHOW, relatedTarget);
  113. $(parent).trigger(showEvent);
  114. if (showEvent.isDefaultPrevented()) {
  115. return;
  116. } // Disable totally Popper.js for Dropdown in Navbar
  117. if (!this._inNavbar) {
  118. /**
  119. * Check for Popper dependency
  120. * Popper - https://popper.js.org
  121. */
  122. if (typeof Popper === 'undefined') {
  123. throw new TypeError('Bootstrap dropdown require Popper.js (https://popper.js.org)');
  124. }
  125. var referenceElement = this._element;
  126. if (this._config.reference === 'parent') {
  127. referenceElement = parent;
  128. } else if (Util.isElement(this._config.reference)) {
  129. referenceElement = this._config.reference; // Check if it's jQuery element
  130. if (typeof this._config.reference.jquery !== 'undefined') {
  131. referenceElement = this._config.reference[0];
  132. }
  133. } // If boundary is not `scrollParent`, then set position to `static`
  134. // to allow the menu to "escape" the scroll parent's boundaries
  135. // https://github.com/twbs/bootstrap/issues/24251
  136. if (this._config.boundary !== 'scrollParent') {
  137. $(parent).addClass(ClassName.POSITION_STATIC);
  138. }
  139. this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());
  140. } // If this is a touch-enabled device we add extra
  141. // empty mouseover listeners to the body's immediate children;
  142. // only needed because of broken event delegation on iOS
  143. // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
  144. if ('ontouchstart' in document.documentElement && $(parent).closest(Selector.NAVBAR_NAV).length === 0) {
  145. $(document.body).children().on('mouseover', null, $.noop);
  146. }
  147. this._element.focus();
  148. this._element.setAttribute('aria-expanded', true);
  149. $(this._menu).toggleClass(ClassName.SHOW);
  150. $(parent).toggleClass(ClassName.SHOW).trigger($.Event(Event.SHOWN, relatedTarget));
  151. };
  152. _proto.dispose = function dispose() {
  153. $.removeData(this._element, DATA_KEY);
  154. $(this._element).off(EVENT_KEY);
  155. this._element = null;
  156. this._menu = null;
  157. if (this._popper !== null) {
  158. this._popper.destroy();
  159. this._popper = null;
  160. }
  161. };
  162. _proto.update = function update() {
  163. this._inNavbar = this._detectNavbar();
  164. if (this._popper !== null) {
  165. this._popper.scheduleUpdate();
  166. }
  167. }; // Private
  168. _proto._addEventListeners = function _addEventListeners() {
  169. var _this = this;
  170. $(this._element).on(Event.CLICK, function (event) {
  171. event.preventDefault();
  172. event.stopPropagation();
  173. _this.toggle();
  174. });
  175. };
  176. _proto._getConfig = function _getConfig(config) {
  177. config = _objectSpread({}, this.constructor.Default, $(this._element).data(), config);
  178. Util.typeCheckConfig(NAME, config, this.constructor.DefaultType);
  179. return config;
  180. };
  181. _proto._getMenuElement = function _getMenuElement() {
  182. if (!this._menu) {
  183. var parent = Dropdown._getParentFromElement(this._element);
  184. this._menu = $(parent).find(Selector.MENU)[0];
  185. }
  186. return this._menu;
  187. };
  188. _proto._getPlacement = function _getPlacement() {
  189. var $parentDropdown = $(this._element).parent();
  190. var placement = AttachmentMap.BOTTOM; // Handle dropup
  191. if ($parentDropdown.hasClass(ClassName.DROPUP)) {
  192. placement = AttachmentMap.TOP;
  193. if ($(this._menu).hasClass(ClassName.MENURIGHT)) {
  194. placement = AttachmentMap.TOPEND;
  195. }
  196. } else if ($parentDropdown.hasClass(ClassName.DROPRIGHT)) {
  197. placement = AttachmentMap.RIGHT;
  198. } else if ($parentDropdown.hasClass(ClassName.DROPLEFT)) {
  199. placement = AttachmentMap.LEFT;
  200. } else if ($(this._menu).hasClass(ClassName.MENURIGHT)) {
  201. placement = AttachmentMap.BOTTOMEND;
  202. }
  203. return placement;
  204. };
  205. _proto._detectNavbar = function _detectNavbar() {
  206. return $(this._element).closest('.navbar').length > 0;
  207. };
  208. _proto._getPopperConfig = function _getPopperConfig() {
  209. var _this2 = this;
  210. var offsetConf = {};
  211. if (typeof this._config.offset === 'function') {
  212. offsetConf.fn = function (data) {
  213. data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets) || {});
  214. return data;
  215. };
  216. } else {
  217. offsetConf.offset = this._config.offset;
  218. }
  219. var popperConfig = {
  220. placement: this._getPlacement(),
  221. modifiers: {
  222. offset: offsetConf,
  223. flip: {
  224. enabled: this._config.flip
  225. },
  226. preventOverflow: {
  227. boundariesElement: this._config.boundary
  228. }
  229. } // Disable Popper.js if we have a static display
  230. };
  231. if (this._config.display === 'static') {
  232. popperConfig.modifiers.applyStyle = {
  233. enabled: false
  234. };
  235. }
  236. return popperConfig;
  237. }; // Static
  238. Dropdown._jQueryInterface = function _jQueryInterface(config) {
  239. return this.each(function () {
  240. var data = $(this).data(DATA_KEY);
  241. var _config = typeof config === 'object' ? config : null;
  242. if (!data) {
  243. data = new Dropdown(this, _config);
  244. $(this).data(DATA_KEY, data);
  245. }
  246. if (typeof config === 'string') {
  247. if (typeof data[config] === 'undefined') {
  248. throw new TypeError("No method named \"" + config + "\"");
  249. }
  250. data[config]();
  251. }
  252. });
  253. };
  254. Dropdown._clearMenus = function _clearMenus(event) {
  255. if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
  256. return;
  257. }
  258. var toggles = $.makeArray($(Selector.DATA_TOGGLE));
  259. for (var i = 0; i < toggles.length; i++) {
  260. var parent = Dropdown._getParentFromElement(toggles[i]);
  261. var context = $(toggles[i]).data(DATA_KEY);
  262. var relatedTarget = {
  263. relatedTarget: toggles[i]
  264. };
  265. if (!context) {
  266. continue;
  267. }
  268. var dropdownMenu = context._menu;
  269. if (!$(parent).hasClass(ClassName.SHOW)) {
  270. continue;
  271. }
  272. if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {
  273. continue;
  274. }
  275. var hideEvent = $.Event(Event.HIDE, relatedTarget);
  276. $(parent).trigger(hideEvent);
  277. if (hideEvent.isDefaultPrevented()) {
  278. continue;
  279. } // If this is a touch-enabled device we remove the extra
  280. // empty mouseover listeners we added for iOS support
  281. if ('ontouchstart' in document.documentElement) {
  282. $(document.body).children().off('mouseover', null, $.noop);
  283. }
  284. toggles[i].setAttribute('aria-expanded', 'false');
  285. $(dropdownMenu).removeClass(ClassName.SHOW);
  286. $(parent).removeClass(ClassName.SHOW).trigger($.Event(Event.HIDDEN, relatedTarget));
  287. }
  288. };
  289. Dropdown._getParentFromElement = function _getParentFromElement(element) {
  290. var parent;
  291. var selector = Util.getSelectorFromElement(element);
  292. if (selector) {
  293. parent = $(selector)[0];
  294. }
  295. return parent || element.parentNode;
  296. }; // eslint-disable-next-line complexity
  297. Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
  298. // If not input/textarea:
  299. // - And not a key in REGEXP_KEYDOWN => not a dropdown command
  300. // If input/textarea:
  301. // - If space key => not a dropdown command
  302. // - If key is other than escape
  303. // - If key is not up or down => not a dropdown command
  304. // - If trigger inside the menu => not a dropdown command
  305. if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
  306. return;
  307. }
  308. event.preventDefault();
  309. event.stopPropagation();
  310. if (this.disabled || $(this).hasClass(ClassName.DISABLED)) {
  311. return;
  312. }
  313. var parent = Dropdown._getParentFromElement(this);
  314. var isActive = $(parent).hasClass(ClassName.SHOW);
  315. if (!isActive && (event.which !== ESCAPE_KEYCODE || event.which !== SPACE_KEYCODE) || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
  316. if (event.which === ESCAPE_KEYCODE) {
  317. var toggle = $(parent).find(Selector.DATA_TOGGLE)[0];
  318. $(toggle).trigger('focus');
  319. }
  320. $(this).trigger('click');
  321. return;
  322. }
  323. var items = $(parent).find(Selector.VISIBLE_ITEMS).get();
  324. if (items.length === 0) {
  325. return;
  326. }
  327. var index = items.indexOf(event.target);
  328. if (event.which === ARROW_UP_KEYCODE && index > 0) {
  329. // Up
  330. index--;
  331. }
  332. if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
  333. // Down
  334. index++;
  335. }
  336. if (index < 0) {
  337. index = 0;
  338. }
  339. items[index].focus();
  340. };
  341. _createClass(Dropdown, null, [{
  342. key: "VERSION",
  343. get: function get() {
  344. return VERSION;
  345. }
  346. }, {
  347. key: "Default",
  348. get: function get() {
  349. return Default;
  350. }
  351. }, {
  352. key: "DefaultType",
  353. get: function get() {
  354. return DefaultType;
  355. }
  356. }]);
  357. return Dropdown;
  358. }();
  359. /**
  360. * ------------------------------------------------------------------------
  361. * Data Api implementation
  362. * ------------------------------------------------------------------------
  363. */
  364. $(document).on(Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown._dataApiKeydownHandler).on(Event.CLICK_DATA_API + " " + Event.KEYUP_DATA_API, Dropdown._clearMenus).on(Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
  365. event.preventDefault();
  366. event.stopPropagation();
  367. Dropdown._jQueryInterface.call($(this), 'toggle');
  368. }).on(Event.CLICK_DATA_API, Selector.FORM_CHILD, function (e) {
  369. e.stopPropagation();
  370. });
  371. /**
  372. * ------------------------------------------------------------------------
  373. * jQuery
  374. * ------------------------------------------------------------------------
  375. */
  376. $.fn[NAME] = Dropdown._jQueryInterface;
  377. $.fn[NAME].Constructor = Dropdown;
  378. $.fn[NAME].noConflict = function () {
  379. $.fn[NAME] = JQUERY_NO_CONFLICT;
  380. return Dropdown._jQueryInterface;
  381. };
  382. return Dropdown;
  383. }($, Popper);
  384. //# sourceMappingURL=dropdown.js.map