mirror of https://github.com/twbs/bootstrap.git
This commit is contained in:
parent
e81e7cda90
commit
ef4e2daa48
|
@ -38,7 +38,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./dist/js/bootstrap.bundle.min.js",
|
"path": "./dist/js/bootstrap.bundle.min.js",
|
||||||
"maxSize": "22.75 kB"
|
"maxSize": "23.0 kB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "./dist/js/bootstrap.esm.js",
|
"path": "./dist/js/bootstrap.esm.js",
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* --------------------------------------------------------------------------
|
* --------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isDisabled, isVisible } from '../util/index.js'
|
import { isDisabled, isVisible, parseSelector } from '../util/index.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constants
|
* Constants
|
||||||
|
@ -99,6 +99,7 @@ const SelectorEngine = {
|
||||||
}
|
}
|
||||||
|
|
||||||
selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null
|
selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null
|
||||||
|
selector = parseSelector(selector)
|
||||||
}
|
}
|
||||||
|
|
||||||
return selector
|
return selector
|
||||||
|
|
|
@ -9,6 +9,20 @@ const MAX_UID = 1_000_000
|
||||||
const MILLISECONDS_MULTIPLIER = 1000
|
const MILLISECONDS_MULTIPLIER = 1000
|
||||||
const TRANSITION_END = 'transitionend'
|
const TRANSITION_END = 'transitionend'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properly escape IDs selectors to handle weird IDs
|
||||||
|
* @param {string} selector
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
const parseSelector = selector => {
|
||||||
|
if (selector && window.CSS && window.CSS.escape) {
|
||||||
|
// document.querySelector needs escaping to handle IDs (html5+) containing for instance /
|
||||||
|
selector = selector.replaceAll(/#([^\s"#']+)/g, (match, id) => '#' + CSS.escape(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
return selector
|
||||||
|
}
|
||||||
|
|
||||||
// Shout-out Angus Croll (https://goo.gl/pxwQGp)
|
// Shout-out Angus Croll (https://goo.gl/pxwQGp)
|
||||||
const toType = object => {
|
const toType = object => {
|
||||||
if (object === null || object === undefined) {
|
if (object === null || object === undefined) {
|
||||||
|
@ -76,7 +90,7 @@ const getElement = object => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof object === 'string' && object.length > 0) {
|
if (typeof object === 'string' && object.length > 0) {
|
||||||
return document.querySelector(object)
|
return document.querySelector(parseSelector(object))
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
@ -285,6 +299,7 @@ export {
|
||||||
isVisible,
|
isVisible,
|
||||||
noop,
|
noop,
|
||||||
onDOMContentLoaded,
|
onDOMContentLoaded,
|
||||||
|
parseSelector,
|
||||||
reflow,
|
reflow,
|
||||||
triggerTransitionEnd,
|
triggerTransitionEnd,
|
||||||
toType
|
toType
|
||||||
|
|
|
@ -887,17 +887,17 @@ describe('Collapse', () => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
fixtureEl.innerHTML = [
|
fixtureEl.innerHTML = [
|
||||||
'<a id="trigger1" role="button" data-bs-toggle="collapse" href="#test1"></a>',
|
'<a id="trigger1" role="button" data-bs-toggle="collapse" href="#test1"></a>',
|
||||||
'<a id="trigger2" role="button" data-bs-toggle="collapse" href="#test2"></a>',
|
'<a id="trigger2" role="button" data-bs-toggle="collapse" href="#0/my/id"></a>',
|
||||||
'<a id="trigger3" role="button" data-bs-toggle="collapse" href=".multi"></a>',
|
'<a id="trigger3" role="button" data-bs-toggle="collapse" href=".multi"></a>',
|
||||||
'<div id="test1" class="multi"></div>',
|
'<div id="test1" class="multi"></div>',
|
||||||
'<div id="test2" class="multi"></div>'
|
'<div id="0/my/id" class="multi"></div>'
|
||||||
].join('')
|
].join('')
|
||||||
|
|
||||||
const trigger1 = fixtureEl.querySelector('#trigger1')
|
const trigger1 = fixtureEl.querySelector('#trigger1')
|
||||||
const trigger2 = fixtureEl.querySelector('#trigger2')
|
const trigger2 = fixtureEl.querySelector('#trigger2')
|
||||||
const trigger3 = fixtureEl.querySelector('#trigger3')
|
const trigger3 = fixtureEl.querySelector('#trigger3')
|
||||||
const target1 = fixtureEl.querySelector('#test1')
|
const target1 = fixtureEl.querySelector('#test1')
|
||||||
const target2 = fixtureEl.querySelector('#test2')
|
const target2 = fixtureEl.querySelector('#' + CSS.escape('0/my/id'))
|
||||||
|
|
||||||
const target2Shown = () => {
|
const target2Shown = () => {
|
||||||
expect(trigger1).not.toHaveClass('collapsed')
|
expect(trigger1).not.toHaveClass('collapsed')
|
||||||
|
|
|
@ -177,6 +177,43 @@ describe('Tab', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should work with tab id being an int', done => {
|
||||||
|
fixtureEl.innerHTML = [
|
||||||
|
'<div class="card-header d-block d-inline-block">',
|
||||||
|
' <ul class="nav nav-tabs card-header-tabs" id="page_tabs">',
|
||||||
|
' <li class="nav-item">',
|
||||||
|
' <a class="nav-link" draggable="false" data-toggle="tab" href="#tab1">',
|
||||||
|
' Working Tab 1 (#tab1)',
|
||||||
|
' </a>',
|
||||||
|
' </li>',
|
||||||
|
' <li class="nav-item">',
|
||||||
|
' <a id="trigger2" class="nav-link" draggable="false" data-toggle="tab" href="#2">',
|
||||||
|
' Tab with numeric ID should work (#2)',
|
||||||
|
' </a>',
|
||||||
|
' </li>',
|
||||||
|
' </ul>',
|
||||||
|
'</div>',
|
||||||
|
'<div class="card-body">',
|
||||||
|
' <div class="tab-content" id="page_content">',
|
||||||
|
' <div class="tab-pane fade" id="tab1">',
|
||||||
|
' Working Tab 1 (#tab1) Content Here',
|
||||||
|
' </div>',
|
||||||
|
' <div class="tab-pane fade" id="2">',
|
||||||
|
' Working Tab 2 (#2) with numeric ID',
|
||||||
|
' </div>',
|
||||||
|
'</div>'
|
||||||
|
].join('')
|
||||||
|
const profileTriggerEl = fixtureEl.querySelector('#trigger2')
|
||||||
|
const tab = new Tab(profileTriggerEl)
|
||||||
|
|
||||||
|
profileTriggerEl.addEventListener('shown.bs.tab', () => {
|
||||||
|
expect(fixtureEl.querySelector('#' + CSS.escape('2'))).toHaveClass('active')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
tab.show()
|
||||||
|
})
|
||||||
|
|
||||||
it('should not fire shown when show is prevented', () => {
|
it('should not fire shown when show is prevented', () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fixtureEl.innerHTML = '<div class="nav"><div class="nav-link"></div></div>'
|
fixtureEl.innerHTML = '<div class="nav"><div class="nav-link"></div></div>'
|
||||||
|
|
Loading…
Reference in New Issue