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
    if (this._isShown || showEvent.defaultPrevented) {
Johann-S's avatar
Johann-S committed
123
124
      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
    if (!this._isShown || hideEvent.defaultPrevented) {
Johann-S's avatar
Johann-S committed
165
166
      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() {
Johann-S's avatar
Johann-S committed
285
286
287
288
289
290
291
292
    EventHandler.off(document, Event.FOCUSIN) // guard against infinite focus loop
    EventHandler.on(document, Event.FOCUSIN, (event) => {
      if (document !== event.target &&
          this._element !== event.target &&
          !this._element.contains(event.target)) {
        this._element.focus()
      }
    })
Johann-S's avatar
Johann-S committed
293
  }
294

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

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

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

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

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

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

      if (animate) {
        this._backdrop.classList.add(animate)
347
348
      }

349
      document.body.appendChild(this._backdrop)
Johann-S's avatar
Johann-S committed
350

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

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

370
      this._backdrop.classList.add(ClassName.SHOW)
371

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

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

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

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

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

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

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

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

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

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

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

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

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

Johann-S's avatar
Johann-S committed
437
438
439
440
441
442
  _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
443
444
445
446
447
448
449
      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`
        })
450

Johann-S's avatar
Johann-S committed
451
      // Adjust sticky content margin
452
453
454
455
456
457
458
      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`
        })
459

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

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

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

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

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

Johann-S's avatar
Johann-S committed
492
    // Restore body padding
493
    const padding = Manipulator.getDataAttribute(document.body, 'padding-right')
494
495
496
497
498
499
    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
500
  }
501

Johann-S's avatar
Johann-S committed
502
503
504
505
506
507
508
509
  _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
  }
510

Johann-S's avatar
Johann-S committed
511
512
513
514
  // Static

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

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

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

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

/**
 * ------------------------------------------------------------------------
 * Data Api implementation
 * ------------------------------------------------------------------------
 */
547

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

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

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

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

566
567
568
  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
569
      return
570
571
    }

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

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

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

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
 */
592

593
594
595
596
597
598
599
600
601
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
602
}
603
604

export default Modal