dropdown.js 14.6 KB
Newer Older
fat's avatar
fat committed
1
2
/**
 * --------------------------------------------------------------------------
3
 * Bootstrap (v5.0.0-alpha1): dropdown.js
4
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
fat's avatar
fat committed
5
6
7
 * --------------------------------------------------------------------------
 */

8
import {
9
  getjQuery,
10
  getElementFromSelector,
11
  isElement,
12
  isVisible,
13
14
  noop,
  typeCheckConfig
15
16
17
18
} from './util/index'
import Data from './dom/data'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
19
import Popper from 'popper.js'
20
import SelectorEngine from './dom/selector-engine'
21

Johann-S's avatar
Johann-S committed
22
23
24
25
26
/**
 * ------------------------------------------------------------------------
 * Constants
 * ------------------------------------------------------------------------
 */
fat's avatar
fat committed
27

XhmikosR's avatar
XhmikosR committed
28
const NAME = 'dropdown'
29
const VERSION = '5.0.0-alpha1'
XhmikosR's avatar
XhmikosR committed
30
31
32
const DATA_KEY = 'bs.dropdown'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
XhmikosR's avatar
XhmikosR committed
33

34
35
36
37
38
39
const ESCAPE_KEY = 'Escape'
const SPACE_KEY = 'Space'
const TAB_KEY = 'Tab'
const ARROW_UP_KEY = 'ArrowUp'
const ARROW_DOWN_KEY = 'ArrowDown'
const RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button
Johann-S's avatar
Johann-S committed
40

41
const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)
Johann-S's avatar
Johann-S committed
42

XhmikosR's avatar
XhmikosR committed
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_CLICK = `click${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`

const CLASS_NAME_DISABLED = 'disabled'
const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_DROPUP = 'dropup'
const CLASS_NAME_DROPRIGHT = 'dropright'
const CLASS_NAME_DROPLEFT = 'dropleft'
const CLASS_NAME_MENURIGHT = 'dropdown-menu-right'
const CLASS_NAME_NAVBAR = 'navbar'
const CLASS_NAME_POSITION_STATIC = 'position-static'

const SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]'
const SELECTOR_FORM_CHILD = '.dropdown form'
const SELECTOR_MENU = '.dropdown-menu'
const SELECTOR_NAVBAR_NAV = '.navbar-nav'
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'

const PLACEMENT_TOP = 'top-start'
const PLACEMENT_TOPEND = 'top-end'
const PLACEMENT_BOTTOM = 'bottom-start'
const PLACEMENT_BOTTOMEND = 'bottom-end'
const PLACEMENT_RIGHT = 'right-start'
const PLACEMENT_LEFT = 'left-start'
Johann-S's avatar
Johann-S committed
73
74

const Default = {
XhmikosR's avatar
XhmikosR committed
75
76
77
78
  offset: 0,
  flip: true,
  boundary: 'scrollParent',
  reference: 'toggle',
79
80
  display: 'dynamic',
  popperConfig: null
Johann-S's avatar
Johann-S committed
81
82
83
}

const DefaultType = {
XhmikosR's avatar
XhmikosR committed
84
85
86
87
  offset: '(number|string|function)',
  flip: 'boolean',
  boundary: '(string|element)',
  reference: '(string|element)',
88
89
  display: 'string',
  popperConfig: '(null|object)'
Johann-S's avatar
Johann-S committed
90
91
92
93
94
95
96
}

/**
 * ------------------------------------------------------------------------
 * Class Definition
 * ------------------------------------------------------------------------
 */
fat's avatar
fat committed
97

Johann-S's avatar
Johann-S committed
98
99
class Dropdown {
  constructor(element, config) {
XhmikosR's avatar
XhmikosR committed
100
101
102
103
    this._element = element
    this._popper = null
    this._config = this._getConfig(config)
    this._menu = this._getMenuElement()
Johann-S's avatar
Johann-S committed
104
105
106
    this._inNavbar = this._detectNavbar()

    this._addEventListeners()
107
    Data.setData(element, DATA_KEY, this)
fat's avatar
fat committed
108
109
  }

Johann-S's avatar
Johann-S committed
110
111
112
113
  // Getters

