OSDN Git Service

Remove unwanted dependencies
[bytom/vapor.git] / tools / side_chain_tool / web / node_modules / bootstrap / js / src / dropdown.js
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