diff options
| author | Bobby <[email protected]> | 2024-08-16 20:47:33 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-08-16 20:47:33 -0400 |
| commit | 6b28433d9cfde435be8ec2bd6cf91e6324d08865 (patch) | |
| tree | 8343c27b8b95ff5639233e81cf157f92e5688466 /js/src/dom/selector-engine.js | |
| parent | d53094ec16ba385faae2973ddee648698b32ab24 (diff) | |
| parent | 048f56f51460df75e92a2f7b472e1c56baeb68f7 (diff) | |
| download | bootstrap-main.tar.xz bootstrap-main.zip | |
Diffstat (limited to 'js/src/dom/selector-engine.js')
| -rw-r--r-- | js/src/dom/selector-engine.js | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/js/src/dom/selector-engine.js b/js/src/dom/selector-engine.js index af27dc379..a4d81f3b9 100644 --- a/js/src/dom/selector-engine.js +++ b/js/src/dom/selector-engine.js @@ -1,17 +1,36 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.1.3): dom/selector-engine.js + * Bootstrap dom/selector-engine.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ -import { isDisabled, isVisible } from '../util/index' +import { isDisabled, isVisible, parseSelector } from '../util/index.js' -/** - * Constants - */ +const getSelector = element => { + let selector = element.getAttribute('data-bs-target') + + if (!selector || selector === '#') { + let hrefAttribute = element.getAttribute('href') + + // The only valid content that could double as a selector are IDs or classes, + // so everything starting with `#` or `.`. If a "real" URL is used as the selector, + // `document.querySelector` will rightfully complain it is invalid. + // See https://github.com/twbs/bootstrap/issues/32273 + if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) { + return null + } + + // Just in case some CMS puts out a full URL with the anchor appended + if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) { + hrefAttribute = `#${hrefAttribute.split('#')[1]}` + } + + selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null + } -const NODE_TEXT = 3 + return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null +} const SelectorEngine = { find(selector, element = document.documentElement) { @@ -28,14 +47,11 @@ const SelectorEngine = { parents(element, selector) { const parents = [] - let ancestor = element.parentNode - - while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) { - if (ancestor.matches(selector)) { - parents.push(ancestor) - } + let ancestor = element.parentNode.closest(selector) - ancestor = ancestor.parentNode + while (ancestor) { + parents.push(ancestor) + ancestor = ancestor.parentNode.closest(selector) } return parents @@ -54,7 +70,7 @@ const SelectorEngine = { return [] }, - + // TODO: this is now unused; remove later along with prev() next(element, selector) { let next = element.nextElementSibling @@ -79,9 +95,31 @@ const SelectorEngine = { 'details', '[tabindex]', '[contenteditable="true"]' - ].map(selector => `${selector}:not([tabindex^="-"])`).join(', ') + ].map(selector => `${selector}:not([tabindex^="-"])`).join(',') return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)) + }, + + getSelectorFromElement(element) { + const selector = getSelector(element) + + if (selector) { + return SelectorEngine.findOne(selector) ? selector : null + } + + return null + }, + + getElementFromSelector(element) { + const selector = getSelector(element) + + return selector ? SelectorEngine.findOne(selector) : null + }, + + getMultipleElementsFromSelector(element) { + const selector = getSelector(element) + + return selector ? SelectorEngine.find(selector) : [] } } |
