modal.js 16.8 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
91
  }

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

  static get VERSION() {
    return VERSION
96
97
  }

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

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

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

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

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

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

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

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

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

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

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

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

141
142
143
    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
144
145
146
147
          this._ignoreBackdropClick = true
        }
      })
    })
148

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

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

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

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

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

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

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

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

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

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

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


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

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

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

    /**
     * `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
     */
204
    EventHandler.off(document, Event.FOCUSIN)
205

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

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

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

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

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

Johann-S's avatar
Johann-S committed
234
235
  _showElement(relatedTarget) {
    const transition = $(this._element).hasClass(ClassName.FADE)
236

Johann-S's avatar
Johann-S committed
237
238
239
240
    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
241
242
    }

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

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

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

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

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

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

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

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

  _enforceFocus() {
284
285
286
287
288
    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
289
        }
Johann-S's avatar
Johann-S committed
290
      })
291
292
293
    } else if (!this._isShown) {
      EventHandler.off(this._element, Event.KEYDOWN_DISMISS)
    }
Johann-S's avatar
Johann-S committed
294
  }
295

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      if (!data) {
        data = new Modal(this, _config)
525
        Data.setData(this, DATA_KEY, data)
Johann-S's avatar
Johann-S committed
526
      }
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
  }
Johann-S's avatar
Johann-S committed
538
539
540
541
542
543
544
}

/**
 * ------------------------------------------------------------------------
 * Data Api implementation
 * ------------------------------------------------------------------------
 */
545

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

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

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

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

564
565
566
  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
567
      return
568
569
    }

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

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

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

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
 */
591

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

export default Modal