dropdown.js 14.6 KB
Newer Older
fat's avatar
fat committed
1
2
/**
 * --------------------------------------------------------------------------
XhmikosR's avatar
XhmikosR committed
3
 * Bootstrap (v5.0.0-alpha3): 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
  onDOMContentLoaded,
11
  getElementFromSelector,
12
  isElement,
13
  isVisible,
14
15
  noop,
  typeCheckConfig
16
17
18
19
} from './util/index'
import Data from './dom/data'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
20
import Popper from 'popper.js'
21
import SelectorEngine from './dom/selector-engine'
22

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

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

35
36
37
38
39
40
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
41

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

XhmikosR's avatar
XhmikosR committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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'

Rohit Sharma's avatar
Rohit Sharma committed
62
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]'
XhmikosR's avatar
XhmikosR committed
63
64
65
66
67
68
69
70
71
72
73
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
74
75

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

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

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

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

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

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

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

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

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

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

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

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

134
    Dropdown.clearMenus()
135

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

140
141
142
143
    this.show()
  }

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

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

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

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

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

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

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

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

Johann-S's avatar
Johann-S committed
178
179
180
181
      // 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
182
        parent.classList.add(CLASS_NAME_POSITION_STATIC)
183
      }
XhmikosR's avatar
XhmikosR committed
184

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

Johann-S's avatar
Johann-S committed
188
189
190
191
192
    // 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 &&
193
      !parent.closest(SELECTOR_NAVBAR_NAV)) {
194
      [].concat(...document.body.children)
XhmikosR's avatar
XhmikosR committed
195
        .forEach(elem => EventHandler.on(elem, 'mouseover', null, noop()))
fat's avatar
fat committed
196
197
    }

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

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

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

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

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

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

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

226
227
    this._menu.classList.toggle(CLASS_NAME_SHOW)
    this._element.classList.toggle(CLASS_NAME_SHOW)
XhmikosR's avatar
XhmikosR committed
228
    EventHandler.trigger(parent, EVENT_HIDDEN, relatedTarget)
229
230
  }

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

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

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

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

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

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

    return config
  }

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

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

Johann-S's avatar
Johann-S committed
279
    // Handle dropup
XhmikosR's avatar
XhmikosR committed
280
    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
281
282
283
      placement = this._menu.classList.contains(CLASS_NAME_MENURIGHT) ?
        PLACEMENT_TOPEND :
        PLACEMENT_TOP
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

332
    // Disable Popper if we have a static display
Johann-S's avatar
Johann-S committed
333
334
335
    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
517
518

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
519
 * add .Dropdown to jQuery only if jQuery is present
Johann-S's avatar
Johann-S committed
520
 */
521
522
523
524
525
526
527
528
529
530
531
532

onDOMContentLoaded(() => {
  const $ = getjQuery()
  /* istanbul ignore if */
  if ($) {
    const JQUERY_NO_CONFLICT = $.fn[NAME]
    $.fn[NAME] = Dropdown.jQueryInterface
    $.fn[NAME].Constructor = Dropdown
    $.fn[NAME].noConflict = () => {
      $.fn[NAME] = JQUERY_NO_CONFLICT
      return Dropdown.jQueryInterface
    }
Johann-S's avatar
Johann-S committed
533
  }
534
})
fat's avatar
fat committed
535
536

export default Dropdown