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

8
9
10
11
import Data from './dom/data'
import EventHandler from './dom/eventHandler'
import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selectorEngine'
12
13
import Util from './util'

Johann-S's avatar
Johann-S committed
14
15
16
17
18
/**
 * ------------------------------------------------------------------------
 * Constants
 * ------------------------------------------------------------------------
 */
19

Johann-S's avatar
Johann-S committed
20
const NAME               = 'modal'
XhmikosR's avatar
XhmikosR committed
21
const VERSION            = '4.3.1'
Johann-S's avatar
Johann-S committed
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const DATA_KEY           = 'bs.modal'
const EVENT_KEY          = `.${DATA_KEY}`
const DATA_API_KEY       = '.data-api'
const ESCAPE_KEYCODE     = 27 // KeyboardEvent.which value for Escape (Esc) key

const Default = {
  backdrop : true,
  keyboard : true,
  focus    : true,
  show     : true
}

const DefaultType = {
  backdrop : '(boolean|string)',
  keyboard : 'boolean',
  focus    : 'boolean',
  show     : 'boolean'
}

const Event = {
  HIDE              : `hide${EVENT_KEY}`,
  HIDDEN            : `hidden${EVENT_KEY}`,
  SHOW              : `show${EVENT_KEY}`,
  SHOWN             : `shown${EVENT_KEY}`,
  FOCUSIN           : `focusin${EVENT_KEY}`,
  RESIZE            : `resize${EVENT_KEY}`,
  CLICK_DISMISS     : `click.dismiss${EVENT_KEY}`,
  KEYDOWN_DISMISS   : `keydown.dismiss${EVENT_KEY}`,
  MOUSEUP_DISMISS   : `mouseup.dismiss${EVENT_KEY}`,
  MOUSEDOWN_DISMISS : `mousedown.dismiss${EVENT_KEY}`,
  CLICK_DATA_API    : `click${EVENT_KEY}${DATA_API_KEY}`
}

const ClassName = {
Shohei Yoshida's avatar
Shohei Yoshida committed
56
  SCROLLABLE         : 'modal-dialog-scrollable',
Johann-S's avatar
Johann-S committed
57
58
59
60
61
62
63
64
  SCROLLBAR_MEASURER : 'modal-scrollbar-measure',
  BACKDROP           : 'modal-backdrop',
  OPEN               : 'modal-open',
  FADE               : 'fade',
  SHOW               : 'show'
}

const Selector = {
65
  DIALOG         : '.modal-dialog',
Shohei Yoshida's avatar
Shohei Yoshida committed
66
  MODAL_BODY     : '.modal-body',
67
68
69
70
  DATA_TOGGLE    : '[data-toggle="modal"]',
  DATA_DISMISS   : '[data-dismiss="modal"]',
  FIXED_CONTENT  : '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
  STICKY_CONTENT : '.sticky-top'
Johann-S's avatar
Johann-S committed
71
}
fat's avatar
fat committed
72

Johann-S's avatar
Johann-S committed
73
74
75
76
77
/**
 * ------------------------------------------------------------------------
 * Class Definition
 * ------------------------------------------------------------------------
 */
78

Johann-S's avatar
Johann-S committed
79
80
81
82
class Modal {
  constructor(element, config) {
    this._config              = this._getConfig(config)
    this._element             = element
83
    this._dialog              = SelectorEngine.findOne(Selector.DIALOG, element)
Johann-S's avatar
Johann-S committed
84
85
86
87
    this._backdrop            = null
    this._isShown             = false
    this._isBodyOverflowing   = false
    this._ignoreBackdropClick = false
88
    this._isTransitioning     = false
Johann-S's avatar
Johann-S committed
89
    this._scrollbarWidth      = 0
90
    Data.setData(element, DATA_KEY, this)
91
92
  }

Johann-S's avatar
Johann-S committed
93
94
95
96
  // Getters

