diff options
| author | Johann-S <[email protected]> | 2019-03-16 16:10:23 +0200 |
|---|---|---|
| committer | XhmikosR <[email protected]> | 2019-03-18 01:11:05 +0200 |
| commit | 08679ac0b5f34e1a1f1766be460e51bc1aa8d82a (patch) | |
| tree | 2cef1cf8f17668c56b410c4c3e32a55bd4853af9 /js/src | |
| parent | f7c1b1e683976ee780faadddc4edc70b477aa01f (diff) | |
| download | bootstrap-08679ac0b5f34e1a1f1766be460e51bc1aa8d82a.tar.xz bootstrap-08679ac0b5f34e1a1f1766be460e51bc1aa8d82a.zip | |
Add back support for IE 11
Diffstat (limited to 'js/src')
| -rw-r--r-- | js/src/button.js | 10 | ||||
| -rw-r--r-- | js/src/dom/eventHandler.js | 6 | ||||
| -rw-r--r-- | js/src/dom/polyfill.js | 179 | ||||
| -rw-r--r-- | js/src/dom/selectorEngine.js | 7 | ||||
| -rw-r--r-- | js/src/util/index.js | 5 |
5 files changed, 139 insertions, 68 deletions
diff --git a/js/src/button.js b/js/src/button.js index 6453137e4..78b0fea8c 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -166,12 +166,18 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, eve EventHandler.on(document, Event.FOCUS_DATA_API, Selector.DATA_TOGGLE_CARROT, event => { const button = SelectorEngine.closest(event.target, Selector.BUTTON) - button.classList.add(ClassName.FOCUS) + + if (button) { + button.classList.add(ClassName.FOCUS) + } }) EventHandler.on(document, Event.BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, event => { const button = SelectorEngine.closest(event.target, Selector.BUTTON) - button.classList.remove(ClassName.FOCUS) + + if (button) { + button.classList.remove(ClassName.FOCUS) + } }) /** diff --git a/js/src/dom/eventHandler.js b/js/src/dom/eventHandler.js index 177465053..65c671fac 100644 --- a/js/src/dom/eventHandler.js +++ b/js/src/dom/eventHandler.js @@ -6,7 +6,7 @@ */ import { jQuery as $ } from '../util/index' -import Polyfill from './polyfill' +import { createCustomEvent, defaultPreventedPreservedOnDispatch } from './polyfill' /** * ------------------------------------------------------------------------ @@ -305,7 +305,7 @@ const EventHandler = { evt = document.createEvent('HTMLEvents') evt.initEvent(typeEvent, bubbles, true) } else { - evt = new CustomEvent(event, { + evt = createCustomEvent(event, { bubbles, cancelable: true }) @@ -326,7 +326,7 @@ const EventHandler = { if (defaultPrevented) { evt.preventDefault() - if (!Polyfill.defaultPreventedPreservedOnDispatch) { + if (!defaultPreventedPreservedOnDispatch) { Object.defineProperty(evt, 'defaultPrevented', { get: () => true }) diff --git a/js/src/dom/polyfill.js b/js/src/dom/polyfill.js index f6cd23bdb..fd857cb38 100644 --- a/js/src/dom/polyfill.js +++ b/js/src/dom/polyfill.js @@ -1,3 +1,5 @@ +/* istanbul ignore file */ + /** * -------------------------------------------------------------------------- * Bootstrap (v4.3.1): dom/polyfill.js @@ -7,83 +9,144 @@ import { getUID } from '../util/index' -/* istanbul ignore next */ -const Polyfill = (() => { - // MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached - const defaultPreventedPreservedOnDispatch = (() => { - const e = new CustomEvent('Bootstrap', { - cancelable: true - }) +let { matches, closest } = Element.prototype +let find = Element.prototype.querySelectorAll +let findOne = Element.prototype.querySelector +let createCustomEvent = (eventName, params) => { + const cEvent = new CustomEvent(eventName, params) - const element = document.createElement('div') - element.addEventListener('Bootstrap', () => null) + return cEvent +} - e.preventDefault() - element.dispatchEvent(e) - return e.defaultPrevented - })() +if (typeof window.CustomEvent !== 'function') { + createCustomEvent = (eventName, params) => { + params = params || { bubbles: false, cancelable: false, detail: null } - let find = Element.prototype.querySelectorAll - let findOne = Element.prototype.querySelector + const evt = document.createEvent('CustomEvent') - const scopeSelectorRegex = /:scope\b/ - const supportScopeQuery = (() => { - const element = document.createElement('div') + evt.initCustomEvent(eventName, params.bubbles, params.cancelable, params.detail) + return evt + } +} - try { - element.querySelectorAll(':scope *') - } catch (error) { - return false +const workingDefaultPrevented = (() => { + const e = document.createEvent('CustomEvent') + + e.initEvent('Bootstrap', true, true) + e.preventDefault() + return e.defaultPrevented +})() + +if (!workingDefaultPrevented) { + const origPreventDefault = Event.prototype.preventDefault + + Event.prototype.preventDefault = function () { + if (!this.cancelable) { + return } - return true - })() + origPreventDefault.call(this) + Object.defineProperty(this, 'defaultPrevented', { + get() { + return true + }, + configurable: true + }) + } +} - if (!supportScopeQuery) { - find = function (selector) { - if (!scopeSelectorRegex.test(selector)) { - return this.querySelectorAll(selector) - } +// MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached +const defaultPreventedPreservedOnDispatch = (() => { + const e = createCustomEvent('Bootstrap', { + cancelable: true + }) - const hasId = Boolean(this.id) + const element = document.createElement('div') + element.addEventListener('Bootstrap', () => null) - if (!hasId) { - this.id = getUID('scope') - } + e.preventDefault() + element.dispatchEvent(e) + return e.defaultPrevented +})() + +if (!matches) { + matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector +} - let nodeList = null - try { - selector = selector.replace(scopeSelectorRegex, `#${this.id}`) - nodeList = this.querySelectorAll(selector) - } finally { - if (!hasId) { - this.removeAttribute('id') - } +if (!closest) { + closest = function (selector) { + let element = this + + do { + if (matches.call(element, selector)) { + return element } - return nodeList + element = element.parentElement || element.parentNode + } while (element !== null && element.nodeType === 1) + + return null + } +} + +const scopeSelectorRegex = /:scope\b/ +const supportScopeQuery = (() => { + const element = document.createElement('div') + + try { + element.querySelectorAll(':scope *') + } catch (error) { + return false + } + + return true +})() + +if (!supportScopeQuery) { + find = function (selector) { + if (!scopeSelectorRegex.test(selector)) { + return this.querySelectorAll(selector) } - findOne = function (selector) { - if (!scopeSelectorRegex.test(selector)) { - return this.querySelector(selector) - } + const hasId = Boolean(this.id) - const matches = find.call(this, selector) + if (!hasId) { + this.id = getUID('scope') + } - if (typeof matches[0] !== 'undefined') { - return matches[0] + let nodeList = null + try { + selector = selector.replace(scopeSelectorRegex, `#${this.id}`) + nodeList = this.querySelectorAll(selector) + } finally { + if (!hasId) { + this.removeAttribute('id') } - - return null } - } - return { - defaultPreventedPreservedOnDispatch, - find, - findOne + return nodeList } -})() -export default Polyfill + 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 + } +} + +export { + createCustomEvent, + find, + findOne, + matches, + closest, + defaultPreventedPreservedOnDispatch +} diff --git a/js/src/dom/selectorEngine.js b/js/src/dom/selectorEngine.js index a54b18e58..fad3a43b5 100644 --- a/js/src/dom/selectorEngine.js +++ b/js/src/dom/selectorEngine.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -import Polyfill from './polyfill' +import { find as findFn, findOne, matches, closest } from './polyfill' import { makeArray } from '../util/index' /** @@ -14,12 +14,11 @@ import { makeArray } from '../util/index' * ------------------------------------------------------------------------ */ -const { find: findFn, findOne } = Polyfill const NODE_TEXT = 3 const SelectorEngine = { matches(element, selector) { - return element.matches(selector) + return matches.call(element, selector) }, find(selector, element = document.documentElement) { @@ -72,7 +71,7 @@ const SelectorEngine = { return null } - return element.closest(selector) + return closest.call(element, selector) }, prev(element, selector) { diff --git a/js/src/util/index.js b/js/src/util/index.js index aea369558..5788c8749 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -71,7 +71,10 @@ const getTransitionDurationFromElement = element => { } const triggerTransitionEnd = element => { - element.dispatchEvent(new Event(TRANSITION_END)) + const evt = document.createEvent('HTMLEvents') + + evt.initEvent(TRANSITION_END, true, true) + element.dispatchEvent(evt) } const isElement = obj => (obj[0] || obj).nodeType |