  static get VERSION() {
    return VERSION
Johann-S's avatar
Johann-S committed
114
115
  }

Johann-S's avatar
Johann-S committed
116
117
  static get Default() {
    return Default
Johann-S's avatar
Johann-S committed
118
119
  }

Johann-S's avatar
Johann-S committed
120
121
  static get DefaultType() {
    return DefaultType
Johann-S's avatar
Johann-S committed
122
123
  }

Johann-S's avatar
Johann-S committed
124
125
126
  // Public

  toggle() {
XhmikosR's avatar
XhmikosR committed
127
    if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED)) {
Johann-S's avatar
Johann-S committed
128
      return
fat's avatar
fat committed
129
130
    }

131
    const isActive = this._element.classList.contains(CLASS_NAME_SHOW)
132

133
    Dropdown.clearMenus()
134

Johann-S's avatar
Johann-S committed
135
136
    if (isActive) {
      return
Johann-S's avatar
Johann-S committed
137
138
    }

139
140
141
142
    this.show()
  }

  show() {
XhmikosR's avatar
XhmikosR committed
143
    if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || this._menu.classList.contains(CLASS_NAME_SHOW)) {
144
145
146
147
      return
    }

    const parent = Dropdown.getParentFromElement(this._element)
Johann-S's avatar
Johann-S committed
148
149
    const relatedTarget = {
      relatedTarget: this._element
Johann-S's avatar
Johann-S committed
150
    }
151

152
    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)
Johann-S's avatar
Johann-S committed
153

Johann-S's avatar
Johann-S committed
154
    if (showEvent.defaultPrevented) {
Johann-S's avatar
Johann-S committed
155
156
      return
    }
fat's avatar
fat committed
157

Johann-S's avatar
Johann-S committed
158
159
160
    // Disable totally Popper.js for Dropdown in Navbar
    if (!this._inNavbar) {
      if (typeof Popper === 'undefined') {
161
        throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org)')
fat's avatar
fat committed
162
163
      }

Johann-S's avatar
Johann-S committed
164
      let referenceElement = this._element
fat's avatar
fat committed
165

Johann-S's avatar
Johann-S committed
166
167
      if (this._config.reference === 'parent') {
        referenceElement = parent
168
      } else if (isElement(this._config.reference)) {
Johann-S's avatar
Johann-S committed
169
        referenceElement = this._config.reference
fat's avatar
fat committed
170

Johann-S's avatar
Johann-S committed
171
172
173
        // Check if it's jQuery element
        if (typeof this._config.reference.jquery !== 'undefined') {
          referenceElement = this._config.reference[0]
174
        }
175
      }
176

Johann-S's avatar
Johann-S committed
177
178
179
180
      // If boundary is not `scrollParent`, then set position to `static`
      // to allow the menu to "escape" the scroll parent's boundaries
      // https://github.com/twbs/bootstrap/issues/24251
      if (this._config.boundary !== 'scrollParent') {
XhmikosR's avatar
XhmikosR committed
181
        parent.classList.add(CLASS_NAME_POSITION_STATIC)
182
      }
XhmikosR's avatar
XhmikosR committed
183

Johann-S's avatar
Johann-S committed
184
      this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig())
fat's avatar
fat committed
185
186
    }

Johann-S's avatar
Johann-S committed
187
188
189
190
191
    // If this is a touch-enabled device we add extra
    // empty mouseover listeners to the body's immediate children;
    // only needed because of broken event delegation on iOS
    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
    if ('ontouchstart' in document.documentElement &&
192
      !parent.closest(SELECTOR_NAVBAR_NAV)) {
193
      [].concat(...document.body.children)
XhmikosR's avatar
XhmikosR committed
194
        .forEach(elem => EventHandler.on(elem, 'mouseover', null, noop()))
fat's avatar
fat committed
195
196
    }

Johann-S's avatar
Johann-S committed
197
198
    this._element.focus()
    this._element.setAttribute('aria-expanded', true)