  static get VERSION() {
    return VERSION
97
98
  }

Johann-S's avatar
Johann-S committed
99
100
101
  static get Default() {
    return Default
  }
102

Johann-S's avatar
Johann-S committed
103
  // Public
104

Johann-S's avatar
Johann-S committed
105
106
107
  toggle(relatedTarget) {
    return this._isShown ? this.hide() : this.show(relatedTarget)
  }
108

Johann-S's avatar
Johann-S committed
109
  show(relatedTarget) {
110
    if (this._isShown || this._isTransitioning) {
Johann-S's avatar
Johann-S committed
111
      return
112
113
    }

114
    if (this._element.classList.contains(ClassName.FADE)) {
Johann-S's avatar
Johann-S committed
115
      this._isTransitioning = true
116
117
    }

118
    const showEvent = EventHandler.trigger(this._element, Event.SHOW, {
Johann-S's avatar
Johann-S committed
119
120
      relatedTarget
    })
121

Johann-S's avatar
Johann-S committed
122
123
124
    if (this._isShown || showEvent.isDefaultPrevented()) {
      return
    }
125

Johann-S's avatar
Johann-S committed
126
    this._isShown = true
127

Johann-S's avatar
Johann-S committed
128
129
    this._checkScrollbar()
    this._setScrollbar()
130

Johann-S's avatar
Johann-S committed
131
    this._adjustDialog()
132

Johann-S's avatar
Johann-S committed
133
134
    this._setEscapeEvent()
    this._setResizeEvent()
David Bailey's avatar
David Bailey committed
135

136
    EventHandler.on(this._element,
Johann-S's avatar
Johann-S committed
137
138
139
140
      Event.CLICK_DISMISS,
      Selector.DATA_DISMISS,
      (event) => this.hide(event)
    )
141

142
143
144
    EventHandler.on(this._dialog, Event.MOUSEDOWN_DISMISS, () => {
      EventHandler.one(this._element, Event.MOUSEUP_DISMISS, (event) => {
        if (event.target === this._element) {
Johann-S's avatar
Johann-S committed
145
146
147
148
          this._ignoreBackdropClick = true
        }
      })
    })
149

Johann-S's avatar
Johann-S committed
150
151
    this._showBackdrop(() => this._showElement(relatedTarget))
  }
152

Johann-S's avatar
Johann-S committed
153
154
155
156
  hide(event) {
    if (event) {
      event.preventDefault()
    }
157

158
    if (!this._isShown || this._isTransitioning) {
Johann-S's avatar
Johann-S committed
159
      return
160
161
    }

162
    const hideEvent = EventHandler.trigger(this._element, Event.HIDE)
163

Johann-S's avatar
Johann-S committed
164
165
166
    if (!this._isShown || hideEvent.isDefaultPrevented()) {
      return
    }
167

Johann-S's avatar
Johann-S committed
168
    this._isShown = false
169
    const transition = this._element.classList.contains(ClassName.FADE)
170

Johann-S's avatar
Johann-S committed
171
172
173
    if (transition) {
      this._isTransitioning = true
    }
174

Johann-S's avatar
Johann-S committed
175
176
    this._setEscapeEvent()
    this._setResizeEvent()
177

178
    EventHandler.off(document, Event.FOCUSIN)
179

180
    this._element.classList.remove(ClassName.SHOW)
181

182
183
    EventHandler.off(this._element, Event.CLICK_DISMISS)
    EventHandler.off(this._dialog, Event.MOUSEDOWN_DISMISS)
184
185


Johann-S's avatar
Johann-S committed
186
187
    if (transition) {
      const transitionDuration  = Util.getTransitionDurationFromElement(this._element)
188

189
      EventHandler.one(this._element, Util.TRANSITION_END, (event) => this._hideModal(event))
Johann-S's avatar
Johann-S committed
190
      Util.emulateTransitionEnd(this._element, transitionDuration)
Johann-S's avatar
Johann-S committed
191
192
193
194
    } else {
      this._hideModal()
    }
  }
195

Johann-S's avatar
Johann-S committed
196
  dispose() {
197
    [window, this._element, this._dialog]
198
      .forEach((htmlElement) => EventHandler.off(htmlElement, EVENT_KEY))
199
200
201
202
203
204

    /**
     * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API`
     * Do not move `document` in `htmlElements` array
     * It will remove `Event.CLICK_DATA_API` event that should remain
     */
205
    EventHandler.off(document, Event.FOCUSIN)
206

207
    Data.removeData(this._element, DATA_KEY)
208

Johann-S's avatar
Johann-S committed
209
210
211
212
213
214
215
    this._config              = null
    this._element             = null
    this._dialog              = null
    this._backdrop            = null
    this._isShown             = null
    this._isBodyOverflowing   = null
    this._ignoreBackdropClick = null
216
    this._isTransitioning     = null
Johann-S's avatar
Johann-S committed
217
218
    this._scrollbarWidth      = null
  }
fat's avatar
fat committed
219

Johann-S's avatar
Johann-S committed
220
221
222
  handleUpdate() {
    this._adjustDialog()
  }
fat's avatar
fat committed
223

Johann-S's avatar
Johann-S committed
224
  // Private
fat's avatar
fat committed
225

Johann-S's avatar
Johann-S committed
226
227
228
229
  _getConfig(config) {
    config = {
      ...Default,
      ...config
230
    }
Johann-S's avatar
Johann-S committed
231
232
233
    Util.typeCheckConfig(NAME, config, DefaultType)
    return config
  }
234

Johann-S's avatar
Johann-S committed
235
  _showElement(relatedTarget) {
236
    const transition = this._element.classList.contains(ClassName.FADE)
237

Johann-S's avatar
Johann-S committed
238
239
240
241
    if (!this._element.parentNode ||
        this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
      // Don't move modal's DOM position
      document.body.appendChild(this._element)
fat's avatar
fat committed
242
243
    }

Johann-S's avatar
Johann-S committed
244
245
    this._element.style.display = 'block'
    this._element.removeAttribute('aria-hidden')
246
    this._element.setAttribute('aria-modal', true)
Shohei Yoshida's avatar
Shohei Yoshida committed
247
248
249
250
251
252

    if ($(this._dialog).hasClass(ClassName.SCROLLABLE)) {
      this._dialog.querySelector(Selector.MODAL_BODY).scrollTop = 0
    } else {
      this._element.scrollTop = 0
    }
253

Johann-S's avatar
Johann-S committed
254
255
256
    if (transition) {
      Util.reflow(this._element)
    }
257

258
    this._element.classList.add(ClassName.SHOW)
259

Johann-S's avatar
Johann-S committed
260
261
262
    if (this._config.focus) {
      this._enforceFocus()
    }
263

Johann-S's avatar
Johann-S committed
264
    const transitionComplete = () => {
Jacob Thornton's avatar
Jacob Thornton committed
265
      if (this._config.focus) {
Johann-S's avatar
Johann-S committed
266
        this._element.focus()
Jacob Thornton's avatar
Jacob Thornton committed
267
      }
Johann-S's avatar
Johann-S committed
268
      this._isTransitioning = false
269
270
271
      EventHandler.trigger(this._element, Event.SHOWN, {
        relatedTarget
      })
Johann-S's avatar
Johann-S committed
272
    }
273

Johann-S's avatar
Johann-S committed
274
    if (transition) {
275
      const transitionDuration  = Util.getTransitionDurationFromElement(this._dialog)
276

277
278
      EventHandler.one(this._dialog, Util.TRANSITION_END, transitionComplete)
      Util.emulateTransitionEnd(this._dialog, transitionDuration)
Johann-S's avatar
Johann-S committed
279
280
281
282
283
284
    } else {
      transitionComplete()
    }
  }

