]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
refactor(polyfill): a file for polyfills
authorJohann-S <johann.servoire@gmail.com>
Sat, 9 Jun 2018 16:24:06 +0000 (18:24 +0200)
committerXhmikosR <xhmikosr@gmail.com>
Wed, 20 Feb 2019 20:05:45 +0000 (22:05 +0200)
js/src/dom/eventHandler.js
js/src/dom/polyfill.js
js/src/dom/selectorEngine.js
js/tests/karma.conf.js

index c73bcd2ab844ff59839347d782805694fa8f4d39..dda1eb216f5fe11d7531570d2b3393f3d95d99dc 100644 (file)
@@ -1,88 +1,14 @@
+import Polyfill from './polyfill'
 import Util from '../util'
 
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.0.0-beta): dom/eventHandler.js
+ * Bootstrap (v4.1.1): dom/eventHandler.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
  * --------------------------------------------------------------------------
  */
 
 const EventHandler = (() => {
-  /**
-   * ------------------------------------------------------------------------
-   * Polyfills
-   * ------------------------------------------------------------------------
-   */
-
-  // defaultPrevented is broken in IE.
-  // https://connect.microsoft.com/IE/feedback/details/790389/event-defaultprevented-returns-false-after-preventdefault-was-called
-  const workingDefaultPrevented = (() => {
-    const e = document.createEvent('CustomEvent')
-    e.initEvent('Bootstrap', true, true)
-    e.preventDefault()
-    return e.defaultPrevented
-  })()
-
-  let defaultPreventedPreservedOnDispatch = true
-
-  // CustomEvent polyfill for IE (see: https://mzl.la/2v76Zvn)
-  if (typeof window.CustomEvent !== 'function') {
-    window.CustomEvent = (event, params) => {
-      params = params || {
-        bubbles: false,
-        cancelable: false,
-        detail: null
-      }
-      const evt = document.createEvent('CustomEvent')
-      evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail)
-      if (!workingDefaultPrevented) {
-        const origPreventDefault = Event.prototype.preventDefault
-        evt.preventDefault = () => {
-          if (!evt.cancelable) {
-            return
-          }
-
-          origPreventDefault.call(evt)
-          Object.defineProperty(evt, 'defaultPrevented', {
-            get() {
-              return true
-            },
-            configurable: true
-          })
-        }
-      }
-      return evt
-    }
-
-    window.CustomEvent.prototype = window.Event.prototype
-  } else {
-    // MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached
-    defaultPreventedPreservedOnDispatch = (() => {
-      const e = new CustomEvent('Bootstrap', {
-        cancelable: true
-      })
-
-      const element = document.createElement('div')
-      element.addEventListener('Bootstrap', () => null)
-
-      e.preventDefault()
-      element.dispatchEvent(e)
-      return e.defaultPrevented
-    })()
-  }
-
-  // Event constructor shim
-  if (!window.Event || typeof window.Event !== 'function') {
-    const origEvent = window.Event
-    window.Event = (inType, params) => {
-      params = params || {}
-      const e = document.createEvent('Event')
-      e.initEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable))
-      return e
-    }
-    window.Event.prototype = origEvent.prototype
-  }
-
   /**
    * ------------------------------------------------------------------------
    * Constants
@@ -361,7 +287,7 @@ const EventHandler = (() => {
       if (defaultPrevented) {
         evt.preventDefault()
 
-        if (!defaultPreventedPreservedOnDispatch) {
+        if (!Polyfill.defaultPreventedPreservedOnDispatch) {
           Object.defineProperty(evt, 'defaultPrevented', {
             get: () => true
           })
@@ -382,7 +308,7 @@ const EventHandler = (() => {
 })()
 
 // focusin and focusout polyfill
-if (typeof window.onfocusin === 'undefined') {
+if (Polyfill.focusIn) {
   (() => {
     function listenerFocus(event) {
       EventHandler.trigger(event.target, 'focusin')
index 644e6025b141f630e633ae22f80bbe68eb037c79..2c811c25af0903bf8f6478e657819977617473f9 100644 (file)
@@ -1,8 +1,14 @@
-import EventHandler from './eventHandler'
+import Util from '../util'
+
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap (v4.1.1): dom/polyfill.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * --------------------------------------------------------------------------
+ */
 
 const Polyfill = (() => {
-  // defaultPrevented is broken in IE.
-  // https://connect.microsoft.com/IE/feedback/details/790389/event-defaultprevented-returns-false-after-preventdefault-was-called
+  // defaultPrevented is broken in IE
   const workingDefaultPrevented = (() => {
     const e = document.createEvent('CustomEvent')
     e.initEvent('Bootstrap', true, true)
@@ -10,7 +16,22 @@ const Polyfill = (() => {
     return e.defaultPrevented
   })()
 
-  let defaultPreventedPreservedOnDispatch = true
+  if (!workingDefaultPrevented) {
+    const origPreventDefault = Event.prototype.preventDefault
+    Event.prototype.preventDefault = function () {
+      if (!this.cancelable) {
+        return
+      }
+
+      origPreventDefault.call(this)
+      Object.defineProperty(this, 'defaultPrevented', {
+        get() {
+          return true
+        },
+        configurable: true
+      })
+    }
+  }
 
   // CustomEvent polyfill for IE (see: https://mzl.la/2v76Zvn)
   if (typeof window.CustomEvent !== 'function') {
@@ -22,41 +43,25 @@ const Polyfill = (() => {
       }
       const evt = document.createEvent('CustomEvent')
       evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail)
-      if (!workingDefaultPrevented) {
-        const origPreventDefault = Event.prototype.preventDefault
-        evt.preventDefault = () => {
-          if (!evt.cancelable) {
-            return
-          }
-
-          origPreventDefault.call(evt)
-          Object.defineProperty(evt, 'defaultPrevented', {
-            get() {
-              return true
-            },
-            configurable: true
-          })
-        }
-      }
       return evt
     }
 
     window.CustomEvent.prototype = window.Event.prototype
-  } else {
-    // MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached
-    defaultPreventedPreservedOnDispatch = (() => {
-      const e = new CustomEvent('Bootstrap', {
-        cancelable: true
-      })
+  }
 
-      const element = document.createElement('div')
-      element.addEventListener('Bootstrap', () => null)
+  // MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached
+  const defaultPreventedPreservedOnDispatch = (() => {
+    const e = new CustomEvent('Bootstrap', {
+      cancelable: true
+    })
 
-      e.preventDefault()
-      element.dispatchEvent(e)
-      return e.defaultPrevented
-    })()
-  }
+    const element = document.createElement('div')
+    element.addEventListener('Bootstrap', () => null)
+
+    e.preventDefault()
+    element.dispatchEvent(e)
+    return e.defaultPrevented
+  })()
 
   // Event constructor shim
   if (!window.Event || typeof window.Event !== 'function') {
@@ -70,24 +75,91 @@ const Polyfill = (() => {
     window.Event.prototype = origEvent.prototype
   }
 
-  // focusin and focusout polyfill
-  if (typeof window.onfocusin === 'undefined') {
-    (() => {
-      function listenerFocus(event) {
-        EventHandler.trigger(event.target, 'focusin')
+  // matches polyfill (see: https://mzl.la/2ikXneG)
+  if (!Element.prototype.matches) {
+    Element.prototype.matches =
+      Element.prototype.msMatchesSelector ||
+      Element.prototype.webkitMatchesSelector
+  }
+
+  // closest polyfill (see: https://mzl.la/2vXggaI)
+  let closest
+  if (!Element.prototype.closest) {
+    closest = (element, selector) => {
+      let ancestor = element
+      do {
+        if (ancestor.matches(selector)) {
+          return ancestor
+        }
+
+        ancestor = ancestor.parentElement
+      } while (ancestor !== null && ancestor.nodeType === Node.ELEMENT_NODE)
+
+      return null
+    }
+  } else {
+    closest = (element, selector) => element.closest(selector)
+  }
+
+  const supportScopeQuery = (() => {
+    const element = document.createElement('div')
+    try {
+      element.querySelectorAll(':scope *')
+    } catch (e) {
+      return false
+    }
+
+    return true
+  })()
+
+  const scopeSelectorRegex = /:scope\b/
+  let find = Element.prototype.querySelectorAll
+  let findOne = Element.prototype.querySelector
+
+  if (!supportScopeQuery) {
+    find = function (selector) {
+      if (!scopeSelectorRegex.test(selector)) {
+        return this.querySelectorAll(selector)
       }
-      function listenerBlur(event) {
-        EventHandler.trigger(event.target, 'focusout')
+
+      const hasId = Boolean(this.id)
+      if (!hasId) {
+        this.id = Util.getUID('scope')
       }
-      EventHandler.on(document, 'focus', 'input', listenerFocus)
-      EventHandler.on(document, 'blur', 'input', listenerBlur)
-    })()
+
+      let nodeList = null
+      try {
+        selector = selector.replace(scopeSelectorRegex, `#${this.id}`)
+        nodeList = this.querySelectorAll(selector)
+      } finally {
+        if (!hasId) {
+          this.removeAttribute('id')
+        }
+      }
+
+      return nodeList
+    }
+
+    findOne = function (selector) {
+      if (!scopeSelectorRegex.test(selector)) {
+        return this.querySelector(selector)
+      }
+
+      const matches = find.call(this, selector)
+      if (typeof matches[0] !== 'undefined') {
+        return matches[0]
+      }
+
+      return null
+    }
   }
 
   return {
-    get defaultPreventedPreservedOnDispatch() {
-      return defaultPreventedPreservedOnDispatch
-    }
+    defaultPreventedPreservedOnDispatch,
+    focusIn: typeof window.onfocusin === 'undefined',
+    closest,
+    find,
+    findOne
   }
 })()
 
index e515164458e702a1f113e84b0b027fe1738d6e07..b6b45bacb4d4895608de359a5197e252f29b8534 100644 (file)
@@ -1,3 +1,4 @@
+import Polyfill from './polyfill'
 import Util from '../util'
 
 /**
@@ -10,100 +11,17 @@ import Util from '../util'
 const SelectorEngine = (() => {
   /**
    * ------------------------------------------------------------------------
-   * Polyfills
+   * Constants
    * ------------------------------------------------------------------------
    */
 
-  // matches polyfill (see: https://mzl.la/2ikXneG)
-  let fnMatches = null
-  if (!Element.prototype.matches) {
-    fnMatches =
-      Element.prototype.msMatchesSelector ||
-      Element.prototype.webkitMatchesSelector
-  } else {
-    fnMatches = Element.prototype.matches
-  }
-
-  // closest polyfill (see: https://mzl.la/2vXggaI)
-  let fnClosest = null
-  if (!Element.prototype.closest) {
-    fnClosest = (element, selector) => {
-      let ancestor = element
-      do {
-        if (fnMatches.call(ancestor, selector)) {
-          return ancestor
-        }
-
-        ancestor = ancestor.parentElement
-      } while (ancestor !== null && ancestor.nodeType === Node.ELEMENT_NODE)
-
-      return null
-    }
-  } else {
-    // eslint-disable-next-line arrow-body-style
-    fnClosest = (element, selector) => {
-      return element.closest(selector)
-    }
-  }
-
-  const scopeSelectorRegex = /:scope\b/
-  const supportScopeQuery = (() => {
-    const element = document.createElement('div')
-    try {
-      element.querySelectorAll(':scope *')
-    } catch (e) {
-      return false
-    }
-
-    return true
-  })()
-
-  let findFn = null
-  let findOneFn = null
-  if (supportScopeQuery) {
-    findFn = Element.prototype.querySelectorAll
-    findOneFn = Element.prototype.querySelector
-  } else {
-    findFn = function (selector) {
-      if (!scopeSelectorRegex.test(selector)) {
-        return this.querySelectorAll(selector)
-      }
-
-      const hasId = Boolean(this.id)
-      if (!hasId) {
-        this.id = Util.getUID('scope')
-      }
-
-      let nodeList = null
-      try {
-        selector = selector.replace(scopeSelectorRegex, `#${this.id}`)
-        nodeList = this.querySelectorAll(selector)
-      } finally {
-        if (!hasId) {
-          this.removeAttribute('id')
-        }
-      }
-
-      return nodeList
-    }
-
-    findOneFn = function (selector) {
-      if (!scopeSelectorRegex.test(selector)) {
-        return this.querySelector(selector)
-      }
-
-      const matches = findFn.call(this, selector)
-      if (typeof matches[0] !== 'undefined') {
-        return matches[0]
-      }
-
-      return null
-    }
-  }
+  const closest = Polyfill.closest
+  const find = Polyfill.find
+  const findOne = Polyfill.findOne
 
   return {
     matches(element, selector) {
-      return fnMatches.call(element, selector)
+      return element.matches(selector)
     },
 
     find(selector, element = document.documentElement) {
@@ -111,7 +29,7 @@ const SelectorEngine = (() => {
         return null
       }
 
-      return findFn.call(element, selector)
+      return find.call(element, selector)
     },
 
     findOne(selector, element = document.documentElement) {
@@ -119,7 +37,7 @@ const SelectorEngine = (() => {
         return null
       }
 
-      return findOneFn.call(element, selector)
+      return findOne.call(element, selector)
     },
 
     children(element, selector) {
@@ -140,7 +58,7 @@ const SelectorEngine = (() => {
 
       let ancestor = element.parentNode
       while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE) {
-        if (fnMatches.call(ancestor, selector)) {
+        if (ancestor.matches(selector)) {
           parents.push(ancestor)
         }
 
@@ -151,7 +69,7 @@ const SelectorEngine = (() => {
     },
 
     closest(element, selector) {
-      return fnClosest(element, selector)
+      return closest(element, selector)
     },
 
     prev(element, selector) {
@@ -163,7 +81,7 @@ const SelectorEngine = (() => {
 
       let previous = element.previousSibling
       while (previous) {
-        if (fnMatches.call(previous, selector)) {
+        if (previous.matches(selector)) {
           siblings.push(previous)
         }
 
index f6570cdcb4b13631901ff60d907453902c2f194a..066165a14d63d9a4e995f0c1437f40b9e89eb019 100644 (file)
@@ -98,7 +98,8 @@ if (bundle) {
     'js/coverage/dist/dom/data.js',
     'js/coverage/dist/dom/manipulator.js',
     'js/coverage/dist/util.js',
-    'js/coverage/dist/dom/*.js',
+    'js/coverage/dist/dom/polyfill.js',
+    'js/coverage/dist/dom/!(polyfill).js',
     'js/coverage/dist/tooltip.js',
     'js/coverage/dist/!(util|index|tooltip).js', // include all of our js/dist files except util.js, index.js and tooltip.js
     'js/tests/unit/*.js',
@@ -119,7 +120,8 @@ if (bundle) {
     'js/coverage/dist/dom/data.js',
     'js/coverage/dist/dom/manipulator.js',
     'js/coverage/dist/util.js',
-    'js/coverage/dist/dom/*.js',
+    'js/coverage/dist/dom/polyfill.js',
+    'js/coverage/dist/dom/!(polyfill).js',
     'js/coverage/dist/tooltip.js',
     'js/coverage/dist/!(util|index|tooltip).js', // include all of our js/dist files except util.js, index.js and tooltip.js
     'js/tests/unit/*.js',