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