dropdown.js 17 KB

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