fat's avatar
fat committed
199

XhmikosR's avatar
XhmikosR committed
200
    Manipulator.toggleClass(this._menu, CLASS_NAME_SHOW)
201
    Manipulator.toggleClass(this._element, CLASS_NAME_SHOW)
XhmikosR's avatar
XhmikosR committed
202
    EventHandler.trigger(parent, EVENT_SHOWN, relatedTarget)
Johann-S's avatar
Johann-S committed
203
  }
fat's avatar
fat committed
204

205
  hide() {
XhmikosR's avatar
XhmikosR committed
206
    if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || !this._menu.classList.contains(CLASS_NAME_SHOW)) {
207
208
209
      return
    }

210
    const parent = Dropdown.getParentFromElement(this._element)
211
212
213
    const relatedTarget = {
      relatedTarget: this._element
    }
214

XhmikosR's avatar
XhmikosR committed
215
    const hideEvent = EventHandler.trigger(parent, EVENT_HIDE, relatedTarget)
216

Johann-S's avatar
Johann-S committed
217
    if (hideEvent.defaultPrevented) {
218
219
220
      return
    }

221
222
223
224
    if (this._popper) {
      this._popper.destroy()
    }

XhmikosR's avatar
XhmikosR committed
225
    Manipulator.toggleClass(this._menu, CLASS_NAME_SHOW)
226
    Manipulator.toggleClass(this._element, CLASS_NAME_SHOW)
XhmikosR's avatar
XhmikosR committed
227
    EventHandler.trigger(parent, EVENT_HIDDEN, relatedTarget)
228
229
  }

Johann-S's avatar
Johann-S committed
230
  dispose() {
Johann-S's avatar
Johann-S committed
231
232
    Data.removeData(this._element, DATA_KEY)
    EventHandler.off(this._element, EVENT_KEY)
Johann-S's avatar
Johann-S committed
233
234
    this._element = null
    this._menu = null
235
    if (this._popper) {
Johann-S's avatar
Johann-S committed
236
237
      this._popper.destroy()
      this._popper = null
fat's avatar
fat committed
238
    }
Johann-S's avatar
Johann-S committed
239
  }
fat's avatar
fat committed
240

Johann-S's avatar
Johann-S committed
241
242
  update() {
    this._inNavbar = this._detectNavbar()
243
    if (this._popper) {
Johann-S's avatar
Johann-S committed
244
245
246
      this._popper.scheduleUpdate()
    }
  }
Johann-S's avatar
Johann-S committed
247

Johann-S's avatar
Johann-S committed
248
249
250
  // Private

  _addEventListeners() {
XhmikosR's avatar
XhmikosR committed
251
    EventHandler.on(this._element, EVENT_CLICK, event => {
Johann-S's avatar
Johann-S committed
252
253
254
255
256
      event.preventDefault()
      event.stopPropagation()
      this.toggle()
    })
  }
Johann-S's avatar
Johann-S committed
257

Johann-S's avatar
Johann-S committed
258
259
260
  _getConfig(config) {
    config = {
      ...this.constructor.Default,
261
      ...Manipulator.getDataAttributes(this._element),
Johann-S's avatar
Johann-S committed
262
      ...config
Johann-S's avatar
Johann-S committed
263
264
    }

XhmikosR's avatar
XhmikosR committed
265
    typeCheckConfig(NAME, config, this.constructor.DefaultType)
Johann-S's avatar
Johann-S committed
266
267
268
269
270

    return config
  }

  _getMenuElement() {
271
    return SelectorEngine.next(this._element, SELECTOR_MENU)[0]
Johann-S's avatar
Johann-S committed
272
  }
fat's avatar
fat committed
273

