Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
/**
2
 * --------------------------------------------------------------------------
3
 * Bootstrap util/index.js
4
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5
 * --------------------------------------------------------------------------
6
 */
7
 
8
const MAX_UID = 1_000_000
9
const MILLISECONDS_MULTIPLIER = 1000
10
const TRANSITION_END = 'transitionend'
11
 
12
/**
13
 * Properly escape IDs selectors to handle weird IDs
14
 * @param {string} selector
15
 * @returns {string}
16
 */
17
const parseSelector = selector => {
18
  if (selector && window.CSS && window.CSS.escape) {
19
    // document.querySelector needs escaping to handle IDs (html5+) containing for instance /
20
    selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`)
21
  }
22
 
23
  return selector
24
}
25
 
26
// Shout-out Angus Croll (https://goo.gl/pxwQGp)
27
const toType = object => {
28
  if (object === null || object === undefined) {
29
    return `${object}`
30
  }
31
 
32
  return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase()
33
}
34
 
35
/**
36
 * Public Util API
37
 */
38
 
39
const getUID = prefix => {
40
  do {
41
    prefix += Math.floor(Math.random() * MAX_UID)
42
  } while (document.getElementById(prefix))
43
 
44
  return prefix
45
}
46
 
47
const getTransitionDurationFromElement = element => {
48
  if (!element) {
49
    return 0
50
  }
51
 
52
  // Get transition-duration of the element
53
  let { transitionDuration, transitionDelay } = window.getComputedStyle(element)
54
 
55
  const floatTransitionDuration = Number.parseFloat(transitionDuration)
56
  const floatTransitionDelay = Number.parseFloat(transitionDelay)
57
 
58
  // Return 0 if element or transition duration is not found
59
  if (!floatTransitionDuration && !floatTransitionDelay) {
60
    return 0
61
  }
62
 
63
  // If multiple durations are defined, take the first
64
  transitionDuration = transitionDuration.split(',')[0]
65
  transitionDelay = transitionDelay.split(',')[0]
66
 
67
  return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
68
}
69
 
70
const triggerTransitionEnd = element => {
71
  element.dispatchEvent(new Event(TRANSITION_END))
72
}
73
 
74
const isElement = object => {
75
  if (!object || typeof object !== 'object') {
76
    return false
77
  }
78
 
79
  if (typeof object.jquery !== 'undefined') {
80
    object = object[0]
81
  }
82
 
83
  return typeof object.nodeType !== 'undefined'
84
}
85
 
86
const getElement = object => {
87
  // it's a jQuery object or a node element
88
  if (isElement(object)) {
89
    return object.jquery ? object[0] : object
90
  }
91
 
92
  if (typeof object === 'string' && object.length > 0) {
93
    return document.querySelector(parseSelector(object))
94
  }
95
 
96
  return null
97
}
98
 
99
const isVisible = element => {
100
  if (!isElement(element) || element.getClientRects().length === 0) {
101
    return false
102
  }
103
 
104
  const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'
105
  // Handle `details` element as its content may falsie appear visible when it is closed
106
  const closedDetails = element.closest('details:not([open])')
107
 
108
  if (!closedDetails) {
109
    return elementIsVisible
110
  }
111
 
112
  if (closedDetails !== element) {
113
    const summary = element.closest('summary')
114
    if (summary && summary.parentNode !== closedDetails) {
115
      return false
116
    }
117
 
118
    if (summary === null) {
119
      return false
120
    }
121
  }
122
 
123
  return elementIsVisible
124
}
125
 
126
const isDisabled = element => {
127
  if (!element || element.nodeType !== Node.ELEMENT_NODE) {
128
    return true
129
  }
130
 
131
  if (element.classList.contains('disabled')) {
132
    return true
133
  }
134
 
135
  if (typeof element.disabled !== 'undefined') {
136
    return element.disabled
137
  }
138
 
139
  return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'
140
}
141
 
142
const findShadowRoot = element => {
143
  if (!document.documentElement.attachShadow) {
144
    return null
145
  }
146
 
147
  // Can find the shadow root otherwise it'll return the document
148
  if (typeof element.getRootNode === 'function') {
149
    const root = element.getRootNode()
150
    return root instanceof ShadowRoot ? root : null
151
  }
152
 
153
  if (element instanceof ShadowRoot) {
154
    return element
155
  }
156
 
157
  // when we don't find a shadow root
158
  if (!element.parentNode) {
159
    return null
160
  }
161
 
162
  return findShadowRoot(element.parentNode)
163
}
164
 
165
const noop = () => {}
166
 
167
/**
168
 * Trick to restart an element's animation
169
 *
170
 * @param {HTMLElement} element
171
 * @return void
172
 *
173
 * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
174
 */
175
const reflow = element => {
176
  element.offsetHeight // eslint-disable-line no-unused-expressions
177
}
178
 
179
const getjQuery = () => {
180
  if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
181
    return window.jQuery
182
  }
183
 
184
  return null
185
}
186
 
187
const DOMContentLoadedCallbacks = []
188
 
189
const onDOMContentLoaded = callback => {
190
  if (document.readyState === 'loading') {
191
    // add listener on the first call when the document is in loading state
192
    if (!DOMContentLoadedCallbacks.length) {
193
      document.addEventListener('DOMContentLoaded', () => {
194
        for (const callback of DOMContentLoadedCallbacks) {
195
          callback()
196
        }
197
      })
198
    }
199
 
200
    DOMContentLoadedCallbacks.push(callback)
201
  } else {
202
    callback()
203
  }
204
}
205
 
206
const isRTL = () => document.documentElement.dir === 'rtl'
207
 
208
const defineJQueryPlugin = plugin => {
209
  onDOMContentLoaded(() => {
210
    const $ = getjQuery()
211
    /* istanbul ignore if */
212
    if ($) {
213
      const name = plugin.NAME
214
      const JQUERY_NO_CONFLICT = $.fn[name]
215
      $.fn[name] = plugin.jQueryInterface
216
      $.fn[name].Constructor = plugin
217
      $.fn[name].noConflict = () => {
218
        $.fn[name] = JQUERY_NO_CONFLICT
219
        return plugin.jQueryInterface
220
      }
221
    }
222
  })
223
}
224
 
225
const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
226
  return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue
227
}
228
 
229
const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
230
  if (!waitForTransition) {
231
    execute(callback)
232
    return
233
  }
234
 
235
  const durationPadding = 5
236
  const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding
237
 
238
  let called = false
239
 
240
  const handler = ({ target }) => {
241
    if (target !== transitionElement) {
242
      return
243
    }
244
 
245
    called = true
246
    transitionElement.removeEventListener(TRANSITION_END, handler)
247
    execute(callback)
248
  }
249
 
250
  transitionElement.addEventListener(TRANSITION_END, handler)
251
  setTimeout(() => {
252
    if (!called) {
253
      triggerTransitionEnd(transitionElement)
254
    }
255
  }, emulatedDuration)
256
}
257
 
258
/**
259
 * Return the previous/next element of a list.
260
 *
261
 * @param {array} list    The list of elements
262
 * @param activeElement   The active element
263
 * @param shouldGetNext   Choose to get next or previous element
264
 * @param isCycleAllowed
265
 * @return {Element|elem} The proper element
266
 */
267
const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
268
  const listLength = list.length
269
  let index = list.indexOf(activeElement)
270
 
271
  // if the element does not exist in the list return an element
272
  // depending on the direction and if cycle is allowed
273
  if (index === -1) {
274
    return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]
275
  }
276
 
277
  index += shouldGetNext ? 1 : -1
278
 
279
  if (isCycleAllowed) {
280
    index = (index + listLength) % listLength
281
  }
282
 
283
  return list[Math.max(0, Math.min(index, listLength - 1))]
284
}
285
 
286
export {
287
  defineJQueryPlugin,
288
  execute,
289
  executeAfterTransition,
290
  findShadowRoot,
291
  getElement,
292
  getjQuery,
293
  getNextActiveElement,
294
  getTransitionDurationFromElement,
295
  getUID,
296
  isDisabled,
297
  isElement,
298
  isRTL,
299
  isVisible,
300
  noop,
301
  onDOMContentLoaded,
302
  parseSelector,
303
  reflow,
304
  triggerTransitionEnd,
305
  toType
306
}