Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/bootstrap.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
authorJohann-S <johann.servoire@gmail.com>2019-03-16 17:10:23 +0300
committerXhmikosR <xhmikosr@gmail.com>2019-03-18 02:11:05 +0300
commit08679ac0b5f34e1a1f1766be460e51bc1aa8d82a (patch)
tree2cef1cf8f17668c56b410c4c3e32a55bd4853af9 /js
parentf7c1b1e683976ee780faadddc4edc70b477aa01f (diff)
Add back support for IE 11
Diffstat (limited to 'js')
-rw-r--r--js/src/button.js10
-rw-r--r--js/src/dom/eventHandler.js6
-rw-r--r--js/src/dom/polyfill.js179
-rw-r--r--js/src/dom/selectorEngine.js7
-rw-r--r--js/src/util/index.js5
-rw-r--r--js/tests/browsers.js7
-rw-r--r--js/tests/karma.conf.js9
-rw-r--r--js/tests/unit/modal.js25
-rw-r--r--js/tests/unit/tests-polyfills.js28
9 files changed, 198 insertions, 78 deletions
diff --git a/js/src/button.js b/js/src/button.js
index 6453137e4e..78b0fea8cd 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 1774650533..65c671facd 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 f6cd23bdb9..fd857cb38c 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 a54b18e581..fad3a43b54 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 aea369558a..5788c8749e 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
diff --git a/js/tests/browsers.js b/js/tests/browsers.js
index 859f9505cc..a0d43da864 100644
--- a/js/tests/browsers.js
+++ b/js/tests/browsers.js
@@ -30,6 +30,13 @@ const browsers = {
browser: 'Edge',
browser_version: 'latest'
},
+ ie11Win10: {
+ base: 'BrowserStack',
+ os: 'Windows',
+ os_version: '10',
+ browser: 'IE',
+ browser_version: '11.0'
+ },
chromeWin10: {
base: 'BrowserStack',
os: 'Windows',
diff --git a/js/tests/karma.conf.js b/js/tests/karma.conf.js
index 122d95753b..16f07cbf1a 100644
--- a/js/tests/karma.conf.js
+++ b/js/tests/karma.conf.js
@@ -79,8 +79,9 @@ if (bundle) {
conf.detectBrowsers = detectBrowsers
files = files.concat([
jqueryFile,
+ 'js/tests/unit/tests-polyfills.js',
'dist/js/bootstrap.js',
- 'js/tests/unit/*.js'
+ 'js/tests/unit/!(tests-polyfills).js'
])
} else if (browserStack) {
conf.hostname = ip.address()
@@ -97,6 +98,7 @@ if (bundle) {
reporters.push('BrowserStack')
files = files.concat([
jqueryFile,
+ 'js/tests/unit/tests-polyfills.js',
'js/coverage/dist/util/util.js',
'js/coverage/dist/util/sanitizer.js',
'js/coverage/dist/dom/polyfill.js',
@@ -107,7 +109,7 @@ if (bundle) {
'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',
+ 'js/tests/unit/!(tests-polyfills).js',
'js/tests/unit/dom/*.js',
'js/tests/unit/util/*.js'
])
@@ -121,6 +123,7 @@ if (bundle) {
)
files = files.concat([
jqueryFile,
+ 'js/tests/unit/tests-polyfills.js',
'js/coverage/dist/util/util.js',
'js/coverage/dist/util/sanitizer.js',
'js/coverage/dist/dom/polyfill.js',
@@ -131,7 +134,7 @@ if (bundle) {
'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',
+ 'js/tests/unit/!(tests-polyfills).js',
'js/tests/unit/dom/*.js',
'js/tests/unit/util/*.js'
])
diff --git a/js/tests/unit/modal.js b/js/tests/unit/modal.js
index 87d778b868..82b37f2367 100644
--- a/js/tests/unit/modal.js
+++ b/js/tests/unit/modal.js
@@ -731,7 +731,14 @@ $(function () {
})
QUnit.test('should enforce focus', function (assert) {
- assert.expect(2)
+ var isIE11 = Boolean(window.MSInputMethodContext) && Boolean(document.documentMode)
+
+ if (isIE11) {
+ assert.expect(1)
+ } else {
+ assert.expect(2)
+ }
+
var done = assert.async()
var $modal = $([
@@ -759,14 +766,18 @@ $(function () {
done()
}
- document.addEventListener('focusin', focusInListener)
+ if (isIE11) {
+ done()
+ } else {
+ document.addEventListener('focusin', focusInListener)
- var focusInEvent = new Event('focusin')
- Object.defineProperty(focusInEvent, 'target', {
- value: $('#qunit-fixture')[0]
- })
+ var focusInEvent = new Event('focusin')
+ Object.defineProperty(focusInEvent, 'target', {
+ value: $('#qunit-fixture')[0]
+ })
- document.dispatchEvent(focusInEvent)
+ document.dispatchEvent(focusInEvent)
+ }
})
.bootstrapModal('show')
})
diff --git a/js/tests/unit/tests-polyfills.js b/js/tests/unit/tests-polyfills.js
new file mode 100644
index 0000000000..4f2583e0db
--- /dev/null
+++ b/js/tests/unit/tests-polyfills.js
@@ -0,0 +1,28 @@
+// Polyfills for our unit tests
+(function () {
+ 'use strict'
+
+ // Event constructor shim
+ if (!window.Event || typeof window.Event !== 'function') {
+ var origEvent = window.Event
+ window.Event = function (inType, params) {
+ params = params || {}
+ var e = document.createEvent('Event')
+ e.initEvent(inType, Boolean(params.bubbles), Boolean(params.cancelable))
+ return e
+ }
+
+ window.Event.prototype = origEvent.prototype
+ }
+
+ if (typeof window.CustomEvent !== 'function') {
+ window.CustomEvent = function (event, params) {
+ params = params || { bubbles: false, cancelable: false, detail: null }
+ var evt = document.createEvent('CustomEvent')
+ evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail)
+ return evt
+ }
+
+ CustomEvent.prototype = window.Event.prototype
+ }
+})()