Johann-S's avatar
Johann-S committed
274
  _getPlacement() {
Johann-S's avatar
Johann-S committed
275
    const parentDropdown = this._element.parentNode
XhmikosR's avatar
XhmikosR committed
276
    let placement = PLACEMENT_BOTTOM
277

Johann-S's avatar
Johann-S committed
278
    // Handle dropup
XhmikosR's avatar
XhmikosR committed
279
280
281
282
    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
      placement = PLACEMENT_TOP
      if (this._menu.classList.contains(CLASS_NAME_MENURIGHT)) {
        placement = PLACEMENT_TOPEND
283
      }
XhmikosR's avatar
XhmikosR committed
284
285
286
287
288
289
    } else if (parentDropdown.classList.contains(CLASS_NAME_DROPRIGHT)) {
      placement = PLACEMENT_RIGHT
    } else if (parentDropdown.classList.contains(CLASS_NAME_DROPLEFT)) {
      placement = PLACEMENT_LEFT
    } else if (this._menu.classList.contains(CLASS_NAME_MENURIGHT)) {
      placement = PLACEMENT_BOTTOMEND
290
    }
XhmikosR's avatar
XhmikosR committed
291

Johann-S's avatar
Johann-S committed
292
293
    return placement
  }
294

Johann-S's avatar
Johann-S committed
295
  _detectNavbar() {
296
    return Boolean(this._element.closest(`.${CLASS_NAME_NAVBAR}`))
Johann-S's avatar
Johann-S committed
297
  }
298

299
300
301
  _getOffset() {
    const offset = {}

Johann-S's avatar
Johann-S committed
302
    if (typeof this._config.offset === 'function') {
XhmikosR's avatar
XhmikosR committed
303
      offset.fn = data => {
Johann-S's avatar
Johann-S committed
304
305
        data.offsets = {
          ...data.offsets,
306
          ...this._config.offset(data.offsets, this._element) || {}
307
        }
308

Johann-S's avatar
Johann-S committed
309
        return data
310
      }
Johann-S's avatar
Johann-S committed
311
    } else {
312
      offset.offset = this._config.offset
Johann-S's avatar
Johann-S committed
313
    }
314

315
316
317
318
    return offset
  }

  _getPopperConfig() {
319
    const popperConfig = {
Johann-S's avatar
Johann-S committed
320
321
      placement: this._getPlacement(),
      modifiers: {
322
        offset: this._getOffset(),
Johann-S's avatar
Johann-S committed
323
324
325
326
327
        flip: {
          enabled: this._config.flip
        },
        preventOverflow: {
          boundariesElement: this._config.boundary
328
329
        }
      }
Johann-S's avatar
Johann-S committed
330
    }
331

Johann-S's avatar
Johann-S committed
332
333
334
335
    // Disable Popper.js if we have a static display
    if (this._config.display === 'static') {
      popperConfig.modifiers.applyStyle = {
        enabled: false
336
      }
337
    }
338

339
340
341
    return {
      ...popperConfig,
      ...this._config.popperConfig
342
    }
Johann-S's avatar
Johann-S committed
343
  }
344

Johann-S's avatar
Johann-S committed
345
  // Static
fat's avatar
fat committed
346

347
  static dropdownInterface(element, config) {
Johann-S's avatar
Johann-S committed
348
349
    let data = Data.getData(element, DATA_KEY)
    const _config = typeof config === 'object' ? config : null
fat's avatar
fat committed
350

Johann-S's avatar
Johann-S committed
351
352
353
    if (!data) {
      data = new Dropdown(element, _config)
    }
fat's avatar
fat committed
354

Johann-S's avatar
Johann-S committed
355
356
    if (typeof config === 'string') {
      if (typeof data[config] === 'undefined') {
XhmikosR's avatar
XhmikosR committed
357
        throw new TypeError(`No method named "${config}"`)
Johann-S's avatar
Johann-S committed
358
      }
XhmikosR's avatar
XhmikosR committed
359

Johann-S's avatar
Johann-S committed
360
361
362
363
      data[config]()
    }
  }

364
  static jQueryInterface(config) {
Johann-S's avatar
Johann-S committed
365
    return this.each(function () {
366
      Dropdown.dropdownInterface(this, config)
Johann-S's avatar
Johann-S committed
367
368
369
    })
  }

