dropdown.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*!
  2. * Bootstrap dropdown.js v4.6.2 (https://getbootstrap.com/)
  3. * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
  4. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery'), require('popper.js'), require('./util.js')) :
  8. typeof define === 'function' && define.amd ? define(['jquery', 'popper.js', './util'], factory) :
  9. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Dropdown = factory(global.jQuery, global.Popper, global.Util));
  10. })(this, (function ($, Popper, Util) { 'use strict';
  11. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  12. var $__default = /*#__PURE__*/_interopDefaultLegacy($);
  13. var Popper__default = /*#__PURE__*/_interopDefaultLegacy(Popper);
  14. var Util__default = /*#__PURE__*/_interopDefaultLegacy(Util);
  15. function _defineProperties(target, props) {
  16. for (var i = 0; i < props.length; i++) {
  17. var descriptor = props[i];
  18. descriptor.enumerable = descriptor.enumerable || false;
  19. descriptor.configurable = true;
  20. if ("value" in descriptor) descriptor.writable = true;
  21. Object.defineProperty(target, descriptor.key, descriptor);
  22. }
  23. }
  24. function _createClass(Constructor, protoProps, staticProps) {
  25. if (protoProps) _defineProperties(Constructor.prototype, protoProps);
  26. if (staticProps) _defineProperties(Constructor, staticProps);
  27. Object.defineProperty(Constructor, "prototype", {
  28. writable: false
  29. });
  30. return Constructor;
  31. }
  32. function _extends() {
  33. _extends = Object.assign ? Object.assign.bind() : function (target) {
  34. for (var i = 1; i < arguments.length; i++) {
  35. var source = arguments[i];
  36. for (var key in source) {
  37. if (Object.prototype.hasOwnProperty.call(source, key)) {
  38. target[key] = source[key];
  39. }
  40. }
  41. }
  42. return target;
  43. };
  44. return _extends.apply(this, arguments);
  45. }
  46. /**
  47. * Constants
  48. */
  49. var NAME = 'dropdown';
  50. var VERSION = '4.6.2';
  51. var DATA_KEY = 'bs.dropdown';
  52. var EVENT_KEY = "." + DATA_KEY;
  53. var DATA_API_KEY = '.data-api';
  54. var JQUERY_NO_CONFLICT = $__default["default"].fn[NAME];
  55. var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
  56. var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key
  57. var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key
  58. var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
  59. var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
  60. var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
  61. var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE);
  62. var CLASS_NAME_DISABLED = 'disabled';
  63. var CLASS_NAME_SHOW = 'show';
  64. var CLASS_NAME_DROPUP = 'dropup';
  65. var CLASS_NAME_DROPRIGHT = 'dropright';
  66. var CLASS_NAME_DROPLEFT = 'dropleft';
  67. var CLASS_NAME_MENURIGHT = 'dropdown-menu-right';
  68. var CLASS_NAME_POSITION_STATIC = 'position-static';
  69. var EVENT_HIDE = "hide" + EVENT_KEY;
  70. var EVENT_HIDDEN = "hidden" + EVENT_KEY;
  71. var EVENT_SHOW = "show" + EVENT_KEY;
  72. var EVENT_SHOWN = "shown" + EVENT_KEY;
  73. var EVENT_CLICK = "click" + EVENT_KEY;
  74. var EVENT_CLICK_DATA_API = "click" + EVENT_KEY + DATA_API_KEY;
  75. var EVENT_KEYDOWN_DATA_API = "keydown" + EVENT_KEY + DATA_API_KEY;
  76. var EVENT_KEYUP_DATA_API = "keyup" + EVENT_KEY + DATA_API_KEY;
  77. var SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]';
  78. var SELECTOR_FORM_CHILD = '.dropdown form';
  79. var SELECTOR_MENU = '.dropdown-menu';
  80. var SELECTOR_NAVBAR_NAV = '.navbar-nav';
  81. var SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';
  82. var PLACEMENT_TOP = 'top-start';
  83. var PLACEMENT_TOPEND = 'top-end';
  84. var PLACEMENT_BOTTOM = 'bottom-start';
  85. var PLACEMENT_BOTTOMEND = 'bottom-end';
  86. var PLACEMENT_RIGHT = 'right-start';
  87. var PLACEMENT_LEFT = 'left-start';
  88. var Default = {
  89. offset: 0,
  90. flip: true,
  91. boundary: 'scrollParent',
  92. reference: 'toggle',
  93. display: 'dynamic',
  94. popperConfig: null
  95. };
  96. var DefaultType = {
  97. offset: '(number|string|function)',
  98. flip: 'boolean',
  99. boundary: '(string|element)',
  100. reference: '(string|element)',
  101. display: 'string',
  102. popperConfig: '(null|object)'
  103. };
  104. /**
  105. * Class definition
  106. */
  107. var Dropdown = /*#__PURE__*/function () {
  108. function Dropdown(element, config) {
  109. this._element = element;
  110. this._popper = null;
  111. this._config = this._getConfig(config);
  112. this._menu = this._getMenuElement();
  113. this._inNavbar = this._detectNavbar();
  114. this._addEventListeners();
  115. } // Getters
  116. var _proto = Dropdown.prototype;
  117. // Public
  118. _proto.toggle = function toggle() {
  119. if (this._element.disabled || $__default["default"](this._element).hasClass(CLASS_NAME_DISABLED)) {
  120. return;
  121. }
  122. var isActive = $__default["default"](this._menu).hasClass(CLASS_NAME_SHOW);
  123. Dropdown._clearMenus();
  124. if (isActive) {
  125. return;
  126. }
  127. this.show(true);
  128. };
  129. _proto.show = function show(usePopper) {
  130. if (usePopper === void 0) {
  131. usePopper = false;
  132. }
  133. if (this._element.disabled || $__default["default"](this._element).hasClass(CLASS_NAME_DISABLED) || $__default["default"](this._menu).hasClass(CLASS_NAME_SHOW)) {
  134. return;
  135. }
  136. var relatedTarget = {
  137. relatedTarget: this._element
  138. };
  139. var showEvent = $__default["default"].Event(EVENT_SHOW, relatedTarget);
  140. var parent = Dropdown._getParentFromElement(this._element);
  141. $__default["default"](parent).trigger(showEvent);
  142. if (showEvent.isDefaultPrevented()) {
  143. return;
  144. } // Totally disable Popper for Dropdowns in Navbar
  145. if (!this._inNavbar && usePopper) {
  146. // Check for Popper dependency
  147. if (typeof Popper__default["default"] === 'undefined') {
  148. throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)');
  149. }
  150. var referenceElement = this._element;
  151. if (this._config.reference === 'parent') {
  152. referenceElement = parent;
  153. } else if (Util__default["default"].isElement(this._config.reference)) {
  154. referenceElement = this._config.reference; // Check if it's jQuery element
  155. if (typeof this._config.reference.jquery !== 'undefined') {
  156. referenceElement = this._config.reference[0];
  157. }
  158. } // If boundary is not `scrollParent`, then set position to `static`
  159. // to allow the menu to "escape" the scroll parent's boundaries
  160. // https://github.com/twbs/bootstrap/issues/24251
  161. if (this._config.boundary !== 'scrollParent') {
  162. $__default["default"](parent).addClass(CLASS_NAME_POSITION_STATIC);
  163. }
  164. this._popper = new Popper__default["default"](referenceElement, this._menu, this._getPopperConfig());
  165. } // If this is a touch-enabled device we add extra
  166. // empty mouseover listeners to the body's immediate children;
  167. // only needed because of broken event delegation on iOS
  168. // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
  169. if ('ontouchstart' in document.documentElement && $__default["default"](parent).closest(SELECTOR_NAVBAR_NAV).length === 0) {
  170. $__default["default"](document.body).children().on('mouseover', null, $__default["default"].noop);
  171. }
  172. this._element.focus();
  173. this._element.setAttribute('aria-expanded', true);
  174. $__default["default"](this._menu).toggleClass(CLASS_NAME_SHOW);
  175. $__default["default"](parent).toggleClass(CLASS_NAME_SHOW).trigger($__default["default"].Event(EVENT_SHOWN, relatedTarget));
  176. };
  177. _proto.hide = function hide() {
  178. if (this._element.disabled || $__default["default"](this._element).hasClass(CLASS_NAME_DISABLED) || !$__default["default"](this._menu).hasClass(CLASS_NAME_SHOW)) {
  179. return;
  180. }
  181. var relatedTarget = {
  182. relatedTarget: this._element
  183. };
  184. var hideEvent = $__default["default"].Event(EVENT_HIDE, relatedTarget);
  185. var parent = Dropdown._getParentFromElement(this._element);
  186. $__default["default"](parent).trigger(hideEvent);
  187. if (hideEvent.isDefaultPrevented()) {
  188. return;
  189. }
  190. if (this._popper) {
  191. this._popper.destroy();
  192. }
  193. $__default["default"](this._menu).toggleClass(CLASS_NAME_SHOW);
  194. $__default["default"](parent).toggleClass(CLASS_NAME_SHOW).trigger($__default["default"].Event(EVENT_HIDDEN, relatedTarget));
  195. };
  196. _proto.dispose = function dispose() {
  197. $__default["default"].removeData(this._element, DATA_KEY);
  198. $__default["default"](this._element).off(EVENT_KEY);
  199. this._element = null;
  200. this._menu = null;
  201. if (this._popper !== null) {
  202. this._popper.destroy();
  203. this._popper = null;
  204. }
  205. };
  206. _proto.update = function update() {
  207. this._inNavbar = this._detectNavbar();
  208. if (this._popper !== null) {
  209. this._popper.scheduleUpdate();
  210. }
  211. } // Private
  212. ;
  213. _proto._addEventListeners = function _addEventListeners() {
  214. var _this = this;
  215. $__default["default"](this._element).on(EVENT_CLICK, function (event) {
  216. event.preventDefault();
  217. event.stopPropagation();
  218. _this.toggle();
  219. });
  220. };
  221. _proto._getConfig = function _getConfig(config) {
  222. config = _extends({}, this.constructor.Default, $__default["default"](this._element).data(), config);
  223. Util__default["default"].typeCheckConfig(NAME, config, this.constructor.DefaultType);
  224. return config;
  225. };
  226. _proto._getMenuElement = function _getMenuElement() {
  227. if (!this._menu) {
  228. var parent = Dropdown._getParentFromElement(this._element);
  229. if (parent) {
  230. this._menu = parent.querySelector(SELECTOR_MENU);
  231. }
  232. }
  233. return this._menu;
  234. };
  235. _proto._getPlacement = function _getPlacement() {
  236. var $parentDropdown = $__default["default"](this._element.parentNode);
  237. var placement = PLACEMENT_BOTTOM; // Handle dropup
  238. if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) {
  239. placement = $__default["default"](this._menu).hasClass(CLASS_NAME_MENURIGHT) ? PLACEMENT_TOPEND : PLACEMENT_TOP;
  240. } else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) {
  241. placement = PLACEMENT_RIGHT;
  242. } else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) {
  243. placement = PLACEMENT_LEFT;
  244. } else if ($__default["default"](this._menu).hasClass(CLASS_NAME_MENURIGHT)) {
  245. placement = PLACEMENT_BOTTOMEND;
  246. }
  247. return placement;
  248. };
  249. _proto._detectNavbar = function _detectNavbar() {
  250. return $__default["default"](this._element).closest('.navbar').length > 0;
  251. };
  252. _proto._getOffset = function _getOffset() {
  253. var _this2 = this;
  254. var offset = {};
  255. if (typeof this._config.offset === 'function') {
  256. offset.fn = function (data) {
  257. data.offsets = _extends({}, data.offsets, _this2._config.offset(data.offsets, _this2._element));
  258. return data;
  259. };
  260. } else {
  261. offset.offset = this._config.offset;
  262. }
  263. return offset;
  264. };
  265. _proto._getPopperConfig = function _getPopperConfig() {
  266. var popperConfig = {
  267. placement: this._getPlacement(),
  268. modifiers: {
  269. offset: this._getOffset(),
  270. flip: {
  271. enabled: this._config.flip
  272. },
  273. preventOverflow: {
  274. boundariesElement: this._config.boundary
  275. }
  276. }
  277. }; // Disable Popper if we have a static display
  278. if (this._config.display === 'static') {
  279. popperConfig.modifiers.applyStyle = {
  280. enabled: false
  281. };
  282. }
  283. return _extends({}, popperConfig, this._config.popperConfig);
  284. } // Static
  285. ;
  286. Dropdown._jQueryInterface = function _jQueryInterface(config) {
  287. return this.each(function () {
  288. var data = $__default["default"](this).data(DATA_KEY);
  289. var _config = typeof config === 'object' ? config : null;
  290. if (!data) {
  291. data = new Dropdown(this, _config);
  292. $__default["default"](this).data(DATA_KEY, data);
  293. }
  294. if (typeof config === 'string') {
  295. if (typeof data[config] === 'undefined') {
  296. throw new TypeError("No method named \"" + config + "\"");
  297. }
  298. data[config]();
  299. }
  300. });
  301. };
  302. Dropdown._clearMenus = function _clearMenus(event) {
  303. if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
  304. return;
  305. }
  306. var toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE));
  307. for (var i = 0, len = toggles.length; i < len; i++) {
  308. var parent = Dropdown._getParentFromElement(toggles[i]);
  309. var context = $__default["default"](toggles[i]).data(DATA_KEY);
  310. var relatedTarget = {
  311. relatedTarget: toggles[i]
  312. };
  313. if (event && event.type === 'click') {
  314. relatedTarget.clickEvent = event;
  315. }
  316. if (!context) {
  317. continue;
  318. }
  319. var dropdownMenu = context._menu;
  320. if (!$__default["default"](parent).hasClass(CLASS_NAME_SHOW)) {
  321. continue;
  322. }
  323. if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $__default["default"].contains(parent, event.target)) {
  324. continue;
  325. }
  326. var hideEvent = $__default["default"].Event(EVENT_HIDE, relatedTarget);
  327. $__default["default"](parent).trigger(hideEvent);
  328. if (hideEvent.isDefaultPrevented()) {
  329. continue;
  330. } // If this is a touch-enabled device we remove the extra
  331. // empty mouseover listeners we added for iOS support
  332. if ('ontouchstart' in document.documentElement) {
  333. $__default["default"](document.body).children().off('mouseover', null, $__default["default"].noop);
  334. }
  335. toggles[i].setAttribute('aria-expanded', 'false');
  336. if (context._popper) {
  337. context._popper.destroy();
  338. }
  339. $__default["default"](dropdownMenu).removeClass(CLASS_NAME_SHOW);
  340. $__default["default"](parent).removeClass(CLASS_NAME_SHOW).trigger($__default["default"].Event(EVENT_HIDDEN, relatedTarget));
  341. }
  342. };
  343. Dropdown._getParentFromElement = function _getParentFromElement(element) {
  344. var parent;
  345. var selector = Util__default["default"].getSelectorFromElement(element);
  346. if (selector) {
  347. parent = document.querySelector(selector);
  348. }
  349. return parent || element.parentNode;
  350. } // eslint-disable-next-line complexity
  351. ;
  352. Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
  353. // If not input/textarea:
  354. // - And not a key in REGEXP_KEYDOWN => not a dropdown command
  355. // If input/textarea:
  356. // - If space key => not a dropdown command
  357. // - If key is other than escape
  358. // - If key is not up or down => not a dropdown command
  359. // - If trigger inside the menu => not a dropdown command
  360. 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 || $__default["default"](event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
  361. return;
  362. }
  363. if (this.disabled || $__default["default"](this).hasClass(CLASS_NAME_DISABLED)) {
  364. return;
  365. }
  366. var parent = Dropdown._getParentFromElement(this);
  367. var isActive = $__default["default"](parent).hasClass(CLASS_NAME_SHOW);
  368. if (!isActive && event.which === ESCAPE_KEYCODE) {
  369. return;
  370. }
  371. event.preventDefault();
  372. event.stopPropagation();
  373. if (!isActive || event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE) {
  374. if (event.which === ESCAPE_KEYCODE) {
  375. $__default["default"](parent.querySelector(SELECTOR_DATA_TOGGLE)).trigger('focus');
  376. }
  377. $__default["default"](this).trigger('click');
  378. return;
  379. }
  380. var items = [].slice.call(parent.querySelectorAll(SELECTOR_VISIBLE_ITEMS)).filter(function (item) {
  381. return $__default["default"](item).is(':visible');
  382. });
  383. if (items.length === 0) {
  384. return;
  385. }
  386. var index = items.indexOf(event.target);
  387. if (event.which === ARROW_UP_KEYCODE && index > 0) {
  388. // Up
  389. index--;
  390. }
  391. if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
  392. // Down
  393. index++;
  394. }
  395. if (index < 0) {
  396. index = 0;
  397. }
  398. items[index].focus();
  399. };
  400. _createClass(Dropdown, null, [{
  401. key: "VERSION",
  402. get: function get() {
  403. return VERSION;
  404. }
  405. }, {
  406. key: "Default",
  407. get: function get() {
  408. return Default;
  409. }
  410. }, {
  411. key: "DefaultType",
  412. get: function get() {
  413. return DefaultType;
  414. }
  415. }]);
  416. return Dropdown;
  417. }();
  418. /**
  419. * Data API implementation
  420. */
  421. $__default["default"](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) {
  422. event.preventDefault();
  423. event.stopPropagation();
  424. Dropdown._jQueryInterface.call($__default["default"](this), 'toggle');
  425. }).on(EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, function (e) {
  426. e.stopPropagation();
  427. });
  428. /**
  429. * jQuery
  430. */
  431. $__default["default"].fn[NAME] = Dropdown._jQueryInterface;
  432. $__default["default"].fn[NAME].Constructor = Dropdown;
  433. $__default["default"].fn[NAME].noConflict = function () {
  434. $__default["default"].fn[NAME] = JQUERY_NO_CONFLICT;
  435. return Dropdown._jQueryInterface;
  436. };
  437. return Dropdown;
  438. }));
  439. //# sourceMappingURL=dropdown.js.map