util.js 5.51 KB
Newer Older
fat's avatar
fat committed
1
2
/**
 * --------------------------------------------------------------------------
XhmikosR's avatar
XhmikosR committed
3
 * Bootstrap (v4.3.1): util.js
fat's avatar
fat committed
4
5
6
7
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * --------------------------------------------------------------------------
 */

Johann-S's avatar
Johann-S committed
8
import EventHandler from './dom/eventHandler'
fat's avatar
fat committed
9

Johann-S's avatar
Johann-S committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * ------------------------------------------------------------------------
 * Private TransitionEnd Helpers
 * ------------------------------------------------------------------------
 */

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

// Shoutout AngusCroll (https://goo.gl/pxwQGp)
function toType(obj) {
  return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase()
}

const Util = {
fat's avatar
fat committed
26

Johann-S's avatar
Johann-S committed
27
  TRANSITION_END: 'bsTransitionEnd',
28

Johann-S's avatar
Johann-S committed
29
30
31
32
33
34
35
  getUID(prefix) {
    do {
      // eslint-disable-next-line no-bitwise
      prefix += ~~(Math.random() * MAX_UID) // "~~" acts like a faster Math.floor() here
    } while (document.getElementById(prefix))
    return prefix
  },
fat's avatar
fat committed
36

Johann-S's avatar
Johann-S committed
37
38
  getSelectorFromElement(element) {
    let selector = element.getAttribute('data-target')
39

Johann-S's avatar
Johann-S committed
40
41
42
43
    if (!selector || selector === '#') {
      const hrefAttr = element.getAttribute('href')
      selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''
    }
44

45
46
47
48
49
    try {
      return document.querySelector(selector) ? selector : null
    } catch (err) {
      return null
    }
Johann-S's avatar
Johann-S committed
50
  },
fat's avatar
fat committed
51

Johann-S's avatar
Johann-S committed
52
53
54
55
  getTransitionDurationFromElement(element) {
    if (!element) {
      return 0
    }
56

Johann-S's avatar
Johann-S committed
57
    // Get transition-duration of the element
XhmikosR's avatar
XhmikosR committed
58
59
    let transitionDuration = element.style.transitionDuration
    let transitionDelay = element.style.transitionDelay
60

Johann-S's avatar
Johann-S committed
61
    const floatTransitionDuration = parseFloat(transitionDuration)
62
    const floatTransitionDelay = parseFloat(transitionDelay)
63

Johann-S's avatar
Johann-S committed
64
    // Return 0 if element or transition duration is not found
65
    if (!floatTransitionDuration && !floatTransitionDelay) {
Johann-S's avatar
Johann-S committed
66
67
      return 0
    }
68

Johann-S's avatar
Johann-S committed
69
70
    // If multiple durations are defined, take the first
    transitionDuration = transitionDuration.split(',')[0]
71
    transitionDelay = transitionDelay.split(',')[0]
Johann-S's avatar
Johann-S committed
72

73
    return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
Johann-S's avatar
Johann-S committed
74
75
76
77
78
79
80
  },

  reflow(element) {
    return element.offsetHeight
  },

  triggerTransitionEnd(element) {
Johann-S's avatar
Johann-S committed
81
    EventHandler.trigger(element, Util.TRANSITION_END)
Johann-S's avatar
Johann-S committed
82
83
84
85
86
87
88
89
90
91
92
  },

  // TODO: Remove in v5
  supportsTransitionEnd() {
    return Boolean(TRANSITION_END)
  },

  isElement(obj) {
    return (obj[0] || obj).nodeType
  },

Johann-S's avatar
Johann-S committed
93
94
95
96
97
98
  emulateTransitionEnd(element, duration) {
    setTimeout(() => {
      Util.triggerTransitionEnd(element)
    }, duration)
  },

Johann-S's avatar
Johann-S committed
99
100
101
102
103
104
105
106
107
108
109
110
111
  typeCheckConfig(componentName, config, configTypes) {
    for (const property in configTypes) {
      if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
        const expectedTypes = configTypes[property]
        const value         = config[property]
        const valueType     = value && Util.isElement(value)
          ? 'element' : toType(value)

        if (!new RegExp(expectedTypes).test(valueType)) {
          throw new Error(
            `${componentName.toUpperCase()}: ` +
            `Option "${property}" provided type "${valueType}" ` +
            `but expected type "${expectedTypes}".`)
fat's avatar
fat committed
112
113
        }
      }
Johann-S's avatar
Johann-S committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    },

    extend(obj1, obj2) {
      for (const secondProp in obj2) {
        if (Object.prototype.hasOwnProperty.call(obj2, secondProp)) {
          const secondVal = obj2[secondProp]
          // Is this value an object?  If so, iterate over its properties, copying them over
          if (secondVal && Object.prototype.toString.call(secondVal) === '[object Object]') {
            obj1[secondProp] = obj1[secondProp] || {}
            Util.extend(obj1[secondProp], secondVal)
          } else {
            obj1[secondProp] = secondVal
          }
        }
      }
      return obj1
    },

    makeArray(nodeList) {
      if (typeof nodeList === 'undefined' || nodeList === null) {
        return []
      }
      return Array.prototype.slice.call(nodeList)
    },

    getDataAttributes(element) {
      if (typeof element === 'undefined' || element === null) {
        return {}
      }

      const attributes = {}
      for (let i = 0; i < element.attributes.length; i++) {
        const attribute = element.attributes[i]
        if (attribute.nodeName.indexOf('data-') !== -1) {
          // remove 'data-' part of the attribute name
          const attributeName = attribute.nodeName.substring('data-'.length)
          attributes[attributeName] = attribute.nodeValue
        }
      }
      return attributes
    },

    isVisible(element) {
      if (typeof element === 'undefined' || element === null) {
        return false
      }

      if (element.style !== null && element.parentNode !== null && typeof element.parentNode.style !== 'undefined') {
        return element.style.display !== 'none'
          && element.parentNode.style.display !== 'none'
          && element.style.visibility !== 'hidden'
      }
      return false
167
    }
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  },

  findShadowRoot(element) {
    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 Util.findShadowRoot(element.parentNode)
fat's avatar
fat committed
191
  }
Johann-S's avatar
Johann-S committed
192
}
fat's avatar
fat committed
193

194
export default Util