370
  static clearMenus(event) {
371
372
    if (event && (event.button === RIGHT_MOUSE_BUTTON ||
      (event.type === 'keyup' && event.key !== TAB_KEY))) {
Johann-S's avatar
Johann-S committed
373
      return
fat's avatar
fat committed
374
375
    }

376
377
    const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)

Johann-S's avatar
Johann-S committed
378
    for (let i = 0, len = toggles.length; i < len; i++) {
379
      const parent = Dropdown.getParentFromElement(toggles[i])
XhmikosR's avatar
XhmikosR committed
380
      const context = Data.getData(toggles[i], DATA_KEY)
Johann-S's avatar
Johann-S committed
381
382
      const relatedTarget = {
        relatedTarget: toggles[i]
fat's avatar
fat committed
383
384
      }

Johann-S's avatar
Johann-S committed
385
386
387
      if (event && event.type === 'click') {
        relatedTarget.clickEvent = event
      }
388

Johann-S's avatar
Johann-S committed
389
390
391
      if (!context) {
        continue
      }
Johann-S's avatar
Johann-S committed
392

Johann-S's avatar
Johann-S committed
393
      const dropdownMenu = context._menu
394
      if (!toggles[i].classList.contains(CLASS_NAME_SHOW)) {
Johann-S's avatar
Johann-S committed
395
396
        continue
      }
fat's avatar
fat committed
397

398
399
      if (event && ((event.type === 'click' &&
          /input|textarea/i.test(event.target.tagName)) ||
400
          (event.type === 'keyup' && event.key === TAB_KEY)) &&
401
          dropdownMenu.contains(event.target)) {
Johann-S's avatar
Johann-S committed
402
403
        continue
      }
fat's avatar
fat committed
404

XhmikosR's avatar
XhmikosR committed
405
      const hideEvent = EventHandler.trigger(parent, EVENT_HIDE, relatedTarget)
Johann-S's avatar
Johann-S committed
406
      if (hideEvent.defaultPrevented) {
Johann-S's avatar
Johann-S committed
407
408
        continue
      }
fat's avatar
fat committed
409

Johann-S's avatar
Johann-S committed
410
411
412
      // If this is a touch-enabled device we remove the extra
      // empty mouseover listeners we added for iOS support
      if ('ontouchstart' in document.documentElement) {
413
        [].concat(...document.body.children)
XhmikosR's avatar
XhmikosR committed
414
          .forEach(elem => EventHandler.off(elem, 'mouseover', null, noop()))
Johann-S's avatar
Johann-S committed
415
      }
416

Johann-S's avatar
Johann-S committed
417
      toggles[i].setAttribute('aria-expanded', 'false')
fat's avatar
fat committed
418

419
420
421
422
      if (context._popper) {
        context._popper.destroy()
      }

XhmikosR's avatar
XhmikosR committed
423
      dropdownMenu.classList.remove(CLASS_NAME_SHOW)
424
      toggles[i].classList.remove(CLASS_NAME_SHOW)
XhmikosR's avatar
XhmikosR committed
425
      EventHandler.trigger(parent, EVENT_HIDDEN, relatedTarget)
fat's avatar
fat committed
426
    }
Johann-S's avatar
Johann-S committed
427
  }
fat's avatar
fat committed
428

429
  static getParentFromElement(element) {
430
    return getElementFromSelector(element) || element.parentNode
Johann-S's avatar
Johann-S committed
431
  }
fat's avatar
fat committed
432

433
  static dataApiKeydownHandler(event) {
Johann-S's avatar
Johann-S committed
434
435
436
437
438
439
440
    // If not input/textarea:
    //  - And not a key in REGEXP_KEYDOWN => not a dropdown command
    // If input/textarea:
    //  - If space key => not a dropdown command
    //  - If key is other than escape
    //    - If key is not up or down => not a dropdown command
    //    - If trigger inside the menu => not a dropdown command
XhmikosR's avatar
XhmikosR committed
441
    if (/input|textarea/i.test(event.target.tagName) ?
442
443
      event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&
      ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||
444
        event.target.closest(SELECTOR_MENU))) :
445
      !REGEXP_KEYDOWN.test(event.key)) {
Johann-S's avatar
Johann-S committed
446
447
      return
    }