  _enforceFocus() {
285
286
287
288
289
    if (this._isShown && this._config.keyboard) {
      EventHandler.on(this._element, Event.KEYDOWN_DISMISS, (event) => {
        if (event.which === ESCAPE_KEYCODE) {
          event.preventDefault()
          this.hide()
Jacob Thornton's avatar
Jacob Thornton committed
290
        }
Johann-S's avatar
Johann-S committed
291
      })
292
293
294
    } else if (!this._isShown) {
      EventHandler.off(this._element, Event.KEYDOWN_DISMISS)
    }
Johann-S's avatar
Johann-S committed
295
  }
296

Johann-S's avatar
Johann-S committed
297
298
  _setEscapeEvent() {
    if (this._isShown && this._config.keyboard) {
299
      EventHandler.on(this._element, Event.KEYDOWN_DISMISS, (event) => {
Johann-S's avatar
Johann-S committed
300
301
302
303
304
305
        if (event.which === ESCAPE_KEYCODE) {
          event.preventDefault()
          this.hide()
        }
      })
    } else if (!this._isShown) {
306
      EventHandler.off(this._element, Event.KEYDOWN_DISMISS)
307
    }
Johann-S's avatar
Johann-S committed
308
  }
309

Johann-S's avatar
Johann-S committed
310
311
  _setResizeEvent() {
    if (this._isShown) {
312
      EventHandler.on(window, Event.RESIZE, (event) => this.handleUpdate(event))
Johann-S's avatar
Johann-S committed
313
    } else {
314
      EventHandler.off(window, Event.RESIZE)
315
    }
Johann-S's avatar
Johann-S committed
316
  }
317

Johann-S's avatar
Johann-S committed
318
319
320
  _hideModal() {
    this._element.style.display = 'none'
    this._element.setAttribute('aria-hidden', true)
321
    this._element.removeAttribute('aria-modal')
Johann-S's avatar
Johann-S committed
322
323
    this._isTransitioning = false
    this._showBackdrop(() => {
324
      document.body.classList.remove(ClassName.OPEN)
Johann-S's avatar
Johann-S committed
325
326
      this._resetAdjustments()
      this._resetScrollbar()
327
      EventHandler.trigger(this._element, Event.HIDDEN)
Johann-S's avatar
Johann-S committed
328
329
330
331
332
    })
  }

