mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-10 07:37:27 +02:00
move util in a util folder with the sanitizer
This commit is contained in:
@@ -130,7 +130,7 @@
|
|||||||
"func-call-spacing": "error",
|
"func-call-spacing": "error",
|
||||||
"func-name-matching": "error",
|
"func-name-matching": "error",
|
||||||
"func-names": "off",
|
"func-names": "off",
|
||||||
"func-style": ["error", "declaration"],
|
"func-style": "off",
|
||||||
"id-blacklist": "error",
|
"id-blacklist": "error",
|
||||||
"id-length": "off",
|
"id-length": "off",
|
||||||
"id-match": "error",
|
"id-match": "error",
|
||||||
|
@@ -41,23 +41,25 @@ const bsPlugins = {
|
|||||||
ScrollSpy: path.resolve(__dirname, '../js/src/scrollspy.js'),
|
ScrollSpy: path.resolve(__dirname, '../js/src/scrollspy.js'),
|
||||||
Tab: path.resolve(__dirname, '../js/src/tab.js'),
|
Tab: path.resolve(__dirname, '../js/src/tab.js'),
|
||||||
Toast: path.resolve(__dirname, '../js/src/toast.js'),
|
Toast: path.resolve(__dirname, '../js/src/toast.js'),
|
||||||
Tooltip: path.resolve(__dirname, '../js/src/tooltip.js'),
|
Tooltip: path.resolve(__dirname, '../js/src/tooltip.js')
|
||||||
Util: path.resolve(__dirname, '../js/src/util.js')
|
|
||||||
}
|
}
|
||||||
const rootPath = TEST ? '../js/coverage/dist/' : '../js/dist/'
|
const rootPath = TEST ? '../js/coverage/dist/' : '../js/dist/'
|
||||||
|
|
||||||
|
if (TEST) {
|
||||||
|
bsPlugins.Util = path.resolve(__dirname, '../js/src/util/index.js')
|
||||||
|
bsPlugins.Sanitizer = path.resolve(__dirname, '../js/src/util/sanitizer.js')
|
||||||
|
}
|
||||||
|
|
||||||
const defaultPluginConfig = {
|
const defaultPluginConfig = {
|
||||||
external: [
|
external: [
|
||||||
bsPlugins.Data,
|
bsPlugins.Data,
|
||||||
bsPlugins.EventHandler,
|
bsPlugins.EventHandler,
|
||||||
bsPlugins.SelectorEngine,
|
bsPlugins.SelectorEngine
|
||||||
bsPlugins.Util
|
|
||||||
],
|
],
|
||||||
globals: {
|
globals: {
|
||||||
[bsPlugins.Data]: 'Data',
|
[bsPlugins.Data]: 'Data',
|
||||||
[bsPlugins.EventHandler]: 'EventHandler',
|
[bsPlugins.EventHandler]: 'EventHandler',
|
||||||
[bsPlugins.SelectorEngine]: 'SelectorEngine',
|
[bsPlugins.SelectorEngine]: 'SelectorEngine'
|
||||||
[bsPlugins.Util]: 'Util'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +67,9 @@ function getConfigByPluginKey(pluginKey) {
|
|||||||
if (
|
if (
|
||||||
pluginKey === 'Data' ||
|
pluginKey === 'Data' ||
|
||||||
pluginKey === 'Manipulator' ||
|
pluginKey === 'Manipulator' ||
|
||||||
pluginKey === 'Util'
|
pluginKey === 'Polyfill' ||
|
||||||
|
pluginKey === 'Util' ||
|
||||||
|
pluginKey === 'Sanitizer'
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
external: [],
|
external: [],
|
||||||
@@ -76,21 +80,10 @@ function getConfigByPluginKey(pluginKey) {
|
|||||||
if (pluginKey === 'EventHandler' || pluginKey === 'SelectorEngine') {
|
if (pluginKey === 'EventHandler' || pluginKey === 'SelectorEngine') {
|
||||||
return {
|
return {
|
||||||
external: [
|
external: [
|
||||||
bsPlugins.Polyfill,
|
bsPlugins.Polyfill
|
||||||
bsPlugins.Util
|
|
||||||
],
|
],
|
||||||
globals: {
|
globals: {
|
||||||
[bsPlugins.Polyfill]: 'Polyfill',
|
[bsPlugins.Polyfill]: 'Polyfill'
|
||||||
[bsPlugins.Util]: 'Util'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pluginKey === 'Polyfill') {
|
|
||||||
return {
|
|
||||||
external: [bsPlugins.Util],
|
|
||||||
globals: {
|
|
||||||
[bsPlugins.Util]: 'Util'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,14 +118,12 @@ function getConfigByPluginKey(pluginKey) {
|
|||||||
external: [
|
external: [
|
||||||
bsPlugins.Data,
|
bsPlugins.Data,
|
||||||
bsPlugins.SelectorEngine,
|
bsPlugins.SelectorEngine,
|
||||||
bsPlugins.Tooltip,
|
bsPlugins.Tooltip
|
||||||
bsPlugins.Util
|
|
||||||
],
|
],
|
||||||
globals: {
|
globals: {
|
||||||
[bsPlugins.Data]: 'Data',
|
[bsPlugins.Data]: 'Data',
|
||||||
[bsPlugins.SelectorEngine]: 'SelectorEngine',
|
[bsPlugins.SelectorEngine]: 'SelectorEngine',
|
||||||
[bsPlugins.Tooltip]: 'Tooltip',
|
[bsPlugins.Tooltip]: 'Tooltip'
|
||||||
[bsPlugins.Util]: 'Util'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,14 +133,12 @@ function getConfigByPluginKey(pluginKey) {
|
|||||||
external: [
|
external: [
|
||||||
bsPlugins.Data,
|
bsPlugins.Data,
|
||||||
bsPlugins.EventHandler,
|
bsPlugins.EventHandler,
|
||||||
bsPlugins.Manipulator,
|
bsPlugins.Manipulator
|
||||||
bsPlugins.Util
|
|
||||||
],
|
],
|
||||||
globals: {
|
globals: {
|
||||||
[bsPlugins.Data]: 'Data',
|
[bsPlugins.Data]: 'Data',
|
||||||
[bsPlugins.EventHandler]: 'EventHandler',
|
[bsPlugins.EventHandler]: 'EventHandler',
|
||||||
[bsPlugins.Manipulator]: 'Manipulator',
|
[bsPlugins.Manipulator]: 'Manipulator'
|
||||||
[bsPlugins.Util]: 'Util'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,14 +150,28 @@ function build(plugin) {
|
|||||||
const config = getConfigByPluginKey(plugin)
|
const config = getConfigByPluginKey(plugin)
|
||||||
const external = config.external
|
const external = config.external
|
||||||
const globals = config.globals
|
const globals = config.globals
|
||||||
|
let pluginPath = rootPath
|
||||||
|
|
||||||
const pluginPath = [
|
const utilObjects = [
|
||||||
|
'Util',
|
||||||
|
'Sanitizer'
|
||||||
|
]
|
||||||
|
|
||||||
|
const domObjects = [
|
||||||
'Data',
|
'Data',
|
||||||
'EventHandler',
|
'EventHandler',
|
||||||
'Manipulator',
|
'Manipulator',
|
||||||
'Polyfill',
|
'Polyfill',
|
||||||
'SelectorEngine'
|
'SelectorEngine'
|
||||||
].includes(plugin) ? `${rootPath}/dom/` : rootPath
|
]
|
||||||
|
|
||||||
|
if (utilObjects.includes(plugin)) {
|
||||||
|
pluginPath = `${rootPath}/util/`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domObjects.includes(plugin)) {
|
||||||
|
pluginPath = `${rootPath}/dom/`
|
||||||
|
}
|
||||||
|
|
||||||
const pluginFilename = `${plugin.toLowerCase()}.js`
|
const pluginFilename = `${plugin.toLowerCase()}.js`
|
||||||
|
|
||||||
|
@@ -5,10 +5,16 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
TRANSITION_END,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
getSelectorFromElement,
|
||||||
|
getTransitionDurationFromElement
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -83,7 +89,7 @@ class Alert {
|
|||||||
// Private
|
// Private
|
||||||
|
|
||||||
_getRootElement(element) {
|
_getRootElement(element) {
|
||||||
const selector = Util.getSelectorFromElement(element)
|
const selector = getSelectorFromElement(element)
|
||||||
let parent = false
|
let parent = false
|
||||||
|
|
||||||
if (selector) {
|
if (selector) {
|
||||||
@@ -109,11 +115,11 @@ class Alert {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(element)
|
const transitionDuration = getTransitionDurationFromElement(element)
|
||||||
|
|
||||||
EventHandler
|
EventHandler
|
||||||
.one(element, Util.TRANSITION_END, (event) => this._destroyElement(element, event))
|
.one(element, TRANSITION_END, (event) => this._destroyElement(element, event))
|
||||||
Util.emulateTransitionEnd(element, transitionDuration)
|
emulateTransitionEnd(element, transitionDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
_destroyElement(element) {
|
_destroyElement(element) {
|
||||||
@@ -170,7 +176,6 @@ EventHandler
|
|||||||
* add .alert to jQuery only if jQuery is present
|
* add .alert to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Alert._jQueryInterface
|
$.fn[NAME] = Alert._jQueryInterface
|
||||||
|
@@ -5,10 +5,12 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -180,7 +182,6 @@ EventHandler.on(document, Event.BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, (eve
|
|||||||
* add .button to jQuery only if jQuery is present
|
* add .button to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Button._jQueryInterface
|
$.fn[NAME] = Button._jQueryInterface
|
||||||
|
@@ -5,11 +5,22 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
TRANSITION_END,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
getSelectorFromElement,
|
||||||
|
getTransitionDurationFromElement,
|
||||||
|
isVisible,
|
||||||
|
makeArray,
|
||||||
|
reflow,
|
||||||
|
triggerTransitionEnd,
|
||||||
|
typeCheckConfig
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import Manipulator from './dom/manipulator'
|
import Manipulator from './dom/manipulator'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -143,7 +154,7 @@ class Carousel {
|
|||||||
nextWhenVisible() {
|
nextWhenVisible() {
|
||||||
// Don't call next when the page isn't visible
|
// Don't call next when the page isn't visible
|
||||||
// or the carousel or its parent isn't visible
|
// or the carousel or its parent isn't visible
|
||||||
if (!document.hidden && Util.isVisible(this._element)) {
|
if (!document.hidden && isVisible(this._element)) {
|
||||||
this.next()
|
this.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +171,7 @@ class Carousel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (SelectorEngine.findOne(Selector.NEXT_PREV, this._element)) {
|
if (SelectorEngine.findOne(Selector.NEXT_PREV, this._element)) {
|
||||||
Util.triggerTransitionEnd(this._element)
|
triggerTransitionEnd(this._element)
|
||||||
this.cycle(true)
|
this.cycle(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,7 +244,7 @@ class Carousel {
|
|||||||
...Default,
|
...Default,
|
||||||
...config
|
...config
|
||||||
}
|
}
|
||||||
Util.typeCheckConfig(NAME, config, DefaultType)
|
typeCheckConfig(NAME, config, DefaultType)
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +331,7 @@ class Carousel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.makeArray(SelectorEngine.find(Selector.ITEM_IMG, this._element)).forEach((itemImg) => {
|
makeArray(SelectorEngine.find(Selector.ITEM_IMG, this._element)).forEach((itemImg) => {
|
||||||
EventHandler.on(itemImg, Event.DRAG_START, (e) => e.preventDefault())
|
EventHandler.on(itemImg, Event.DRAG_START, (e) => e.preventDefault())
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -356,7 +367,7 @@ class Carousel {
|
|||||||
|
|
||||||
_getItemIndex(element) {
|
_getItemIndex(element) {
|
||||||
this._items = element && element.parentNode
|
this._items = element && element.parentNode
|
||||||
? Util.makeArray(SelectorEngine.find(Selector.ITEM, element.parentNode))
|
? makeArray(SelectorEngine.find(Selector.ITEM, element.parentNode))
|
||||||
: []
|
: []
|
||||||
|
|
||||||
return this._items.indexOf(element)
|
return this._items.indexOf(element)
|
||||||
@@ -459,7 +470,7 @@ class Carousel {
|
|||||||
if (this._element.classList.contains(ClassName.SLIDE)) {
|
if (this._element.classList.contains(ClassName.SLIDE)) {
|
||||||
nextElement.classList.add(orderClassName)
|
nextElement.classList.add(orderClassName)
|
||||||
|
|
||||||
Util.reflow(nextElement)
|
reflow(nextElement)
|
||||||
|
|
||||||
activeElement.classList.add(directionalClassName)
|
activeElement.classList.add(directionalClassName)
|
||||||
nextElement.classList.add(directionalClassName)
|
nextElement.classList.add(directionalClassName)
|
||||||
@@ -472,10 +483,10 @@ class Carousel {
|
|||||||
this._config.interval = this._config.defaultInterval || this._config.interval
|
this._config.interval = this._config.defaultInterval || this._config.interval
|
||||||
}
|
}
|
||||||
|
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(activeElement)
|
const transitionDuration = getTransitionDurationFromElement(activeElement)
|
||||||
|
|
||||||
EventHandler
|
EventHandler
|
||||||
.one(activeElement, Util.TRANSITION_END, () => {
|
.one(activeElement, TRANSITION_END, () => {
|
||||||
nextElement.classList.remove(directionalClassName)
|
nextElement.classList.remove(directionalClassName)
|
||||||
nextElement.classList.remove(orderClassName)
|
nextElement.classList.remove(orderClassName)
|
||||||
nextElement.classList.add(ClassName.ACTIVE)
|
nextElement.classList.add(ClassName.ACTIVE)
|
||||||
@@ -496,7 +507,7 @@ class Carousel {
|
|||||||
}, 0)
|
}, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
Util.emulateTransitionEnd(activeElement, transitionDuration)
|
emulateTransitionEnd(activeElement, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
activeElement.classList.remove(ClassName.ACTIVE)
|
activeElement.classList.remove(ClassName.ACTIVE)
|
||||||
nextElement.classList.add(ClassName.ACTIVE)
|
nextElement.classList.add(ClassName.ACTIVE)
|
||||||
@@ -557,7 +568,7 @@ class Carousel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static _dataApiClickHandler(event) {
|
static _dataApiClickHandler(event) {
|
||||||
const selector = Util.getSelectorFromElement(this)
|
const selector = getSelectorFromElement(this)
|
||||||
|
|
||||||
if (!selector) {
|
if (!selector) {
|
||||||
return
|
return
|
||||||
@@ -603,7 +614,7 @@ EventHandler
|
|||||||
.on(document, Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler)
|
.on(document, Event.CLICK_DATA_API, Selector.DATA_SLIDE, Carousel._dataApiClickHandler)
|
||||||
|
|
||||||
EventHandler.on(window, Event.LOAD_DATA_API, () => {
|
EventHandler.on(window, Event.LOAD_DATA_API, () => {
|
||||||
const carousels = Util.makeArray(SelectorEngine.find(Selector.DATA_RIDE))
|
const carousels = makeArray(SelectorEngine.find(Selector.DATA_RIDE))
|
||||||
for (let i = 0, len = carousels.length; i < len; i++) {
|
for (let i = 0, len = carousels.length; i < len; i++) {
|
||||||
Carousel._carouselInterface(carousels[i], Data.getData(carousels[i], DATA_KEY))
|
Carousel._carouselInterface(carousels[i], Data.getData(carousels[i], DATA_KEY))
|
||||||
}
|
}
|
||||||
@@ -616,7 +627,6 @@ EventHandler.on(window, Event.LOAD_DATA_API, () => {
|
|||||||
* add .carousel to jQuery only if jQuery is present
|
* add .carousel to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Carousel._jQueryInterface
|
$.fn[NAME] = Carousel._jQueryInterface
|
||||||
|
@@ -5,11 +5,21 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
TRANSITION_END,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
getSelectorFromElement,
|
||||||
|
getTransitionDurationFromElement,
|
||||||
|
isElement,
|
||||||
|
makeArray,
|
||||||
|
reflow,
|
||||||
|
typeCheckConfig
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import Manipulator from './dom/manipulator'
|
import Manipulator from './dom/manipulator'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -69,16 +79,16 @@ class Collapse {
|
|||||||
this._isTransitioning = false
|
this._isTransitioning = false
|
||||||
this._element = element
|
this._element = element
|
||||||
this._config = this._getConfig(config)
|
this._config = this._getConfig(config)
|
||||||
this._triggerArray = Util.makeArray(SelectorEngine.find(
|
this._triggerArray = makeArray(SelectorEngine.find(
|
||||||
`[data-toggle="collapse"][href="#${element.id}"],` +
|
`[data-toggle="collapse"][href="#${element.id}"],` +
|
||||||
`[data-toggle="collapse"][data-target="#${element.id}"]`
|
`[data-toggle="collapse"][data-target="#${element.id}"]`
|
||||||
))
|
))
|
||||||
|
|
||||||
const toggleList = Util.makeArray(SelectorEngine.find(Selector.DATA_TOGGLE))
|
const toggleList = makeArray(SelectorEngine.find(Selector.DATA_TOGGLE))
|
||||||
for (let i = 0, len = toggleList.length; i < len; i++) {
|
for (let i = 0, len = toggleList.length; i < len; i++) {
|
||||||
const elem = toggleList[i]
|
const elem = toggleList[i]
|
||||||
const selector = Util.getSelectorFromElement(elem)
|
const selector = getSelectorFromElement(elem)
|
||||||
const filterElement = Util.makeArray(SelectorEngine.find(selector))
|
const filterElement = makeArray(SelectorEngine.find(selector))
|
||||||
.filter((foundElem) => foundElem === element)
|
.filter((foundElem) => foundElem === element)
|
||||||
|
|
||||||
if (selector !== null && filterElement.length) {
|
if (selector !== null && filterElement.length) {
|
||||||
@@ -130,7 +140,7 @@ class Collapse {
|
|||||||
let activesData
|
let activesData
|
||||||
|
|
||||||
if (this._parent) {
|
if (this._parent) {
|
||||||
actives = Util.makeArray(SelectorEngine.find(Selector.ACTIVES, this._parent))
|
actives = makeArray(SelectorEngine.find(Selector.ACTIVES, this._parent))
|
||||||
.filter((elem) => {
|
.filter((elem) => {
|
||||||
if (typeof this._config.parent === 'string') {
|
if (typeof this._config.parent === 'string') {
|
||||||
return elem.getAttribute('data-parent') === this._config.parent
|
return elem.getAttribute('data-parent') === this._config.parent
|
||||||
@@ -201,11 +211,11 @@ class Collapse {
|
|||||||
|
|
||||||
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)
|
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)
|
||||||
const scrollSize = `scroll${capitalizedDimension}`
|
const scrollSize = `scroll${capitalizedDimension}`
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
|
const transitionDuration = getTransitionDurationFromElement(this._element)
|
||||||
|
|
||||||
EventHandler.one(this._element, Util.TRANSITION_END, complete)
|
EventHandler.one(this._element, TRANSITION_END, complete)
|
||||||
|
|
||||||
Util.emulateTransitionEnd(this._element, transitionDuration)
|
emulateTransitionEnd(this._element, transitionDuration)
|
||||||
this._element.style[dimension] = `${this._element[scrollSize]}px`
|
this._element.style[dimension] = `${this._element[scrollSize]}px`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,7 +234,7 @@ class Collapse {
|
|||||||
|
|
||||||
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`
|
this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`
|
||||||
|
|
||||||
Util.reflow(this._element)
|
reflow(this._element)
|
||||||
|
|
||||||
this._element.classList.add(ClassName.COLLAPSING)
|
this._element.classList.add(ClassName.COLLAPSING)
|
||||||
this._element.classList.remove(ClassName.COLLAPSE)
|
this._element.classList.remove(ClassName.COLLAPSE)
|
||||||
@@ -234,7 +244,7 @@ class Collapse {
|
|||||||
if (triggerArrayLength > 0) {
|
if (triggerArrayLength > 0) {
|
||||||
for (let i = 0; i < triggerArrayLength; i++) {
|
for (let i = 0; i < triggerArrayLength; i++) {
|
||||||
const trigger = this._triggerArray[i]
|
const trigger = this._triggerArray[i]
|
||||||
const selector = Util.getSelectorFromElement(trigger)
|
const selector = getSelectorFromElement(trigger)
|
||||||
|
|
||||||
if (selector !== null) {
|
if (selector !== null) {
|
||||||
const elem = SelectorEngine.findOne(selector)
|
const elem = SelectorEngine.findOne(selector)
|
||||||
@@ -257,10 +267,10 @@ class Collapse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._element.style[dimension] = ''
|
this._element.style[dimension] = ''
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
|
const transitionDuration = getTransitionDurationFromElement(this._element)
|
||||||
|
|
||||||
EventHandler.one(this._element, Util.TRANSITION_END, complete)
|
EventHandler.one(this._element, TRANSITION_END, complete)
|
||||||
Util.emulateTransitionEnd(this._element, transitionDuration)
|
emulateTransitionEnd(this._element, transitionDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
setTransitioning(isTransitioning) {
|
setTransitioning(isTransitioning) {
|
||||||
@@ -285,7 +295,7 @@ class Collapse {
|
|||||||
...config
|
...config
|
||||||
}
|
}
|
||||||
config.toggle = Boolean(config.toggle) // Coerce string values
|
config.toggle = Boolean(config.toggle) // Coerce string values
|
||||||
Util.typeCheckConfig(NAME, config, DefaultType)
|
typeCheckConfig(NAME, config, DefaultType)
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +307,7 @@ class Collapse {
|
|||||||
_getParent() {
|
_getParent() {
|
||||||
let parent
|
let parent
|
||||||
|
|
||||||
if (Util.isElement(this._config.parent)) {
|
if (isElement(this._config.parent)) {
|
||||||
parent = this._config.parent
|
parent = this._config.parent
|
||||||
|
|
||||||
// it's a jQuery object
|
// it's a jQuery object
|
||||||
@@ -311,7 +321,7 @@ class Collapse {
|
|||||||
const selector =
|
const selector =
|
||||||
`[data-toggle="collapse"][data-parent="${this._config.parent}"]`
|
`[data-toggle="collapse"][data-parent="${this._config.parent}"]`
|
||||||
|
|
||||||
Util.makeArray(SelectorEngine.find(selector, parent))
|
makeArray(SelectorEngine.find(selector, parent))
|
||||||
.forEach((element) => {
|
.forEach((element) => {
|
||||||
this._addAriaAndCollapsedClass(
|
this._addAriaAndCollapsedClass(
|
||||||
Collapse._getTargetFromElement(element),
|
Collapse._getTargetFromElement(element),
|
||||||
@@ -342,7 +352,7 @@ class Collapse {
|
|||||||
// Static
|
// Static
|
||||||
|
|
||||||
static _getTargetFromElement(element) {
|
static _getTargetFromElement(element) {
|
||||||
const selector = Util.getSelectorFromElement(element)
|
const selector = getSelectorFromElement(element)
|
||||||
return selector ? SelectorEngine.findOne(selector) : null
|
return selector ? SelectorEngine.findOne(selector) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,8 +404,8 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const triggerData = Manipulator.getDataAttributes(this)
|
const triggerData = Manipulator.getDataAttributes(this)
|
||||||
const selector = Util.getSelectorFromElement(this)
|
const selector = getSelectorFromElement(this)
|
||||||
const selectorElements = Util.makeArray(SelectorEngine.find(selector))
|
const selectorElements = makeArray(SelectorEngine.find(selector))
|
||||||
|
|
||||||
selectorElements.forEach((element) => {
|
selectorElements.forEach((element) => {
|
||||||
const data = Data.getData(element, DATA_KEY)
|
const data = Data.getData(element, DATA_KEY)
|
||||||
@@ -422,7 +432,6 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (
|
|||||||
* add .collapse to jQuery only if jQuery is present
|
* add .collapse to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Collapse._jQueryInterface
|
$.fn[NAME] = Collapse._jQueryInterface
|
||||||
|
@@ -5,8 +5,10 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $
|
||||||
|
} from '../util/index'
|
||||||
import Polyfill from './polyfill'
|
import Polyfill from './polyfill'
|
||||||
import Util from '../util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -248,7 +250,6 @@ const EventHandler = {
|
|||||||
const typeEvent = event.replace(stripNameRegex, '')
|
const typeEvent = event.replace(stripNameRegex, '')
|
||||||
const inNamespace = event !== typeEvent
|
const inNamespace = event !== typeEvent
|
||||||
const isNative = nativeEvents.indexOf(typeEvent) > -1
|
const isNative = nativeEvents.indexOf(typeEvent) > -1
|
||||||
const $ = Util.jQuery
|
|
||||||
|
|
||||||
let jQueryEvent
|
let jQueryEvent
|
||||||
let bubbles = true
|
let bubbles = true
|
||||||
|
@@ -5,7 +5,9 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Util from '../util'
|
import {
|
||||||
|
getUID
|
||||||
|
} from '../util/index'
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
const Polyfill = (() => {
|
const Polyfill = (() => {
|
||||||
@@ -48,7 +50,7 @@ const Polyfill = (() => {
|
|||||||
const hasId = Boolean(this.id)
|
const hasId = Boolean(this.id)
|
||||||
|
|
||||||
if (!hasId) {
|
if (!hasId) {
|
||||||
this.id = Util.getUID('scope')
|
this.id = getUID('scope')
|
||||||
}
|
}
|
||||||
|
|
||||||
let nodeList = null
|
let nodeList = null
|
||||||
|
@@ -6,7 +6,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Polyfill from './polyfill'
|
import Polyfill from './polyfill'
|
||||||
import Util from '../util'
|
import {
|
||||||
|
makeArray
|
||||||
|
} from '../util/index'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -44,7 +46,7 @@ const SelectorEngine = {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const children = Util.makeArray(element.children)
|
const children = makeArray(element.children)
|
||||||
|
|
||||||
return children.filter((child) => this.matches(child, selector))
|
return children.filter((child) => this.matches(child, selector))
|
||||||
},
|
},
|
||||||
|
@@ -5,12 +5,19 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
getSelectorFromElement,
|
||||||
|
isElement,
|
||||||
|
makeArray,
|
||||||
|
noop,
|
||||||
|
typeCheckConfig
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import Manipulator from './dom/manipulator'
|
import Manipulator from './dom/manipulator'
|
||||||
import Popper from 'popper.js'
|
import Popper from 'popper.js'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -159,7 +166,7 @@ class Dropdown {
|
|||||||
|
|
||||||
if (this._config.reference === 'parent') {
|
if (this._config.reference === 'parent') {
|
||||||
referenceElement = parent
|
referenceElement = parent
|
||||||
} else if (Util.isElement(this._config.reference)) {
|
} else if (isElement(this._config.reference)) {
|
||||||
referenceElement = this._config.reference
|
referenceElement = this._config.reference
|
||||||
|
|
||||||
// Check if it's jQuery element
|
// Check if it's jQuery element
|
||||||
@@ -182,9 +189,9 @@ class Dropdown {
|
|||||||
// only needed because of broken event delegation on iOS
|
// only needed because of broken event delegation on iOS
|
||||||
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
||||||
if ('ontouchstart' in document.documentElement &&
|
if ('ontouchstart' in document.documentElement &&
|
||||||
!Util.makeArray(SelectorEngine.closest(parent, Selector.NAVBAR_NAV)).length) {
|
!makeArray(SelectorEngine.closest(parent, Selector.NAVBAR_NAV)).length) {
|
||||||
Util.makeArray(document.body.children)
|
makeArray(document.body.children)
|
||||||
.forEach((elem) => EventHandler.on(elem, 'mouseover', null, Util.noop()))
|
.forEach((elem) => EventHandler.on(elem, 'mouseover', null, noop()))
|
||||||
}
|
}
|
||||||
|
|
||||||
this._element.focus()
|
this._element.focus()
|
||||||
@@ -272,7 +279,7 @@ class Dropdown {
|
|||||||
...config
|
...config
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.typeCheckConfig(
|
typeCheckConfig(
|
||||||
NAME,
|
NAME,
|
||||||
config,
|
config,
|
||||||
this.constructor.DefaultType
|
this.constructor.DefaultType
|
||||||
@@ -389,7 +396,7 @@ class Dropdown {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggles = Util.makeArray(SelectorEngine.find(Selector.DATA_TOGGLE))
|
const toggles = makeArray(SelectorEngine.find(Selector.DATA_TOGGLE))
|
||||||
for (let i = 0, len = toggles.length; i < len; i++) {
|
for (let i = 0, len = toggles.length; i < len; i++) {
|
||||||
const parent = Dropdown._getParentFromElement(toggles[i])
|
const parent = Dropdown._getParentFromElement(toggles[i])
|
||||||
const context = Data.getData(toggles[i], DATA_KEY)
|
const context = Data.getData(toggles[i], DATA_KEY)
|
||||||
@@ -425,8 +432,8 @@ class Dropdown {
|
|||||||
// If this is a touch-enabled device we remove the extra
|
// If this is a touch-enabled device we remove the extra
|
||||||
// empty mouseover listeners we added for iOS support
|
// empty mouseover listeners we added for iOS support
|
||||||
if ('ontouchstart' in document.documentElement) {
|
if ('ontouchstart' in document.documentElement) {
|
||||||
Util.makeArray(document.body.children)
|
makeArray(document.body.children)
|
||||||
.forEach((elem) => EventHandler.off(elem, 'mouseover', null, Util.noop()))
|
.forEach((elem) => EventHandler.off(elem, 'mouseover', null, noop()))
|
||||||
}
|
}
|
||||||
|
|
||||||
toggles[i].setAttribute('aria-expanded', 'false')
|
toggles[i].setAttribute('aria-expanded', 'false')
|
||||||
@@ -439,7 +446,7 @@ class Dropdown {
|
|||||||
|
|
||||||
static _getParentFromElement(element) {
|
static _getParentFromElement(element) {
|
||||||
let parent
|
let parent
|
||||||
const selector = Util.getSelectorFromElement(element)
|
const selector = getSelectorFromElement(element)
|
||||||
|
|
||||||
if (selector) {
|
if (selector) {
|
||||||
parent = SelectorEngine.findOne(selector)
|
parent = SelectorEngine.findOne(selector)
|
||||||
@@ -482,7 +489,7 @@ class Dropdown {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = Util.makeArray(SelectorEngine.find(Selector.VISIBLE_ITEMS, parent))
|
const items = makeArray(SelectorEngine.find(Selector.VISIBLE_ITEMS, parent))
|
||||||
|
|
||||||
if (!items.length) {
|
if (!items.length) {
|
||||||
return
|
return
|
||||||
@@ -535,7 +542,6 @@ EventHandler
|
|||||||
* add .dropdown to jQuery only if jQuery is present
|
* add .dropdown to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Dropdown._jQueryInterface
|
$.fn[NAME] = Dropdown._jQueryInterface
|
||||||
|
@@ -16,10 +16,8 @@ import ScrollSpy from './scrollspy'
|
|||||||
import Tab from './tab'
|
import Tab from './tab'
|
||||||
import Toast from './toast'
|
import Toast from './toast'
|
||||||
import Tooltip from './tooltip'
|
import Tooltip from './tooltip'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Util,
|
|
||||||
Alert,
|
Alert,
|
||||||
Button,
|
Button,
|
||||||
Carousel,
|
Carousel,
|
||||||
|
@@ -5,11 +5,21 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
TRANSITION_END,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
getSelectorFromElement,
|
||||||
|
getTransitionDurationFromElement,
|
||||||
|
isVisible,
|
||||||
|
makeArray,
|
||||||
|
reflow,
|
||||||
|
typeCheckConfig
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import Manipulator from './dom/manipulator'
|
import Manipulator from './dom/manipulator'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -184,10 +194,10 @@ class Modal {
|
|||||||
|
|
||||||
|
|
||||||
if (transition) {
|
if (transition) {
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
|
const transitionDuration = getTransitionDurationFromElement(this._element)
|
||||||
|
|
||||||
EventHandler.one(this._element, Util.TRANSITION_END, (event) => this._hideModal(event))
|
EventHandler.one(this._element, TRANSITION_END, (event) => this._hideModal(event))
|
||||||
Util.emulateTransitionEnd(this._element, transitionDuration)
|
emulateTransitionEnd(this._element, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
this._hideModal()
|
this._hideModal()
|
||||||
}
|
}
|
||||||
@@ -228,7 +238,7 @@ class Modal {
|
|||||||
...Default,
|
...Default,
|
||||||
...config
|
...config
|
||||||
}
|
}
|
||||||
Util.typeCheckConfig(NAME, config, DefaultType)
|
typeCheckConfig(NAME, config, DefaultType)
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +262,7 @@ class Modal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (transition) {
|
if (transition) {
|
||||||
Util.reflow(this._element)
|
reflow(this._element)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._element.classList.add(ClassName.SHOW)
|
this._element.classList.add(ClassName.SHOW)
|
||||||
@@ -272,10 +282,10 @@ class Modal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (transition) {
|
if (transition) {
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(this._dialog)
|
const transitionDuration = getTransitionDurationFromElement(this._dialog)
|
||||||
|
|
||||||
EventHandler.one(this._dialog, Util.TRANSITION_END, transitionComplete)
|
EventHandler.one(this._dialog, TRANSITION_END, transitionComplete)
|
||||||
Util.emulateTransitionEnd(this._dialog, transitionDuration)
|
emulateTransitionEnd(this._dialog, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
transitionComplete()
|
transitionComplete()
|
||||||
}
|
}
|
||||||
@@ -364,7 +374,7 @@ class Modal {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
Util.reflow(this._backdrop)
|
reflow(this._backdrop)
|
||||||
}
|
}
|
||||||
|
|
||||||
this._backdrop.classList.add(ClassName.SHOW)
|
this._backdrop.classList.add(ClassName.SHOW)
|
||||||
@@ -378,10 +388,10 @@ class Modal {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)
|
const backdropTransitionDuration = getTransitionDurationFromElement(this._backdrop)
|
||||||
|
|
||||||
EventHandler.one(this._backdrop, Util.TRANSITION_END, callback)
|
EventHandler.one(this._backdrop, TRANSITION_END, callback)
|
||||||
Util.emulateTransitionEnd(this._backdrop, backdropTransitionDuration)
|
emulateTransitionEnd(this._backdrop, backdropTransitionDuration)
|
||||||
} else if (!this._isShown && this._backdrop) {
|
} else if (!this._isShown && this._backdrop) {
|
||||||
this._backdrop.classList.remove(ClassName.SHOW)
|
this._backdrop.classList.remove(ClassName.SHOW)
|
||||||
|
|
||||||
@@ -393,9 +403,9 @@ class Modal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._element.classList.contains(ClassName.FADE)) {
|
if (this._element.classList.contains(ClassName.FADE)) {
|
||||||
const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)
|
const backdropTransitionDuration = getTransitionDurationFromElement(this._backdrop)
|
||||||
EventHandler.one(this._backdrop, Util.TRANSITION_END, callbackRemove)
|
EventHandler.one(this._backdrop, TRANSITION_END, callbackRemove)
|
||||||
Util.emulateTransitionEnd(this._backdrop, backdropTransitionDuration)
|
emulateTransitionEnd(this._backdrop, backdropTransitionDuration)
|
||||||
} else {
|
} else {
|
||||||
callbackRemove()
|
callbackRemove()
|
||||||
}
|
}
|
||||||
@@ -439,7 +449,7 @@ class Modal {
|
|||||||
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
|
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
|
||||||
|
|
||||||
// Adjust fixed content padding
|
// Adjust fixed content padding
|
||||||
Util.makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
|
makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
|
||||||
.forEach((element) => {
|
.forEach((element) => {
|
||||||
const actualPadding = element.style.paddingRight
|
const actualPadding = element.style.paddingRight
|
||||||
const calculatedPadding = window.getComputedStyle(element)['padding-right']
|
const calculatedPadding = window.getComputedStyle(element)['padding-right']
|
||||||
@@ -448,7 +458,7 @@ class Modal {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Adjust sticky content margin
|
// Adjust sticky content margin
|
||||||
Util.makeArray(SelectorEngine.find(Selector.STICKY_CONTENT))
|
makeArray(SelectorEngine.find(Selector.STICKY_CONTENT))
|
||||||
.forEach((element) => {
|
.forEach((element) => {
|
||||||
const actualMargin = element.style.marginRight
|
const actualMargin = element.style.marginRight
|
||||||
const calculatedMargin = window.getComputedStyle(element)['margin-right']
|
const calculatedMargin = window.getComputedStyle(element)['margin-right']
|
||||||
@@ -469,7 +479,7 @@ class Modal {
|
|||||||
|
|
||||||
_resetScrollbar() {
|
_resetScrollbar() {
|
||||||
// Restore fixed content padding
|
// Restore fixed content padding
|
||||||
Util.makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
|
makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
|
||||||
.forEach((element) => {
|
.forEach((element) => {
|
||||||
const padding = Manipulator.getDataAttribute(element, 'padding-right')
|
const padding = Manipulator.getDataAttribute(element, 'padding-right')
|
||||||
if (typeof padding !== 'undefined') {
|
if (typeof padding !== 'undefined') {
|
||||||
@@ -479,7 +489,7 @@ class Modal {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Restore sticky content and navbar-toggler margin
|
// Restore sticky content and navbar-toggler margin
|
||||||
Util.makeArray(SelectorEngine.find(`${Selector.STICKY_CONTENT}`))
|
makeArray(SelectorEngine.find(`${Selector.STICKY_CONTENT}`))
|
||||||
.forEach((element) => {
|
.forEach((element) => {
|
||||||
const margin = Manipulator.getDataAttribute(element, 'margin-right')
|
const margin = Manipulator.getDataAttribute(element, 'margin-right')
|
||||||
if (typeof margin !== 'undefined') {
|
if (typeof margin !== 'undefined') {
|
||||||
@@ -546,7 +556,7 @@ class Modal {
|
|||||||
|
|
||||||
EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
|
EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
|
||||||
let target
|
let target
|
||||||
const selector = Util.getSelectorFromElement(this)
|
const selector = getSelectorFromElement(this)
|
||||||
|
|
||||||
if (selector) {
|
if (selector) {
|
||||||
target = SelectorEngine.findOne(selector)
|
target = SelectorEngine.findOne(selector)
|
||||||
@@ -569,7 +579,7 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (
|
|||||||
}
|
}
|
||||||
|
|
||||||
EventHandler.one(target, Event.HIDDEN, () => {
|
EventHandler.one(target, Event.HIDDEN, () => {
|
||||||
if (Util.isVisible(this)) {
|
if (isVisible(this)) {
|
||||||
this.focus()
|
this.focus()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -589,7 +599,6 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (
|
|||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Modal._jQueryInterface
|
$.fn[NAME] = Modal._jQueryInterface
|
||||||
|
@@ -5,10 +5,12 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Tooltip from './tooltip'
|
import Tooltip from './tooltip'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -177,7 +179,6 @@ class Popover extends Tooltip {
|
|||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Popover._jQueryInterface
|
$.fn[NAME] = Popover._jQueryInterface
|
||||||
|
@@ -5,11 +5,17 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
getSelectorFromElement,
|
||||||
|
getUID,
|
||||||
|
makeArray,
|
||||||
|
typeCheckConfig
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import Manipulator from './dom/manipulator'
|
import Manipulator from './dom/manipulator'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -118,12 +124,12 @@ class ScrollSpy {
|
|||||||
|
|
||||||
this._scrollHeight = this._getScrollHeight()
|
this._scrollHeight = this._getScrollHeight()
|
||||||
|
|
||||||
const targets = Util.makeArray(SelectorEngine.find(this._selector))
|
const targets = makeArray(SelectorEngine.find(this._selector))
|
||||||
|
|
||||||
targets
|
targets
|
||||||
.map((element) => {
|
.map((element) => {
|
||||||
let target
|
let target
|
||||||
const targetSelector = Util.getSelectorFromElement(element)
|
const targetSelector = getSelectorFromElement(element)
|
||||||
|
|
||||||
if (targetSelector) {
|
if (targetSelector) {
|
||||||
target = SelectorEngine.findOne(targetSelector)
|
target = SelectorEngine.findOne(targetSelector)
|
||||||
@@ -174,13 +180,13 @@ class ScrollSpy {
|
|||||||
if (typeof config.target !== 'string') {
|
if (typeof config.target !== 'string') {
|
||||||
let id = config.target.id
|
let id = config.target.id
|
||||||
if (!id) {
|
if (!id) {
|
||||||
id = Util.getUID(NAME)
|
id = getUID(NAME)
|
||||||
config.target.id = id
|
config.target.id = id
|
||||||
}
|
}
|
||||||
config.target = `#${id}`
|
config.target = `#${id}`
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.typeCheckConfig(NAME, config, DefaultType)
|
typeCheckConfig(NAME, config, DefaultType)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
@@ -284,7 +290,7 @@ class ScrollSpy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_clear() {
|
_clear() {
|
||||||
Util.makeArray(SelectorEngine.find(this._selector))
|
makeArray(SelectorEngine.find(this._selector))
|
||||||
.filter((node) => node.classList.contains(ClassName.ACTIVE))
|
.filter((node) => node.classList.contains(ClassName.ACTIVE))
|
||||||
.forEach((node) => node.classList.remove(ClassName.ACTIVE))
|
.forEach((node) => node.classList.remove(ClassName.ACTIVE))
|
||||||
}
|
}
|
||||||
@@ -321,7 +327,7 @@ class ScrollSpy {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
EventHandler.on(window, Event.LOAD_DATA_API, () => {
|
EventHandler.on(window, Event.LOAD_DATA_API, () => {
|
||||||
Util.makeArray(SelectorEngine.find(Selector.DATA_SPY))
|
makeArray(SelectorEngine.find(Selector.DATA_SPY))
|
||||||
.forEach((spy) => new ScrollSpy(spy, Manipulator.getDataAttributes(spy)))
|
.forEach((spy) => new ScrollSpy(spy, Manipulator.getDataAttributes(spy)))
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -331,7 +337,6 @@ EventHandler.on(window, Event.LOAD_DATA_API, () => {
|
|||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = ScrollSpy._jQueryInterface
|
$.fn[NAME] = ScrollSpy._jQueryInterface
|
||||||
|
@@ -5,10 +5,18 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
TRANSITION_END,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
getSelectorFromElement,
|
||||||
|
getTransitionDurationFromElement,
|
||||||
|
makeArray,
|
||||||
|
reflow
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -80,11 +88,11 @@ class Tab {
|
|||||||
let target
|
let target
|
||||||
let previous
|
let previous
|
||||||
const listElement = SelectorEngine.closest(this._element, Selector.NAV_LIST_GROUP)
|
const listElement = SelectorEngine.closest(this._element, Selector.NAV_LIST_GROUP)
|
||||||
const selector = Util.getSelectorFromElement(this._element)
|
const selector = getSelectorFromElement(this._element)
|
||||||
|
|
||||||
if (listElement) {
|
if (listElement) {
|
||||||
const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector.ACTIVE_UL : Selector.ACTIVE
|
const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector.ACTIVE_UL : Selector.ACTIVE
|
||||||
previous = Util.makeArray(SelectorEngine.find(itemSelector, listElement))
|
previous = makeArray(SelectorEngine.find(itemSelector, listElement))
|
||||||
previous = previous[previous.length - 1]
|
previous = previous[previous.length - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,11 +161,11 @@ class Tab {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (active && isTransitioning) {
|
if (active && isTransitioning) {
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(active)
|
const transitionDuration = getTransitionDurationFromElement(active)
|
||||||
active.classList.remove(ClassName.SHOW)
|
active.classList.remove(ClassName.SHOW)
|
||||||
|
|
||||||
EventHandler.one(active, Util.TRANSITION_END, complete)
|
EventHandler.one(active, TRANSITION_END, complete)
|
||||||
Util.emulateTransitionEnd(active, transitionDuration)
|
emulateTransitionEnd(active, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
complete()
|
complete()
|
||||||
}
|
}
|
||||||
@@ -183,7 +191,7 @@ class Tab {
|
|||||||
element.setAttribute('aria-selected', true)
|
element.setAttribute('aria-selected', true)
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.reflow(element)
|
reflow(element)
|
||||||
|
|
||||||
if (element.classList.contains(ClassName.FADE)) {
|
if (element.classList.contains(ClassName.FADE)) {
|
||||||
element.classList.add(ClassName.SHOW)
|
element.classList.add(ClassName.SHOW)
|
||||||
@@ -193,7 +201,7 @@ class Tab {
|
|||||||
const dropdownElement = SelectorEngine.closest(element, Selector.DROPDOWN)
|
const dropdownElement = SelectorEngine.closest(element, Selector.DROPDOWN)
|
||||||
|
|
||||||
if (dropdownElement) {
|
if (dropdownElement) {
|
||||||
Util.makeArray(SelectorEngine.find(Selector.DROPDOWN_TOGGLE))
|
makeArray(SelectorEngine.find(Selector.DROPDOWN_TOGGLE))
|
||||||
.forEach((dropdown) => dropdown.classList.add(ClassName.ACTIVE))
|
.forEach((dropdown) => dropdown.classList.add(ClassName.ACTIVE))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,9 +250,9 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (
|
|||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
* jQuery
|
* jQuery
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
|
* add .tab to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Tab._jQueryInterface
|
$.fn[NAME] = Tab._jQueryInterface
|
||||||
|
@@ -5,10 +5,16 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
TRANSITION_END,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
getTransitionDurationFromElement,
|
||||||
|
typeCheckConfig
|
||||||
|
} from './util/index'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import Manipulator from './dom/manipulator'
|
import Manipulator from './dom/manipulator'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -104,10 +110,10 @@ class Toast {
|
|||||||
this._element.classList.remove(ClassName.HIDE)
|
this._element.classList.remove(ClassName.HIDE)
|
||||||
this._element.classList.add(ClassName.SHOWING)
|
this._element.classList.add(ClassName.SHOWING)
|
||||||
if (this._config.animation) {
|
if (this._config.animation) {
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
|
const transitionDuration = getTransitionDurationFromElement(this._element)
|
||||||
|
|
||||||
EventHandler.one(this._element, Util.TRANSITION_END, complete)
|
EventHandler.one(this._element, TRANSITION_END, complete)
|
||||||
Util.emulateTransitionEnd(this._element, transitionDuration)
|
emulateTransitionEnd(this._element, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
complete()
|
complete()
|
||||||
}
|
}
|
||||||
@@ -153,7 +159,7 @@ class Toast {
|
|||||||
...typeof config === 'object' && config ? config : {}
|
...typeof config === 'object' && config ? config : {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.typeCheckConfig(
|
typeCheckConfig(
|
||||||
NAME,
|
NAME,
|
||||||
config,
|
config,
|
||||||
this.constructor.DefaultType
|
this.constructor.DefaultType
|
||||||
@@ -179,10 +185,10 @@ class Toast {
|
|||||||
|
|
||||||
this._element.classList.remove(ClassName.SHOW)
|
this._element.classList.remove(ClassName.SHOW)
|
||||||
if (this._config.animation) {
|
if (this._config.animation) {
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(this._element)
|
const transitionDuration = getTransitionDurationFromElement(this._element)
|
||||||
|
|
||||||
EventHandler.one(this._element, Util.TRANSITION_END, complete)
|
EventHandler.one(this._element, TRANSITION_END, complete)
|
||||||
Util.emulateTransitionEnd(this._element, transitionDuration)
|
emulateTransitionEnd(this._element, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
complete()
|
complete()
|
||||||
}
|
}
|
||||||
@@ -221,7 +227,6 @@ class Toast {
|
|||||||
* add .toast to jQuery only if jQuery is present
|
* add .toast to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Toast._jQueryInterface
|
$.fn[NAME] = Toast._jQueryInterface
|
||||||
|
@@ -5,16 +5,27 @@
|
|||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
jQuery as $,
|
||||||
|
TRANSITION_END,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
findShadowRoot,
|
||||||
|
getTransitionDurationFromElement,
|
||||||
|
getUID,
|
||||||
|
isElement,
|
||||||
|
makeArray,
|
||||||
|
noop,
|
||||||
|
typeCheckConfig
|
||||||
|
} from './util/index'
|
||||||
import {
|
import {
|
||||||
DefaultWhitelist,
|
DefaultWhitelist,
|
||||||
sanitizeHtml
|
sanitizeHtml
|
||||||
} from './tools/sanitizer'
|
} from './util/sanitizer'
|
||||||
import Data from './dom/data'
|
import Data from './dom/data'
|
||||||
import EventHandler from './dom/eventHandler'
|
import EventHandler from './dom/eventHandler'
|
||||||
import Manipulator from './dom/manipulator'
|
import Manipulator from './dom/manipulator'
|
||||||
import Popper from 'popper.js'
|
import Popper from 'popper.js'
|
||||||
import SelectorEngine from './dom/selectorEngine'
|
import SelectorEngine from './dom/selectorEngine'
|
||||||
import Util from './util'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
@@ -257,7 +268,7 @@ class Tooltip {
|
|||||||
|
|
||||||
if (this.isWithContent() && this._isEnabled) {
|
if (this.isWithContent() && this._isEnabled) {
|
||||||
const showEvent = EventHandler.trigger(this.element, this.constructor.Event.SHOW)
|
const showEvent = EventHandler.trigger(this.element, this.constructor.Event.SHOW)
|
||||||
const shadowRoot = Util.findShadowRoot(this.element)
|
const shadowRoot = findShadowRoot(this.element)
|
||||||
const isInTheDom = shadowRoot !== null
|
const isInTheDom = shadowRoot !== null
|
||||||
? shadowRoot.contains(this.element)
|
? shadowRoot.contains(this.element)
|
||||||
: this.element.ownerDocument.documentElement.contains(this.element)
|
: this.element.ownerDocument.documentElement.contains(this.element)
|
||||||
@@ -267,7 +278,7 @@ class Tooltip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tip = this.getTipElement()
|
const tip = this.getTipElement()
|
||||||
const tipId = Util.getUID(this.constructor.NAME)
|
const tipId = getUID(this.constructor.NAME)
|
||||||
|
|
||||||
tip.setAttribute('id', tipId)
|
tip.setAttribute('id', tipId)
|
||||||
this.element.setAttribute('aria-describedby', tipId)
|
this.element.setAttribute('aria-describedby', tipId)
|
||||||
@@ -323,8 +334,8 @@ class Tooltip {
|
|||||||
// only needed because of broken event delegation on iOS
|
// only needed because of broken event delegation on iOS
|
||||||
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
|
||||||
if ('ontouchstart' in document.documentElement) {
|
if ('ontouchstart' in document.documentElement) {
|
||||||
Util.makeArray(document.body.children).forEach((element) => {
|
makeArray(document.body.children).forEach((element) => {
|
||||||
EventHandler.on(element, 'mouseover', Util.noop())
|
EventHandler.on(element, 'mouseover', noop())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,9 +354,9 @@ class Tooltip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.tip.classList.contains(ClassName.FADE)) {
|
if (this.tip.classList.contains(ClassName.FADE)) {
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(this.tip)
|
const transitionDuration = getTransitionDurationFromElement(this.tip)
|
||||||
EventHandler.one(this.tip, Util.TRANSITION_END, complete)
|
EventHandler.one(this.tip, TRANSITION_END, complete)
|
||||||
Util.emulateTransitionEnd(this.tip, transitionDuration)
|
emulateTransitionEnd(this.tip, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
complete()
|
complete()
|
||||||
}
|
}
|
||||||
@@ -381,8 +392,8 @@ class Tooltip {
|
|||||||
// If this is a touch-enabled device we remove the extra
|
// If this is a touch-enabled device we remove the extra
|
||||||
// empty mouseover listeners we added for iOS support
|
// empty mouseover listeners we added for iOS support
|
||||||
if ('ontouchstart' in document.documentElement) {
|
if ('ontouchstart' in document.documentElement) {
|
||||||
Util.makeArray(document.body.children)
|
makeArray(document.body.children)
|
||||||
.forEach((element) => EventHandler.off(element, 'mouseover', Util.noop))
|
.forEach((element) => EventHandler.off(element, 'mouseover', noop))
|
||||||
}
|
}
|
||||||
|
|
||||||
this._activeTrigger[Trigger.CLICK] = false
|
this._activeTrigger[Trigger.CLICK] = false
|
||||||
@@ -390,9 +401,10 @@ class Tooltip {
|
|||||||
this._activeTrigger[Trigger.HOVER] = false
|
this._activeTrigger[Trigger.HOVER] = false
|
||||||
|
|
||||||
if (this.tip.classList.contains(ClassName.FADE)) {
|
if (this.tip.classList.contains(ClassName.FADE)) {
|
||||||
const transitionDuration = Util.getTransitionDurationFromElement(tip)
|
const transitionDuration = getTransitionDurationFromElement(tip)
|
||||||
EventHandler.one(tip, Util.TRANSITION_END, complete)
|
|
||||||
Util.emulateTransitionEnd(tip, transitionDuration)
|
EventHandler.one(tip, TRANSITION_END, complete)
|
||||||
|
emulateTransitionEnd(tip, transitionDuration)
|
||||||
} else {
|
} else {
|
||||||
complete()
|
complete()
|
||||||
}
|
}
|
||||||
@@ -507,7 +519,7 @@ class Tooltip {
|
|||||||
return document.body
|
return document.body
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Util.isElement(this.config.container)) {
|
if (isElement(this.config.container)) {
|
||||||
return this.config.container
|
return this.config.container
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,7 +717,7 @@ class Tooltip {
|
|||||||
config.content = config.content.toString()
|
config.content = config.content.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
Util.typeCheckConfig(
|
typeCheckConfig(
|
||||||
NAME,
|
NAME,
|
||||||
config,
|
config,
|
||||||
this.constructor.DefaultType
|
this.constructor.DefaultType
|
||||||
@@ -795,8 +807,9 @@ class Tooltip {
|
|||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
* jQuery
|
* jQuery
|
||||||
* ------------------------------------------------------------------------
|
* ------------------------------------------------------------------------
|
||||||
|
* add .tooltip to jQuery only if jQuery is present
|
||||||
*/
|
*/
|
||||||
const $ = Util.jQuery
|
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
const JQUERY_NO_CONFLICT = $.fn[NAME]
|
||||||
$.fn[NAME] = Tooltip._jQueryInterface
|
$.fn[NAME] = Tooltip._jQueryInterface
|
||||||
|
179
js/src/util.js
179
js/src/util.js
@@ -1,179 +0,0 @@
|
|||||||
/**
|
|
||||||
* --------------------------------------------------------------------------
|
|
||||||
* Bootstrap (v4.3.1): util.js
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* --------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ------------------------------------------------------------------------
|
|
||||||
* Private TransitionEnd Helpers
|
|
||||||
* ------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* --------------------------------------------------------------------------
|
|
||||||
* Public Util Api
|
|
||||||
* --------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
const Util = {
|
|
||||||
TRANSITION_END: 'transitionend',
|
|
||||||
|
|
||||||
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
|
|
||||||
},
|
|
||||||
|
|
||||||
getSelectorFromElement(element) {
|
|
||||||
let selector = element.getAttribute('data-target')
|
|
||||||
|
|
||||||
if (!selector || selector === '#') {
|
|
||||||
const hrefAttr = element.getAttribute('href')
|
|
||||||
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return document.querySelector(selector) ? selector : null
|
|
||||||
} catch (err) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getTransitionDurationFromElement(element) {
|
|
||||||
if (!element) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get transition-duration of the element
|
|
||||||
let transitionDuration = window.getComputedStyle(element).transitionDuration
|
|
||||||
let transitionDelay = window.getComputedStyle(element).transitionDelay
|
|
||||||
|
|
||||||
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
|
|
||||||
},
|
|
||||||
|
|
||||||
reflow(element) {
|
|
||||||
return element.offsetHeight
|
|
||||||
},
|
|
||||||
|
|
||||||
triggerTransitionEnd(element) {
|
|
||||||
element.dispatchEvent(new Event(Util.TRANSITION_END))
|
|
||||||
},
|
|
||||||
|
|
||||||
isElement(obj) {
|
|
||||||
return (obj[0] || obj).nodeType
|
|
||||||
},
|
|
||||||
|
|
||||||
emulateTransitionEnd(element, duration) {
|
|
||||||
let called = false
|
|
||||||
const durationPadding = 5
|
|
||||||
const emulatedDuration = duration + durationPadding
|
|
||||||
function listener() {
|
|
||||||
called = true
|
|
||||||
element.removeEventListener(Util.TRANSITION_END, listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
element.addEventListener(Util.TRANSITION_END, listener)
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!called) {
|
|
||||||
Util.triggerTransitionEnd(element)
|
|
||||||
}
|
|
||||||
}, emulatedDuration)
|
|
||||||
},
|
|
||||||
|
|
||||||
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}".`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
makeArray(nodeList) {
|
|
||||||
if (!nodeList) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return [].slice.call(nodeList)
|
|
||||||
},
|
|
||||||
|
|
||||||
isVisible(element) {
|
|
||||||
if (!element) {
|
|
||||||
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
|
|
||||||
},
|
|
||||||
|
|
||||||
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)
|
|
||||||
},
|
|
||||||
|
|
||||||
noop() {
|
|
||||||
// eslint-disable-next-line no-empty-function
|
|
||||||
return function () {}
|
|
||||||
},
|
|
||||||
|
|
||||||
get jQuery() {
|
|
||||||
return window.jQuery
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Util
|
|
177
js/src/util/index.js
Normal file
177
js/src/util/index.js
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* 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'
|
||||||
|
const jQuery = window.jQuery
|
||||||
|
|
||||||
|
// Shoutout AngusCroll (https://goo.gl/pxwQGp)
|
||||||
|
const toType = (obj) => ({}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
* Public Util Api
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
const 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
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelectorFromElement = (element) => {
|
||||||
|
let selector = element.getAttribute('data-target')
|
||||||
|
|
||||||
|
if (!selector || selector === '#') {
|
||||||
|
const hrefAttr = element.getAttribute('href')
|
||||||
|
|
||||||
|
selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return document.querySelector(selector) ? selector : null
|
||||||
|
} catch (err) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTransitionDurationFromElement = (element) => {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
const triggerTransitionEnd = (element) => {
|
||||||
|
element.dispatchEvent(new Event(TRANSITION_END))
|
||||||
|
}
|
||||||
|
|
||||||
|
const isElement = (obj) => (obj[0] || obj).nodeType
|
||||||
|
|
||||||
|
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)
|
||||||
|
.forEach((property) => {
|
||||||
|
const expectedTypes = configTypes[property]
|
||||||
|
const value = config[property]
|
||||||
|
const valueType = value && 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}".`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeArray = (nodeList) => {
|
||||||
|
if (!nodeList) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return [].slice.call(nodeList)
|
||||||
|
}
|
||||||
|
|
||||||
|
const isVisible = (element) => {
|
||||||
|
if (!element) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.style && element.parentNode && element.parentNode.style) {
|
||||||
|
return element.style.display !== 'none' &&
|
||||||
|
element.parentNode.style.display !== 'none' &&
|
||||||
|
element.style.visibility !== 'hidden'
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const 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 findShadowRoot(element.parentNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-empty-function
|
||||||
|
const noop = () => function () {}
|
||||||
|
|
||||||
|
const reflow = (element) => element.offsetHeight
|
||||||
|
|
||||||
|
export {
|
||||||
|
jQuery,
|
||||||
|
TRANSITION_END,
|
||||||
|
getUID,
|
||||||
|
getSelectorFromElement,
|
||||||
|
getTransitionDurationFromElement,
|
||||||
|
triggerTransitionEnd,
|
||||||
|
isElement,
|
||||||
|
emulateTransitionEnd,
|
||||||
|
typeCheckConfig,
|
||||||
|
makeArray,
|
||||||
|
isVisible,
|
||||||
|
findShadowRoot,
|
||||||
|
noop,
|
||||||
|
reflow
|
||||||
|
}
|
@@ -1,11 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
* Bootstrap (v4.3.1): tools/sanitizer.js
|
* Bootstrap (v4.3.1): util/sanitizer.js
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Util from '../util'
|
import {
|
||||||
|
makeArray
|
||||||
|
} from './index'
|
||||||
|
|
||||||
const uriAttrs = [
|
const uriAttrs = [
|
||||||
'background',
|
'background',
|
||||||
@@ -20,6 +22,43 @@ const uriAttrs = [
|
|||||||
|
|
||||||
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
|
const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pattern that recognizes a commonly useful subset of URLs that are safe.
|
||||||
|
*
|
||||||
|
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
||||||
|
*/
|
||||||
|
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A pattern that matches safe data URLs. Only matches image, video and audio types.
|
||||||
|
*
|
||||||
|
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
||||||
|
*/
|
||||||
|
const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
|
||||||
|
|
||||||
|
const allowedAttribute = (attr, allowedAttributeList) => {
|
||||||
|
const attrName = attr.nodeName.toLowerCase()
|
||||||
|
|
||||||
|
if (allowedAttributeList.indexOf(attrName) !== -1) {
|
||||||
|
if (uriAttrs.indexOf(attrName) !== -1) {
|
||||||
|
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const regExp = allowedAttributeList.filter((attrRegex) => attrRegex instanceof RegExp)
|
||||||
|
|
||||||
|
// Check if a regular expression validates the attribute.
|
||||||
|
for (let i = 0, l = regExp.length; i < l; i++) {
|
||||||
|
if (attrName.match(regExp[i])) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
export const DefaultWhitelist = {
|
export const DefaultWhitelist = {
|
||||||
// Global attributes allowed on any supplied element below.
|
// Global attributes allowed on any supplied element below.
|
||||||
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
|
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
|
||||||
@@ -54,45 +93,8 @@ export const DefaultWhitelist = {
|
|||||||
ul: []
|
ul: []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A pattern that recognizes a commonly useful subset of URLs that are safe.
|
|
||||||
*
|
|
||||||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
|
||||||
*/
|
|
||||||
const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A pattern that matches safe data URLs. Only matches image, video and audio types.
|
|
||||||
*
|
|
||||||
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
|
|
||||||
*/
|
|
||||||
const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
|
|
||||||
|
|
||||||
function allowedAttribute(attr, allowedAttributeList) {
|
|
||||||
const attrName = attr.nodeName.toLowerCase()
|
|
||||||
|
|
||||||
if (allowedAttributeList.indexOf(attrName) !== -1) {
|
|
||||||
if (uriAttrs.indexOf(attrName) !== -1) {
|
|
||||||
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const regExp = allowedAttributeList.filter((attrRegex) => attrRegex instanceof RegExp)
|
|
||||||
|
|
||||||
// Check if a regular expression validates the attribute.
|
|
||||||
for (let i = 0, l = regExp.length; i < l; i++) {
|
|
||||||
if (attrName.match(regExp[i])) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
|
export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
|
||||||
if (unsafeHtml.length === 0) {
|
if (!unsafeHtml.length) {
|
||||||
return unsafeHtml
|
return unsafeHtml
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,19 +105,19 @@ export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
|
|||||||
const domParser = new window.DOMParser()
|
const domParser = new window.DOMParser()
|
||||||
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
|
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
|
||||||
const whitelistKeys = Object.keys(whiteList)
|
const whitelistKeys = Object.keys(whiteList)
|
||||||
const elements = Util.makeArray(createdDocument.body.querySelectorAll('*'))
|
const elements = makeArray(createdDocument.body.querySelectorAll('*'))
|
||||||
|
|
||||||
for (let i = 0, len = elements.length; i < len; i++) {
|
for (let i = 0, len = elements.length; i < len; i++) {
|
||||||
const el = elements[i]
|
const el = elements[i]
|
||||||
const elName = el.nodeName.toLowerCase()
|
const elName = el.nodeName.toLowerCase()
|
||||||
|
|
||||||
if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {
|
if (whitelistKeys.indexOf(elName) === -1) {
|
||||||
el.parentNode.removeChild(el)
|
el.parentNode.removeChild(el)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const attributeList = Util.makeArray(el.attributes)
|
const attributeList = makeArray(el.attributes)
|
||||||
const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
|
const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
|
||||||
|
|
||||||
attributeList.forEach((attr) => {
|
attributeList.forEach((attr) => {
|
@@ -1,142 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
<title>Bootstrap Plugin Test Suite</title>
|
|
||||||
|
|
||||||
<!-- jQuery -->
|
|
||||||
<script src="../../node_modules/jquery/dist/jquery.slim.min.js"></script>
|
|
||||||
<script src="../../node_modules/popper.js/dist/umd/popper.min.js"></script>
|
|
||||||
|
|
||||||
<!-- QUnit -->
|
|
||||||
<link rel="stylesheet" href="../../node_modules/qunit/qunit/qunit.css" media="screen">
|
|
||||||
<script src="../../node_modules/qunit/qunit/qunit.js"></script>
|
|
||||||
|
|
||||||
<!-- Sinon -->
|
|
||||||
<script src="../../node_modules/sinon/pkg/sinon-no-sourcemaps.js"></script>
|
|
||||||
|
|
||||||
<!-- Hammer simulator -->
|
|
||||||
<script src="../../node_modules/hammer-simulator/index.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Disable jQuery event aliases to ensure we don't accidentally use any of them
|
|
||||||
[
|
|
||||||
'blur',
|
|
||||||
'focus',
|
|
||||||
'focusin',
|
|
||||||
'focusout',
|
|
||||||
'resize',
|
|
||||||
'scroll',
|
|
||||||
'click',
|
|
||||||
'dblclick',
|
|
||||||
'mousedown',
|
|
||||||
'mouseup',
|
|
||||||
'mousemove',
|
|
||||||
'mouseover',
|
|
||||||
'mouseout',
|
|
||||||
'mouseenter',
|
|
||||||
'mouseleave',
|
|
||||||
'change',
|
|
||||||
'select',
|
|
||||||
'submit',
|
|
||||||
'keydown',
|
|
||||||
'keypress',
|
|
||||||
'keyup',
|
|
||||||
'contextmenu'
|
|
||||||
].forEach(function(eventAlias) {
|
|
||||||
$.fn[eventAlias] = function() {
|
|
||||||
throw new Error('Using the ".' + eventAlias + '()" method is not allowed, so that Bootstrap can be compatible with custom jQuery builds which exclude the "event aliases" module that defines said method. See https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#js')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Require assert.expect in each test
|
|
||||||
QUnit.config.requireExpects = true
|
|
||||||
|
|
||||||
// See https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit
|
|
||||||
var log = []
|
|
||||||
var testName
|
|
||||||
|
|
||||||
QUnit.done(function(testResults) {
|
|
||||||
var tests = []
|
|
||||||
for (var i = 0; i < log.length; i++) {
|
|
||||||
var details = log[i]
|
|
||||||
tests.push({
|
|
||||||
name: details.name,
|
|
||||||
result: details.result,
|
|
||||||
expected: details.expected,
|
|
||||||
actual: details.actual,
|
|
||||||
source: details.source
|
|
||||||
})
|
|
||||||
}
|
|
||||||
testResults.tests = tests
|
|
||||||
|
|
||||||
window.global_test_results = testResults
|
|
||||||
})
|
|
||||||
|
|
||||||
QUnit.testStart(function(testDetails) {
|
|
||||||
QUnit.log(function(details) {
|
|
||||||
if (!details.result) {
|
|
||||||
details.name = testDetails.name
|
|
||||||
log.push(details)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Display fixture on-screen on iOS to avoid false positives
|
|
||||||
// See https://github.com/twbs/bootstrap/pull/15955
|
|
||||||
if (/iPhone|iPad|iPod/.test(navigator.userAgent)) {
|
|
||||||
QUnit.begin(function() {
|
|
||||||
$('#qunit-fixture').css({ top: 0, left: 0 })
|
|
||||||
})
|
|
||||||
|
|
||||||
QUnit.done(function() {
|
|
||||||
$('#qunit-fixture').css({ top: '', left: '' })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Transpiled Plugins -->
|
|
||||||
<script src="../dist/util.js"></script>
|
|
||||||
<script src="../dist/dom/polyfill.js"></script>
|
|
||||||
<script src="../dist/dom/manipulator.js"></script>
|
|
||||||
<script src="../dist/dom/eventHandler.js"></script>
|
|
||||||
<script src="../dist/dom/selectorEngine.js"></script>
|
|
||||||
<script src="../dist/dom/data.js"></script>
|
|
||||||
<script src="../dist/alert.js"></script>
|
|
||||||
<script src="../dist/button.js"></script>
|
|
||||||
<script src="../dist/carousel.js"></script>
|
|
||||||
<script src="../dist/collapse.js"></script>
|
|
||||||
<script src="../dist/dropdown.js"></script>
|
|
||||||
<script src="../dist/modal.js"></script>
|
|
||||||
<script src="../dist/scrollspy.js"></script>
|
|
||||||
<script src="../dist/tab.js"></script>
|
|
||||||
<script src="../dist/tooltip.js"></script>
|
|
||||||
<script src="../dist/popover.js"></script>
|
|
||||||
<script src="../dist/toast.js"></script>
|
|
||||||
|
|
||||||
<!-- Unit Tests -->
|
|
||||||
<script src="unit/dom/eventHandler.js"></script>
|
|
||||||
<script src="unit/dom/manipulator.js"></script>
|
|
||||||
<script src="unit/dom/data.js"></script>
|
|
||||||
<script src="unit/dom/selectorEngine.js"></script>
|
|
||||||
<script src="unit/alert.js"></script>
|
|
||||||
<script src="unit/button.js"></script>
|
|
||||||
<script src="unit/carousel.js"></script>
|
|
||||||
<script src="unit/collapse.js"></script>
|
|
||||||
<script src="unit/dropdown.js"></script>
|
|
||||||
<script src="unit/modal.js"></script>
|
|
||||||
<script src="unit/scrollspy.js"></script>
|
|
||||||
<script src="unit/tab.js"></script>
|
|
||||||
<script src="unit/tooltip.js"></script>
|
|
||||||
<script src="unit/popover.js"></script>
|
|
||||||
<script src="unit/util.js"></script>
|
|
||||||
<script src="unit/toast.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="qunit-container">
|
|
||||||
<div id="qunit"></div>
|
|
||||||
<div id="qunit-fixture"></div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@@ -2,8 +2,6 @@ import 'popper.js'
|
|||||||
import bootstrap from '../../../dist/js/bootstrap'
|
import bootstrap from '../../../dist/js/bootstrap'
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
document.getElementById('resultUID').innerHTML = bootstrap.Util.getUID('bs')
|
Array.from(document.querySelectorAll('[data-toggle="tooltip"]'))
|
||||||
|
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('[data-toggle="tooltip"]'))
|
|
||||||
.map((tooltipNode) => new bootstrap.Tooltip(tooltipNode))
|
.map((tooltipNode) => new bootstrap.Tooltip(tooltipNode))
|
||||||
})
|
})
|
||||||
|
@@ -13,11 +13,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Hello, world!</h1>
|
<h1>Hello, world!</h1>
|
||||||
<div class="col-12">
|
<div class="col-12 mt-5">
|
||||||
<div class="mt-5 mb-3">
|
|
||||||
<span>Util.getUID: </span>
|
|
||||||
<span id="resultUID"></span>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-secondary" data-toggle="tooltip" data-placement="top" title="Tooltip on top">
|
<button type="button" class="btn btn-secondary" data-toggle="tooltip" data-placement="top" title="Tooltip on top">
|
||||||
Tooltip on top
|
Tooltip on top
|
||||||
</button>
|
</button>
|
||||||
|
@@ -11,6 +11,7 @@ const {
|
|||||||
const jqueryFile = process.env.USE_OLD_JQUERY ? 'https://code.jquery.com/jquery-1.9.1.min.js' : 'node_modules/jquery/dist/jquery.slim.min.js'
|
const jqueryFile = process.env.USE_OLD_JQUERY ? 'https://code.jquery.com/jquery-1.9.1.min.js' : 'node_modules/jquery/dist/jquery.slim.min.js'
|
||||||
const bundle = process.env.BUNDLE === 'true'
|
const bundle = process.env.BUNDLE === 'true'
|
||||||
const browserStack = process.env.BROWSER === 'true'
|
const browserStack = process.env.BROWSER === 'true'
|
||||||
|
const debug = process.env.DEBUG === 'true'
|
||||||
|
|
||||||
const frameworks = [
|
const frameworks = [
|
||||||
'qunit',
|
'qunit',
|
||||||
@@ -28,11 +29,11 @@ const detectBrowsers = {
|
|||||||
usePhantomJS: false,
|
usePhantomJS: false,
|
||||||
postDetection(availableBrowser) {
|
postDetection(availableBrowser) {
|
||||||
if (typeof process.env.TRAVIS_JOB_ID !== 'undefined' || availableBrowser.includes('Chrome')) {
|
if (typeof process.env.TRAVIS_JOB_ID !== 'undefined' || availableBrowser.includes('Chrome')) {
|
||||||
return ['ChromeHeadless']
|
return debug ? ['Chrome'] : ['ChromeHeadless']
|
||||||
}
|
}
|
||||||
|
|
||||||
if (availableBrowser.includes('Firefox')) {
|
if (availableBrowser.includes('Firefox')) {
|
||||||
return ['FirefoxHeadless']
|
return debug ? ['Firefox'] : ['FirefoxHeadless']
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Please install Firefox or Chrome')
|
throw new Error('Please install Firefox or Chrome')
|
||||||
@@ -76,7 +77,8 @@ if (bundle) {
|
|||||||
conf.detectBrowsers = detectBrowsers
|
conf.detectBrowsers = detectBrowsers
|
||||||
files = files.concat([
|
files = files.concat([
|
||||||
jqueryFile,
|
jqueryFile,
|
||||||
'dist/js/bootstrap.js'
|
'dist/js/bootstrap.js',
|
||||||
|
'js/tests/unit/*.js'
|
||||||
])
|
])
|
||||||
} else if (browserStack) {
|
} else if (browserStack) {
|
||||||
conf.hostname = ip.address()
|
conf.hostname = ip.address()
|
||||||
@@ -93,7 +95,8 @@ if (bundle) {
|
|||||||
reporters.push('BrowserStack')
|
reporters.push('BrowserStack')
|
||||||
files = files.concat([
|
files = files.concat([
|
||||||
'node_modules/jquery/dist/jquery.slim.min.js',
|
'node_modules/jquery/dist/jquery.slim.min.js',
|
||||||
'js/coverage/dist/util.js',
|
'js/coverage/dist/util/util.js',
|
||||||
|
'js/coverage/dist/util/sanitizer.js',
|
||||||
'js/coverage/dist/dom/polyfill.js',
|
'js/coverage/dist/dom/polyfill.js',
|
||||||
'js/coverage/dist/dom/eventHandler.js',
|
'js/coverage/dist/dom/eventHandler.js',
|
||||||
'js/coverage/dist/dom/selectorEngine.js',
|
'js/coverage/dist/dom/selectorEngine.js',
|
||||||
@@ -103,7 +106,8 @@ if (bundle) {
|
|||||||
'js/coverage/dist/tooltip.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/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/*.js',
|
||||||
'js/tests/unit/dom/*.js'
|
'js/tests/unit/dom/*.js',
|
||||||
|
'js/tests/unit/util/*.js'
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
frameworks.push('detectBrowsers')
|
frameworks.push('detectBrowsers')
|
||||||
@@ -115,7 +119,8 @@ if (bundle) {
|
|||||||
)
|
)
|
||||||
files = files.concat([
|
files = files.concat([
|
||||||
jqueryFile,
|
jqueryFile,
|
||||||
'js/coverage/dist/util.js',
|
'js/coverage/dist/util/util.js',
|
||||||
|
'js/coverage/dist/util/sanitizer.js',
|
||||||
'js/coverage/dist/dom/polyfill.js',
|
'js/coverage/dist/dom/polyfill.js',
|
||||||
'js/coverage/dist/dom/eventHandler.js',
|
'js/coverage/dist/dom/eventHandler.js',
|
||||||
'js/coverage/dist/dom/selectorEngine.js',
|
'js/coverage/dist/dom/selectorEngine.js',
|
||||||
@@ -125,7 +130,8 @@ if (bundle) {
|
|||||||
'js/coverage/dist/tooltip.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/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/*.js',
|
||||||
'js/tests/unit/dom/*.js'
|
'js/tests/unit/dom/*.js',
|
||||||
|
'js/tests/unit/util/*.js'
|
||||||
])
|
])
|
||||||
reporters.push('coverage-istanbul')
|
reporters.push('coverage-istanbul')
|
||||||
conf.customLaunchers = customLaunchers
|
conf.customLaunchers = customLaunchers
|
||||||
@@ -153,9 +159,12 @@ if (bundle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
files.push('js/tests/unit/*.js')
|
if (debug) {
|
||||||
|
conf.singleRun = false
|
||||||
|
conf.autoWatch = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conf.frameworks = frameworks
|
conf.frameworks = frameworks
|
||||||
conf.plugins = plugins
|
conf.plugins = plugins
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
"bootstrap": false,
|
"bootstrap": false,
|
||||||
"sinon": false,
|
"sinon": false,
|
||||||
"Util": false,
|
"Util": false,
|
||||||
|
"Sanitizer": false,
|
||||||
"Data": false,
|
"Data": false,
|
||||||
"Alert": false,
|
"Alert": false,
|
||||||
"Button": false,
|
"Button": false,
|
||||||
|
@@ -695,13 +695,10 @@ $(function () {
|
|||||||
].join('')
|
].join('')
|
||||||
|
|
||||||
var $modal = $(modalHTML).appendTo('#qunit-fixture')
|
var $modal = $(modalHTML).appendTo('#qunit-fixture')
|
||||||
var expectedTransitionDuration = 300
|
|
||||||
var spy = sinon.spy(Util, 'getTransitionDurationFromElement')
|
|
||||||
|
|
||||||
$modal.on('shown.bs.modal', function () {
|
$modal.on('shown.bs.modal', function () {
|
||||||
assert.ok(spy.returned(expectedTransitionDuration))
|
|
||||||
$style.remove()
|
$style.remove()
|
||||||
spy.restore()
|
assert.ok(true)
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.bootstrapModal('show')
|
.bootstrapModal('show')
|
||||||
|
@@ -722,8 +722,10 @@ $(function () {
|
|||||||
|
|
||||||
QUnit.test('should not reload the tooltip on subsequent mouseenter events', function (assert) {
|
QUnit.test('should not reload the tooltip on subsequent mouseenter events', function (assert) {
|
||||||
assert.expect(1)
|
assert.expect(1)
|
||||||
|
var fakeId = 1
|
||||||
var titleHtml = function () {
|
var titleHtml = function () {
|
||||||
var uid = Util.getUID('tooltip')
|
var uid = fakeId
|
||||||
|
fakeId++
|
||||||
return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>'
|
return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,8 +755,10 @@ $(function () {
|
|||||||
QUnit.test('should not reload the tooltip if the mouse leaves and re-enters before hiding', function (assert) {
|
QUnit.test('should not reload the tooltip if the mouse leaves and re-enters before hiding', function (assert) {
|
||||||
assert.expect(4)
|
assert.expect(4)
|
||||||
|
|
||||||
|
var fakeId = 1
|
||||||
var titleHtml = function () {
|
var titleHtml = function () {
|
||||||
var uid = Util.getUID('tooltip')
|
var uid = 'tooltip' + fakeId
|
||||||
|
fakeId++
|
||||||
return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>'
|
return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,24 +1156,6 @@ $(function () {
|
|||||||
assert.strictEqual(tooltip.config.template.indexOf('onError'), -1)
|
assert.strictEqual(tooltip.config.template.indexOf('onError'), -1)
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('should sanitize template by removing tags with XSS', function (assert) {
|
|
||||||
assert.expect(1)
|
|
||||||
|
|
||||||
var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>')
|
|
||||||
.appendTo('#qunit-fixture')
|
|
||||||
.bootstrapTooltip({
|
|
||||||
template: [
|
|
||||||
'<div>',
|
|
||||||
' <a href="javascript:alert(7)">Click me</a>',
|
|
||||||
' <span>Some content</span>',
|
|
||||||
'</div>'
|
|
||||||
].join('')
|
|
||||||
})
|
|
||||||
|
|
||||||
var tooltip = Tooltip._getInstance($trigger[0])
|
|
||||||
assert.strictEqual(tooltip.config.template.indexOf('script'), -1)
|
|
||||||
})
|
|
||||||
|
|
||||||
QUnit.test('should allow custom sanitization rules', function (assert) {
|
QUnit.test('should allow custom sanitization rules', function (assert) {
|
||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
|
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
$(function () {
|
$(function () {
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
window.Util = typeof bootstrap !== 'undefined' ? bootstrap.Util : Util
|
|
||||||
|
|
||||||
QUnit.module('util', {
|
QUnit.module('util', {
|
||||||
afterEach: function () {
|
afterEach: function () {
|
||||||
$('#qunit-fixture').html('')
|
$('#qunit-fixture').html('')
|
51
js/tests/unit/util/sanitizer.js
Normal file
51
js/tests/unit/util/sanitizer.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
$(function () {
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
QUnit.module('sanitizer', {
|
||||||
|
afterEach: function () {
|
||||||
|
$('#qunit-fixture').html('')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
QUnit.test('should export a default white list', function (assert) {
|
||||||
|
assert.expect(1)
|
||||||
|
|
||||||
|
assert.ok(Sanitizer.DefaultWhitelist)
|
||||||
|
})
|
||||||
|
|
||||||
|
QUnit.test('should sanitize template by removing tags with XSS', function (assert) {
|
||||||
|
assert.expect(1)
|
||||||
|
|
||||||
|
var template = [
|
||||||
|
'<div>',
|
||||||
|
' <a href="javascript:alert(7)">Click me</a>',
|
||||||
|
' <span>Some content</span>',
|
||||||
|
'</div>'
|
||||||
|
].join('')
|
||||||
|
|
||||||
|
var result = Sanitizer.sanitizeHtml(template, Sanitizer.DefaultWhitelist, null)
|
||||||
|
|
||||||
|
assert.strictEqual(result.indexOf('script'), -1)
|
||||||
|
})
|
||||||
|
|
||||||
|
QUnit.test('should not use native api to sanitize if a custom function passed', function (assert) {
|
||||||
|
assert.expect(2)
|
||||||
|
|
||||||
|
var template = [
|
||||||
|
'<div>',
|
||||||
|
' <span>Some content</span>',
|
||||||
|
'</div>'
|
||||||
|
].join('')
|
||||||
|
|
||||||
|
function mySanitize(htmlUnsafe) {
|
||||||
|
return htmlUnsafe
|
||||||
|
}
|
||||||
|
|
||||||
|
var spy = sinon.spy(DOMParser.prototype, 'parseFromString')
|
||||||
|
var result = Sanitizer.sanitizeHtml(template, Sanitizer.DefaultWhitelist, mySanitize)
|
||||||
|
|
||||||
|
assert.strictEqual(result, template)
|
||||||
|
assert.strictEqual(spy.called, false)
|
||||||
|
spy.restore()
|
||||||
|
})
|
||||||
|
})
|
@@ -60,13 +60,13 @@
|
|||||||
<script src="../../dist/toast.js"></script>
|
<script src="../../dist/toast.js"></script>
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
Util.makeArray(document.querySelectorAll('.toast'))
|
Array.from(document.querySelectorAll('.toast'))
|
||||||
.forEach(function (toastNode) {
|
.forEach(function (toastNode) {
|
||||||
new Toast(toastNode)
|
new Toast(toastNode)
|
||||||
})
|
})
|
||||||
|
|
||||||
document.getElementById('btnShowToast').addEventListener('click', function () {
|
document.getElementById('btnShowToast').addEventListener('click', function () {
|
||||||
Util.makeArray(document.querySelectorAll('.toast'))
|
Array.from(document.querySelectorAll('.toast'))
|
||||||
.forEach(function (toastNode) {
|
.forEach(function (toastNode) {
|
||||||
var toast = Toast._getInstance(toastNode)
|
var toast = Toast._getInstance(toastNode)
|
||||||
toast.show()
|
toast.show()
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
document.getElementById('btnHideToast').addEventListener('click', function () {
|
document.getElementById('btnHideToast').addEventListener('click', function () {
|
||||||
Util.makeArray(document.querySelectorAll('.toast'))
|
Array.from(document.querySelectorAll('.toast'))
|
||||||
.forEach(function (toastNode) {
|
.forEach(function (toastNode) {
|
||||||
var toast = Toast._getInstance(toastNode)
|
var toast = Toast._getInstance(toastNode)
|
||||||
toast.hide()
|
toast.hide()
|
||||||
|
@@ -56,6 +56,7 @@
|
|||||||
"js-minify-bundle": "terser --compress --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.bundle.js.map,includeSources,url=bootstrap.bundle.min.js.map\" --output dist/js/bootstrap.bundle.min.js dist/js/bootstrap.bundle.js",
|
"js-minify-bundle": "terser --compress --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.bundle.js.map,includeSources,url=bootstrap.bundle.min.js.map\" --output dist/js/bootstrap.bundle.min.js dist/js/bootstrap.bundle.js",
|
||||||
"js-minify-docs": "cross-env-shell terser --mangle --comments \\\"/^!/\\\" --output site/docs/$npm_package_version_short/assets/js/docs.min.js site/docs/$npm_package_version_short/assets/js/vendor/anchor.min.js site/docs/$npm_package_version_short/assets/js/vendor/clipboard.min.js site/docs/$npm_package_version_short/assets/js/vendor/bs-custom-file-input.min.js \"site/docs/$npm_package_version_short/assets/js/src/*.js\"",
|
"js-minify-docs": "cross-env-shell terser --mangle --comments \\\"/^!/\\\" --output site/docs/$npm_package_version_short/assets/js/docs.min.js site/docs/$npm_package_version_short/assets/js/vendor/anchor.min.js site/docs/$npm_package_version_short/assets/js/vendor/clipboard.min.js site/docs/$npm_package_version_short/assets/js/vendor/bs-custom-file-input.min.js \"site/docs/$npm_package_version_short/assets/js/src/*.js\"",
|
||||||
"js-test": "npm-run-all js-test-karma* js-test-integration",
|
"js-test": "npm-run-all js-test-karma* js-test-integration",
|
||||||
|
"js-debug": "cross-env DEBUG=true karma start js/tests/karma.conf.js",
|
||||||
"js-test-karma": "karma start js/tests/karma.conf.js",
|
"js-test-karma": "karma start js/tests/karma.conf.js",
|
||||||
"js-test-karma-old": "cross-env USE_OLD_JQUERY=true npm run js-test-karma",
|
"js-test-karma-old": "cross-env USE_OLD_JQUERY=true npm run js-test-karma",
|
||||||
"js-test-karma-bundle": "cross-env BUNDLE=true npm run js-test-karma",
|
"js-test-karma-bundle": "cross-env BUNDLE=true npm run js-test-karma",
|
||||||
|
@@ -15,20 +15,24 @@
|
|||||||
(function () {
|
(function () {
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
function makeArray(list) {
|
||||||
|
return [].slice.call(list)
|
||||||
|
}
|
||||||
|
|
||||||
// Tooltip and popover demos
|
// Tooltip and popover demos
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.tooltip-demo'))
|
makeArray(document.querySelectorAll('.tooltip-demo'))
|
||||||
.forEach(function (tooltip) {
|
.forEach(function (tooltip) {
|
||||||
new bootstrap.Tooltip(tooltip, {
|
new bootstrap.Tooltip(tooltip, {
|
||||||
selector: '[data-toggle="tooltip"]'
|
selector: '[data-toggle="tooltip"]'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('[data-toggle="popover"]'))
|
makeArray(document.querySelectorAll('[data-toggle="popover"]'))
|
||||||
.forEach(function (popover) {
|
.forEach(function (popover) {
|
||||||
new bootstrap.Popover(popover)
|
new bootstrap.Popover(popover)
|
||||||
})
|
})
|
||||||
|
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.toast'))
|
makeArray(document.querySelectorAll('.toast'))
|
||||||
.forEach(function (toastNode) {
|
.forEach(function (toastNode) {
|
||||||
var toast = new bootstrap.Toast(toastNode, {
|
var toast = new bootstrap.Toast(toastNode, {
|
||||||
autohide: false
|
autohide: false
|
||||||
@@ -38,24 +42,24 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Demos within modals
|
// Demos within modals
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.tooltip-test'))
|
makeArray(document.querySelectorAll('.tooltip-test'))
|
||||||
.forEach(function (tooltip) {
|
.forEach(function (tooltip) {
|
||||||
new bootstrap.Tooltip(tooltip)
|
new bootstrap.Tooltip(tooltip)
|
||||||
})
|
})
|
||||||
|
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.popover-test'))
|
makeArray(document.querySelectorAll('.popover-test'))
|
||||||
.forEach(function (popover) {
|
.forEach(function (popover) {
|
||||||
new bootstrap.Popover(popover)
|
new bootstrap.Popover(popover)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Indeterminate checkbox example
|
// Indeterminate checkbox example
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.bd-example-indeterminate [type="checkbox"]'))
|
makeArray(document.querySelectorAll('.bd-example-indeterminate [type="checkbox"]'))
|
||||||
.forEach(function (checkbox) {
|
.forEach(function (checkbox) {
|
||||||
checkbox.indeterminate = true
|
checkbox.indeterminate = true
|
||||||
})
|
})
|
||||||
|
|
||||||
// Disable empty links in docs examples
|
// Disable empty links in docs examples
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.bd-content [href="#"]'))
|
makeArray(document.querySelectorAll('.bd-content [href="#"]'))
|
||||||
.forEach(function (link) {
|
.forEach(function (link) {
|
||||||
link.addEventListener('click', function (e) {
|
link.addEventListener('click', function (e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -79,7 +83,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Activate animated progress bar
|
// Activate animated progress bar
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.bd-toggle-animated-progress > .progress-bar-striped'))
|
makeArray(document.querySelectorAll('.bd-toggle-animated-progress > .progress-bar-striped'))
|
||||||
.forEach(function (progressBar) {
|
.forEach(function (progressBar) {
|
||||||
progressBar.addEventListener('click', function () {
|
progressBar.addEventListener('click', function () {
|
||||||
if (progressBar.classList.contains('progress-bar-animated')) {
|
if (progressBar.classList.contains('progress-bar-animated')) {
|
||||||
@@ -92,12 +96,12 @@
|
|||||||
|
|
||||||
// Insert copy to clipboard button before .highlight
|
// Insert copy to clipboard button before .highlight
|
||||||
var btnHtml = '<div class="bd-clipboard"><button type="button" class="btn-clipboard" title="Copy to clipboard">Copy</button></div>'
|
var btnHtml = '<div class="bd-clipboard"><button type="button" class="btn-clipboard" title="Copy to clipboard">Copy</button></div>'
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('figure.highlight, div.highlight'))
|
makeArray(document.querySelectorAll('figure.highlight, div.highlight'))
|
||||||
.forEach(function (element) {
|
.forEach(function (element) {
|
||||||
element.insertAdjacentHTML('beforebegin', btnHtml)
|
element.insertAdjacentHTML('beforebegin', btnHtml)
|
||||||
})
|
})
|
||||||
|
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.btn-clipboard'))
|
makeArray(document.querySelectorAll('.btn-clipboard'))
|
||||||
.forEach(function (btn) {
|
.forEach(function (btn) {
|
||||||
var tooltipBtn = new bootstrap.Tooltip(btn)
|
var tooltipBtn = new bootstrap.Tooltip(btn)
|
||||||
|
|
||||||
@@ -146,7 +150,7 @@
|
|||||||
anchors.add('.bd-content > h2, .bd-content > h3, .bd-content > h4, .bd-content > h5')
|
anchors.add('.bd-content > h2, .bd-content > h3, .bd-content > h4, .bd-content > h5')
|
||||||
|
|
||||||
// Wrap inner
|
// Wrap inner
|
||||||
bootstrap.Util.makeArray(document.querySelectorAll('.bd-content > h2, .bd-content > h3, .bd-content > h4, .bd-content > h5'))
|
makeArray(document.querySelectorAll('.bd-content > h2, .bd-content > h3, .bd-content > h4, .bd-content > h5'))
|
||||||
.forEach(function (hEl) {
|
.forEach(function (hEl) {
|
||||||
hEl.innerHTML = '<span class="bd-content-title">' + hEl.innerHTML + '</span>'
|
hEl.innerHTML = '<span class="bd-content-title">' + hEl.innerHTML + '</span>'
|
||||||
})
|
})
|
||||||
|
@@ -134,12 +134,6 @@ Bootstrap's plugins don't fall back particularly gracefully when JavaScript is d
|
|||||||
{% endcapture %}
|
{% endcapture %}
|
||||||
{% include callout.html content=callout type="warning" %}
|
{% include callout.html content=callout type="warning" %}
|
||||||
|
|
||||||
## Util
|
|
||||||
|
|
||||||
All Bootstrap's JavaScript files depend on `util.js` and it has to be included alongside the other JavaScript files. If you're using the compiled (or minified) `bootstrap.js`, there is no need to include this—it's already there.
|
|
||||||
|
|
||||||
`util.js` includes utility functions and a basic helper for `transitionEnd` events as well as a CSS transition emulator. It's used by the other plugins to check for CSS transition support and to catch hanging transitions.
|
|
||||||
|
|
||||||
## Sanitizer
|
## Sanitizer
|
||||||
|
|
||||||
Tooltips and Popovers use our built-in sanitizer to sanitize options which accept HTML.
|
Tooltips and Popovers use our built-in sanitizer to sanitize options which accept HTML.
|
||||||
|
@@ -21,7 +21,6 @@ import 'bootstrap';
|
|||||||
Alternatively, you may **import plugins individually** as needed:
|
Alternatively, you may **import plugins individually** as needed:
|
||||||
|
|
||||||
{% highlight js %}
|
{% highlight js %}
|
||||||
import 'bootstrap/js/dist/util';
|
|
||||||
import 'bootstrap/js/dist/alert';
|
import 'bootstrap/js/dist/alert';
|
||||||
...
|
...
|
||||||
{% endhighlight %}
|
{% endhighlight %}
|
||||||
|
Reference in New Issue
Block a user