fat's avatar
fat committed
448

Johann-S's avatar
Johann-S committed
449
450
    event.preventDefault()
    event.stopPropagation()
fat's avatar
fat committed
451

XhmikosR's avatar
XhmikosR committed
452
    if (this.disabled || this.classList.contains(CLASS_NAME_DISABLED)) {
Johann-S's avatar
Johann-S committed
453
454
      return
    }
fat's avatar
fat committed
455

456
    const parent = Dropdown.getParentFromElement(this)
457
    const isActive = this.classList.contains(CLASS_NAME_SHOW)
fat's avatar
fat committed
458

459
    if (event.key === ESCAPE_KEY) {
460
461
462
463
464
      const button = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]
      button.focus()
      Dropdown.clearMenus()
      return
    }
fat's avatar
fat committed
465

466
    if (!isActive || event.key === SPACE_KEY) {
467
      Dropdown.clearMenus()
Johann-S's avatar
Johann-S committed
468
469
      return
    }
fat's avatar
fat committed
470

XhmikosR's avatar
XhmikosR committed
471
    const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent).filter(isVisible)
fat's avatar
fat committed
472

Johann-S's avatar
Johann-S committed
473
    if (!items.length) {
Johann-S's avatar
Johann-S committed
474
475
      return
    }
fat's avatar
fat committed
476

477
    let index = items.indexOf(event.target)
Jacob Thornton's avatar
Jacob Thornton committed
478

479
    if (event.key === ARROW_UP_KEY && index > 0) { // Up
Johann-S's avatar
Johann-S committed
480
481
      index--
    }
Jacob Thornton's avatar
Jacob Thornton committed
482

483
    if (event.key === ARROW_DOWN_KEY && index < items.length - 1) { // Down
Johann-S's avatar
Johann-S committed
484
485
      index++
    }
fat's avatar
fat committed
486

487
488
489
    // index is -1 if the first keydown is an ArrowUp
    index = index === -1 ? 0 : index

Johann-S's avatar
Johann-S committed
490
    items[index].focus()
fat's avatar
fat committed
491
  }
492

493
  static getInstance(element) {
494
495
    return Data.getData(element, DATA_KEY)
  }
Johann-S's avatar
Johann-S committed
496
}
fat's avatar
fat committed
497

Johann-S's avatar
Johann-S committed
498
499
500
501
502
/**
 * ------------------------------------------------------------------------
 * Data Api implementation
 * ------------------------------------------------------------------------
 */
fat's avatar
fat committed
503

XhmikosR's avatar
XhmikosR committed
504
505
506
507
508
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
Johann-S's avatar
Johann-S committed
509
510
  event.preventDefault()
  event.stopPropagation()
511
  Dropdown.dropdownInterface(this, 'toggle')
Johann-S's avatar
Johann-S committed
512
})
XhmikosR's avatar
XhmikosR committed
513
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stopPropagation())
Johann-S's avatar
Johann-S committed
514

515
516
const $ = getjQuery()

Johann-S's avatar
Johann-S committed
517
518
519
520
/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
Johann-S's avatar
Johann-S committed
521
 * add .dropdown to jQuery only if jQuery is present
Johann-S's avatar
Johann-S committed
522
 */
Johann-S's avatar
Johann-S committed
523
/* istanbul ignore if */
524
if ($) {
Johann-S's avatar
Johann-S committed
525
  const JQUERY_NO_CONFLICT = $.fn[NAME]
526
  $.fn[NAME] = Dropdown.jQueryInterface
XhmikosR's avatar
XhmikosR committed
527
528
  $.fn[NAME].Constructor = Dropdown
  $.fn[NAME].noConflict = () => {
Johann-S's avatar
Johann-S committed
529
    $.fn[NAME] = JQUERY_NO_CONFLICT
530
    return Dropdown.jQueryInterface
Johann-S's avatar
Johann-S committed
531
  }
Johann-S's avatar
Johann-S committed
532
}
fat's avatar
fat committed
533
534

export default Dropdown