  _removeBackdrop() {
    if (this._backdrop) {
333
      this._backdrop.parentNode.removeChild(this._backdrop)
Johann-S's avatar
Johann-S committed
334
      this._backdrop = null
335
    }
Johann-S's avatar
Johann-S committed
336
  }
337

Johann-S's avatar
Johann-S committed
338
  _showBackdrop(callback) {
339
340
341
    const animate = this._element.classList.contains(ClassName.FADE)
      ? ClassName.FADE
      : ''
Johann-S's avatar
Johann-S committed
342
343
344
345
346
347
348

    if (this._isShown && this._config.backdrop) {
      this._backdrop = document.createElement('div')
      this._backdrop.className = ClassName.BACKDROP

      if (animate) {
        this._backdrop.classList.add(animate)
349
350
      }

351
      document.body.appendChild(this._backdrop)
Johann-S's avatar
Johann-S committed
352

353
      EventHandler.on(this._element, Event.CLICK_DISMISS, (event) => {
Johann-S's avatar
Johann-S committed
354
355
356
357
358
359
360
361
362
363
364
365
        if (this._ignoreBackdropClick) {
          this._ignoreBackdropClick = false
          return
        }
        if (event.target !== event.currentTarget) {
          return
        }
        if (this._config.backdrop === 'static') {
          this._element.focus()
        } else {
          this.hide()
        }
366
367
      })

Johann-S's avatar
Johann-S committed
368
369
      if (animate) {
        Util.reflow(this._backdrop)
370
371
      }

372
      this._backdrop.classList.add(ClassName.SHOW)
373

Johann-S's avatar
Johann-S committed
374
375
376
      if (!callback) {
        return
      }
377

Johann-S's avatar
Johann-S committed
378
379
380
381
      if (!animate) {
        callback()
        return
      }
382

Johann-S's avatar
Johann-S committed
383
      const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)
384

385
      EventHandler.one(this._backdrop, Util.TRANSITION_END, callback)
Johann-S's avatar
Johann-S committed
386
      Util.emulateTransitionEnd(backdropTransitionDuration)
Johann-S's avatar
Johann-S committed
387
    } else if (!this._isShown && this._backdrop) {
388
      this._backdrop.classList.remove(ClassName.SHOW)
389

Johann-S's avatar
Johann-S committed
390
391
392
      const callbackRemove = () => {
        this._removeBackdrop()
        if (callback) {
393
394
          callback()
        }
Johann-S's avatar
Johann-S committed
395
      }
396

397
      if (this._element.classList.contains(ClassName.FADE)) {
398
399
        const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)

400
        EventHandler.one(this._backdrop, Util.TRANSITION_END, callbackRemove)
Johann-S's avatar
Johann-S committed
401
        Util.emulateTransitionEnd(backdropTransitionDuration)
Johann-S's avatar
Johann-S committed
402
403
      } else {
        callbackRemove()
404
      }
Johann-S's avatar
Johann-S committed
405
406
    } else if (callback) {
      callback()
407
    }
