0
0
mirror of https://github.com/twbs/bootstrap.git synced 2024-12-01 13:24:25 +01:00

Merge branch 'master' into underline-links

This commit is contained in:
Martijn Cuppens 2020-03-20 12:30:41 +01:00 committed by GitHub
commit 4a37677dda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 700 additions and 947 deletions

View File

@ -6,8 +6,8 @@ not dead
Chrome >= 60
Firefox >= 60
Edge >= 16.16299
Explorer 11
iOS >= 10
Safari >= 10
Android >= 6
not Explorer <= 11
not ExplorerMobile <= 11

View File

@ -6,6 +6,6 @@ Before opening:
Bug reports must include:
- Operating system and version (Windows, macOS, Android, iOS, Win10 Mobile)
- Browser and version (Chrome, Firefox, Safari, IE, MS Edge, Opera 15+, Android Browser)
- Operating system and version (Windows, macOS, Android, iOS)
- Browser and version (Chrome, Firefox, Safari, Microsoft Edge, Opera, Android Browser)
- [Reduced test case](https://css-tricks.com/reduced-test-cases/) and suggested fix using [CodePen](https://codepen.io/) or [JS Bin](https://jsbin.com/)

View File

@ -12,6 +12,6 @@ Before opening:
Bug reports must include:
- Operating system and version (Windows, macOS, Android, iOS, Win10 Mobile)
- Browser and version (Chrome, Firefox, Safari, IE, MS Edge, Opera 15+, Android Browser)
- Operating system and version (Windows, macOS, Android, iOS)
- Browser and version (Chrome, Firefox, Safari, Microsoft Edge, Opera, Android Browser)
- [Reduced test case](https://css-tricks.com/reduced-test-cases/) and suggested fix using [CodePen](https://codepen.io/) or [JS Bin](https://jsbin.com/)

View File

@ -37,10 +37,7 @@ childProcess.exec('java -version', (error, stdout, stderr) => {
'The “month” input type is not supported in all browsers.*',
'The “color” input type is not supported in all browsers.*',
'The “datetime-local” input type is not supported in all browsers.*',
'The “time” input type is not supported in all browsers.*',
// IE11 doesn't recognize <main> / give the element an implicit "main" landmark.
// Explicit role="main" is redundant for other modern browsers, but still valid.
'The “main” role is unnecessary for element “main”.'
'The “time” input type is not supported in all browsers.*'
].join('|')
const args = [

View File

@ -38,7 +38,7 @@
},
{
"path": "./dist/js/bootstrap.bundle.min.js",
"maxSize": "24 kB"
"maxSize": "23 kB"
},
{
"path": "./dist/js/bootstrap.esm.js",
@ -54,7 +54,7 @@
},
{
"path": "./dist/js/bootstrap.min.js",
"maxSize": "17.5 kB"
"maxSize": "16.5 kB"
}
]
}

View File

@ -51,7 +51,7 @@ params:
current_ruby_version: "4.3.1"
rfs_version: "9.0.2"
docs_version: "4.3"
repo: "https://github.com/twbs/bootstrap"
repo: "https://github.com/twbs"
twitter: "getbootstrap"
slack: "https://bootstrap-slack.herokuapp.com/"
opencollective: "https://opencollective.com/bootstrap"

View File

@ -28,21 +28,15 @@ const DATA_KEY = 'bs.alert'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const Selector = {
DISMISS: '[data-dismiss="alert"]'
}
const SELECTOR_DISMISS = '[data-dismiss="alert"]'
const Event = {
CLOSE: `close${EVENT_KEY}`,
CLOSED: `closed${EVENT_KEY}`,
CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_CLOSE = `close${EVENT_KEY}`
const EVENT_CLOSED = `closed${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const ClassName = {
ALERT: 'alert',
FADE: 'fade',
SHOW: 'show'
}
const CLASSNAME_ALERT = 'alert'
const CLASSNAME_FADE = 'fade'
const CLASSNAME_SHOW = 'show'
/**
* ------------------------------------------------------------------------
@ -93,20 +87,20 @@ class Alert {
let parent = getElementFromSelector(element)
if (!parent) {
parent = SelectorEngine.closest(element, `.${ClassName.ALERT}`)
parent = SelectorEngine.closest(element, `.${CLASSNAME_ALERT}`)
}
return parent
}
_triggerCloseEvent(element) {
return EventHandler.trigger(element, Event.CLOSE)
return EventHandler.trigger(element, EVENT_CLOSE)
}
_removeElement(element) {
element.classList.remove(ClassName.SHOW)
element.classList.remove(CLASSNAME_SHOW)
if (!element.classList.contains(ClassName.FADE)) {
if (!element.classList.contains(CLASSNAME_FADE)) {
this._destroyElement(element)
return
}
@ -123,7 +117,7 @@ class Alert {
element.parentNode.removeChild(element)
}
EventHandler.trigger(element, Event.CLOSED)
EventHandler.trigger(element, EVENT_CLOSED)
}
// Static
@ -163,7 +157,7 @@ class Alert {
* ------------------------------------------------------------------------
*/
EventHandler
.on(document, Event.CLICK_DATA_API, Selector.DISMISS, Alert.handleDismiss(new Alert()))
.on(document, EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert.handleDismiss(new Alert()))
const $ = getjQuery()

View File

@ -22,26 +22,20 @@ const DATA_KEY = 'bs.button'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const ClassName = {
ACTIVE: 'active',
BUTTON: 'btn',
DISABLED: 'disabled',
FOCUS: 'focus'
}
const CLASS_NAME_ACTIVE = 'active'
const CLASS_NAME_BUTTON = 'btn'
const CLASS_NAME_DISABLED = 'disabled'
const CLASS_NAME_FOCUS = 'focus'
const Selector = {
DATA_TOGGLE_CARROT: '[data-toggle^="button"]',
DATA_TOGGLE: '[data-toggle="buttons"]',
INPUT: 'input:not([type="hidden"])',
ACTIVE: '.active',
BUTTON: '.btn'
}
const SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^="button"]'
const SELECTOR_DATA_TOGGLE = '[data-toggle="buttons"]'
const SELECTOR_INPUT = 'input:not([type="hidden"])'
const SELECTOR_ACTIVE = '.active'
const SELECTOR_BUTTON = '.btn'
const Event = {
CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`,
FOCUS_DATA_API: `focus${EVENT_KEY}${DATA_API_KEY}`,
BLUR_DATA_API: `blur${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const EVENT_FOCUS_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY}`
const EVENT_BLUR_DATA_API = `blur${EVENT_KEY}${DATA_API_KEY}`
/**
* ------------------------------------------------------------------------
@ -69,33 +63,33 @@ class Button {
const rootElement = SelectorEngine.closest(
this._element,
Selector.DATA_TOGGLE
SELECTOR_DATA_TOGGLE
)
if (rootElement) {
const input = SelectorEngine.findOne(Selector.INPUT, this._element)
const input = SelectorEngine.findOne(SELECTOR_INPUT, this._element)
if (input && input.type === 'radio') {
if (input.checked &&
this._element.classList.contains(ClassName.ACTIVE)) {
this._element.classList.contains(CLASS_NAME_ACTIVE)) {
triggerChangeEvent = false
} else {
const activeElement = SelectorEngine.findOne(Selector.ACTIVE, rootElement)
const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE, rootElement)
if (activeElement) {
activeElement.classList.remove(ClassName.ACTIVE)
activeElement.classList.remove(CLASS_NAME_ACTIVE)
}
}
if (triggerChangeEvent) {
if (input.hasAttribute('disabled') ||
rootElement.hasAttribute('disabled') ||
input.classList.contains(ClassName.DISABLED) ||
rootElement.classList.contains(ClassName.DISABLED)) {
input.classList.contains(CLASS_NAME_DISABLED) ||
rootElement.classList.contains(CLASS_NAME_DISABLED)) {
return
}
input.checked = !this._element.classList.contains(ClassName.ACTIVE)
input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE)
EventHandler.trigger(input, 'change')
}
@ -106,11 +100,11 @@ class Button {
if (addAriaPressed) {
this._element.setAttribute('aria-pressed',
!this._element.classList.contains(ClassName.ACTIVE))
!this._element.classList.contains(CLASS_NAME_ACTIVE))
}
if (triggerChangeEvent) {
this._element.classList.toggle(ClassName.ACTIVE)
this._element.classList.toggle(CLASS_NAME_ACTIVE)
}
}
@ -146,12 +140,12 @@ class Button {
* ------------------------------------------------------------------------
*/
EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, event => {
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => {
event.preventDefault()
let button = event.target
if (!button.classList.contains(ClassName.BUTTON)) {
button = SelectorEngine.closest(button, Selector.BUTTON)
if (!button.classList.contains(CLASS_NAME_BUTTON)) {
button = SelectorEngine.closest(button, SELECTOR_BUTTON)
}
let data = Data.getData(button, DATA_KEY)
@ -162,19 +156,19 @@ EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE_CARROT, eve
data.toggle()
})
EventHandler.on(document, Event.FOCUS_DATA_API, Selector.DATA_TOGGLE_CARROT, event => {
const button = SelectorEngine.closest(event.target, Selector.BUTTON)
EventHandler.on(document, EVENT_FOCUS_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => {
const button = SelectorEngine.closest(event.target, SELECTOR_BUTTON)
if (button) {
button.classList.add(ClassName.FOCUS)
button.classList.add(CLASS_NAME_FOCUS)
}
})
EventHandler.on(document, Event.BLUR_DATA_API, Selector.DATA_TOGGLE_CARROT, event => {
const button = SelectorEngine.closest(event.target, Selector.BUTTON)
EventHandler.on(document, EVENT_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => {
const button = SelectorEngine.closest(event.target, SELECTOR_BUTTON)
if (button) {
button.classList.remove(ClassName.FOCUS)
button.classList.remove(CLASS_NAME_FOCUS)
}
})

View File

@ -33,6 +33,7 @@ const VERSION = '4.3.1'
const DATA_KEY = 'bs.carousel'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key
const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key
const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch
@ -56,51 +57,42 @@ const DefaultType = {
touch: 'boolean'
}
const Direction = {
NEXT: 'next',
PREV: 'prev',
LEFT: 'left',
RIGHT: 'right'
}
const DIRECTION_NEXT = 'next'
const DIRECTION_PREV = 'prev'
const DIRECTION_LEFT = 'left'
const DIRECTION_RIGHT = 'right'
const Event = {
SLIDE: `slide${EVENT_KEY}`,
SLID: `slid${EVENT_KEY}`,
KEYDOWN: `keydown${EVENT_KEY}`,
MOUSEENTER: `mouseenter${EVENT_KEY}`,
MOUSELEAVE: `mouseleave${EVENT_KEY}`,
TOUCHSTART: `touchstart${EVENT_KEY}`,
TOUCHMOVE: `touchmove${EVENT_KEY}`,
TOUCHEND: `touchend${EVENT_KEY}`,
POINTERDOWN: `pointerdown${EVENT_KEY}`,
POINTERUP: `pointerup${EVENT_KEY}`,
DRAG_START: `dragstart${EVENT_KEY}`,
LOAD_DATA_API: `load${EVENT_KEY}${DATA_API_KEY}`,
CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_SLIDE = `slide${EVENT_KEY}`
const EVENT_SLID = `slid${EVENT_KEY}`
const EVENT_KEYDOWN = `keydown${EVENT_KEY}`
const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`
const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`
const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`
const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`
const EVENT_TOUCHEND = `touchend${EVENT_KEY}`
const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`
const EVENT_POINTERUP = `pointerup${EVENT_KEY}`
const EVENT_DRAG_START = `dragstart${EVENT_KEY}`
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const ClassName = {
CAROUSEL: 'carousel',
ACTIVE: 'active',
SLIDE: 'slide',
RIGHT: 'carousel-item-right',
LEFT: 'carousel-item-left',
NEXT: 'carousel-item-next',
PREV: 'carousel-item-prev',
ITEM: 'carousel-item',
POINTER_EVENT: 'pointer-event'
}
const CLASS_NAME_CAROUSEL = 'carousel'
const CLASS_NAME_ACTIVE = 'active'
const CLASS_NAME_SLIDE = 'slide'
const CLASS_NAME_RIGHT = 'carousel-item-right'
const CLASS_NAME_LEFT = 'carousel-item-left'
const CLASS_NAME_NEXT = 'carousel-item-next'
const CLASS_NAME_PREV = 'carousel-item-prev'
const CLASS_NAME_POINTER_EVENT = 'pointer-event'
const Selector = {
ACTIVE: '.active',
ACTIVE_ITEM: '.active.carousel-item',
ITEM: '.carousel-item',
ITEM_IMG: '.carousel-item img',
NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
INDICATORS: '.carousel-indicators',
DATA_SLIDE: '[data-slide], [data-slide-to]',
DATA_RIDE: '[data-ride="carousel"]'
}
const SELECTOR_ACTIVE = '.active'
const SELECTOR_ACTIVE_ITEM = '.active.carousel-item'
const SELECTOR_ITEM = '.carousel-item'
const SELECTOR_ITEM_IMG = '.carousel-item img'
const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'
const SELECTOR_INDICATORS = '.carousel-indicators'
const SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]'
const SELECTOR_DATA_RIDE = '[data-ride="carousel"]'
const PointerType = {
TOUCH: 'touch',
@ -125,7 +117,7 @@ class Carousel {
this._config = this._getConfig(config)
this._element = element
this._indicatorsElement = SelectorEngine.findOne(Selector.INDICATORS, this._element)
this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)
this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent)
@ -147,7 +139,7 @@ class Carousel {
next() {
if (!this._isSliding) {
this._slide(Direction.NEXT)
this._slide(DIRECTION_NEXT)
}
}
@ -161,7 +153,7 @@ class Carousel {
prev() {
if (!this._isSliding) {
this._slide(Direction.PREV)
this._slide(DIRECTION_PREV)
}
}
@ -170,7 +162,7 @@ class Carousel {
this._isPaused = true
}
if (SelectorEngine.findOne(Selector.NEXT_PREV, this._element)) {
if (SelectorEngine.findOne(SELECTOR_NEXT_PREV, this._element)) {
triggerTransitionEnd(this._element)
this.cycle(true)
}
@ -198,7 +190,7 @@ class Carousel {
}
to(index) {
this._activeElement = SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element)
this._activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)
const activeIndex = this._getItemIndex(this._activeElement)
if (index > this._items.length - 1 || index < 0) {
@ -206,7 +198,7 @@ class Carousel {
}
if (this._isSliding) {
EventHandler.one(this._element, Event.SLID, () => this.to(index))
EventHandler.one(this._element, EVENT_SLID, () => this.to(index))
return
}
@ -217,8 +209,8 @@ class Carousel {
}
const direction = index > activeIndex ?
Direction.NEXT :
Direction.PREV
DIRECTION_NEXT :
DIRECTION_PREV
this._slide(direction, this._items[index])
}
@ -273,14 +265,14 @@ class Carousel {
_addEventListeners() {
if (this._config.keyboard) {
EventHandler
.on(this._element, Event.KEYDOWN, event => this._keydown(event))
.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))
}
if (this._config.pause === 'hover') {
EventHandler
.on(this._element, Event.MOUSEENTER, event => this.pause(event))
.on(this._element, EVENT_MOUSEENTER, event => this.pause(event))
EventHandler
.on(this._element, Event.MOUSELEAVE, event => this.cycle(event))
.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event))
}
if (this._config.touch && this._touchSupported) {
@ -330,19 +322,19 @@ class Carousel {
}
}
makeArray(SelectorEngine.find(Selector.ITEM_IMG, this._element)).forEach(itemImg => {
EventHandler.on(itemImg, Event.DRAG_START, e => e.preventDefault())
makeArray(SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)).forEach(itemImg => {
EventHandler.on(itemImg, EVENT_DRAG_START, e => e.preventDefault())
})
if (this._pointerEvent) {
EventHandler.on(this._element, Event.POINTERDOWN, event => start(event))
EventHandler.on(this._element, Event.POINTERUP, event => end(event))
EventHandler.on(this._element, EVENT_POINTERDOWN, event => start(event))
EventHandler.on(this._element, EVENT_POINTERUP, event => end(event))
this._element.classList.add(ClassName.POINTER_EVENT)
this._element.classList.add(CLASS_NAME_POINTER_EVENT)
} else {
EventHandler.on(this._element, Event.TOUCHSTART, event => start(event))
EventHandler.on(this._element, Event.TOUCHMOVE, event => move(event))
EventHandler.on(this._element, Event.TOUCHEND, event => end(event))
EventHandler.on(this._element, EVENT_TOUCHSTART, event => start(event))
EventHandler.on(this._element, EVENT_TOUCHMOVE, event => move(event))
EventHandler.on(this._element, EVENT_TOUCHEND, event => end(event))
}
}
@ -366,15 +358,15 @@ class Carousel {
_getItemIndex(element) {
this._items = element && element.parentNode ?
makeArray(SelectorEngine.find(Selector.ITEM, element.parentNode)) :
makeArray(SelectorEngine.find(SELECTOR_ITEM, element.parentNode)) :
[]
return this._items.indexOf(element)
}
_getItemByDirection(direction, activeElement) {
const isNextDirection = direction === Direction.NEXT
const isPrevDirection = direction === Direction.PREV
const isNextDirection = direction === DIRECTION_NEXT
const isPrevDirection = direction === DIRECTION_PREV
const activeIndex = this._getItemIndex(activeElement)
const lastItemIndex = this._items.length - 1
const isGoingToWrap = (isPrevDirection && activeIndex === 0) ||
@ -384,7 +376,7 @@ class Carousel {
return activeElement
}
const delta = direction === Direction.PREV ? -1 : 1
const delta = direction === DIRECTION_PREV ? -1 : 1
const itemIndex = (activeIndex + delta) % this._items.length
return itemIndex === -1 ?
@ -394,9 +386,9 @@ class Carousel {
_triggerSlideEvent(relatedTarget, eventDirectionName) {
const targetIndex = this._getItemIndex(relatedTarget)
const fromIndex = this._getItemIndex(SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element))
const fromIndex = this._getItemIndex(SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element))
return EventHandler.trigger(this._element, Event.SLIDE, {
return EventHandler.trigger(this._element, EVENT_SLIDE, {
relatedTarget,
direction: eventDirectionName,
from: fromIndex,
@ -406,9 +398,9 @@ class Carousel {
_setActiveIndicatorElement(element) {
if (this._indicatorsElement) {
const indicators = SelectorEngine.find(Selector.ACTIVE, this._indicatorsElement)
const indicators = SelectorEngine.find(SELECTOR_ACTIVE, this._indicatorsElement)
for (let i = 0; i < indicators.length; i++) {
indicators[i].classList.remove(ClassName.ACTIVE)
indicators[i].classList.remove(CLASS_NAME_ACTIVE)
}
const nextIndicator = this._indicatorsElement.children[
@ -416,13 +408,13 @@ class Carousel {
]
if (nextIndicator) {
nextIndicator.classList.add(ClassName.ACTIVE)
nextIndicator.classList.add(CLASS_NAME_ACTIVE)
}
}
}
_slide(direction, element) {
const activeElement = SelectorEngine.findOne(Selector.ACTIVE_ITEM, this._element)
const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)
const activeElementIndex = this._getItemIndex(activeElement)
const nextElement = element || (activeElement &&
this._getItemByDirection(direction, activeElement))
@ -434,17 +426,17 @@ class Carousel {
let orderClassName
let eventDirectionName
if (direction === Direction.NEXT) {
directionalClassName = ClassName.LEFT
orderClassName = ClassName.NEXT
eventDirectionName = Direction.LEFT
if (direction === DIRECTION_NEXT) {
directionalClassName = CLASS_NAME_LEFT
orderClassName = CLASS_NAME_NEXT
eventDirectionName = DIRECTION_LEFT
} else {
directionalClassName = ClassName.RIGHT
orderClassName = ClassName.PREV
eventDirectionName = Direction.RIGHT
directionalClassName = CLASS_NAME_RIGHT
orderClassName = CLASS_NAME_PREV
eventDirectionName = DIRECTION_RIGHT
}
if (nextElement && nextElement.classList.contains(ClassName.ACTIVE)) {
if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE)) {
this._isSliding = false
return
}
@ -467,7 +459,7 @@ class Carousel {
this._setActiveIndicatorElement(nextElement)
if (this._element.classList.contains(ClassName.SLIDE)) {
if (this._element.classList.contains(CLASS_NAME_SLIDE)) {
nextElement.classList.add(orderClassName)
reflow(nextElement)
@ -489,16 +481,16 @@ class Carousel {
.one(activeElement, TRANSITION_END, () => {
nextElement.classList.remove(directionalClassName)
nextElement.classList.remove(orderClassName)
nextElement.classList.add(ClassName.ACTIVE)
nextElement.classList.add(CLASS_NAME_ACTIVE)
activeElement.classList.remove(ClassName.ACTIVE)
activeElement.classList.remove(CLASS_NAME_ACTIVE)
activeElement.classList.remove(orderClassName)
activeElement.classList.remove(directionalClassName)
this._isSliding = false
setTimeout(() => {
EventHandler.trigger(this._element, Event.SLID, {
EventHandler.trigger(this._element, EVENT_SLID, {
relatedTarget: nextElement,
direction: eventDirectionName,
from: activeElementIndex,
@ -509,11 +501,11 @@ class Carousel {
emulateTransitionEnd(activeElement, transitionDuration)
} else {
activeElement.classList.remove(ClassName.ACTIVE)
nextElement.classList.add(ClassName.ACTIVE)
activeElement.classList.remove(CLASS_NAME_ACTIVE)
nextElement.classList.add(CLASS_NAME_ACTIVE)
this._isSliding = false
EventHandler.trigger(this._element, Event.SLID, {
EventHandler.trigger(this._element, EVENT_SLID, {
relatedTarget: nextElement,
direction: eventDirectionName,
from: activeElementIndex,
@ -571,7 +563,7 @@ class Carousel {
static dataApiClickHandler(event) {
const target = getElementFromSelector(this)
if (!target || !target.classList.contains(ClassName.CAROUSEL)) {
if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
return
}
@ -606,10 +598,10 @@ class Carousel {
*/
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, () => {
const carousels = makeArray(SelectorEngine.find(Selector.DATA_RIDE))
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
const carousels = makeArray(SelectorEngine.find(SELECTOR_DATA_RIDE))
for (let i = 0, len = carousels.length; i < len; i++) {
Carousel.carouselInterface(carousels[i], Data.getData(carousels[i], DATA_KEY))
}

View File

@ -44,30 +44,22 @@ const DefaultType = {
parent: '(string|element)'
}
const Event = {
SHOW: `show${EVENT_KEY}`,
SHOWN: `shown${EVENT_KEY}`,
HIDE: `hide${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const ClassName = {
SHOW: 'show',
COLLAPSE: 'collapse',
COLLAPSING: 'collapsing',
COLLAPSED: 'collapsed'
}
const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_COLLAPSE = 'collapse'
const CLASS_NAME_COLLAPSING = 'collapsing'
const CLASS_NAME_COLLAPSED = 'collapsed'
const Dimension = {
WIDTH: 'width',
HEIGHT: 'height'
}
const WIDTH = 'width'
const HEIGHT = 'height'
const Selector = {
ACTIVES: '.show, .collapsing',
DATA_TOGGLE: '[data-toggle="collapse"]'
}
const SELECTOR_ACTIVES = '.show, .collapsing'
const SELECTOR_DATA_TOGGLE = '[data-toggle="collapse"]'
/**
* ------------------------------------------------------------------------
@ -81,11 +73,11 @@ class Collapse {
this._element = element
this._config = this._getConfig(config)
this._triggerArray = makeArray(SelectorEngine.find(
`${Selector.DATA_TOGGLE}[href="#${element.id}"],` +
`${Selector.DATA_TOGGLE}[data-target="#${element.id}"]`
`${SELECTOR_DATA_TOGGLE}[href="#${element.id}"],` +
`${SELECTOR_DATA_TOGGLE}[data-target="#${element.id}"]`
))
const toggleList = makeArray(SelectorEngine.find(Selector.DATA_TOGGLE))
const toggleList = makeArray(SelectorEngine.find(SELECTOR_DATA_TOGGLE))
for (let i = 0, len = toggleList.length; i < len; i++) {
const elem = toggleList[i]
const selector = getSelectorFromElement(elem)
@ -124,7 +116,7 @@ class Collapse {
// Public
toggle() {
if (this._element.classList.contains(ClassName.SHOW)) {
if (this._element.classList.contains(CLASS_NAME_SHOW)) {
this.hide()
} else {
this.show()
@ -133,7 +125,7 @@ class Collapse {
show() {
if (this._isTransitioning ||
this._element.classList.contains(ClassName.SHOW)) {
this._element.classList.contains(CLASS_NAME_SHOW)) {
return
}
@ -141,13 +133,13 @@ class Collapse {
let activesData
if (this._parent) {
actives = makeArray(SelectorEngine.find(Selector.ACTIVES, this._parent))
actives = makeArray(SelectorEngine.find(SELECTOR_ACTIVES, this._parent))
.filter(elem => {
if (typeof this._config.parent === 'string') {
return elem.getAttribute('data-parent') === this._config.parent
}
return elem.classList.contains(ClassName.COLLAPSE)
return elem.classList.contains(CLASS_NAME_COLLAPSE)
})
if (actives.length === 0) {
@ -165,7 +157,7 @@ class Collapse {
}
}
const startEvent = EventHandler.trigger(this._element, Event.SHOW)
const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)
if (startEvent.defaultPrevented) {
return
}
@ -184,14 +176,14 @@ class Collapse {
const dimension = this._getDimension()
this._element.classList.remove(ClassName.COLLAPSE)
this._element.classList.add(ClassName.COLLAPSING)
this._element.classList.remove(CLASS_NAME_COLLAPSE)
this._element.classList.add(CLASS_NAME_COLLAPSING)
this._element.style[dimension] = 0
if (this._triggerArray.length) {
this._triggerArray.forEach(element => {
element.classList.remove(ClassName.COLLAPSED)
element.classList.remove(CLASS_NAME_COLLAPSED)
element.setAttribute('aria-expanded', true)
})
}
@ -199,15 +191,15 @@ class Collapse {
this.setTransitioning(true)
const complete = () => {
this._element.classList.remove(ClassName.COLLAPSING)
this._element.classList.add(ClassName.COLLAPSE)
this._element.classList.add(ClassName.SHOW)
this._element.classList.remove(CLASS_NAME_COLLAPSING)
this._element.classList.add(CLASS_NAME_COLLAPSE)
this._element.classList.add(CLASS_NAME_SHOW)
this._element.style[dimension] = ''
this.setTransitioning(false)
EventHandler.trigger(this._element, Event.SHOWN)
EventHandler.trigger(this._element, EVENT_SHOWN)
}
const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)
@ -222,11 +214,11 @@ class Collapse {
hide() {
if (this._isTransitioning ||
!this._element.classList.contains(ClassName.SHOW)) {
!this._element.classList.contains(CLASS_NAME_SHOW)) {
return
}
const startEvent = EventHandler.trigger(this._element, Event.HIDE)
const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)
if (startEvent.defaultPrevented) {
return
}
@ -237,9 +229,9 @@ class Collapse {
reflow(this._element)
this._element.classList.add(ClassName.COLLAPSING)
this._element.classList.remove(ClassName.COLLAPSE)
this._element.classList.remove(ClassName.SHOW)
this._element.classList.add(CLASS_NAME_COLLAPSING)
this._element.classList.remove(CLASS_NAME_COLLAPSE)
this._element.classList.remove(CLASS_NAME_SHOW)
const triggerArrayLength = this._triggerArray.length
if (triggerArrayLength > 0) {
@ -247,8 +239,8 @@ class Collapse {
const trigger = this._triggerArray[i]
const elem = getElementFromSelector(trigger)
if (elem && !elem.classList.contains(ClassName.SHOW)) {
trigger.classList.add(ClassName.COLLAPSED)
if (elem && !elem.classList.contains(CLASS_NAME_SHOW)) {
trigger.classList.add(CLASS_NAME_COLLAPSED)
trigger.setAttribute('aria-expanded', false)
}
}
@ -258,9 +250,9 @@ class Collapse {
const complete = () => {
this.setTransitioning(false)
this._element.classList.remove(ClassName.COLLAPSING)
this._element.classList.add(ClassName.COLLAPSE)
EventHandler.trigger(this._element, Event.HIDDEN)
this._element.classList.remove(CLASS_NAME_COLLAPSING)
this._element.classList.add(CLASS_NAME_COLLAPSE)
EventHandler.trigger(this._element, EVENT_HIDDEN)
}
this._element.style[dimension] = ''
@ -297,8 +289,8 @@ class Collapse {
}
_getDimension() {
const hasWidth = this._element.classList.contains(Dimension.WIDTH)
return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT
const hasWidth = this._element.classList.contains(WIDTH)
return hasWidth ? WIDTH : HEIGHT
}
_getParent() {
@ -313,7 +305,7 @@ class Collapse {
parent = SelectorEngine.findOne(parent)
}
const selector = `${Selector.DATA_TOGGLE}[data-parent="${parent}"]`
const selector = `${SELECTOR_DATA_TOGGLE}[data-parent="${parent}"]`
makeArray(SelectorEngine.find(selector, parent))
.forEach(element => {
@ -330,14 +322,14 @@ class Collapse {
_addAriaAndCollapsedClass(element, triggerArray) {
if (element) {
const isOpen = element.classList.contains(ClassName.SHOW)
const isOpen = element.classList.contains(CLASS_NAME_SHOW)
if (triggerArray.length) {
triggerArray.forEach(elem => {
if (isOpen) {
elem.classList.remove(ClassName.COLLAPSED)
elem.classList.remove(CLASS_NAME_COLLAPSED)
} else {
elem.classList.add(ClassName.COLLAPSED)
elem.classList.add(CLASS_NAME_COLLAPSED)
}
elem.setAttribute('aria-expanded', isOpen)
@ -390,7 +382,7 @@ class Collapse {
* ------------------------------------------------------------------------
*/
EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element
if (event.target.tagName === 'A') {
event.preventDefault()

View File

@ -6,7 +6,7 @@
*/
import { getjQuery } from '../util/index'
import { createCustomEvent, defaultPreventedPreservedOnDispatch } from './polyfill'
import { defaultPreventedPreservedOnDispatch } from './polyfill'
/**
* ------------------------------------------------------------------------
@ -307,7 +307,7 @@ const EventHandler = {
evt = document.createEvent('HTMLEvents')
evt.initEvent(typeEvent, bubbles, true)
} else {
evt = createCustomEvent(event, {
evt = new CustomEvent(event, {
bubbles,
cancelable: true
})

View File

@ -9,55 +9,12 @@
import { getUID } from '../util/index'
let { matches, closest } = Element.prototype
let find = Element.prototype.querySelectorAll
let findOne = Element.prototype.querySelector
let createCustomEvent = (eventName, params) => {
const cEvent = new CustomEvent(eventName, params)
return cEvent
}
if (typeof window.CustomEvent !== 'function') {
createCustomEvent = (eventName, params) => {
params = params || { bubbles: false, cancelable: false, detail: null }
const evt = document.createEvent('CustomEvent')
evt.initCustomEvent(eventName, params.bubbles, params.cancelable, params.detail)
return evt
}
}
const workingDefaultPrevented = (() => {
const e = document.createEvent('CustomEvent')
e.initEvent('Bootstrap', true, true)
e.preventDefault()
return e.defaultPrevented
})()
if (!workingDefaultPrevented) {
const origPreventDefault = Event.prototype.preventDefault
Event.prototype.preventDefault = function () {
if (!this.cancelable) {
return
}
origPreventDefault.call(this)
Object.defineProperty(this, 'defaultPrevented', {
get() {
return true
},
configurable: true
})
}
}
// MSEdge resets defaultPrevented flag upon dispatchEvent call if at least one listener is attached
const defaultPreventedPreservedOnDispatch = (() => {
const e = createCustomEvent('Bootstrap', {
const e = new CustomEvent('Bootstrap', {
cancelable: true
})
@ -69,26 +26,6 @@ const defaultPreventedPreservedOnDispatch = (() => {
return e.defaultPrevented
})()
if (!matches) {
matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector
}
if (!closest) {
closest = function (selector) {
let element = this
do {
if (matches.call(element, selector)) {
return element
}
element = element.parentElement || element.parentNode
} while (element !== null && element.nodeType === 1)
return null
}
}
const scopeSelectorRegex = /:scope\b/
const supportScopeQuery = (() => {
const element = document.createElement('div')
@ -143,10 +80,7 @@ if (!supportScopeQuery) {
}
export {
createCustomEvent,
find,
findOne,
matches,
closest,
defaultPreventedPreservedOnDispatch
}

View File

@ -5,7 +5,7 @@
* --------------------------------------------------------------------------
*/
import { find as findFn, findOne, matches, closest } from './polyfill'
import { find as findFn, findOne } from './polyfill'
import { makeArray } from '../util/index'
/**
@ -18,7 +18,7 @@ const NODE_TEXT = 3
const SelectorEngine = {
matches(element, selector) {
return matches.call(element, selector)
return element.matches(selector)
},
find(selector, element = document.documentElement) {
@ -52,7 +52,7 @@ const SelectorEngine = {
},
closest(element, selector) {
return closest.call(element, selector)
return element.closest(selector)
},
prev(element, selector) {

View File

@ -31,54 +31,46 @@ const VERSION = '4.3.1'
const DATA_KEY = 'bs.dropdown'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key
const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key
const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key
const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key
const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)
const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`)
const Event = {
HIDE: `hide${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
SHOW: `show${EVENT_KEY}`,
SHOWN: `shown${EVENT_KEY}`,
CLICK: `click${EVENT_KEY}`,
CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`,
KEYDOWN_DATA_API: `keydown${EVENT_KEY}${DATA_API_KEY}`,
KEYUP_DATA_API: `keyup${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_CLICK = `click${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`
const ClassName = {
DISABLED: 'disabled',
SHOW: 'show',
DROPUP: 'dropup',
DROPRIGHT: 'dropright',
DROPLEFT: 'dropleft',
MENURIGHT: 'dropdown-menu-right',
NAVBAR: 'navbar',
POSITION_STATIC: 'position-static'
}
const CLASS_NAME_DISABLED = 'disabled'
const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_DROPUP = 'dropup'
const CLASS_NAME_DROPRIGHT = 'dropright'
const CLASS_NAME_DROPLEFT = 'dropleft'
const CLASS_NAME_MENURIGHT = 'dropdown-menu-right'
const CLASS_NAME_NAVBAR = 'navbar'
const CLASS_NAME_POSITION_STATIC = 'position-static'
const Selector = {
DATA_TOGGLE: '[data-toggle="dropdown"]',
FORM_CHILD: '.dropdown form',
MENU: '.dropdown-menu',
NAVBAR_NAV: '.navbar-nav',
VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
}
const SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]'
const SELECTOR_FORM_CHILD = '.dropdown form'
const SELECTOR_MENU = '.dropdown-menu'
const SELECTOR_NAVBAR_NAV = '.navbar-nav'
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
const AttachmentMap = {
TOP: 'top-start',
TOPEND: 'top-end',
BOTTOM: 'bottom-start',
BOTTOMEND: 'bottom-end',
RIGHT: 'right-start',
RIGHTEND: 'right-end',
LEFT: 'left-start',
LEFTEND: 'left-end'
}
const PLACEMENT_TOP = 'top-start'
const PLACEMENT_TOPEND = 'top-end'
const PLACEMENT_BOTTOM = 'bottom-start'
const PLACEMENT_BOTTOMEND = 'bottom-end'
const PLACEMENT_RIGHT = 'right-start'
const PLACEMENT_LEFT = 'left-start'
const Default = {
offset: 0,
@ -133,11 +125,11 @@ class Dropdown {
// Public
toggle() {
if (this._element.disabled || this._element.classList.contains(ClassName.DISABLED)) {
if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED)) {
return
}
const isActive = this._menu.classList.contains(ClassName.SHOW)
const isActive = this._menu.classList.contains(CLASS_NAME_SHOW)
Dropdown.clearMenus()
@ -149,7 +141,7 @@ class Dropdown {
}
show() {
if (this._element.disabled || this._element.classList.contains(ClassName.DISABLED) || this._menu.classList.contains(ClassName.SHOW)) {
if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || this._menu.classList.contains(CLASS_NAME_SHOW)) {
return
}
@ -158,7 +150,7 @@ class Dropdown {
relatedTarget: this._element
}
const showEvent = EventHandler.trigger(parent, Event.SHOW, relatedTarget)
const showEvent = EventHandler.trigger(parent, EVENT_SHOW, relatedTarget)
if (showEvent.defaultPrevented) {
return
@ -187,7 +179,7 @@ class Dropdown {
// to allow the menu to "escape" the scroll parent's boundaries
// https://github.com/twbs/bootstrap/issues/24251
if (this._config.boundary !== 'scrollParent') {
parent.classList.add(ClassName.POSITION_STATIC)
parent.classList.add(CLASS_NAME_POSITION_STATIC)
}
this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig())
@ -198,7 +190,7 @@ class Dropdown {
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement &&
!makeArray(SelectorEngine.closest(parent, Selector.NAVBAR_NAV)).length) {
!makeArray(SelectorEngine.closest(parent, SELECTOR_NAVBAR_NAV)).length) {
makeArray(document.body.children)
.forEach(elem => EventHandler.on(elem, 'mouseover', null, noop()))
}
@ -206,13 +198,13 @@ class Dropdown {
this._element.focus()
this._element.setAttribute('aria-expanded', true)
Manipulator.toggleClass(this._menu, ClassName.SHOW)
Manipulator.toggleClass(parent, ClassName.SHOW)
EventHandler.trigger(parent, Event.SHOWN, relatedTarget)
Manipulator.toggleClass(this._menu, CLASS_NAME_SHOW)
Manipulator.toggleClass(parent, CLASS_NAME_SHOW)
EventHandler.trigger(parent, EVENT_SHOWN, relatedTarget)
}
hide() {
if (this._element.disabled || this._element.classList.contains(ClassName.DISABLED) || !this._menu.classList.contains(ClassName.SHOW)) {
if (this._element.disabled || this._element.classList.contains(CLASS_NAME_DISABLED) || !this._menu.classList.contains(CLASS_NAME_SHOW)) {
return
}
@ -221,7 +213,7 @@ class Dropdown {
relatedTarget: this._element
}
const hideEvent = EventHandler.trigger(parent, Event.HIDE, relatedTarget)
const hideEvent = EventHandler.trigger(parent, EVENT_HIDE, relatedTarget)
if (hideEvent.defaultPrevented) {
return
@ -231,9 +223,9 @@ class Dropdown {
this._popper.destroy()
}
Manipulator.toggleClass(this._menu, ClassName.SHOW)
Manipulator.toggleClass(parent, ClassName.SHOW)
EventHandler.trigger(parent, Event.HIDDEN, relatedTarget)
Manipulator.toggleClass(this._menu, CLASS_NAME_SHOW)
Manipulator.toggleClass(parent, CLASS_NAME_SHOW)
EventHandler.trigger(parent, EVENT_HIDDEN, relatedTarget)
}
dispose() {
@ -257,7 +249,7 @@ class Dropdown {
// Private
_addEventListeners() {
EventHandler.on(this._element, Event.CLICK, event => {
EventHandler.on(this._element, EVENT_CLICK, event => {
event.preventDefault()
event.stopPropagation()
this.toggle()
@ -283,32 +275,32 @@ class Dropdown {
_getMenuElement() {
const parent = Dropdown.getParentFromElement(this._element)
return SelectorEngine.findOne(Selector.MENU, parent)
return SelectorEngine.findOne(SELECTOR_MENU, parent)
}
_getPlacement() {
const parentDropdown = this._element.parentNode
let placement = AttachmentMap.BOTTOM
let placement = PLACEMENT_BOTTOM
// Handle dropup
if (parentDropdown.classList.contains(ClassName.DROPUP)) {
placement = AttachmentMap.TOP
if (this._menu.classList.contains(ClassName.MENURIGHT)) {
placement = AttachmentMap.TOPEND
if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
placement = PLACEMENT_TOP
if (this._menu.classList.contains(CLASS_NAME_MENURIGHT)) {
placement = PLACEMENT_TOPEND
}
} else if (parentDropdown.classList.contains(ClassName.DROPRIGHT)) {
placement = AttachmentMap.RIGHT
} else if (parentDropdown.classList.contains(ClassName.DROPLEFT)) {
placement = AttachmentMap.LEFT
} else if (this._menu.classList.contains(ClassName.MENURIGHT)) {
placement = AttachmentMap.BOTTOMEND
} else if (parentDropdown.classList.contains(CLASS_NAME_DROPRIGHT)) {
placement = PLACEMENT_RIGHT
} else if (parentDropdown.classList.contains(CLASS_NAME_DROPLEFT)) {
placement = PLACEMENT_LEFT
} else if (this._menu.classList.contains(CLASS_NAME_MENURIGHT)) {
placement = PLACEMENT_BOTTOMEND
}
return placement
}
_detectNavbar() {
return Boolean(SelectorEngine.closest(this._element, `.${ClassName.NAVBAR}`))
return Boolean(SelectorEngine.closest(this._element, `.${CLASS_NAME_NAVBAR}`))
}
_getOffset() {
@ -388,7 +380,7 @@ class Dropdown {
return
}
const toggles = makeArray(SelectorEngine.find(Selector.DATA_TOGGLE))
const toggles = makeArray(SelectorEngine.find(SELECTOR_DATA_TOGGLE))
for (let i = 0, len = toggles.length; i < len; i++) {
const parent = Dropdown.getParentFromElement(toggles[i])
const context = Data.getData(toggles[i], DATA_KEY)
@ -405,7 +397,7 @@ class Dropdown {
}
const dropdownMenu = context._menu
if (!parent.classList.contains(ClassName.SHOW)) {
if (!parent.classList.contains(CLASS_NAME_SHOW)) {
continue
}
@ -416,7 +408,7 @@ class Dropdown {
continue
}
const hideEvent = EventHandler.trigger(parent, Event.HIDE, relatedTarget)
const hideEvent = EventHandler.trigger(parent, EVENT_HIDE, relatedTarget)
if (hideEvent.defaultPrevented) {
continue
}
@ -434,9 +426,9 @@ class Dropdown {
context._popper.destroy()
}
dropdownMenu.classList.remove(ClassName.SHOW)
parent.classList.remove(ClassName.SHOW)
EventHandler.trigger(parent, Event.HIDDEN, relatedTarget)
dropdownMenu.classList.remove(CLASS_NAME_SHOW)
parent.classList.remove(CLASS_NAME_SHOW)
EventHandler.trigger(parent, EVENT_HIDDEN, relatedTarget)
}
}
@ -455,7 +447,7 @@ class Dropdown {
if (/input|textarea/i.test(event.target.tagName) ?
event.which === SPACE_KEYCODE || (event.which !== ESCAPE_KEYCODE &&
((event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE) ||
SelectorEngine.closest(event.target, Selector.MENU))) :
SelectorEngine.closest(event.target, SELECTOR_MENU))) :
!REGEXP_KEYDOWN.test(event.which)) {
return
}
@ -463,23 +455,23 @@ class Dropdown {
event.preventDefault()
event.stopPropagation()
if (this.disabled || this.classList.contains(ClassName.DISABLED)) {
if (this.disabled || this.classList.contains(CLASS_NAME_DISABLED)) {
return
}
const parent = Dropdown.getParentFromElement(this)
const isActive = parent.classList.contains(ClassName.SHOW)
const isActive = parent.classList.contains(CLASS_NAME_SHOW)
if (!isActive || (isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE))) {
if (event.which === ESCAPE_KEYCODE) {
SelectorEngine.findOne(Selector.DATA_TOGGLE, parent).focus()
SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, parent).focus()
}
Dropdown.clearMenus()
return
}
const items = makeArray(SelectorEngine.find(Selector.VISIBLE_ITEMS, parent))
const items = makeArray(SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, parent))
.filter(isVisible)
if (!items.length) {
@ -514,17 +506,17 @@ class Dropdown {
* ------------------------------------------------------------------------
*/
EventHandler.on(document, Event.KEYDOWN_DATA_API, Selector.DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, Event.KEYDOWN_DATA_API, Selector.MENU, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, Event.CLICK_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, Event.KEYUP_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault()
event.stopPropagation()
Dropdown.dropdownInterface(this, 'toggle')
})
EventHandler
.on(document, Event.CLICK_DATA_API, Selector.FORM_CHILD, e => e.stopPropagation())
.on(document, EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => e.stopPropagation())
const $ = getjQuery()

View File

@ -48,39 +48,33 @@ const DefaultType = {
show: 'boolean'
}
const Event = {
HIDE: `hide${EVENT_KEY}`,
HIDE_PREVENTED: `hidePrevented${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
SHOW: `show${EVENT_KEY}`,
SHOWN: `shown${EVENT_KEY}`,
FOCUSIN: `focusin${EVENT_KEY}`,
RESIZE: `resize${EVENT_KEY}`,
CLICK_DISMISS: `click.dismiss${EVENT_KEY}`,
KEYDOWN_DISMISS: `keydown.dismiss${EVENT_KEY}`,
MOUSEUP_DISMISS: `mouseup.dismiss${EVENT_KEY}`,
MOUSEDOWN_DISMISS: `mousedown.dismiss${EVENT_KEY}`,
CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
const EVENT_RESIZE = `resize${EVENT_KEY}`
const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`
const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const ClassName = {
SCROLLABLE: 'modal-dialog-scrollable',
SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
BACKDROP: 'modal-backdrop',
OPEN: 'modal-open',
FADE: 'fade',
SHOW: 'show',
STATIC: 'modal-static'
}
const CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable'
const CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure'
const CLASS_NAME_BACKDROP = 'modal-backdrop'
const CLASS_NAME_OPEN = 'modal-open'
const CLASS_NAME_FADE = 'fade'
const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_STATIC = 'modal-static'
const Selector = {
DIALOG: '.modal-dialog',
MODAL_BODY: '.modal-body',
DATA_TOGGLE: '[data-toggle="modal"]',
DATA_DISMISS: '[data-dismiss="modal"]',
FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
STICKY_CONTENT: '.sticky-top'
}
const SELECTOR_DIALOG = '.modal-dialog'
const SELECTOR_MODAL_BODY = '.modal-body'
const SELECTOR_DATA_TOGGLE = '[data-toggle="modal"]'
const SELECTOR_DATA_DISMISS = '[data-dismiss="modal"]'
const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
const SELECTOR_STICKY_CONTENT = '.sticky-top'
/**
* ------------------------------------------------------------------------
@ -92,7 +86,7 @@ class Modal {
constructor(element, config) {
this._config = this._getConfig(config)
this._element = element
this._dialog = SelectorEngine.findOne(Selector.DIALOG, element)
this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, element)
this._backdrop = null
this._isShown = false
this._isBodyOverflowing = false
@ -123,11 +117,11 @@ class Modal {
return
}
if (this._element.classList.contains(ClassName.FADE)) {
if (this._element.classList.contains(CLASS_NAME_FADE)) {
this._isTransitioning = true
}
const showEvent = EventHandler.trigger(this._element, Event.SHOW, {
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
relatedTarget
})
@ -146,13 +140,13 @@ class Modal {
this._setResizeEvent()
EventHandler.on(this._element,
Event.CLICK_DISMISS,
Selector.DATA_DISMISS,
EVENT_CLICK_DISMISS,
SELECTOR_DATA_DISMISS,
event => this.hide(event)
)
EventHandler.on(this._dialog, Event.MOUSEDOWN_DISMISS, () => {
EventHandler.one(this._element, Event.MOUSEUP_DISMISS, event => {
EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => {
EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => {
if (event.target === this._element) {
this._ignoreBackdropClick = true
}
@ -171,14 +165,14 @@ class Modal {
return
}
const hideEvent = EventHandler.trigger(this._element, Event.HIDE)
const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
if (hideEvent.defaultPrevented) {
return
}
this._isShown = false
const transition = this._element.classList.contains(ClassName.FADE)
const transition = this._element.classList.contains(CLASS_NAME_FADE)
if (transition) {
this._isTransitioning = true
@ -187,12 +181,12 @@ class Modal {
this._setEscapeEvent()
this._setResizeEvent()
EventHandler.off(document, Event.FOCUSIN)
EventHandler.off(document, EVENT_FOCUSIN)
this._element.classList.remove(ClassName.SHOW)
this._element.classList.remove(CLASS_NAME_SHOW)
EventHandler.off(this._element, Event.CLICK_DISMISS)
EventHandler.off(this._dialog, Event.MOUSEDOWN_DISMISS)
EventHandler.off(this._element, EVENT_CLICK_DISMISS)
EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS)
if (transition) {
const transitionDuration = getTransitionDurationFromElement(this._element)
@ -209,11 +203,11 @@ class Modal {
.forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY))
/**
* `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API`
* `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`
* Do not move `document` in `htmlElements` array
* It will remove `Event.CLICK_DATA_API` event that should remain
* It will remove `EVENT_CLICK_DATA_API` event that should remain
*/
EventHandler.off(document, Event.FOCUSIN)
EventHandler.off(document, EVENT_FOCUSIN)
Data.removeData(this._element, DATA_KEY)
@ -244,8 +238,8 @@ class Modal {
}
_showElement(relatedTarget) {
const transition = this._element.classList.contains(ClassName.FADE)
const modalBody = SelectorEngine.findOne(Selector.MODAL_BODY, this._dialog)
const transition = this._element.classList.contains(CLASS_NAME_FADE)
const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)
if (!this._element.parentNode ||
this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
@ -257,7 +251,7 @@ class Modal {
this._element.removeAttribute('aria-hidden')
this._element.setAttribute('aria-modal', true)
if (this._dialog.classList.contains(ClassName.SCROLLABLE) && modalBody) {
if (this._dialog.classList.contains(CLASS_NAME_SCROLLABLE) && modalBody) {
modalBody.scrollTop = 0
} else {
this._element.scrollTop = 0
@ -267,7 +261,7 @@ class Modal {
reflow(this._element)
}
this._element.classList.add(ClassName.SHOW)
this._element.classList.add(CLASS_NAME_SHOW)
if (this._config.focus) {
this._enforceFocus()
@ -279,7 +273,7 @@ class Modal {
}
this._isTransitioning = false
EventHandler.trigger(this._element, Event.SHOWN, {
EventHandler.trigger(this._element, EVENT_SHOWN, {
relatedTarget
})
}
@ -295,8 +289,8 @@ class Modal {
}
_enforceFocus() {
EventHandler.off(document, Event.FOCUSIN) // guard against infinite focus loop
EventHandler.on(document, Event.FOCUSIN, event => {
EventHandler.off(document, EVENT_FOCUSIN) // guard against infinite focus loop
EventHandler.on(document, EVENT_FOCUSIN, event => {
if (document !== event.target &&
this._element !== event.target &&
!this._element.contains(event.target)) {
@ -307,7 +301,7 @@ class Modal {
_setEscapeEvent() {
if (this._isShown) {
EventHandler.on(this._element, Event.KEYDOWN_DISMISS, event => {
EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
if (this._config.keyboard && event.which === ESCAPE_KEYCODE) {
event.preventDefault()
this.hide()
@ -316,15 +310,15 @@ class Modal {
}
})
} else {
EventHandler.off(this._element, Event.KEYDOWN_DISMISS)
EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS)
}
}
_setResizeEvent() {
if (this._isShown) {
EventHandler.on(window, Event.RESIZE, () => this._adjustDialog())
EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog())
} else {
EventHandler.off(window, Event.RESIZE)
EventHandler.off(window, EVENT_RESIZE)
}
}
@ -334,10 +328,10 @@ class Modal {
this._element.removeAttribute('aria-modal')
this._isTransitioning = false
this._showBackdrop(() => {
document.body.classList.remove(ClassName.OPEN)
document.body.classList.remove(CLASS_NAME_OPEN)
this._resetAdjustments()
this._resetScrollbar()
EventHandler.trigger(this._element, Event.HIDDEN)
EventHandler.trigger(this._element, EVENT_HIDDEN)
})
}
@ -347,13 +341,13 @@ class Modal {
}
_showBackdrop(callback) {
const animate = this._element.classList.contains(ClassName.FADE) ?
ClassName.FADE :
const animate = this._element.classList.contains(CLASS_NAME_FADE) ?
CLASS_NAME_FADE :
''
if (this._isShown && this._config.backdrop) {
this._backdrop = document.createElement('div')
this._backdrop.className = ClassName.BACKDROP
this._backdrop.className = CLASS_NAME_BACKDROP
if (animate) {
this._backdrop.classList.add(animate)
@ -361,7 +355,7 @@ class Modal {
document.body.appendChild(this._backdrop)
EventHandler.on(this._element, Event.CLICK_DISMISS, event => {
EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => {
if (this._ignoreBackdropClick) {
this._ignoreBackdropClick = false
return
@ -378,7 +372,7 @@ class Modal {
reflow(this._backdrop)
}
this._backdrop.classList.add(ClassName.SHOW)
this._backdrop.classList.add(CLASS_NAME_SHOW)
if (!animate) {
callback()
@ -390,14 +384,14 @@ class Modal {
EventHandler.one(this._backdrop, TRANSITION_END, callback)
emulateTransitionEnd(this._backdrop, backdropTransitionDuration)
} else if (!this._isShown && this._backdrop) {
this._backdrop.classList.remove(ClassName.SHOW)
this._backdrop.classList.remove(CLASS_NAME_SHOW)
const callbackRemove = () => {
this._removeBackdrop()
callback()
}
if (this._element.classList.contains(ClassName.FADE)) {
if (this._element.classList.contains(CLASS_NAME_FADE)) {
const backdropTransitionDuration = getTransitionDurationFromElement(this._backdrop)
EventHandler.one(this._backdrop, TRANSITION_END, callbackRemove)
emulateTransitionEnd(this._backdrop, backdropTransitionDuration)
@ -411,15 +405,15 @@ class Modal {
_triggerBackdropTransition() {
if (this._config.backdrop === 'static') {
const hideEvent = EventHandler.trigger(this._element, Event.HIDE_PREVENTED)
const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
if (hideEvent.defaultPrevented) {
return
}
this._element.classList.add(ClassName.STATIC)
this._element.classList.add(CLASS_NAME_STATIC)
const modalTransitionDuration = getTransitionDurationFromElement(this._element)
EventHandler.one(this._element, TRANSITION_END, () => {
this._element.classList.remove(ClassName.STATIC)
this._element.classList.remove(CLASS_NAME_STATIC)
})
emulateTransitionEnd(this._element, modalTransitionDuration)
this._element.focus()
@ -462,7 +456,7 @@ class Modal {
// while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
// Adjust fixed content padding
makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
makeArray(SelectorEngine.find(SELECTOR_FIXED_CONTENT))
.forEach(element => {
const actualPadding = element.style.paddingRight
const calculatedPadding = window.getComputedStyle(element)['padding-right']
@ -471,7 +465,7 @@ class Modal {
})
// Adjust sticky content margin
makeArray(SelectorEngine.find(Selector.STICKY_CONTENT))
makeArray(SelectorEngine.find(SELECTOR_STICKY_CONTENT))
.forEach(element => {
const actualMargin = element.style.marginRight
const calculatedMargin = window.getComputedStyle(element)['margin-right']
@ -487,12 +481,12 @@ class Modal {
document.body.style.paddingRight = `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`
}
document.body.classList.add(ClassName.OPEN)
document.body.classList.add(CLASS_NAME_OPEN)
}
_resetScrollbar() {
// Restore fixed content padding
makeArray(SelectorEngine.find(Selector.FIXED_CONTENT))
makeArray(SelectorEngine.find(SELECTOR_FIXED_CONTENT))
.forEach(element => {
const padding = Manipulator.getDataAttribute(element, 'padding-right')
if (typeof padding !== 'undefined') {
@ -502,7 +496,7 @@ class Modal {
})
// Restore sticky content and navbar-toggler margin
makeArray(SelectorEngine.find(`${Selector.STICKY_CONTENT}`))
makeArray(SelectorEngine.find(`${SELECTOR_STICKY_CONTENT}`))
.forEach(element => {
const margin = Manipulator.getDataAttribute(element, 'margin-right')
if (typeof margin !== 'undefined') {
@ -523,7 +517,7 @@ class Modal {
_getScrollbarWidth() { // thx d.walsh
const scrollDiv = document.createElement('div')
scrollDiv.className = ClassName.SCROLLBAR_MEASURER
scrollDiv.className = CLASS_NAME_SCROLLBAR_MEASURER
document.body.appendChild(scrollDiv)
const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth
document.body.removeChild(scrollDiv)
@ -568,20 +562,20 @@ 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) {
const target = getElementFromSelector(this)
if (this.tagName === 'A' || this.tagName === 'AREA') {
event.preventDefault()
}
EventHandler.one(target, Event.SHOW, showEvent => {
EventHandler.one(target, EVENT_SHOW, showEvent => {
if (showEvent.defaultPrevented) {
// only register focus restorer if modal will actually get shown
return
}
EventHandler.one(target, Event.HIDDEN, () => {
EventHandler.one(target, EVENT_HIDDEN, () => {
if (isVisible(this)) {
this.focus()
}

View File

@ -39,16 +39,6 @@ const DefaultType = {
content: '(string|element|function)'
}
const ClassName = {
FADE: 'fade',
SHOW: 'show'
}
const Selector = {
TITLE: '.popover-header',
CONTENT: '.popover-body'
}
const Event = {
HIDE: `hide${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
@ -62,6 +52,12 @@ const Event = {
MOUSELEAVE: `mouseleave${EVENT_KEY}`
}
const CLASS_NAME_FADE = 'fade'
const CLASS_NAME_SHOW = 'show'
const SELECTOR_TITLE = '.popover-header'
const SELECTOR_CONTENT = '.popover-body'
/**
* ------------------------------------------------------------------------
* Class Definition
@ -109,16 +105,16 @@ class Popover extends Tooltip {
const tip = this.getTipElement()
// we use append for html objects to maintain js events
this.setElementContent(SelectorEngine.findOne(Selector.TITLE, tip), this.getTitle())
this.setElementContent(SelectorEngine.findOne(SELECTOR_TITLE, tip), this.getTitle())
let content = this._getContent()
if (typeof content === 'function') {
content = content.call(this.element)
}
this.setElementContent(SelectorEngine.findOne(Selector.CONTENT, tip), content)
this.setElementContent(SelectorEngine.findOne(SELECTOR_CONTENT, tip), content)
tip.classList.remove(ClassName.FADE)
tip.classList.remove(ClassName.SHOW)
tip.classList.remove(CLASS_NAME_FADE)
tip.classList.remove(CLASS_NAME_SHOW)
}
_addAttachmentClass(attachment) {

View File

@ -41,31 +41,23 @@ const DefaultType = {
target: '(string|element)'
}
const Event = {
ACTIVATE: `activate${EVENT_KEY}`,
SCROLL: `scroll${EVENT_KEY}`,
LOAD_DATA_API: `load${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_ACTIVATE = `activate${EVENT_KEY}`
const EVENT_SCROLL = `scroll${EVENT_KEY}`
const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
const ClassName = {
DROPDOWN_ITEM: 'dropdown-item',
ACTIVE: 'active'
}
const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'
const CLASS_NAME_ACTIVE = 'active'
const Selector = {
DATA_SPY: '[data-spy="scroll"]',
NAV_LIST_GROUP: '.nav, .list-group',
NAV_LINKS: '.nav-link',
NAV_ITEMS: '.nav-item',
LIST_ITEMS: '.list-group-item',
DROPDOWN: '.dropdown',
DROPDOWN_TOGGLE: '.dropdown-toggle'
}
const SELECTOR_DATA_SPY = '[data-spy="scroll"]'
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
const SELECTOR_NAV_LINKS = '.nav-link'
const SELECTOR_NAV_ITEMS = '.nav-item'
const SELECTOR_LIST_ITEMS = '.list-group-item'
const SELECTOR_DROPDOWN = '.dropdown'
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
const OffsetMethod = {
OFFSET: 'offset',
POSITION: 'position'
}
const METHOD_OFFSET = 'offset'
const METHOD_POSITION = 'position'
/**
* ------------------------------------------------------------------------
@ -78,15 +70,15 @@ class ScrollSpy {
this._element = element
this._scrollElement = element.tagName === 'BODY' ? window : element
this._config = this._getConfig(config)
this._selector = `${this._config.target} ${Selector.NAV_LINKS},` +
`${this._config.target} ${Selector.LIST_ITEMS},` +
`${this._config.target} .${ClassName.DROPDOWN_ITEM}`
this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS},` +
`${this._config.target} ${SELECTOR_LIST_ITEMS},` +
`${this._config.target} .${CLASS_NAME_DROPDOWN_ITEM}`
this._offsets = []
this._targets = []
this._activeTarget = null
this._scrollHeight = 0
EventHandler.on(this._scrollElement, Event.SCROLL, event => this._process(event))
EventHandler.on(this._scrollElement, EVENT_SCROLL, event => this._process(event))
this.refresh()
this._process()
@ -108,14 +100,14 @@ class ScrollSpy {
refresh() {
const autoMethod = this._scrollElement === this._scrollElement.window ?
OffsetMethod.OFFSET :
OffsetMethod.POSITION
METHOD_OFFSET :
METHOD_POSITION
const offsetMethod = this._config.method === 'auto' ?
autoMethod :
this._config.method
const offsetBase = offsetMethod === OffsetMethod.POSITION ?
const offsetBase = offsetMethod === METHOD_POSITION ?
this._getScrollTop() :
0
@ -261,42 +253,42 @@ class ScrollSpy {
const link = SelectorEngine.findOne(queries.join(','))
if (link.classList.contains(ClassName.DROPDOWN_ITEM)) {
if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
SelectorEngine
.findOne(Selector.DROPDOWN_TOGGLE, SelectorEngine.closest(link, Selector.DROPDOWN))
.classList.add(ClassName.ACTIVE)
.findOne(SELECTOR_DROPDOWN_TOGGLE, SelectorEngine.closest(link, SELECTOR_DROPDOWN))
.classList.add(CLASS_NAME_ACTIVE)
link.classList.add(ClassName.ACTIVE)
link.classList.add(CLASS_NAME_ACTIVE)
} else {
// Set triggered link as active
link.classList.add(ClassName.ACTIVE)
link.classList.add(CLASS_NAME_ACTIVE)
SelectorEngine
.parents(link, Selector.NAV_LIST_GROUP)
.parents(link, SELECTOR_NAV_LIST_GROUP)
.forEach(listGroup => {
// Set triggered links parents as active
// With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
SelectorEngine.prev(listGroup, `${Selector.NAV_LINKS}, ${Selector.LIST_ITEMS}`)
.forEach(item => item.classList.add(ClassName.ACTIVE))
SelectorEngine.prev(listGroup, `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)
.forEach(item => item.classList.add(CLASS_NAME_ACTIVE))
// Handle special case when .nav-link is inside .nav-item
SelectorEngine.prev(listGroup, Selector.NAV_ITEMS)
SelectorEngine.prev(listGroup, SELECTOR_NAV_ITEMS)
.forEach(navItem => {
SelectorEngine.children(navItem, Selector.NAV_LINKS)
.forEach(item => item.classList.add(ClassName.ACTIVE))
SelectorEngine.children(navItem, SELECTOR_NAV_LINKS)
.forEach(item => item.classList.add(CLASS_NAME_ACTIVE))
})
})
}
EventHandler.trigger(this._scrollElement, Event.ACTIVATE, {
EventHandler.trigger(this._scrollElement, EVENT_ACTIVATE, {
relatedTarget: target
})
}
_clear() {
makeArray(SelectorEngine.find(this._selector))
.filter(node => node.classList.contains(ClassName.ACTIVE))
.forEach(node => node.classList.remove(ClassName.ACTIVE))
.filter(node => node.classList.contains(CLASS_NAME_ACTIVE))
.forEach(node => node.classList.remove(CLASS_NAME_ACTIVE))
}
// Static
@ -331,8 +323,8 @@ class ScrollSpy {
* ------------------------------------------------------------------------
*/
EventHandler.on(window, Event.LOAD_DATA_API, () => {
makeArray(SelectorEngine.find(Selector.DATA_SPY))
EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
makeArray(SelectorEngine.find(SELECTOR_DATA_SPY))
.forEach(spy => new ScrollSpy(spy, Manipulator.getDataAttributes(spy)))
})

View File

@ -30,31 +30,25 @@ const DATA_KEY = 'bs.tab'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'
const Event = {
HIDE: `hide${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
SHOW: `show${EVENT_KEY}`,
SHOWN: `shown${EVENT_KEY}`,
CLICK_DATA_API: `click${EVENT_KEY}${DATA_API_KEY}`
}
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const ClassName = {
DROPDOWN_MENU: 'dropdown-menu',
ACTIVE: 'active',
DISABLED: 'disabled',
FADE: 'fade',
SHOW: 'show'
}
const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'
const CLASS_NAME_ACTIVE = 'active'
const CLASS_NAME_DISABLED = 'disabled'
const CLASS_NAME_FADE = 'fade'
const CLASS_NAME_SHOW = 'show'
const Selector = {
DROPDOWN: '.dropdown',
NAV_LIST_GROUP: '.nav, .list-group',
ACTIVE: '.active',
ACTIVE_UL: ':scope > li > .active',
DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
DROPDOWN_TOGGLE: '.dropdown-toggle',
DROPDOWN_ACTIVE_CHILD: ':scope > .dropdown-menu .active'
}
const SELECTOR_DROPDOWN = '.dropdown'
const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
const SELECTOR_ACTIVE = '.active'
const SELECTOR_ACTIVE_UL = ':scope > li > .active'
const SELECTOR_DATA_TOGGLE = '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]'
const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
const SELECTOR_DROPDOWN_ACTIVE_CHILD = ':scope > .dropdown-menu .active'
/**
* ------------------------------------------------------------------------
@ -80,17 +74,17 @@ class Tab {
show() {
if ((this._element.parentNode &&
this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
this._element.classList.contains(ClassName.ACTIVE)) ||
this._element.classList.contains(ClassName.DISABLED)) {
this._element.classList.contains(CLASS_NAME_ACTIVE)) ||
this._element.classList.contains(CLASS_NAME_DISABLED)) {
return
}
let previous
const target = getElementFromSelector(this._element)
const listElement = SelectorEngine.closest(this._element, Selector.NAV_LIST_GROUP)
const listElement = SelectorEngine.closest(this._element, SELECTOR_NAV_LIST_GROUP)
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 = makeArray(SelectorEngine.find(itemSelector, listElement))
previous = previous[previous.length - 1]
}
@ -98,12 +92,12 @@ class Tab {
let hideEvent = null
if (previous) {
hideEvent = EventHandler.trigger(previous, Event.HIDE, {
hideEvent = EventHandler.trigger(previous, EVENT_HIDE, {
relatedTarget: this._element
})
}
const showEvent = EventHandler.trigger(this._element, Event.SHOW, {
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
relatedTarget: previous
})
@ -118,10 +112,10 @@ class Tab {
)
const complete = () => {
EventHandler.trigger(previous, Event.HIDDEN, {
EventHandler.trigger(previous, EVENT_HIDDEN, {
relatedTarget: this._element
})
EventHandler.trigger(this._element, Event.SHOWN, {
EventHandler.trigger(this._element, EVENT_SHOWN, {
relatedTarget: previous
})
}
@ -142,12 +136,12 @@ class Tab {
_activate(element, container, callback) {
const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?
SelectorEngine.find(Selector.ACTIVE_UL, container) :
SelectorEngine.children(container, Selector.ACTIVE)
SelectorEngine.find(SELECTOR_ACTIVE_UL, container) :
SelectorEngine.children(container, SELECTOR_ACTIVE)
const active = activeElements[0]
const isTransitioning = callback &&
(active && active.classList.contains(ClassName.FADE))
(active && active.classList.contains(CLASS_NAME_FADE))
const complete = () => this._transitionComplete(
element,
@ -157,7 +151,7 @@ class Tab {
if (active && isTransitioning) {
const transitionDuration = getTransitionDurationFromElement(active)
active.classList.remove(ClassName.SHOW)
active.classList.remove(CLASS_NAME_SHOW)
EventHandler.one(active, TRANSITION_END, complete)
emulateTransitionEnd(active, transitionDuration)
@ -168,12 +162,12 @@ class Tab {
_transitionComplete(element, active, callback) {
if (active) {
active.classList.remove(ClassName.ACTIVE)
active.classList.remove(CLASS_NAME_ACTIVE)
const dropdownChild = SelectorEngine.findOne(Selector.DROPDOWN_ACTIVE_CHILD, active.parentNode)
const dropdownChild = SelectorEngine.findOne(SELECTOR_DROPDOWN_ACTIVE_CHILD, active.parentNode)
if (dropdownChild) {
dropdownChild.classList.remove(ClassName.ACTIVE)
dropdownChild.classList.remove(CLASS_NAME_ACTIVE)
}
if (active.getAttribute('role') === 'tab') {
@ -181,23 +175,23 @@ class Tab {
}
}
element.classList.add(ClassName.ACTIVE)
element.classList.add(CLASS_NAME_ACTIVE)
if (element.getAttribute('role') === 'tab') {
element.setAttribute('aria-selected', true)
}
reflow(element)
if (element.classList.contains(ClassName.FADE)) {
element.classList.add(ClassName.SHOW)
if (element.classList.contains(CLASS_NAME_FADE)) {
element.classList.add(CLASS_NAME_SHOW)
}
if (element.parentNode && element.parentNode.classList.contains(ClassName.DROPDOWN_MENU)) {
const dropdownElement = SelectorEngine.closest(element, Selector.DROPDOWN)
if (element.parentNode && element.parentNode.classList.contains(CLASS_NAME_DROPDOWN_MENU)) {
const dropdownElement = SelectorEngine.closest(element, SELECTOR_DROPDOWN)
if (dropdownElement) {
makeArray(SelectorEngine.find(Selector.DROPDOWN_TOGGLE))
.forEach(dropdown => dropdown.classList.add(ClassName.ACTIVE))
makeArray(SelectorEngine.find(SELECTOR_DROPDOWN_TOGGLE))
.forEach(dropdown => dropdown.classList.add(CLASS_NAME_ACTIVE))
}
element.setAttribute('aria-expanded', true)
@ -235,7 +229,7 @@ class Tab {
* ------------------------------------------------------------------------
*/
EventHandler.on(document, Event.CLICK_DATA_API, Selector.DATA_TOGGLE, function (event) {
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault()
const data = Data.getData(this, DATA_KEY) || new Tab(this)

View File

@ -28,20 +28,16 @@ const VERSION = '4.3.1'
const DATA_KEY = 'bs.toast'
const EVENT_KEY = `.${DATA_KEY}`
const Event = {
CLICK_DISMISS: `click.dismiss${EVENT_KEY}`,
HIDE: `hide${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
SHOW: `show${EVENT_KEY}`,
SHOWN: `shown${EVENT_KEY}`
}
const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const ClassName = {
FADE: 'fade',
HIDE: 'hide',
SHOW: 'show',
SHOWING: 'showing'
}
const CLASS_NAME_FADE = 'fade'
const CLASS_NAME_HIDE = 'hide'
const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_SHOWING = 'showing'
const DefaultType = {
animation: 'boolean',
@ -55,9 +51,7 @@ const Default = {
delay: 500
}
const Selector = {
DATA_DISMISS: '[data-dismiss="toast"]'
}
const SELECTOR_DATA_DISMISS = '[data-dismiss="toast"]'
/**
* ------------------------------------------------------------------------
@ -91,21 +85,21 @@ class Toast {
// Public
show() {
const showEvent = EventHandler.trigger(this._element, Event.SHOW)
const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)
if (showEvent.defaultPrevented) {
return
}
if (this._config.animation) {
this._element.classList.add(ClassName.FADE)
this._element.classList.add(CLASS_NAME_FADE)
}
const complete = () => {
this._element.classList.remove(ClassName.SHOWING)
this._element.classList.add(ClassName.SHOW)
this._element.classList.remove(CLASS_NAME_SHOWING)
this._element.classList.add(CLASS_NAME_SHOW)
EventHandler.trigger(this._element, Event.SHOWN)
EventHandler.trigger(this._element, EVENT_SHOWN)
if (this._config.autohide) {
this._timeout = setTimeout(() => {
@ -114,9 +108,9 @@ class Toast {
}
}
this._element.classList.remove(ClassName.HIDE)
this._element.classList.remove(CLASS_NAME_HIDE)
reflow(this._element)
this._element.classList.add(ClassName.SHOWING)
this._element.classList.add(CLASS_NAME_SHOWING)
if (this._config.animation) {
const transitionDuration = getTransitionDurationFromElement(this._element)
@ -128,22 +122,22 @@ class Toast {
}
hide() {
if (!this._element.classList.contains(ClassName.SHOW)) {
if (!this._element.classList.contains(CLASS_NAME_SHOW)) {
return
}
const hideEvent = EventHandler.trigger(this._element, Event.HIDE)
const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
if (hideEvent.defaultPrevented) {
return
}
const complete = () => {
this._element.classList.add(ClassName.HIDE)
EventHandler.trigger(this._element, Event.HIDDEN)
this._element.classList.add(CLASS_NAME_HIDE)
EventHandler.trigger(this._element, EVENT_HIDDEN)
}
this._element.classList.remove(ClassName.SHOW)
this._element.classList.remove(CLASS_NAME_SHOW)
if (this._config.animation) {
const transitionDuration = getTransitionDurationFromElement(this._element)
@ -158,11 +152,11 @@ class Toast {
clearTimeout(this._timeout)
this._timeout = null
if (this._element.classList.contains(ClassName.SHOW)) {
this._element.classList.remove(ClassName.SHOW)
if (this._element.classList.contains(CLASS_NAME_SHOW)) {
this._element.classList.remove(CLASS_NAME_SHOW)
}
EventHandler.off(this._element, Event.CLICK_DISMISS)
EventHandler.off(this._element, EVENT_CLICK_DISMISS)
Data.removeData(this._element, DATA_KEY)
this._element = null
@ -190,8 +184,8 @@ class Toast {
_setListeners() {
EventHandler.on(
this._element,
Event.CLICK_DISMISS,
Selector.DATA_DISMISS,
EVENT_CLICK_DISMISS,
SELECTOR_DATA_DISMISS,
() => this.hide()
)
}

View File

@ -89,11 +89,6 @@ const Default = {
popperConfig: null
}
const HoverState = {
SHOW: 'show',
OUT: 'out'
}
const Event = {
HIDE: `hide${EVENT_KEY}`,
HIDDEN: `hidden${EVENT_KEY}`,
@ -107,22 +102,19 @@ const Event = {
MOUSELEAVE: `mouseleave${EVENT_KEY}`
}
const ClassName = {
FADE: 'fade',
MODAL: 'modal',
SHOW: 'show'
}
const CLASS_NAME_FADE = 'fade'
const CLASS_NAME_MODAL = 'modal'
const CLASS_NAME_SHOW = 'show'
const Selector = {
TOOLTIP_INNER: '.tooltip-inner'
}
const HOVER_STATE_SHOW = 'show'
const HOVER_STATE_OUT = 'out'
const Trigger = {
HOVER: 'hover',
FOCUS: 'focus',
CLICK: 'click',
MANUAL: 'manual'
}
const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'
const TRIGGER_HOVER = 'hover'
const TRIGGER_FOCUS = 'focus'
const TRIGGER_CLICK = 'click'
const TRIGGER_MANUAL = 'manual'
/**
* ------------------------------------------------------------------------
@ -221,7 +213,7 @@ class Tooltip {
context._leave(null, context)
}
} else {
if (this.getTipElement().classList.contains(ClassName.SHOW)) {
if (this.getTipElement().classList.contains(CLASS_NAME_SHOW)) {
this._leave(null, this)
return
}
@ -236,7 +228,7 @@ class Tooltip {
Data.removeData(this.element, this.constructor.DATA_KEY)
EventHandler.off(this.element, this.constructor.EVENT_KEY)
EventHandler.off(SelectorEngine.closest(this.element, `.${ClassName.MODAL}`), 'hide.bs.modal', this._hideModalHandler)
EventHandler.off(SelectorEngine.closest(this.element, `.${CLASS_NAME_MODAL}`), 'hide.bs.modal', this._hideModalHandler)
if (this.tip) {
this.tip.parentNode.removeChild(this.tip)
@ -281,7 +273,7 @@ class Tooltip {
this.setContent()
if (this.config.animation) {
tip.classList.add(ClassName.FADE)
tip.classList.add(CLASS_NAME_FADE)
}
const placement = typeof this.config.placement === 'function' ?
@ -302,7 +294,7 @@ class Tooltip {
this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment))
tip.classList.add(ClassName.SHOW)
tip.classList.add(CLASS_NAME_SHOW)
// If this is a touch-enabled device we add extra
// empty mouseover listeners to the body's immediate children;
@ -324,12 +316,12 @@ class Tooltip {
EventHandler.trigger(this.element, this.constructor.Event.SHOWN)
if (prevHoverState === HoverState.OUT) {
if (prevHoverState === HOVER_STATE_OUT) {
this._leave(null, this)
}
}
if (this.tip.classList.contains(ClassName.FADE)) {
if (this.tip.classList.contains(CLASS_NAME_FADE)) {
const transitionDuration = getTransitionDurationFromElement(this.tip)
EventHandler.one(this.tip, TRANSITION_END, complete)
emulateTransitionEnd(this.tip, transitionDuration)
@ -342,7 +334,7 @@ class Tooltip {
hide() {
const tip = this.getTipElement()
const complete = () => {
if (this._hoverState !== HoverState.SHOW && tip.parentNode) {
if (this._hoverState !== HOVER_STATE_SHOW && tip.parentNode) {
tip.parentNode.removeChild(tip)
}
@ -357,7 +349,7 @@ class Tooltip {
return
}
tip.classList.remove(ClassName.SHOW)
tip.classList.remove(CLASS_NAME_SHOW)
// If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
@ -366,11 +358,11 @@ class Tooltip {
.forEach(element => EventHandler.off(element, 'mouseover', noop))
}
this._activeTrigger[Trigger.CLICK] = false
this._activeTrigger[Trigger.FOCUS] = false
this._activeTrigger[Trigger.HOVER] = false
this._activeTrigger[TRIGGER_CLICK] = false
this._activeTrigger[TRIGGER_FOCUS] = false
this._activeTrigger[TRIGGER_HOVER] = false
if (this.tip.classList.contains(ClassName.FADE)) {
if (this.tip.classList.contains(CLASS_NAME_FADE)) {
const transitionDuration = getTransitionDurationFromElement(tip)
EventHandler.one(tip, TRANSITION_END, complete)
@ -408,9 +400,9 @@ class Tooltip {
setContent() {
const tip = this.getTipElement()
this.setElementContent(SelectorEngine.findOne(Selector.TOOLTIP_INNER, tip), this.getTitle())
tip.classList.remove(ClassName.FADE)
tip.classList.remove(ClassName.SHOW)
this.setElementContent(SelectorEngine.findOne(SELECTOR_TOOLTIP_INNER, tip), this.getTitle())
tip.classList.remove(CLASS_NAME_FADE)
tip.classList.remove(CLASS_NAME_SHOW)
}
setElementContent(element, content) {
@ -539,11 +531,11 @@ class Tooltip {
this.config.selector,
event => this.toggle(event)
)
} else if (trigger !== Trigger.MANUAL) {
const eventIn = trigger === Trigger.HOVER ?
} else if (trigger !== TRIGGER_MANUAL) {
const eventIn = trigger === TRIGGER_HOVER ?
this.constructor.Event.MOUSEENTER :
this.constructor.Event.FOCUSIN
const eventOut = trigger === Trigger.HOVER ?
const eventOut = trigger === TRIGGER_HOVER ?
this.constructor.Event.MOUSELEAVE :
this.constructor.Event.FOCUSOUT
@ -566,7 +558,7 @@ class Tooltip {
}
}
EventHandler.on(SelectorEngine.closest(this.element, `.${ClassName.MODAL}`),
EventHandler.on(SelectorEngine.closest(this.element, `.${CLASS_NAME_MODAL}`),
'hide.bs.modal',
this._hideModalHandler
)
@ -609,19 +601,19 @@ class Tooltip {
if (event) {
context._activeTrigger[
event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER
event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER
] = true
}
if (context.getTipElement().classList.contains(ClassName.SHOW) ||
context._hoverState === HoverState.SHOW) {
context._hoverState = HoverState.SHOW
if (context.getTipElement().classList.contains(CLASS_NAME_SHOW) ||
context._hoverState === HOVER_STATE_SHOW) {
context._hoverState = HOVER_STATE_SHOW
return
}
clearTimeout(context._timeout)
context._hoverState = HoverState.SHOW
context._hoverState = HOVER_STATE_SHOW
if (!context.config.delay || !context.config.delay.show) {
context.show()
@ -629,7 +621,7 @@ class Tooltip {
}
context._timeout = setTimeout(() => {
if (context._hoverState === HoverState.SHOW) {
if (context._hoverState === HOVER_STATE_SHOW) {
context.show()
}
}, context.config.delay.show)
@ -649,7 +641,7 @@ class Tooltip {
if (event) {
context._activeTrigger[
event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER
event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER
] = false
}
@ -659,7 +651,7 @@ class Tooltip {
clearTimeout(context._timeout)
context._hoverState = HoverState.OUT
context._hoverState = HOVER_STATE_OUT
if (!context.config.delay || !context.config.delay.hide) {
context.hide()
@ -667,7 +659,7 @@ class Tooltip {
}
context._timeout = setTimeout(() => {
if (context._hoverState === HoverState.OUT) {
if (context._hoverState === HOVER_STATE_OUT) {
context.hide()
}
}, context.config.delay.hide)
@ -768,7 +760,7 @@ class Tooltip {
return
}
tip.classList.remove(ClassName.FADE)
tip.classList.remove(CLASS_NAME_FADE)
this.config.animation = false
this.hide()
this.show()

View File

@ -10,7 +10,13 @@ const MILLISECONDS_MULTIPLIER = 1000
const TRANSITION_END = 'transitionend'
// Shoutout AngusCroll (https://goo.gl/pxwQGp)
const toType = obj => ({}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase())
const toType = obj => {
if (obj === null || obj === undefined) {
return `${obj}`
}
return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase()
}
/**
* --------------------------------------------------------------------------
@ -81,10 +87,7 @@ const getTransitionDurationFromElement = element => {
}
const triggerTransitionEnd = element => {
const evt = document.createEvent('HTMLEvents')
evt.initEvent(TRANSITION_END, true, true)
element.dispatchEvent(evt)
element.dispatchEvent(new Event(TRANSITION_END))
}
const isElement = obj => (obj[0] || obj).nodeType

View File

@ -30,13 +30,6 @@ const browsers = {
browser: 'Edge',
browser_version: 'latest'
},
ie11Win10: {
base: 'BrowserStack',
os: 'Windows',
os_version: '10',
browser: 'IE',
browser_version: '11.0'
},
chromeWin10: {
base: 'BrowserStack',
os: 'Windows',

View File

@ -653,7 +653,6 @@ describe('Modal', () => {
it('should enforce focus', done => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog" /></div>'
const isIE11 = Boolean(window.MSInputMethodContext) && Boolean(document.documentMode)
const modalEl = fixtureEl.querySelector('.modal')
const modal = new Modal(modalEl)
@ -668,11 +667,6 @@ describe('Modal', () => {
modalEl.addEventListener('shown.bs.modal', () => {
expect(modal._enforceFocus).toHaveBeenCalled()
if (isIE11) {
done()
return
}
spyOn(modal._element, 'focus')
document.addEventListener('focusin', focusInListener)

View File

@ -198,8 +198,9 @@ describe('Util', () => {
})
describe('typeCheckConfig', () => {
const namePlugin = 'collapse'
it('should check type of the config object', () => {
const namePlugin = 'collapse'
const defaultType = {
toggle: 'boolean',
parent: '(string|element)'
@ -213,6 +214,34 @@ describe('Util', () => {
Util.typeCheckConfig(namePlugin, config, defaultType)
}).toThrow(new Error('COLLAPSE: Option "parent" provided type "number" but expected type "(string|element)".'))
})
it('should return null stringified when null is passed', () => {
const defaultType = {
toggle: 'boolean',
parent: '(null|element)'
}
const config = {
toggle: true,
parent: null
}
Util.typeCheckConfig(namePlugin, config, defaultType)
expect().nothing()
})
it('should return undefined stringified when undefined is passed', () => {
const defaultType = {
toggle: 'boolean',
parent: '(undefined|element)'
}
const config = {
toggle: true,
parent: undefined
}
Util.typeCheckConfig(namePlugin, config, defaultType)
expect().nothing()
})
})
describe('makeArray', () => {

242
package-lock.json generated
View File

@ -82,9 +82,9 @@
}
},
"@babel/generator": {
"version": "7.8.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.7.tgz",
"integrity": "sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew==",
"version": "7.8.8",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.8.8.tgz",
"integrity": "sha512-HKyUVu69cZoclptr8t8U5b6sx6zoWjh8jiUhnuj3MpZuKT2dJ8zPTuiy31luq32swhI0SpwItCIlU8XW7BZeJg==",
"dev": true,
"requires": {
"@babel/types": "^7.8.7",
@ -137,14 +137,14 @@
}
},
"@babel/helper-create-regexp-features-plugin": {
"version": "7.8.6",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.6.tgz",
"integrity": "sha512-bPyujWfsHhV/ztUkwGHz/RPV1T1TDEsSZDsN42JPehndA+p1KKTh3npvTadux0ZhCrytx9tvjpWNowKby3tM6A==",
"version": "7.8.8",
"resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz",
"integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.8.3",
"@babel/helper-regex": "^7.8.3",
"regexpu-core": "^4.6.0"
"regexpu-core": "^4.7.0"
}
},
"@babel/helper-define-map": {
@ -333,9 +333,9 @@
}
},
"@babel/parser": {
"version": "7.8.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.7.tgz",
"integrity": "sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A==",
"version": "7.8.8",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.8.8.tgz",
"integrity": "sha512-mO5GWzBPsPf6865iIbzNE0AvkKF3NE+2S3eRUpE+FE07BOAkXh6G+GW/Pj01hhXjve1WScbaIO4UlY1JKeqCcA==",
"dev": true
},
"@babel/plugin-proposal-async-generator-functions": {
@ -410,12 +410,12 @@
}
},
"@babel/plugin-proposal-unicode-property-regex": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz",
"integrity": "sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ==",
"version": "7.8.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz",
"integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==",
"dev": true,
"requires": {
"@babel/helper-create-regexp-features-plugin": "^7.8.3",
"@babel/helper-create-regexp-features-plugin": "^7.8.8",
"@babel/helper-plugin-utils": "^7.8.3"
}
},
@ -556,9 +556,9 @@
}
},
"@babel/plugin-transform-destructuring": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz",
"integrity": "sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==",
"version": "7.8.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz",
"integrity": "sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.8.3"
@ -704,9 +704,9 @@
}
},
"@babel/plugin-transform-parameters": {
"version": "7.8.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.7.tgz",
"integrity": "sha512-brYWaEPTRimOctz2NDA3jnBbDi7SVN2T4wYuu0aqSzxC3nozFZngGaw29CJ9ZPweB7k+iFmZuoG3IVPIcXmD2g==",
"version": "7.8.8",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.8.tgz",
"integrity": "sha512-hC4Ld/Ulpf1psQciWWwdnUspQoQco2bMzSrwU6TmzRlvoYQe4rQFy9vnCZDTlVeCQj0JPfL+1RX0V8hCJvkgBA==",
"dev": true,
"requires": {
"@babel/helper-call-delegate": "^7.8.7",
@ -1046,9 +1046,9 @@
"dev": true
},
"@types/node": {
"version": "13.7.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.7.7.tgz",
"integrity": "sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg==",
"version": "13.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.1.tgz",
"integrity": "sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ==",
"dev": true
},
"@types/normalize-package-data": {
@ -1955,11 +1955,13 @@
}
},
"bl": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.1.tgz",
"integrity": "sha512-FL/TdvchukRCuWVxT0YMO/7+L5TNeNrVFvRU2IY63aUyv9mpt8splf2NEr6qXtPo5fya5a66YohQKvGNmLrWNA==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
"integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
"dev": true,
"requires": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
},
"dependencies": {
@ -2385,9 +2387,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001032",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001032.tgz",
"integrity": "sha512-8joOm7BwcpEN4BfVHtfh0hBXSAPVYk+eUIcNntGtMkUWy/6AKRCDZINCLe3kB1vHhT2vBxBF85Hh9VlPXi/qjA==",
"version": "1.0.30001035",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001035.tgz",
"integrity": "sha512-C1ZxgkuA4/bUEdMbU5WrGY4+UhMFFiXrgNAfxiMIqWgFTWfv/xsZCS2xEHT2LMq7xAZfuAnu6mcqyDl0ZR6wLQ==",
"dev": true
},
"capture-stack-trace": {
@ -3633,9 +3635,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.370",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.370.tgz",
"integrity": "sha512-399cXDE9C7qoVF2CUgCA/MLflfvxbo1F0kB/pkB94426freL/JgZ0HNaloomsOfnE+VC/qgTFZqzmivSdaNfPQ==",
"version": "1.3.378",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.378.tgz",
"integrity": "sha512-nBp/AfhaVIOnfwgL1CZxt80IcqWcyYXiX6v5gflAksxy+SzBVz7A7UWR1Nos92c9ofXW74V9PoapzRb0jJfYXw==",
"dev": true
},
"emoji-regex": {
@ -3908,9 +3910,9 @@
}
},
"globals": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz",
"integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==",
"version": "12.4.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
"integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
"dev": true,
"requires": {
"type-fest": "^0.8.1"
@ -4227,12 +4229,12 @@
"dev": true
},
"espree": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.0.tgz",
"integrity": "sha512-Xs8airJ7RQolnDIbLtRutmfvSsAe0xqMMAantCN/GMoqf81TFbeI1T7Jpd56qYu1uuh32dOG5W/X9uO+ghPXzA==",
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
"integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
"dev": true,
"requires": {
"acorn": "^7.1.0",
"acorn": "^7.1.1",
"acorn-jsx": "^5.2.0",
"eslint-visitor-keys": "^1.1.0"
}
@ -5580,9 +5582,9 @@
}
},
"gaxios": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.3.2.tgz",
"integrity": "sha512-K/+py7UvKRDaEwEKlLiRKrFr+wjGjsMz5qH7Vs549QJS7cpSCOT/BbWL7pzqECflc46FcNPipjSfB+V1m8PAhw==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.0.0.tgz",
"integrity": "sha512-9UwpmysNKCwSCSvFqTSTPFZX89RgMpJBFzKknrjpEm6oQGn7QDlFO57mPqJHP9X4llPR8uSt3LAHBZDXoetGnA==",
"dev": true,
"requires": {
"abort-controller": "^3.0.0",
@ -6324,9 +6326,9 @@
"dev": true
},
"in-publish": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
"integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz",
"integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==",
"dev": true
},
"indent-string": {
@ -6370,9 +6372,9 @@
"dev": true
},
"inquirer": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.6.tgz",
"integrity": "sha512-7SVO4h+QIdMq6XcqIqrNte3gS5MzCCKZdsq9DO4PJziBFNYzP3PGFbDjgadDb//MCahzgjCxvQ/O2wa7kx9o4w==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz",
"integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==",
"dev": true,
"requires": {
"ansi-escapes": "^4.2.1",
@ -7140,12 +7142,12 @@
"dev": true
},
"json5": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
"integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.2.tgz",
"integrity": "sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
"minimist": "^1.2.5"
}
},
"jsonexport": {
@ -7583,15 +7585,15 @@
"dev": true
},
"linkinator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/linkinator/-/linkinator-2.0.3.tgz",
"integrity": "sha512-K1AhPAydXL9l4YX0o/FEYQUcBmjQQon3P6xzEZeZvQD1HSpa6FrAVrqZMxaEaDXUc8N1Y7vCmAKKNC6TX+2a5g==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/linkinator/-/linkinator-2.0.4.tgz",
"integrity": "sha512-5CJbZ2CWa2uK/YWvqtglzGuiy8ccYmoCCh+QEmwLa70KDSaphu5/DDbOlPHOSsy5ExN7fnaWtpatmnJi929pBA==",
"dev": true,
"requires": {
"chalk": "^3.0.0",
"cheerio": "^1.0.0-rc.2",
"finalhandler": "^1.1.2",
"gaxios": "^2.0.1",
"gaxios": "^3.0.0",
"jsonexport": "^2.4.1",
"meow": "^6.0.0",
"p-queue": "^6.2.1",
@ -8170,9 +8172,9 @@
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"minimist-options": {
@ -8209,20 +8211,12 @@
}
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
"integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
"dev": true,
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
}
"minimist": "^1.2.5"
}
},
"ms": {
@ -8346,9 +8340,9 @@
}
},
"node-releases": {
"version": "1.1.50",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.50.tgz",
"integrity": "sha512-lgAmPv9eYZ0bGwUYAKlr8MG6K4CvWliWqnkcT2P8mMAgVrH3lqfBPorFlxiG1pHQnqmavJZ9vbMXUTNyMLbrgQ==",
"version": "1.1.52",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.52.tgz",
"integrity": "sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ==",
"dev": true,
"requires": {
"semver": "^6.3.0"
@ -10725,24 +10719,24 @@
"dev": true
},
"regenerate-unicode-properties": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz",
"integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==",
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz",
"integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==",
"dev": true,
"requires": {
"regenerate": "^1.4.0"
}
},
"regenerator-runtime": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz",
"integrity": "sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g==",
"version": "0.13.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
"dev": true
},
"regenerator-transform": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.2.tgz",
"integrity": "sha512-V4+lGplCM/ikqi5/mkkpJ06e9Bujq1NFmNLvsCs56zg3ZbzrnUzAtizZ24TXxtRX/W2jcdScwQCnbL0CICTFkQ==",
"version": "0.14.3",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.3.tgz",
"integrity": "sha512-zXHNKJspmONxBViAb3ZUmFoFPnTBs3zFhCEZJiwp/gkNzxVbTqNJVjYKx6Qk1tQ1P4XLf4TbH9+KBB7wGoAaUw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.8.4",
@ -10773,17 +10767,17 @@
"dev": true
},
"regexpu-core": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz",
"integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==",
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz",
"integrity": "sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ==",
"dev": true,
"requires": {
"regenerate": "^1.4.0",
"regenerate-unicode-properties": "^8.1.0",
"regjsgen": "^0.5.0",
"regjsparser": "^0.6.0",
"regenerate-unicode-properties": "^8.2.0",
"regjsgen": "^0.5.1",
"regjsparser": "^0.6.4",
"unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.1.0"
"unicode-match-property-value-ecmascript": "^1.2.0"
}
},
"registry-auth-token": {
@ -10811,9 +10805,9 @@
"dev": true
},
"regjsparser": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.3.tgz",
"integrity": "sha512-8uZvYbnfAtEm9Ab8NTb3hdLwL4g/LQzEYP7Xs27T96abJCCE2d6r3cPZPQEsLKy0vRSGVNG+/zVGtLr86HQduA==",
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz",
"integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
@ -11048,9 +11042,9 @@
}
},
"rollup": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.0.6.tgz",
"integrity": "sha512-P42IlI6a/bxh52ed8hEXXe44LcHfep2f26OZybMJPN1TTQftibvQEl3CWeOmJrzqGbFxOA000QXDWO9WJaOQpA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.1.0.tgz",
"integrity": "sha512-gfE1455AEazVVTJoeQtcOq/U6GSxwoj4XPSWVsuWmgIxj7sBQNLDOSA82PbdMe+cP8ql8fR1jogPFe8Wg8g4SQ==",
"dev": true,
"requires": {
"fsevents": "~2.1.2"
@ -12745,9 +12739,9 @@
}
},
"stylelint-scss": {
"version": "3.14.2",
"resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.14.2.tgz",
"integrity": "sha512-59/BkIEWyFoORiejDIQB2P2kmg0KcqMn7wtj1y5sRvS4N+Qh+Ng3hbKelOzgS+OM2Ezbai0uEev8xckXxkh9TQ==",
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-3.15.0.tgz",
"integrity": "sha512-c6poL7nsU5XVXxl94jl+RY2Rf3CFfMuL8kWp9PfvDi4A7Op30KGAiIfB5Co1RFKnpIOkzz44EO8ur1T9DEl5mA==",
"dev": true,
"requires": {
"lodash": "^4.17.15",
@ -12857,9 +12851,9 @@
}
},
"tar-stream": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.1.tgz",
"integrity": "sha512-GZjLk64XcE/58qwIc1ZfXGqTSE4OutPMEkfBE/oh9eJ4x1eMRjYkgrLrav7PzddpvIpSJSGi8FgNNYXdB9Vumg==",
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz",
"integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==",
"dev": true,
"requires": {
"bl": "^4.0.1",
@ -12889,9 +12883,9 @@
"dev": true
},
"terser": {
"version": "4.6.6",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.6.tgz",
"integrity": "sha512-4lYPyeNmstjIIESr/ysHg2vUPRGf2tzF9z2yYwnowXVuVzLEamPN1Gfrz7f8I9uEPuHcbFlW4PLIAsJoxXyJ1g==",
"version": "4.6.7",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.6.7.tgz",
"integrity": "sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g==",
"dev": true,
"requires": {
"commander": "^2.20.0",
@ -13207,15 +13201,15 @@
}
},
"unicode-match-property-value-ecmascript": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz",
"integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz",
"integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==",
"dev": true
},
"unicode-property-aliases-ecmascript": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz",
"integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
"integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
"dev": true
},
"unified": {
@ -13918,18 +13912,18 @@
"dev": true
},
"yaml": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.7.2.tgz",
"integrity": "sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw==",
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.2.tgz",
"integrity": "sha512-omakb0d7FjMo3R1D2EbTKVIk6dAVLRxFXdLZMEUToeAvuqgG/YuHMuQOZ5fgk+vQ8cx+cnGKwyg+8g8PNT0xQg==",
"dev": true,
"requires": {
"@babel/runtime": "^7.6.3"
"@babel/runtime": "^7.8.7"
}
},
"yargs": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz",
"integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==",
"version": "15.3.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
"integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
"dev": true,
"requires": {
"cliui": "^6.0.0",
@ -13942,7 +13936,7 @@
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^16.1.0"
"yargs-parser": "^18.1.1"
},
"dependencies": {
"ansi-regex": {
@ -14025,6 +14019,16 @@
"requires": {
"ansi-regex": "^5.0.0"
}
},
"yargs-parser": {
"version": "18.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.1.tgz",
"integrity": "sha512-KRHEsOM16IX7XuLnMOqImcPNbLVXMNHYAoFc3BKR8Ortl5gzDbtXvvEoGx9imk5E+X1VeNKNlcHr8B8vi+7ipA==",
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},

View File

@ -37,9 +37,9 @@
"js-compile-plugins": "node build/build-plugins.js",
"js-lint": "eslint --cache --cache-location .cache/.eslintcache --report-unused-disable-directives .",
"js-minify": "npm-run-all --parallel js-minify-*",
"js-minify-standalone": "terser --compress typeofs=false --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.js.map,includeSources,url=bootstrap.min.js.map\" --output dist/js/bootstrap.min.js dist/js/bootstrap.js",
"js-minify-standalone": "terser --compress --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.js.map,includeSources,url=bootstrap.min.js.map\" --output dist/js/bootstrap.min.js dist/js/bootstrap.js",
"js-minify-standalone-esm": "terser --compress --mangle --comments \"/^!/\" --source-map \"content=dist/js/bootstrap.esm.js.map,includeSources,url=bootstrap.esm.min.js.map\" --output dist/js/bootstrap.esm.min.js dist/js/bootstrap.esm.js",
"js-minify-bundle": "terser --compress typeofs=false --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-test": "npm-run-all --parallel 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",
@ -118,21 +118,21 @@
"karma-jasmine": "^3.1.1",
"karma-jasmine-html-reporter": "^1.5.2",
"karma-rollup-preprocessor": "^7.0.3",
"linkinator": "^2.0.3",
"linkinator": "^2.0.4",
"lockfile-lint": "^4.1.0",
"node-sass": "^4.13.1",
"nodemon": "^2.0.2",
"npm-run-all": "^4.1.5",
"popper.js": "^1.16.0",
"postcss-cli": "^7.1.0",
"rollup": "^2.0.6",
"rollup": "^2.1.0",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-istanbul": "^2.0.1",
"serve": "^11.3.0",
"shelljs": "^0.8.3",
"stylelint": "^13.2.1",
"stylelint-config-twbs-bootstrap": "^2.0.1",
"terser": "^4.6.6",
"terser": "^4.6.7",
"vnu-jar": "20.3.16"
},
"files": [

View File

@ -17,27 +17,13 @@
padding-left: $breadcrumb-item-padding-x;
&::before {
display: inline-block; // Suppress underlining of the separator in modern browsers
display: inline-block; // Suppress underlining of the separator
padding-right: $breadcrumb-item-padding-x;
color: $breadcrumb-divider-color;
content: escape-svg($breadcrumb-divider);
}
}
// IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built
// without `<ul>`s. The `::before` pseudo-element generates an element
// *within* the .breadcrumb-item and thereby inherits the `text-decoration`.
//
// To trick IE into suppressing the underline, we give the pseudo-element an
// underline and then immediately remove it.
+ .breadcrumb-item:hover::before {
text-decoration: underline;
}
// stylelint-disable-next-line no-duplicate-selectors
+ .breadcrumb-item:hover::before {
text-decoration: none;
}
&.active {
color: $breadcrumb-active-color;
}

View File

@ -36,9 +36,6 @@
// Enable `flex-grow: 1` for decks and groups so that card blocks take up
// as much space as possible, ensuring footers are aligned to the bottom.
flex: 1 1 auto;
// Workaround for the image size bug in IE
// See: https://github.com/twbs/bootstrap/pull/28855
min-height: 1px;
padding: $card-spacer-y $card-spacer-x;
color: $card-color;
}
@ -135,7 +132,6 @@
.card-img,
.card-img-top,
.card-img-bottom {
flex-shrink: 0; // For IE: https://github.com/twbs/bootstrap/issues/29396
width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch
}

View File

@ -56,11 +56,9 @@
}
.modal-dialog-scrollable {
display: flex; // IE10/11
max-height: subtract(100%, $modal-dialog-margin * 2);
.modal-content {
max-height: subtract(100vh, $modal-dialog-margin * 2); // IE10/11
overflow: hidden;
}
@ -78,29 +76,6 @@
display: flex;
align-items: center;
min-height: subtract(100%, $modal-dialog-margin * 2);
// Ensure `modal-dialog-centered` extends the full height of the view (IE10/11)
&::before {
display: block; // IE10
height: subtract(100vh, $modal-dialog-margin * 2);
height: min-content; // Reset height to 0 except on IE
content: "";
}
// Ensure `.modal-body` shows scrollbar (IE10/11)
&.modal-dialog-scrollable {
flex-direction: column;
justify-content: center;
height: 100%;
.modal-content {
max-height: none;
}
&::before {
content: none;
}
}
}
// Actual modal
@ -206,19 +181,10 @@
.modal-dialog-scrollable {
max-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
.modal-content {
max-height: subtract(100vh, $modal-dialog-margin-y-sm-up * 2);
}
}
.modal-dialog-centered {
min-height: subtract(100%, $modal-dialog-margin-y-sm-up * 2);
&::before {
height: subtract(100vh, $modal-dialog-margin-y-sm-up * 2);
height: min-content;
}
}
.modal-content {

View File

@ -107,10 +107,10 @@
// the default flexbox row orientation. Requires the use of `flex-wrap: wrap`
// on the `.navbar` parent.
.navbar-collapse {
flex: 1 0 100%;
// For always expanded or extra full navbars, ensure content aligns itself
// properly vertically. Can be easily overridden with flex utilities.
align-items: center;
width: 100%;
}
// Button for toggling the navbar when in its collapsed state
@ -173,9 +173,6 @@
.navbar-collapse {
display: flex !important; // stylelint-disable-line declaration-no-important
// Changes flex-bases to auto because of an IE10 bug
flex-basis: auto;
}
.navbar-toggler {

View File

@ -34,7 +34,7 @@
//
// 1. Remove the margin in all browsers.
// 2. As a best practice, apply a default `background-color`.
// 3. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.
// 3. Prevent adjustments of font size after orientation changes in iOS.
// 4. Change the default tap highlight to be completely transparent in iOS.
body {
@ -145,7 +145,7 @@ p {
// Abbreviations
//
// 1. Duplicate behavior to the data-* attribute for our tooltip plugin
// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
// 3. Add explicit cursor to indicate changed behavior.
// 4. Prevent the text-decoration to be skipped.
@ -344,15 +344,8 @@ figure {
// Images and content
img {
vertical-align: middle;
}
// 1. Workaround for the SVG overflow bug in IE 11 is still required.
// See https://github.com/twbs/bootstrap/issues/26878
img,
svg {
overflow: hidden; // 1
vertical-align: middle;
}
@ -399,7 +392,7 @@ button {
border-radius: 0;
}
// Work around a Firefox/IE bug where the transparent `button` background
// Work around a Firefox bug where the transparent `button` background
// results in a loss of the default `button` focus styles.
// Credit https://github.com/suitcss/base/
@ -487,12 +480,10 @@ input[type="month"] {
-webkit-appearance: textfield;
}
// 1. Remove the default vertical scrollbar in IE.
// 2. Textareas should really only resize vertically so they don't break their (horizontal) containers.
// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers.
textarea {
overflow: auto; // 1
resize: vertical; // 2
resize: vertical; // 1
}
// 1. Browsers set a default `min-width: min-content;` on fieldsets,
@ -510,8 +501,7 @@ fieldset {
}
// 1. By using `float: left`, the legend will behave like a block element
// 2. Correct the color inheritance from `fieldset` elements in IE.
// 3. Correct the text wrapping in Edge and IE.
// 2. Correct the text wrapping in Edge.
legend {
float: left; // 1
@ -521,8 +511,7 @@ legend {
@include font-size($legend-font-size);
font-weight: $legend-font-weight;
line-height: inherit;
color: inherit; // 2
white-space: normal; // 3
white-space: normal; // 2
}
// Fix height of inputs with a type of datetime-local, date, month, week, or time
@ -590,22 +579,6 @@ summary {
}
// Template
//
// Add the correct display for template & main in IE 11
template {
display: none;
}
// Main
main {
display: block;
}
// Progress
//
// Add the correct vertical alignment in Chrome, Firefox, and Opera.

View File

@ -720,7 +720,7 @@ $form-range-thumb-border: 0 !default;
$form-range-thumb-border-radius: 1rem !default;
$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;
$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;
$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge
$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge
$form-range-thumb-active-bg: lighten($component-active-bg, 35%) !default;
$form-range-thumb-disabled-bg: $gray-500 !default;
$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;

View File

@ -22,12 +22,6 @@
@include box-shadow($input-box-shadow);
@include transition($input-transition);
// Unstyle the caret on `<select>`s in IE10+.
&::-ms-expand {
background-color: transparent;
border: 0;
}
// Customize the `:focus` state to imitate native WebKit styles.
&:focus {
color: $input-focus-color;

View File

@ -11,13 +11,6 @@
margin: 0;
opacity: 0;
// Separate rules for :focus and :focus-within as IE doesn't support the latter, and
// thus ignores the entire ruleset. See https://github.com/twbs/bootstrap/pull/29036.
&:focus ~ .form-file-label {
border-color: $form-file-focus-border-color;
box-shadow: $form-file-focus-box-shadow;
}
&:focus-within ~ .form-file-label {
border-color: $form-file-focus-border-color;
box-shadow: $form-file-focus-box-shadow;

View File

@ -37,7 +37,7 @@
// For visual consistency with other platforms/browsers,
// suppress the default white text on blue background highlight given to
// the selected option text when the (still closed) <select> receives focus
// in IE and (under certain conditions) Edge.
// in Edge.
// See https://github.com/twbs/bootstrap/issues/19398.
color: $input-color;
background-color: $input-bg;
@ -57,11 +57,6 @@
border-color: $form-select-disabled-border-color;
}
// Hides the default caret in IE11
&::-ms-expand {
display: none;
}
// Remove outline from select box in FF
&:-moz-focusring {
color: transparent;

View File

@ -463,7 +463,7 @@ In addition to styling the content within cards, Bootstrap includes a few option
### Card groups
Use card groups to render cards as a single, attached element with equal width and height columns. Card groups use `display: flex;` to achieve their uniform sizing.
Use card groups to render cards as a single, attached element with equal width and height columns. Card groups start off stacked and use `display: flex;` to become attached with uniform dimensions starting at the `sm` breakpoint.
{{< example >}}
<div class="card-group">

View File

@ -459,15 +459,15 @@ Use contextual classes to color table rows or individual cells.
<td>Cell</td>
<td>Cell</td>
</tr>
{{< table.inline >}}
{{- range (index $.Site.Data "theme-colors") }}
<tr class="table-{{ .name }}">
<th scope="row">{{ .name | title }}</th>
<td>Cell</td>
<td>Cell</td>
</tr>
{{- end -}}
{{< /table.inline >}}
{{< table.inline >}}
{{- range (index $.Site.Data "theme-colors") }}
<tr class="table-{{ .name }}">
<th scope="row">{{ .name | title }}</th>
<td>Cell</td>
<td>Cell</td>
</tr>
{{- end -}}
{{< /table.inline >}}
</tbody>
</table>
</div>

View File

@ -35,7 +35,7 @@ title: Album example
</div>
</header>
<main role="main">
<main>
<section class="py-5 text-center container">
<div class="row py-lg-5">

View File

@ -82,7 +82,7 @@ include_js: false
</div>
</div>
<main role="main" class="container">
<main class="container">
<div class="row">
<div class="col-md-8 blog-main">
<h3 class="pb-4 mb-4 font-italic border-bottom">

View File

@ -33,7 +33,7 @@ extra_css:
</nav>
</header>
<main role="main">
<main>
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">

View File

@ -20,7 +20,7 @@ include_js: false
</div>
</header>
<main role="main" class="px-3">
<main class="px-3">
<h1>Cover your page.</h1>
<p class="lead">Cover is a one-page template for building simple and beautiful home pages. Download, edit the text, and add your own fullscreen background photo to make it your own.</p>
<p class="lead">

View File

@ -37,13 +37,6 @@ body {
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
}
@supports ((position: -webkit-sticky) or (position: sticky)) {
.sidebar-sticky {
position: -webkit-sticky;
position: sticky;
}
}
.sidebar .nav-link {
font-weight: 500;
color: #333;

View File

@ -27,7 +27,7 @@ extra_js:
<div class="container-fluid">
<div class="row">
<nav id="sidebarMenu" class="col-md-2 d-md-block bg-light sidebar collapse">
<div class="sidebar-sticky">
<div class="position-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">
@ -102,7 +102,7 @@ extra_js:
</div>
</nav>
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
<main class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1>
<div class="btn-toolbar mb-2 mb-md-0">

View File

@ -86,14 +86,3 @@ body {
color: #777;
}
}
/* Fallback for IE
-------------------------------------------------- */
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.form-label-group > label {
display: none;
}
.form-label-group input:-ms-input-placeholder {
color: #777;
}
}

View File

@ -31,7 +31,7 @@ extra_css:
</div>
</nav>
<main role="main" class="container">
<main class="container">
<div class="bg-light p-5 rounded">
<h1>Navbar example</h1>
<p class="lead">This example is a quick exercise to illustrate how fixed to top navbar works. As you scroll, it will remain fixed to the top of your browsers viewport.</p>

View File

@ -31,7 +31,7 @@ extra_css:
</div>
</nav>
<main role="main" class="container">
<main class="container">
<div class="bg-light p-5 rounded">
<h1>Navbar example</h1>
<p class="lead">This example is a quick exercise to illustrate how the top-aligned navbar works. As you scroll, this navbar remains in its original position and moves with the rest of the page.</p>

View File

@ -365,7 +365,7 @@ extra_css:
</div>
</nav>
<main role="main">
<main>
<div class="bg-light p-5 rounded">
<div class="col-sm-8 mx-auto">
<h1>Navbar examples</h1>

View File

@ -63,7 +63,7 @@ body_class: "bg-light"
</nav>
</div>
<main role="main" class="container">
<main class="container">
<div class="d-flex align-items-center p-3 my-3 text-white-50 bg-purple rounded shadow-sm">
<img class="mr-3" src="/docs/{{< param docs_version >}}/assets/brand/bootstrap-outline.svg" alt="" width="48" height="48">
<div class="lh-1">

View File

@ -40,7 +40,7 @@ extra_css:
</div>
</nav>
<main role="main" class="container">
<main class="container">
<div class="starter-template text-center py-5 px-3">
<h1>Bootstrap starter template</h1>

View File

@ -37,7 +37,7 @@ body_class: "d-flex flex-column h-100"
</header>
<!-- Begin page content -->
<main role="main" class="flex-shrink-0">
<main class="flex-shrink-0">
<div class="container">
<h1 class="mt-5">Sticky footer with fixed navbar</h1>
<p class="lead">Pin a footer to the bottom of the viewport in desktop browsers with this custom HTML and CSS. A fixed navbar has been added with <code class="small">padding-top: 60px;</code> on the <code class="small">main &gt; .container</code>.</p>

View File

@ -9,7 +9,7 @@ include_js: false
---
<!-- Begin page content -->
<main role="main" class="flex-shrink-0">
<main class="flex-shrink-0">
<div class="container">
<h1 class="mt-5">Sticky footer</h1>
<p class="lead">Pin a footer to the bottom of the viewport in desktop browsers with this custom HTML and CSS.</p>

View File

@ -78,8 +78,6 @@ If you want to have `<input readonly>` elements in your form styled as plain tex
## Color
Keep in mind color inputs are [not supported in IE](https://caniuse.com/#feat=input-color).
{{< example >}}
<form>
<label for="exampleColorInput">Color picker</label>

View File

@ -8,7 +8,7 @@ toc: true
## Supported browsers
Bootstrap supports the **latest, stable releases** of all major browsers and platforms. On Windows, **we support Internet Explorer 11 / Microsoft Edge**.
Bootstrap supports the **latest, stable releases** of all major browsers and platforms. This also includes the latest version of Legacy Edge (EdgeHTML layout engine).
Alternative browsers which use the latest version of WebKit, Blink, or Gecko, whether directly or via the platform's web view API, are not explicitly supported. However, Bootstrap should (in most cases) display and function correctly in these browsers as well. More specific support information is provided below.
@ -64,7 +64,6 @@ Similarly, the latest versions of most desktop browsers are supported.
<th></th>
<th>Chrome</th>
<th>Firefox</th>
<th>Internet Explorer</th>
<th>Microsoft Edge</th>
<th>Opera</th>
<th>Safari</th>
@ -75,7 +74,6 @@ Similarly, the latest versions of most desktop browsers are supported.
<th scope="row">Mac</th>
<td>Supported</td>
<td>Supported</td>
<td class="text-muted">&mdash;</td>
<td>Supported</td>
<td>Supported</td>
<td>Supported</td>
@ -84,7 +82,6 @@ Similarly, the latest versions of most desktop browsers are supported.
<th scope="row">Windows</th>
<td>Supported</td>
<td>Supported</td>
<td>IE11 only</td>
<td>Supported</td>
<td>Supported</td>
<td class="text-muted">&mdash;</td>
@ -94,11 +91,11 @@ Similarly, the latest versions of most desktop browsers are supported.
For Firefox, in addition to the latest normal stable release, we also support the latest [Extended Support Release (ESR)](https://www.mozilla.org/en-US/firefox/organizations/#faq) version of Firefox.
Unofficially, Bootstrap should look and behave well enough in Chromium and Chrome for Linux, Firefox for Linux, and Internet Explorer 9, though they are not officially supported.
Unofficially, Bootstrap should look and behave well enough in Chromium and Chrome for Linux, and Firefox for Linux, though they are not officially supported.
## Internet Explorer
Internet Explorer 11 is supported; IE10 and down is not. Please be aware that some CSS3 properties and HTML5 elements are not fully supported in Internet Explorer, or require prefixed properties for full functionality. Visit [Can I use...](https://caniuse.com/) for details on browser support of CSS3 and HTML5 features. **If you require IE10 support, use Bootstrap 4.**
Internet Explorer is not supported. **If you require Internet Explorer support, please use Bootstrap v4.**
## Modals and dropdowns on mobile

View File

@ -221,7 +221,7 @@ You can also specify a base color with our color map functions:
#### Escape SVG
We use the `escape-svg` function to escape the `<`, `>` and `#` characters for SVG background images. These characters need to be escaped to properly render the background images in IE.
We use the `escape-svg` function to escape the `<`, `>` and `#` characters for SVG background images.
#### Add and Subtract functions

View File

@ -26,8 +26,6 @@ Position an element at the bottom of the viewport, from edge to edge. Be sure yo
Position an element at the top of the viewport, from edge to edge, but only after you scroll past it. The `.sticky-top` utility uses CSS's `position: sticky`, which isn't fully supported in all browsers.
**IE11 and IE10 will render `position: sticky` as `position: relative`.** As such, we wrap the styles in a `@supports` query, limiting the stickiness to only browsers that can render it properly.
{{< highlight html >}}
<div class="sticky-top">...</div>
{{< /highlight >}}

View File

@ -520,7 +520,7 @@ In practice, here's how it looks. Note you can continue to use this with all oth
## Alignment
Use flexbox alignment utilities to vertically and horizontally align columns. **Internet Explorer 10-11 do not support vertical alignment of flex items when the flex container has a `min-height` as shown below.** [See Flexbugs #3 for more details.](https://github.com/philipwalton/flexbugs#flexbug-3)
Use flexbox alignment utilities to vertically and horizontally align columns.
### Vertical alignment

View File

@ -11,7 +11,7 @@ toc: true
See the browser and devices page for details on what is currently supported in Bootstrap 5. Since v4, here's what's changed to our browser support:
- Dropped support for Internet Explorer NN
- Dropped support for Internet Explorer 10 and 11
- Dropped support for Firefox NN - MM
- Dropped support for Safari NN
- Dropped support for iOS Safari NN

View File

@ -296,8 +296,6 @@ Responsive variations also exist for `flex-grow` and `flex-shrink`.
Flexbox can do some pretty awesome things when you mix flex alignments with auto margins. Shown below are three examples of controlling flex items via auto margins: default (no auto margin), pushing two items to the right (`.mr-auto`), and pushing two items to the left (`.ml-auto`).
**Unfortunately, IE10 and IE11 do not properly support auto margins on flex items whose parent has a non-default `justify-content` value.** [See this StackOverflow answer](https://stackoverflow.com/a/37535548) for more details.
{{< example >}}
<div class="d-flex bd-highlight mb-3">
<div class="p-2 bd-highlight">Flex item</div>

View File

@ -8,7 +8,7 @@
{{ partial "docs-navbar" . }}
<main class="my-auto p-5" id="content" role="main">
<main class="my-auto p-5" id="content">
{{ .Content }}
</main>

View File

@ -15,7 +15,7 @@
{{ partial "docs-sidebar" . }}
</div>
<main class="col-md-9 py-md-3 pl-md-5 bd-content" role="main">
<main class="col-md-9 py-md-3 pl-md-5 bd-content">
<h1 class="bd-title" id="content">{{ .Title | markdownify }}</h1>
<p class="bd-lead">{{ .Page.Params.Description | markdownify }}</p>
{{ partial "ads" . }}

View File

@ -19,7 +19,7 @@
</div>
</header>
<main class="bd-content py-5" id="content" role="main">
<main class="bd-content py-5" id="content">
<div class="container">
{{ .Content }}
</div>

View File

@ -1,3 +1,3 @@
##### Date & color input support
Keep in mind date inputs are [not fully supported](https://caniuse.com/#feat=input-datetime) by IE and Safari. Color inputs also [lack support](https://caniuse.com/#feat=input-color) on IE.
Keep in mind date inputs are [not fully supported](https://caniuse.com/#feat=input-datetime) by all browsers, namely Safari.

View File

@ -16,7 +16,7 @@
<a class="nav-link{{ if eq .Page.Title "Examples" }} active" aria-current="true{{ end }}" href="/docs/{{ .Site.Params.docs_version }}/examples/" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Examples');">Examples</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ .Site.Params.icons }}" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Icons');">Icons</a>
<a class="nav-link" href="{{ .Site.Params.icons }}" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Icons');" target="_blank" rel="noopener">Icons</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ .Site.Params.themes }}" onclick="ga('send', 'event', 'Navbar', 'Community links', 'Themes');" target="_blank" rel="noopener">Themes</a>

View File

@ -1,4 +1,4 @@
<main class="bd-masthead mb-3 mb-md-5 border-bottom" id="content" role="main">
<main class="bd-masthead mb-3 mb-md-5 border-bottom" id="content">
<div class="container">
<div class="row">
<div class="col-6 mx-auto col-md-4 order-md-2 col-lg-5">