index.js 4.89 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * --------------------------------------------------------------------------
 * Bootstrap (v4.3.1): util/index.js
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * --------------------------------------------------------------------------
 */

const MAX_UID = 1000000
const MILLISECONDS_MULTIPLIER = 1000
const TRANSITION_END = 'transitionend'

// Shoutout AngusCroll (https://goo.gl/pxwQGp)
XhmikosR's avatar
XhmikosR committed
13
const toType = obj => ({}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase())
14
15
16
17
18
19
20

/**
 * --------------------------------------------------------------------------
 * Public Util Api
 * --------------------------------------------------------------------------
 */

XhmikosR's avatar
XhmikosR committed
21
const getUID = prefix => {
22
23
24
  do {
    prefix += ~~(Math.random() * MAX_UID) // "~~" acts like a faster Math.floor() here
  } while (document.getElementById(prefix))
XhmikosR's avatar
XhmikosR committed
25

26
27
28
  return prefix
}

29
const getSelector = element => {
30
31
32
33
34
  let selector = element.getAttribute('data-target')

  if (!selector || selector === '#') {
    const hrefAttr = element.getAttribute('href')

35
    selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null
36
37
  }

38
39
40
41
42
43
44
  return selector
}

const getSelectorFromElement = element => {
  const selector = getSelector(element)

  if (selector) {
45
46
    return document.querySelector(selector) ? selector : null
  }
47
48
49
50
51
52
53
54

  return null
}

const getElementFromSelector = element => {
  const selector = getSelector(element)

  return selector ? document.querySelector(selector) : null
55
56
}

XhmikosR's avatar
XhmikosR committed
57
const getTransitionDurationFromElement = element => {
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  if (!element) {
    return 0
  }

  // Get transition-duration of the element
  let {
    transitionDuration,
    transitionDelay
  } = window.getComputedStyle(element)

  const floatTransitionDuration = parseFloat(transitionDuration)
  const floatTransitionDelay = parseFloat(transitionDelay)

  // Return 0 if element or transition duration is not found
  if (!floatTransitionDuration && !floatTransitionDelay) {
    return 0
  }

  // If multiple durations are defined, take the first
  transitionDuration = transitionDuration.split(',')[0]
  transitionDelay = transitionDelay.split(',')[0]

  return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
}

XhmikosR's avatar
XhmikosR committed
83
const triggerTransitionEnd = element => {
Johann-S's avatar
Johann-S committed
84
85
86
87
  const evt = document.createEvent('HTMLEvents')

  evt.initEvent(TRANSITION_END, true, true)
  element.dispatchEvent(evt)
88
89
}

XhmikosR's avatar
XhmikosR committed
90
const isElement = obj => (obj[0] || obj).nodeType
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

const emulateTransitionEnd = (element, duration) => {
  let called = false
  const durationPadding = 5
  const emulatedDuration = duration + durationPadding
  function listener() {
    called = true
    element.removeEventListener(TRANSITION_END, listener)
  }

  element.addEventListener(TRANSITION_END, listener)
  setTimeout(() => {
    if (!called) {
      triggerTransitionEnd(element)
    }
  }, emulatedDuration)
}

const typeCheckConfig = (componentName, config, configTypes) => {
  Object.keys(configTypes)
XhmikosR's avatar
XhmikosR committed
111
    .forEach(property => {
112
      const expectedTypes = configTypes[property]
XhmikosR's avatar
XhmikosR committed
113
114
115
116
      const value = config[property]
      const valueType = value && isElement(value) ?
        'element' :
        toType(value)
117
118
119
120
121
122
123
124
125
126

      if (!new RegExp(expectedTypes).test(valueType)) {
        throw new Error(
          `${componentName.toUpperCase()}: ` +
          `Option "${property}" provided type "${valueType}" ` +
          `but expected type "${expectedTypes}".`)
      }
    })
}

XhmikosR's avatar
XhmikosR committed
127
const makeArray = nodeList => {
128
129
130
131
132
133
134
  if (!nodeList) {
    return []
  }

  return [].slice.call(nodeList)
}

XhmikosR's avatar
XhmikosR committed
135
const isVisible = element => {
136
137
138
139
140
  if (!element) {
    return false
  }

  if (element.style && element.parentNode && element.parentNode.style) {
141
142
143
144
145
146
    const elementStyle = getComputedStyle(element)
    const parentNodeStyle = getComputedStyle(element.parentNode)

    return elementStyle.display !== 'none' &&
      parentNodeStyle.display !== 'none' &&
      elementStyle.visibility !== 'hidden'
147
148
149
150
151
  }

  return false
}

XhmikosR's avatar
XhmikosR committed
152
const findShadowRoot = element => {
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  if (!document.documentElement.attachShadow) {
    return null
  }

  // Can find the shadow root otherwise it'll return the document
  if (typeof element.getRootNode === 'function') {
    const root = element.getRootNode()
    return root instanceof ShadowRoot ? root : null
  }

  if (element instanceof ShadowRoot) {
    return element
  }

  // when we don't find a shadow root
  if (!element.parentNode) {
    return null
  }

  return findShadowRoot(element.parentNode)
}

const noop = () => function () {}

XhmikosR's avatar
XhmikosR committed
177
const reflow = element => element.offsetHeight
178

179
180
181
182
183
184
185
186
187
188
const getjQuery = () => {
  const { jQuery } = window

  if (jQuery && !document.body.hasAttribute('data-no-jquery')) {
    return jQuery
  }

  return null
}

189
export {
190
  getjQuery,
191
192
193
  TRANSITION_END,
  getUID,
  getSelectorFromElement,
194
  getElementFromSelector,
195
196
197
198
199
200
201
202
203
204
205
  getTransitionDurationFromElement,
  triggerTransitionEnd,
  isElement,
  emulateTransitionEnd,
  typeCheckConfig,
  makeArray,
  isVisible,
  findShadowRoot,
  noop,
  reflow
}