Johann-S's avatar
Johann-S committed
408
  }
409

Johann-S's avatar
Johann-S committed
410
411
412
413
  // ----------------------------------------------------------------------
  // the following methods are used to handle overflowing modals
  // todo (fat): these should probably be refactored out of modal.js
  // ----------------------------------------------------------------------
414

Johann-S's avatar
Johann-S committed
415
416
417
  _adjustDialog() {
    const isModalOverflowing =
      this._element.scrollHeight > document.documentElement.clientHeight
418

Johann-S's avatar
Johann-S committed
419
420
    if (!this._isBodyOverflowing && isModalOverflowing) {
      this._element.style.paddingLeft = `${this._scrollbarWidth}px`
421
422
    }

Johann-S's avatar
Johann-S committed
423
424
    if (this._isBodyOverflowing && !isModalOverflowing) {
      this._element.style.paddingRight = `${this._scrollbarWidth}px`
425
    }
Johann-S's avatar
Johann-S committed
426
  }
427

Johann-S's avatar
Johann-S committed
428
429
430
431
  _resetAdjustments() {
    this._element.style.paddingLeft = ''
    this._element.style.paddingRight = ''
  }
432

Johann-S's avatar
Johann-S committed
433
434
435
436
437
  _checkScrollbar() {
    const rect = document.body.getBoundingClientRect()
    this._isBodyOverflowing = rect.left + rect.right < window.innerWidth
    this._scrollbarWidth = this._getScrollbarWidth()
  }
438

Johann-S's avatar
Johann-S committed
439
440
441
442
443
444
  _setScrollbar() {
    if (this._isBodyOverflowing) {
      // Note: DOMNode.style.paddingRight returns the actual value or '' if not set
      //   while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set

      // Adjust fixed content padding
445
446
447
448
449
450
451
      Util.makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
        .forEach((element) => {
          const actualPadding = element.style.paddingRight
          const calculatedPadding = window.getComputedStyle(element)['padding-right']
          Manipulator.setDataAttribute(element, 'padding-right', actualPadding)
          element.style.paddingRight = `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`
        })
452

Johann-S's avatar
Johann-S committed
453
      // Adjust sticky content margin
454
455
456
457
458
459
460
      Util.makeArray(SelectorEngine.find(Selector.STICKY_CONTENT))
        .forEach((element) => {
          const actualMargin = element.style.marginRight
          const calculatedMargin = window.getComputedStyle(element)['margin-right']
          Manipulator.setDataAttribute(element, 'margin-right', actualMargin)
          element.style.marginRight = `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`
        })
461

Johann-S's avatar
Johann-S committed
462
463
      // Adjust body padding
      const actualPadding = document.body.style.paddingRight
464
465
466
467
      const calculatedPadding = window.getComputedStyle(document.body)['padding-right']

      Manipulator.setDataAttribute(document.body, 'padding-right', actualPadding)
      document.body.style.paddingRight = `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`
468
    }
469

470
    document.body.classList.add(ClassName.OPEN)
Johann-S's avatar
Johann-S committed
471
  }
472

Johann-S's avatar
Johann-S committed
473
474
  _resetScrollbar() {
    // Restore fixed content padding
475
476
    Util.makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
      .forEach((element) => {
477
        const padding = Manipulator.getDataAttribute(element, 'padding-right')
478
479
480
481
482
        if (typeof padding !== 'undefined') {
          Manipulator.removeDataAttribute(element, 'padding-right')
          element.style.paddingRight = padding
        }
      })
Johann-S's avatar
Johann-S committed
483

484
485
486
    // Restore sticky content and navbar-toggler margin
    Util.makeArray(SelectorEngine.find(`${Selector.STICKY_CONTENT}`))
      .forEach((element) => {
487
        const margin = Manipulator.getDataAttribute(element, 'margin-right')
488
489
490
491
492
        if (typeof margin !== 'undefined') {
          Manipulator.removeDataAttribute(element, 'margin-right')
          element.style.marginRight = margin
        }
      })
493

Johann-S's avatar
Johann-S committed
494
    // Restore body padding
495
    const padding = Manipulator.getDataAttribute(document.body, 'padding-right')
496
497
498
499
500
501
    if (typeof padding !== 'undefined') {
      Manipulator.removeDataAttribute(document.body, 'padding-right')
      document.body.style.paddingRight = padding
    } else {
      document.body.style.paddingRight = ''
    }
Johann-S's avatar
Johann-S committed
502
  }
