dropdown.js 14.9 KB
Newer Older
fat's avatar
fat committed
1
2
/**
 * --------------------------------------------------------------------------
XhmikosR's avatar
XhmikosR committed
3
 * Bootstrap (v4.3.1): dropdown.js
fat's avatar
fat committed
4
5
6
7
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * --------------------------------------------------------------------------
 */

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
29
30
31
32
const NAME = 'dropdown'
const VERSION = '4.3.1'
const DATA_KEY = 'bs.dropdown'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
XhmikosR's avatar
XhmikosR committed
33

XhmikosR's avatar
XhmikosR committed
34
35
36
37
38
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key
const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key
const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key
const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key
Johann-S's avatar
Johann-S committed
39
40
const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)

XhmikosR's avatar
XhmikosR committed
41
const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`)
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
193
      !SelectorEngine.closest(parent, SELECTOR_NAVBAR_NAV)) {
      [].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
    }

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

    return config
  }

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

Johann-S's avatar
Johann-S committed
278
  _getPlacement() {
Johann-S's avatar
Johann-S committed
279
    const parentDropdown = this._element.parentNode
XhmikosR's avatar
XhmikosR committed
280
    let placement = PLACEMENT_BOTTOM
281

Johann-S's avatar
Johann-S committed
282
    // Handle dropup
XhmikosR's avatar
XhmikosR committed
283
284
285
286
    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
      placement = PLACEMENT_TOP
      if (this._menu.classList.contains(CLASS_NAME_MENURIGHT)) {
        placement = PLACEMENT_TOPEND
287
      }
XhmikosR's avatar
XhmikosR committed
288
289
290
291
292
293
    } 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
294
    }
XhmikosR's avatar
XhmikosR committed
295

Johann-S's avatar
Johann-S committed
296
297
    return placement
  }
298

Johann-S's avatar
Johann-S committed
299
  _detectNavbar() {
XhmikosR's avatar
XhmikosR committed
300
    return Boolean(SelectorEngine.closest(this._element, `.${CLASS_NAME_NAVBAR}`))
Johann-S's avatar
Johann-S committed
301
  }
302

303
304
305
  _getOffset() {
    const offset = {}

Johann-S's avatar
Johann-S committed
306
    if (typeof this._config.offset === 'function') {
XhmikosR's avatar
XhmikosR committed
307
      offset.fn = data => {
Johann-S's avatar
Johann-S committed
308
309
        data.offsets = {
          ...data.offsets,
310
          ...this._config.offset(data.offsets, this._element) || {}
311
        }
312

Johann-S's avatar
Johann-S committed
313
        return data
314
      }
Johann-S's avatar
Johann-S committed
315
    } else {
316
      offset.offset = this._config.offset
Johann-S's avatar
Johann-S committed
317
    }
318

319
320
321
322
    return offset
  }

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

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

343
344
345
    return {
      ...popperConfig,
      ...this._config.popperConfig
346
    }
Johann-S's avatar
Johann-S committed
347
  }
348

Johann-S's avatar
Johann-S committed
349
  // Static
fat's avatar
fat committed
350

351
  static dropdownInterface(element, config) {
Johann-S's avatar
Johann-S committed
352
353
    let data = Data.getData(element, DATA_KEY)
    const _config = typeof config === 'object' ? config : null
fat's avatar
fat committed
354

Johann-S's avatar
Johann-S committed
355
356
357
    if (!data) {
      data = new Dropdown(element, _config)
    }
fat's avatar
fat committed
358

Johann-S's avatar
Johann-S committed
359
360
    if (typeof config === 'string') {
      if (typeof data[config] === 'undefined') {
XhmikosR's avatar
XhmikosR committed
361
        throw new TypeError(`No method named "${config}"`)
Johann-S's avatar
Johann-S committed
362
      }
XhmikosR's avatar
XhmikosR committed
363

Johann-S's avatar
Johann-S committed
364
365
366
367
      data[config]()
    }
  }

368
  static jQueryInterface(config) {
Johann-S's avatar
Johann-S committed
369
    return this.each(function () {
370
      Dropdown.dropdownInterface(this, config)
Johann-S's avatar
Johann-S committed
371
372
373
    })
  }

374
  static clearMenus(event) {
Johann-S's avatar
Johann-S committed
375
    if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH ||
376
      (event.type === 'keyup' && event.which !== TAB_KEYCODE))) {
Johann-S's avatar
Johann-S committed
377
      return
fat's avatar
fat committed
378
379
    }

380
381
    const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)

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

Johann-S's avatar
Johann-S committed
389
390
391
      if (event && event.type === 'click') {
        relatedTarget.clickEvent = event
      }
392

Johann-S's avatar
Johann-S committed
393
394
395
      if (!context) {
        continue
      }
Johann-S's avatar
Johann-S committed
396

Johann-S's avatar
Johann-S committed
397
      const dropdownMenu = context._menu
398
      if (!toggles[i].classList.contains(CLASS_NAME_SHOW)) {
Johann-S's avatar
Johann-S committed
399
400
        continue
      }
fat's avatar
fat committed
401

402
403
404
      if (event && ((event.type === 'click' &&
          /input|textarea/i.test(event.target.tagName)) ||
          (event.type === 'keyup' && event.which === TAB_KEYCODE)) &&
405
          dropdownMenu.contains(event.target)) {
Johann-S's avatar
Johann-S committed
406
407
        continue
      }
fat's avatar
fat committed
408

XhmikosR's avatar
XhmikosR committed
409
      const hideEvent = EventHandler.trigger(parent, EVENT_HIDE, relatedTarget)
Johann-S's avatar
Johann-S committed
410
      if (hideEvent.defaultPrevented) {
Johann-S's avatar
Johann-S committed
411
412
        continue
      }
fat's avatar
fat committed
413

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

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

423
424
425
426
      if (context._popper) {
        context._popper.destroy()
      }

XhmikosR's avatar
XhmikosR committed
427
      dropdownMenu.classList.remove(CLASS_NAME_SHOW)
428
      toggles[i].classList.remove(CLASS_NAME_SHOW)
XhmikosR's avatar
XhmikosR committed
429
      EventHandler.trigger(parent, EVENT_HIDDEN, relatedTarget)
fat's avatar
fat committed
430
    }
Johann-S's avatar
Johann-S committed
431
  }
fat's avatar
fat committed
432

433
  static getParentFromElement(element) {
434
    return getElementFromSelector(element) || element.parentNode
Johann-S's avatar
Johann-S committed
435
  }
fat's avatar
fat committed
436

437
  static dataApiKeydownHandler(event) {
Johann-S's avatar
Johann-S committed
438
439
440
441
442
443
444
    // 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
445
    if (/input|textarea/i.test(event.target.tagName) ?
446
447
      event.which === SPACE_KEYCODE || (event.which !== ESCAPE_KEYCODE &&
      ((event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE) ||
XhmikosR's avatar
XhmikosR committed
448
        SelectorEngine.closest(event.target, SELECTOR_MENU))) :
XhmikosR's avatar
XhmikosR committed
449
      !REGEXP_KEYDOWN.test(event.which)) {
Johann-S's avatar
Johann-S committed
450
451
      return
    }
fat's avatar
fat committed
452

Johann-S's avatar
Johann-S committed
453
454
    event.preventDefault()
    event.stopPropagation()
fat's avatar
fat committed
455

XhmikosR's avatar
XhmikosR committed
456
    if (this.disabled || this.classList.contains(CLASS_NAME_DISABLED)) {
Johann-S's avatar
Johann-S committed
457
458
      return
    }
fat's avatar
fat committed
459

460
    const parent = Dropdown.getParentFromElement(this)
461
    const isActive = this.classList.contains(CLASS_NAME_SHOW)
fat's avatar
fat committed
462

463
464
465
466
467
468
    if (event.which === ESCAPE_KEYCODE) {
      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
469

470
    if (!isActive || event.which === SPACE_KEYCODE) {
471
      Dropdown.clearMenus()
Johann-S's avatar
Johann-S committed
472
473
      return
    }
fat's avatar
fat committed
474

475
    const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent)
476
      .filter(isVisible)
fat's avatar
fat committed
477

Johann-S's avatar
Johann-S committed
478
    if (!items.length) {
Johann-S's avatar
Johann-S committed
479
480
      return
    }
fat's avatar
fat committed
481

482
    let index = items.indexOf(event.target) || 0
Jacob Thornton's avatar
Jacob Thornton committed
483

Johann-S's avatar
Johann-S committed
484
485
486
    if (event.which === ARROW_UP_KEYCODE && index > 0) { // Up
      index--
    }
Jacob Thornton's avatar
Jacob Thornton committed
487

Johann-S's avatar
Johann-S committed
488
489
490
    if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { // Down
      index++
    }
fat's avatar
fat committed
491

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

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

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

XhmikosR's avatar
XhmikosR committed
506
507
508
509
510
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
511
512
  event.preventDefault()
  event.stopPropagation()
513
  Dropdown.dropdownInterface(this, 'toggle')
Johann-S's avatar
Johann-S committed
514
515
})
EventHandler
XhmikosR's avatar
XhmikosR committed
516
  .on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stopPropagation())
Johann-S's avatar
Johann-S committed
517

518
519
const $ = getjQuery()

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

export default Dropdown