source: trip-planner-front/node_modules/bootstrap/js/src/util/index.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/**
2 * --------------------------------------------------------------------------
3 * Bootstrap (v5.1.3): util/index.js
4 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 * --------------------------------------------------------------------------
6 */
7
8const MAX_UID = 1000000
9const MILLISECONDS_MULTIPLIER = 1000
10const TRANSITION_END = 'transitionend'
11
12// Shoutout AngusCroll (https://goo.gl/pxwQGp)
13const toType = obj => {
14 if (obj === null || obj === undefined) {
15 return `${obj}`
16 }
17
18 return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase()
19}
20
21/**
22 * --------------------------------------------------------------------------
23 * Public Util Api
24 * --------------------------------------------------------------------------
25 */
26
27const getUID = prefix => {
28 do {
29 prefix += Math.floor(Math.random() * MAX_UID)
30 } while (document.getElementById(prefix))
31
32 return prefix
33}
34
35const getSelector = element => {
36 let selector = element.getAttribute('data-bs-target')
37
38 if (!selector || selector === '#') {
39 let hrefAttr = element.getAttribute('href')
40
41 // The only valid content that could double as a selector are IDs or classes,
42 // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
43 // `document.querySelector` will rightfully complain it is invalid.
44 // See https://github.com/twbs/bootstrap/issues/32273
45 if (!hrefAttr || (!hrefAttr.includes('#') && !hrefAttr.startsWith('.'))) {
46 return null
47 }
48
49 // Just in case some CMS puts out a full URL with the anchor appended
50 if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
51 hrefAttr = `#${hrefAttr.split('#')[1]}`
52 }
53
54 selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null
55 }
56
57 return selector
58}
59
60const getSelectorFromElement = element => {
61 const selector = getSelector(element)
62
63 if (selector) {
64 return document.querySelector(selector) ? selector : null
65 }
66
67 return null
68}
69
70const getElementFromSelector = element => {
71 const selector = getSelector(element)
72
73 return selector ? document.querySelector(selector) : null
74}
75
76const getTransitionDurationFromElement = element => {
77 if (!element) {
78 return 0
79 }
80
81 // Get transition-duration of the element
82 let { transitionDuration, transitionDelay } = window.getComputedStyle(element)
83
84 const floatTransitionDuration = Number.parseFloat(transitionDuration)
85 const floatTransitionDelay = Number.parseFloat(transitionDelay)
86
87 // Return 0 if element or transition duration is not found
88 if (!floatTransitionDuration && !floatTransitionDelay) {
89 return 0
90 }
91
92 // If multiple durations are defined, take the first
93 transitionDuration = transitionDuration.split(',')[0]
94 transitionDelay = transitionDelay.split(',')[0]
95
96 return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
97}
98
99const triggerTransitionEnd = element => {
100 element.dispatchEvent(new Event(TRANSITION_END))
101}
102
103const isElement = obj => {
104 if (!obj || typeof obj !== 'object') {
105 return false
106 }
107
108 if (typeof obj.jquery !== 'undefined') {
109 obj = obj[0]
110 }
111
112 return typeof obj.nodeType !== 'undefined'
113}
114
115const getElement = obj => {
116 if (isElement(obj)) { // it's a jQuery object or a node element
117 return obj.jquery ? obj[0] : obj
118 }
119
120 if (typeof obj === 'string' && obj.length > 0) {
121 return document.querySelector(obj)
122 }
123
124 return null
125}
126
127const typeCheckConfig = (componentName, config, configTypes) => {
128 Object.keys(configTypes).forEach(property => {
129 const expectedTypes = configTypes[property]
130 const value = config[property]
131 const valueType = value && isElement(value) ? 'element' : toType(value)
132
133 if (!new RegExp(expectedTypes).test(valueType)) {
134 throw new TypeError(
135 `${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`
136 )
137 }
138 })
139}
140
141const isVisible = element => {
142 if (!isElement(element) || element.getClientRects().length === 0) {
143 return false
144 }
145
146 return getComputedStyle(element).getPropertyValue('visibility') === 'visible'
147}
148
149const isDisabled = element => {
150 if (!element || element.nodeType !== Node.ELEMENT_NODE) {
151 return true
152 }
153
154 if (element.classList.contains('disabled')) {
155 return true
156 }
157
158 if (typeof element.disabled !== 'undefined') {
159 return element.disabled
160 }
161
162 return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'
163}
164
165const findShadowRoot = element => {
166 if (!document.documentElement.attachShadow) {
167 return null
168 }
169
170 // Can find the shadow root otherwise it'll return the document
171 if (typeof element.getRootNode === 'function') {
172 const root = element.getRootNode()
173 return root instanceof ShadowRoot ? root : null
174 }
175
176 if (element instanceof ShadowRoot) {
177 return element
178 }
179
180 // when we don't find a shadow root
181 if (!element.parentNode) {
182 return null
183 }
184
185 return findShadowRoot(element.parentNode)
186}
187
188const noop = () => {}
189
190/**
191 * Trick to restart an element's animation
192 *
193 * @param {HTMLElement} element
194 * @return void
195 *
196 * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
197 */
198const reflow = element => {
199 // eslint-disable-next-line no-unused-expressions
200 element.offsetHeight
201}
202
203const getjQuery = () => {
204 const { jQuery } = window
205
206 if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
207 return jQuery
208 }
209
210 return null
211}
212
213const DOMContentLoadedCallbacks = []
214
215const onDOMContentLoaded = callback => {
216 if (document.readyState === 'loading') {
217 // add listener on the first call when the document is in loading state
218 if (!DOMContentLoadedCallbacks.length) {
219 document.addEventListener('DOMContentLoaded', () => {
220 DOMContentLoadedCallbacks.forEach(callback => callback())
221 })
222 }
223
224 DOMContentLoadedCallbacks.push(callback)
225 } else {
226 callback()
227 }
228}
229
230const isRTL = () => document.documentElement.dir === 'rtl'
231
232const defineJQueryPlugin = plugin => {
233 onDOMContentLoaded(() => {
234 const $ = getjQuery()
235 /* istanbul ignore if */
236 if ($) {
237 const name = plugin.NAME
238 const JQUERY_NO_CONFLICT = $.fn[name]
239 $.fn[name] = plugin.jQueryInterface
240 $.fn[name].Constructor = plugin
241 $.fn[name].noConflict = () => {
242 $.fn[name] = JQUERY_NO_CONFLICT
243 return plugin.jQueryInterface
244 }
245 }
246 })
247}
248
249const execute = callback => {
250 if (typeof callback === 'function') {
251 callback()
252 }
253}
254
255const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
256 if (!waitForTransition) {
257 execute(callback)
258 return
259 }
260
261 const durationPadding = 5
262 const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding
263
264 let called = false
265
266 const handler = ({ target }) => {
267 if (target !== transitionElement) {
268 return
269 }
270
271 called = true
272 transitionElement.removeEventListener(TRANSITION_END, handler)
273 execute(callback)
274 }
275
276 transitionElement.addEventListener(TRANSITION_END, handler)
277 setTimeout(() => {
278 if (!called) {
279 triggerTransitionEnd(transitionElement)
280 }
281 }, emulatedDuration)
282}
283
284/**
285 * Return the previous/next element of a list.
286 *
287 * @param {array} list The list of elements
288 * @param activeElement The active element
289 * @param shouldGetNext Choose to get next or previous element
290 * @param isCycleAllowed
291 * @return {Element|elem} The proper element
292 */
293const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
294 let index = list.indexOf(activeElement)
295
296 // if the element does not exist in the list return an element depending on the direction and if cycle is allowed
297 if (index === -1) {
298 return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]
299 }
300
301 const listLength = list.length
302
303 index += shouldGetNext ? 1 : -1
304
305 if (isCycleAllowed) {
306 index = (index + listLength) % listLength
307 }
308
309 return list[Math.max(0, Math.min(index, listLength - 1))]
310}
311
312export {
313 getElement,
314 getUID,
315 getSelectorFromElement,
316 getElementFromSelector,
317 getTransitionDurationFromElement,
318 triggerTransitionEnd,
319 isElement,
320 typeCheckConfig,
321 isVisible,
322 isDisabled,
323 findShadowRoot,
324 noop,
325 getNextActiveElement,
326 reflow,
327 getjQuery,
328 onDOMContentLoaded,
329 isRTL,
330 defineJQueryPlugin,
331 execute,
332 executeAfterTransition
333}
Note: See TracBrowser for help on using the repository browser.