503

Johann-S's avatar
Johann-S committed
504
505
506
507
508
509
510
511
  _getScrollbarWidth() { // thx d.walsh
    const scrollDiv = document.createElement('div')
    scrollDiv.className = ClassName.SCROLLBAR_MEASURER
    document.body.appendChild(scrollDiv)
    const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth
    document.body.removeChild(scrollDiv)
    return scrollbarWidth
  }
512

Johann-S's avatar
Johann-S committed
513
514
515
516
  // Static

  static _jQueryInterface(config, relatedTarget) {
    return this.each(function () {
517
      let data = Data.getData(this, DATA_KEY)
Johann-S's avatar
Johann-S committed
518
519
      const _config = {
        ...Default,
520
        ...Manipulator.getDataAttributes(this),
Johann-S's avatar
Johann-S committed
521
522
523
524
525
526
        ...typeof config === 'object' && config ? config : {}
      }

      if (!data) {
        data = new Modal(this, _config)
      }
527

Johann-S's avatar
Johann-S committed
528
529
530
      if (typeof config === 'string') {
        if (typeof data[config] === 'undefined') {
          throw new TypeError(`No method named "${config}"`)
531
        }
Johann-S's avatar
Johann-S committed
532
533
534
535
536
        data[config](relatedTarget)
      } else if (_config.show) {
        data.show(relatedTarget)
      }
    })
537
  }
538
539
540
541

  static _getInstance(element) {
    return Data.getData(element, DATA_KEY)
  }
Johann-S's avatar
Johann-S committed
542
543
544
545
546
547
548
}

/**
 * ------------------------------------------------------------------------
 * Data Api implementation
 * ------------------------------------------------------------------------
 */
549

550
EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
Johann-S's avatar
Johann-S committed
551
552
  let target
  const selector = Util.getSelectorFromElement(this)
553

Johann-S's avatar
Johann-S committed
554
  if (selector) {
555
    target = SelectorEngine.findOne(selector)
Johann-S's avatar
Johann-S committed
556
  }
557

558
  const config = Data.getData(target, DATA_KEY)
Johann-S's avatar
Johann-S committed
559
    ? 'toggle' : {
560
561
      ...Manipulator.getDataAttributes(target),
      ...Manipulator.getDataAttributes(this)
562
563
    }

Johann-S's avatar
Johann-S committed
564
565
566
  if (this.tagName === 'A' || this.tagName === 'AREA') {
    event.preventDefault()
  }
567

568
569
570
  EventHandler.one(target, Event.SHOW, (showEvent) => {
    if (showEvent.defaultPrevented) {
      // only register focus restorer if modal will actually get shown
Johann-S's avatar
Johann-S committed
571
      return
572
573
    }

574
575
    EventHandler.one(target, Event.HIDDEN, () => {
      if (Util.isVisible(this)) {
Johann-S's avatar
Johann-S committed
576
        this.focus()
577
578
579
580
      }
    })
  })

581
582
583
584
585
586
  let data = Data.getData(target, DATA_KEY)
  if (!data) {
    data = new Modal(target, config)
  }

  data.show(this)
Johann-S's avatar
Johann-S committed
587
588
589
590
591
592
593
})

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
 */
594

595
596
597
598
599
600
601
602
603
const $ = Util.jQuery
if (typeof $ !== 'undefined') {
  const JQUERY_NO_CONFLICT = $.fn[NAME]
  $.fn[NAME]               = Modal._jQueryInterface
  $.fn[NAME].Constructor   = Modal
  $.fn[NAME].noConflict    = () => {
    $.fn[NAME] = JQUERY_NO_CONFLICT
    return Modal._jQueryInterface
  }
Johann-S's avatar
Johann-S committed
604
}
605
606

export default Modal