PageSourceSearch

https://www.shoppoolcity.com/wp-content/themes/bigbear/js/bootstrap/modal.js

js shoppoolcity.com collected 2026-10-07 00:16:54 UTC 12,024 bytes, 448 lines download raw bytes

1/**
2 * --------------------------------------------------------------------------
3 * Bootstrap (v5.0.2): modal.js
4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 * --------------------------------------------------------------------------
6 */
7
8import {
9  defineJQueryPlugin,
10  getElementFromSelector,
11  isRTL,
12  isVisible,
13  reflow,
14  typeCheckConfig
15} from './util/index.js'
16import EventHandler from './dom/event-handler.js'
17import Manipulator from './dom/manipulator.js'
18import SelectorEngine from './dom/selector-engine.js'
19import ScrollBarHelper from './util/scrollbar.js'
20import BaseComponent from './base-component.js'
21import Backdrop from './util/backdrop.js'
22
23/**
24 * ------------------------------------------------------------------------
25 * Constants
26 * ------------------------------------------------------------------------
27 */
28
29const NAME = 'modal'
30const DATA_KEY = 'bs.modal'
31const EVENT_KEY = `.${DATA_KEY}`
32const DATA_API_KEY = '.data-api'
33const ESCAPE_KEY = 'Escape'
34
35const Default = {
36  backdrop: true,
37  keyboard: true,
38  focus: true
39}
40
41const DefaultType = {
42  backdrop: '(boolean|string)',
43  keyboard: 'boolean',
44  focus: 'boolean'
45}
46
47const EVENT_HIDE = `hide${EVENT_KEY}`
48const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`
49const EVENT_HIDDEN = `hidden${EVENT_KEY}`
50const EVENT_SHOW = `show${EVENT_KEY}`
51const EVENT_SHOWN = `shown${EVENT_KEY}`
52const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
53const EVENT_RESIZE = `resize${EVENT_KEY}`
54const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
55const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
56const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`
57const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`
58const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
59
60const CLASS_NAME_OPEN = 'modal-open'
61const CLASS_NAME_FADE = 'fade'
62const CLASS_NAME_SHOW = 'show'
63const CLASS_NAME_STATIC = 'modal-static'
64
65const SELECTOR_DIALOG = '.modal-dialog'
66const SELECTOR_MODAL_BODY = '.modal-body'
67const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="modal"]'
68const SELECTOR_DATA_DISMISS = '[data-bs-dismiss="modal"]'
69
70/**
71 * ------------------------------------------------------------------------
72 * Class Definition
73 * ------------------------------------------------------------------------
74 */
75
76class Modal extends BaseComponent {
77  constructor(element, config) {
78    super(element)
79
80    this._config = this._getConfig(config)
81    this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)
82    this._backdrop = this._initializeBackDrop()
83    this._isShown = false
84    this._ignoreBackdropClick = false
85    this._isTransitioning = false
86    this._scrollBar = new ScrollBarHelper()
87  }
88
89  // Getters
90
91  static get Default() {
92    return Default
93  }
94
95  static get NAME() {
96    return NAME
97  }
98
99  // Public
100
101  toggle(relatedTarget) {
102    return this._isShown ? this.hide() : this.show(relatedTarget)
103  }
104
105  show(relatedTarget) {
106    if (this._isShown || this._isTransitioning) {
107      return
108    }
109
110    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
111      relatedTarget
112    })
113
114    if (showEvent.defaultPrevented) {
115      return
116    }
117
118    this._isShown = true
119
120    if (this._isAnimated()) {
121      this._isTransitioning = true
122    }
123
124    this._scrollBar.hide()
125
126    document.body.classList.add(CLASS_NAME_OPEN)
127
128    this._adjustDialog()
129
130    this._setEscapeEvent()
131    this._setResizeEvent()
132
133    EventHandler.on(this._element, EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, event => this.hide(event))
134
135    EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => {
136      EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => {
137        if (event.target === this._element) {
138          this._ignoreBackdropClick = true
139        }
140      })
141    })
142
143    this._showBackdrop(() => this._showElement(relatedTarget))
144  }
145
146  hide(event) {
147    if (event && ['A', 'AREA'].includes(event.target.tagName)) {
148      event.preventDefault()
149    }
150
151    if (!this._isShown || this._isTransitioning) {
152      return
153    }
154
155    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
156
157    if (hideEvent.defaultPrevented) {
158      return
159    }
160
161    this._isShown = false
162    const isAnimated = this._isAnimated()
163
164    if (isAnimated) {
165      this._isTransitioning = true
166    }
167
168    this._setEscapeEvent()
169    this._setResizeEvent()
170
171    EventHandler.off(document, EVENT_FOCUSIN)
172
173    this._element.classList.remove(CLASS_NAME_SHOW)
174
175    EventHandler.off(this._element, EVENT_CLICK_DISMISS)
176    EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS)
177
178    this._queueCallback(() => this._hideModal(), this._element, isAnimated)
179  }
180
181  dispose() {
182    [window, this._dialog]
183      .forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY))
184
185    this._backdrop.dispose()
186    super.dispose()
187
188    /**
189     * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`
190     * Do not move `document` in `htmlElements` array
191     * It will remove `EVENT_CLICK_DATA_API` event that should remain
192     */
193    EventHandler.off(document, EVENT_FOCUSIN)
194  }
195
196  handleUpdate() {
197    this._adjustDialog()
198  }
199
200  // Private
201
202  _initializeBackDrop() {
203    return new Backdrop({
204      isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value
205      isAnimated: this._isAnimated()
206    })
207  }
208
209  _getConfig(config) {
210    config = {
211      ...Default,
212      ...Manipulator.getDataAttributes(this._element),
213      ...(typeof config === 'object' ? config : {})
214    }
215    typeCheckConfig(NAME, config, DefaultType)
216    return config
217  }
218
219  _showElement(relatedTarget) {
220    const isAnimated = this._isAnimated()
221    const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)
222
223    if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
224      // Don't move modal's DOM position
225      document.body.appendChild(this._element)
226    }
227
228    this._element.style.display = 'block'
229    this._element.removeAttribute('aria-hidden')
230    this._element.setAttribute('aria-modal', true)
231    this._element.setAttribute('role', 'dialog')
232    this._element.scrollTop = 0
233
234    if (modalBody) {
235      modalBody.scrollTop = 0
236    }
237
238    if (isAnimated) {
239      reflow(this._element)
240    }
241
242    this._element.classList.add(CLASS_NAME_SHOW)
243
244    if (this._config.focus) {
245      this._enforceFocus()
246    }
247
248    const transitionComplete = () => {
249      if (this._config.focus) {
250        this._element.focus()
251      }
252
253      this._isTransitioning = false
254      EventHandler.trigger(this._element, EVENT_SHOWN, {
255        relatedTarget
256      })
257    }
258
259    this._queueCallback(transitionComplete, this._dialog, isAnimated)
260  }
261
262  _enforceFocus() {
263    EventHandler.off(document, EVENT_FOCUSIN) // guard against infinite focus loop
264    EventHandler.on(document, EVENT_FOCUSIN, event => {
265      if (document !== event.target &&
266          this._element !== event.target &&
267          !this._element.contains(event.target)) {
268        this._element.focus()
269      }
270    })
271  }
272
273  _setEscapeEvent() {
274    if (this._isShown) {
275      EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
276        if (this._config.keyboard && event.key === ESCAPE_KEY) {
277          event.preventDefault()
278          this.hide()
279        } else if (!this._config.keyboard && event.key === ESCAPE_KEY) {
280          this._triggerBackdropTransition()
281        }
282      })
283    } else {
284      EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS)
285    }
286  }
287
288  _setResizeEvent() {
289    if (this._isShown) {
290      EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog())
291    } else {
292      EventHandler.off(window, EVENT_RESIZE)
293    }
294  }
295
296  _hideModal() {
297    this._element.style.display = 'none'
298    this._element.setAttribute('aria-hidden', true)
299    this._element.removeAttribute('aria-modal')
300    this._element.removeAttribute('role')
301    this._isTransitioning = false
302    this._backdrop.hide(() => {
303      document.body.classList.remove(CLASS_NAME_OPEN)
304      this._resetAdjustments()
305      this._scrollBar.reset()
306      EventHandler.trigger(this._element, EVENT_HIDDEN)
307    })
308  }
309
310  _showBackdrop(callback) {
311    EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => {
312      if (this._ignoreBackdropClick) {
313        this._ignoreBackdropClick = false
314        return
315      }
316
317      if (event.target !== event.currentTarget) {
318        return
319      }
320
321      if (this._config.backdrop === true) {
322        this.hide()
323      } else if (this._config.backdrop === 'static') {
324        this._triggerBackdropTransition()
325      }
326    })
327
328    this._backdrop.show(callback)
329  }
330
331  _isAnimated() {
332    return this._element.classList.contains(CLASS_NAME_FADE)
333  }
334
335  _triggerBackdropTransition() {
336    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
337    if (hideEvent.defaultPrevented) {
338      return
339    }
340
341    const { classList, scrollHeight, style } = this._element
342    const isModalOverflowing = scrollHeight > document.documentElement.clientHeight
343
344    // return if the following background transition hasn't yet completed
345    if ((!isModalOverflowing && style.overflowY === 'hidden') || classList.contains(CLASS_NAME_STATIC)) {
346      return
347    }
348
349    if (!isModalOverflowing) {
350      style.overflowY = 'hidden'
351    }
352
353    classList.add(CLASS_NAME_STATIC)
354    this._queueCallback(() => {
355      classList.remove(CLASS_NAME_STATIC)
356      if (!isModalOverflowing) {
357        this._queueCallback(() => {
358          style.overflowY = ''
359        }, this._dialog)
360      }
361    }, this._dialog)
362
363    this._element.focus()
364  }
365
366  // ----------------------------------------------------------------------
367  // the following methods are used to handle overflowing modals
368  // ----------------------------------------------------------------------
369
370  _adjustDialog() {
371    const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight
372    const scrollbarWidth = this._scrollBar.getWidth()
373    const isBodyOverflowing = scrollbarWidth > 0
374
375    if ((!isBodyOverflowing && isModalOverflowing && !isRTL()) || (isBodyOverflowing && !isModalOverflowing && isRTL())) {
376      this._element.style.paddingLeft = `${scrollbarWidth}px`
377    }
378
379    if ((isBodyOverflowing && !isModalOverflowing && !isRTL()) || (!isBodyOverflowing && isModalOverflowing && isRTL())) {
380      this._element.style.paddingRight = `${scrollbarWidth}px`
381    }
382  }
383
384  _resetAdjustments() {
385    this._element.style.paddingLeft = ''
386    this._element.style.paddingRight = ''
387  }
388
389  // Static
390
391  static jQueryInterface(config, relatedTarget) {
392    return this.each(function () {
393      const data = Modal.getOrCreateInstance(this, config)
394
395      if (typeof config !== 'string') {
396        return
397      }
398
399      if (typeof data[config] === 'undefined') {
400        throw new TypeError(`No method named "${config}"`)
401      }
402
403      data[config](relatedTarget)
404    })
405  }
406}
407
408/**
409 * ------------------------------------------------------------------------
410 * Data Api implementation
411 * ------------------------------------------------------------------------
412 */
413
414EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
415  const target = getElementFromSelector(this)
416
417  if (['A', 'AREA'].includes(this.tagName)) {
418    event.preventDefault()
419  }
420
421  EventHandler.one(target, EVENT_SHOW, showEvent => {
422    if (showEvent.defaultPrevented) {
423      // only register focus restorer if modal will actually get shown
424      return
425    }
426
427    EventHandler.one(target, EVENT_HIDDEN, () => {
428      if (isVisible(this)) {
429        this.focus()
430      }
431    })
432  })
433
434  const data = Modal.getOrCreateInstance(target)
435
436  data.toggle(this)
437})
438
439/**
440 * ------------------------------------------------------------------------
441 * jQuery
442 * ------------------------------------------------------------------------
443 * add .Modal to jQuery only if jQuery is present
444 */
445
446defineJQueryPlugin(Modal)
447
448export default Modal

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.