From 9463d73e9ad270d85169d5d02d3b82fc9d7f3753 Mon Sep 17 00:00:00 2001 From: GeoSot Date: Wed, 16 Mar 2022 11:58:58 +0200 Subject: [PATCH 1/2] refactor: Move `getElementFromSelector` & `getSelectorFromElement` Move `getElementFromSelector` & getSelectorFromElement` inside selector-engine.js, in order to use SelectorEngine methods, avoiding raw querySelector usage Feature: add `getMultipleElementsFromSelector` helper --- js/src/dom/selector-engine.js | 54 ++++++- js/src/tab.js | 2 +- js/src/util/index.js | 43 ------ js/src/util/template-factory.js | 2 +- js/tests/unit/dom/selector-engine.spec.js | 165 +++++++++++++++++++++- js/tests/unit/util/focustrap.spec.js | 2 +- js/tests/unit/util/index.spec.js | 113 --------------- 7 files changed, 218 insertions(+), 163 deletions(-) diff --git a/js/src/dom/selector-engine.js b/js/src/dom/selector-engine.js index 63bc2d1764cc..e9079fe655e3 100644 --- a/js/src/dom/selector-engine.js +++ b/js/src/dom/selector-engine.js @@ -80,4 +80,56 @@ const SelectorEngine = { } } -export default SelectorEngine +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 + } + + return selector +} + +const getSelectorFromElement = element => { + const selector = getSelector(element) + + if (selector) { + return SelectorEngine.findOne(selector) ? selector : null + } + + return null +} + +const getElementFromSelector = element => { + const selector = getSelector(element) + + return selector ? SelectorEngine.findOne(selector) : null +} + +const getMultipleElementsFromSelector = element => { + const selector = getSelector(element) + + return selector ? SelectorEngine.find(selector) : [] +} + +export { + SelectorEngine, + getElementFromSelector, + getMultipleElementsFromSelector, + getSelectorFromElement +} diff --git a/js/src/tab.js b/js/src/tab.js index 19d3bfc361a9..c41ecf986e06 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -7,7 +7,7 @@ import { defineJQueryPlugin, getElementFromSelector, getNextActiveElement, isDisabled } from './util/index.js' import EventHandler from './dom/event-handler.js' -import SelectorEngine from './dom/selector-engine.js' +import { getElementFromSelector, SelectorEngine } from './dom/selector-engine.js' import BaseComponent from './base-component.js' /** diff --git a/js/src/util/index.js b/js/src/util/index.js index ad99f85ed968..b92eddba2535 100644 --- a/js/src/util/index.js +++ b/js/src/util/index.js @@ -30,47 +30,6 @@ const getUID = prefix => { return prefix } -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 - } - - return selector -} - -const getSelectorFromElement = element => { - const selector = getSelector(element) - - if (selector) { - return document.querySelector(selector) ? selector : null - } - - return null -} - -const getElementFromSelector = element => { - const selector = getSelector(element) - - return selector ? document.querySelector(selector) : null -} - const getTransitionDurationFromElement = element => { if (!element) { return 0 @@ -316,10 +275,8 @@ export { executeAfterTransition, findShadowRoot, getElement, - getElementFromSelector, getjQuery, getNextActiveElement, - getSelectorFromElement, getTransitionDurationFromElement, getUID, isDisabled, diff --git a/js/src/util/template-factory.js b/js/src/util/template-factory.js index 9cd12dcdbef9..f5b03727f007 100644 --- a/js/src/util/template-factory.js +++ b/js/src/util/template-factory.js @@ -7,7 +7,7 @@ import { DefaultAllowlist, sanitizeHtml } from './sanitizer.js' import { execute, getElement, isElement } from './index.js' -import SelectorEngine from '../dom/selector-engine.js' +import { SelectorEngine } from '../dom/selector-engine.js' import Config from './config.js' /** diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js index 0245896c6805..eb485c1356bc 100644 --- a/js/tests/unit/dom/selector-engine.spec.js +++ b/js/tests/unit/dom/selector-engine.spec.js @@ -1,5 +1,10 @@ -import SelectorEngine from '../../../src/dom/selector-engine' -import { getFixture, clearFixture } from '../../helpers/fixture' +import { + getElementFromSelector, + getMultipleElementsFromSelector, + getSelectorFromElement, + SelectorEngine +} from '../../../src/dom/selector-engine' +import { clearFixture, getFixture } from '../../helpers/fixture' describe('SelectorEngine', () => { let fixtureEl @@ -232,5 +237,159 @@ describe('SelectorEngine', () => { expect(SelectorEngine.focusableChildren(fixtureEl)).toEqual(expectedElements) }) }) -}) + describe('getSelectorFromElement', () => { + it('should get selector from data-bs-target', () => { + fixtureEl.innerHTML = [ + '
', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getSelectorFromElement(testEl)).toEqual('.target') + }) + + it('should get selector from href if no data-bs-target set', () => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getSelectorFromElement(testEl)).toEqual('.target') + }) + + it('should get selector from href if data-bs-target equal to #', () => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getSelectorFromElement(testEl)).toEqual('.target') + }) + + it('should return null if a selector from a href is a url without an anchor', () => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getSelectorFromElement(testEl)).toBeNull() + }) + + it('should return the anchor if a selector from a href is a url', () => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getSelectorFromElement(testEl)).toEqual('#target') + }) + + it('should return null if selector not found', () => { + fixtureEl.innerHTML = '' + + const testEl = fixtureEl.querySelector('#test') + + expect(getSelectorFromElement(testEl)).toBeNull() + }) + + it('should return null if no selector', () => { + fixtureEl.innerHTML = '
' + + const testEl = fixtureEl.querySelector('div') + + expect(getSelectorFromElement(testEl)).toBeNull() + }) + }) + + describe('getElementFromSelector', () => { + it('should get element from data-bs-target', () => { + fixtureEl.innerHTML = [ + '
', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) + }) + + it('should get element from href if no data-bs-target set', () => { + fixtureEl.innerHTML = [ + '', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) + }) + + it('should return null if element not found', () => { + fixtureEl.innerHTML = '' + + const testEl = fixtureEl.querySelector('#test') + + expect(getElementFromSelector(testEl)).toBeNull() + }) + + it('should return null if no selector', () => { + fixtureEl.innerHTML = '
' + + const testEl = fixtureEl.querySelector('div') + + expect(getElementFromSelector(testEl)).toBeNull() + }) + }) + + describe('getMultipleElementsFromSelector', () => { + it('should get elements from data-bs-target', () => { + fixtureEl.innerHTML = [ + '
', + '
', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) + }) + + it('should get elements in array, from href if no data-bs-target set', () => { + fixtureEl.innerHTML = [ + '', + '
', + '
' + ].join('') + + const testEl = fixtureEl.querySelector('#test') + + expect(getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) + }) + + it('should return empty array if elements not found', () => { + fixtureEl.innerHTML = '' + + const testEl = fixtureEl.querySelector('#test') + + expect(getMultipleElementsFromSelector(testEl)).toHaveSize(0) + }) + + it('should return empty array if no selector', () => { + fixtureEl.innerHTML = '
' + + const testEl = fixtureEl.querySelector('div') + + expect(getMultipleElementsFromSelector(testEl)).toHaveSize(0) + }) + }) +}) diff --git a/js/tests/unit/util/focustrap.spec.js b/js/tests/unit/util/focustrap.spec.js index bedd124c9ec1..6178f7a5c351 100644 --- a/js/tests/unit/util/focustrap.spec.js +++ b/js/tests/unit/util/focustrap.spec.js @@ -1,6 +1,6 @@ import FocusTrap from '../../../src/util/focustrap' import EventHandler from '../../../src/dom/event-handler' -import SelectorEngine from '../../../src/dom/selector-engine' +import { SelectorEngine } from '../../../src/dom/selector-engine' import { clearFixture, createEvent, getFixture } from '../../helpers/fixture' describe('FocusTrap', () => { diff --git a/js/tests/unit/util/index.spec.js b/js/tests/unit/util/index.spec.js index 6edc49433572..202c72061dc5 100644 --- a/js/tests/unit/util/index.spec.js +++ b/js/tests/unit/util/index.spec.js @@ -22,119 +22,6 @@ describe('Util', () => { }) }) - describe('getSelectorFromElement', () => { - it('should get selector from data-bs-target', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getSelectorFromElement(testEl)).toEqual('.target') - }) - - it('should get selector from href if no data-bs-target set', () => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getSelectorFromElement(testEl)).toEqual('.target') - }) - - it('should get selector from href if data-bs-target equal to #', () => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getSelectorFromElement(testEl)).toEqual('.target') - }) - - it('should return null if a selector from a href is a url without an anchor', () => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getSelectorFromElement(testEl)).toBeNull() - }) - - it('should return the anchor if a selector from a href is a url', () => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getSelectorFromElement(testEl)).toEqual('#target') - }) - - it('should return null if selector not found', () => { - fixtureEl.innerHTML = '' - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getSelectorFromElement(testEl)).toBeNull() - }) - - it('should return null if no selector', () => { - fixtureEl.innerHTML = '
' - - const testEl = fixtureEl.querySelector('div') - - expect(Util.getSelectorFromElement(testEl)).toBeNull() - }) - }) - - describe('getElementFromSelector', () => { - it('should get element from data-bs-target', () => { - fixtureEl.innerHTML = [ - '
', - '
' - ].join('') - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) - }) - - it('should get element from href if no data-bs-target set', () => { - fixtureEl.innerHTML = [ - '', - '
' - ].join('') - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) - }) - - it('should return null if element not found', () => { - fixtureEl.innerHTML = '' - - const testEl = fixtureEl.querySelector('#test') - - expect(Util.getElementFromSelector(testEl)).toBeNull() - }) - - it('should return null if no selector', () => { - fixtureEl.innerHTML = '
' - - const testEl = fixtureEl.querySelector('div') - - expect(Util.getElementFromSelector(testEl)).toBeNull() - }) - }) - describe('getTransitionDurationFromElement', () => { it('should get transition from element', () => { fixtureEl.innerHTML = '
' From ce38f1157905d771b53c886e1da60bcf228eedeb Mon Sep 17 00:00:00 2001 From: George Sotiropoulos Date: Thu, 20 Oct 2022 12:10:07 +0200 Subject: [PATCH 2/2] apply Julien's patch --- js/src/carousel.js | 3 +- js/src/collapse.js | 13 ++-- js/src/dom/selector-engine.js | 77 +++++++++++------------ js/src/modal.js | 4 +- js/src/offcanvas.js | 3 +- js/src/tab.js | 10 +-- js/src/util/component-functions.js | 5 +- js/src/util/template-factory.js | 2 +- js/tests/unit/dom/selector-engine.spec.js | 37 +++++------ js/tests/unit/util/focustrap.spec.js | 2 +- 10 files changed, 70 insertions(+), 86 deletions(-) diff --git a/js/src/carousel.js b/js/src/carousel.js index e25395628544..8ba9f351afb0 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -7,7 +7,6 @@ import { defineJQueryPlugin, - getElementFromSelector, getNextActiveElement, isRTL, isVisible, @@ -431,7 +430,7 @@ class Carousel extends BaseComponent { */ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) { - const target = getElementFromSelector(this) + const target = SelectorEngine.getElementFromSelector(this) if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) { return diff --git a/js/src/collapse.js b/js/src/collapse.js index 04a5f4cdf72d..937174011627 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -8,8 +8,6 @@ import { defineJQueryPlugin, getElement, - getElementFromSelector, - getSelectorFromElement, reflow } from './util/index.js' import EventHandler from './dom/event-handler.js' @@ -68,7 +66,7 @@ class Collapse extends BaseComponent { const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE) for (const elem of toggleList) { - const selector = getSelectorFromElement(elem) + const selector = SelectorEngine.getSelectorFromElement(elem) const filterElement = SelectorEngine.find(selector) .filter(foundElement => foundElement === this._element) @@ -185,7 +183,7 @@ class Collapse extends BaseComponent { this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW) for (const trigger of this._triggerArray) { - const element = getElementFromSelector(trigger) + const element = SelectorEngine.getElementFromSelector(trigger) if (element && !this._isShown(element)) { this._addAriaAndCollapsedClass([trigger], false) @@ -229,7 +227,7 @@ class Collapse extends BaseComponent { const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE) for (const element of children) { - const selected = getElementFromSelector(element) + const selected = SelectorEngine.getElementFromSelector(element) if (selected) { this._addAriaAndCollapsedClass([element], this._isShown(selected)) @@ -285,10 +283,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function ( event.preventDefault() } - const selector = getSelectorFromElement(this) - const selectorElements = SelectorEngine.find(selector) - - for (const element of selectorElements) { + for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) { Collapse.getOrCreateInstance(element, { toggle: false }).toggle() } }) diff --git a/js/src/dom/selector-engine.js b/js/src/dom/selector-engine.js index e9079fe655e3..ad10a6083172 100644 --- a/js/src/dom/selector-engine.js +++ b/js/src/dom/selector-engine.js @@ -77,59 +77,54 @@ const SelectorEngine = { ].map(selector => `${selector}:not([tabindex^="-"])`).join(',') return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)) - } -} + }, -const getSelector = element => { - let selector = element.getAttribute('data-bs-target') + getSelector(element) { + let selector = element.getAttribute('data-bs-target') - if (!selector || selector === '#') { - let hrefAttribute = element.getAttribute('href') + 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 - } + // 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]}` - } + // 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 - } + selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null + } - return selector -} + return selector + }, -const getSelectorFromElement = element => { - const selector = getSelector(element) + getSelectorFromElement(element) { + const selector = SelectorEngine.getSelector(element) - if (selector) { - return SelectorEngine.findOne(selector) ? selector : null - } + if (selector) { + return SelectorEngine.findOne(selector) ? selector : null + } - return null -} + return null + }, -const getElementFromSelector = element => { - const selector = getSelector(element) + getElementFromSelector(element) { + const selector = SelectorEngine.getSelector(element) - return selector ? SelectorEngine.findOne(selector) : null -} + return selector ? SelectorEngine.findOne(selector) : null + }, -const getMultipleElementsFromSelector = element => { - const selector = getSelector(element) + getMultipleElementsFromSelector(element) { + const selector = SelectorEngine.getSelector(element) - return selector ? SelectorEngine.find(selector) : [] + return selector ? SelectorEngine.find(selector) : [] + } } -export { - SelectorEngine, - getElementFromSelector, - getMultipleElementsFromSelector, - getSelectorFromElement -} +export default SelectorEngine diff --git a/js/src/modal.js b/js/src/modal.js index 11efab20ad1f..aba3b34a6007 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -5,7 +5,7 @@ * -------------------------------------------------------------------------- */ -import { defineJQueryPlugin, getElementFromSelector, isRTL, isVisible, reflow } from './util/index.js' +import { defineJQueryPlugin, isRTL, isVisible, reflow } from './util/index.js' import EventHandler from './dom/event-handler.js' import SelectorEngine from './dom/selector-engine.js' import ScrollBarHelper from './util/scrollbar.js' @@ -336,7 +336,7 @@ class Modal extends BaseComponent { */ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { - const target = getElementFromSelector(this) + const target = SelectorEngine.getElementFromSelector(this) if (['A', 'AREA'].includes(this.tagName)) { event.preventDefault() diff --git a/js/src/offcanvas.js b/js/src/offcanvas.js index a857c4d7e421..6fd7099207c4 100644 --- a/js/src/offcanvas.js +++ b/js/src/offcanvas.js @@ -7,7 +7,6 @@ import { defineJQueryPlugin, - getElementFromSelector, isDisabled, isVisible } from './util/index.js' @@ -231,7 +230,7 @@ class Offcanvas extends BaseComponent { */ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { - const target = getElementFromSelector(this) + const target = SelectorEngine.getElementFromSelector(this) if (['A', 'AREA'].includes(this.tagName)) { event.preventDefault() diff --git a/js/src/tab.js b/js/src/tab.js index c41ecf986e06..d9e71b5ba4be 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -5,9 +5,9 @@ * -------------------------------------------------------------------------- */ -import { defineJQueryPlugin, getElementFromSelector, getNextActiveElement, isDisabled } from './util/index.js' +import { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js' import EventHandler from './dom/event-handler.js' -import { getElementFromSelector, SelectorEngine } from './dom/selector-engine.js' +import SelectorEngine from './dom/selector-engine.js' import BaseComponent from './base-component.js' /** @@ -106,7 +106,7 @@ class Tab extends BaseComponent { element.classList.add(CLASS_NAME_ACTIVE) - this._activate(getElementFromSelector(element)) // Search and activate/show the proper section + this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section const complete = () => { if (element.getAttribute('role') !== 'tab') { @@ -133,7 +133,7 @@ class Tab extends BaseComponent { element.classList.remove(CLASS_NAME_ACTIVE) element.blur() - this._deactivate(getElementFromSelector(element)) // Search and deactivate the shown section too + this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too const complete = () => { if (element.getAttribute('role') !== 'tab') { @@ -203,7 +203,7 @@ class Tab extends BaseComponent { } _setInitialAttributesOnTargetPanel(child) { - const target = getElementFromSelector(child) + const target = SelectorEngine.getElementFromSelector(child) if (!target) { return diff --git a/js/src/util/component-functions.js b/js/src/util/component-functions.js index 2298ac3717e9..6896faf56998 100644 --- a/js/src/util/component-functions.js +++ b/js/src/util/component-functions.js @@ -6,7 +6,8 @@ */ import EventHandler from '../dom/event-handler.js' -import { getElementFromSelector, isDisabled } from './index.js' +import { isDisabled } from './index.js' +import SelectorEngine from '../dom/selector-engine.js' const enableDismissTrigger = (component, method = 'hide') => { const clickEvent = `click.dismiss${component.EVENT_KEY}` @@ -21,7 +22,7 @@ const enableDismissTrigger = (component, method = 'hide') => { return } - const target = getElementFromSelector(this) || this.closest(`.${name}`) + const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`) const instance = component.getOrCreateInstance(target) // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method diff --git a/js/src/util/template-factory.js b/js/src/util/template-factory.js index f5b03727f007..9cd12dcdbef9 100644 --- a/js/src/util/template-factory.js +++ b/js/src/util/template-factory.js @@ -7,7 +7,7 @@ import { DefaultAllowlist, sanitizeHtml } from './sanitizer.js' import { execute, getElement, isElement } from './index.js' -import { SelectorEngine } from '../dom/selector-engine.js' +import SelectorEngine from '../dom/selector-engine.js' import Config from './config.js' /** diff --git a/js/tests/unit/dom/selector-engine.spec.js b/js/tests/unit/dom/selector-engine.spec.js index eb485c1356bc..905e25baec65 100644 --- a/js/tests/unit/dom/selector-engine.spec.js +++ b/js/tests/unit/dom/selector-engine.spec.js @@ -1,9 +1,4 @@ -import { - getElementFromSelector, - getMultipleElementsFromSelector, - getSelectorFromElement, - SelectorEngine -} from '../../../src/dom/selector-engine' +import SelectorEngine from '../../../src/dom/selector-engine' import { clearFixture, getFixture } from '../../helpers/fixture' describe('SelectorEngine', () => { @@ -247,7 +242,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getSelectorFromElement(testEl)).toEqual('.target') + expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('.target') }) it('should get selector from href if no data-bs-target set', () => { @@ -258,7 +253,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getSelectorFromElement(testEl)).toEqual('.target') + expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('.target') }) it('should get selector from href if data-bs-target equal to #', () => { @@ -269,7 +264,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getSelectorFromElement(testEl)).toEqual('.target') + expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('.target') }) it('should return null if a selector from a href is a url without an anchor', () => { @@ -280,7 +275,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getSelectorFromElement(testEl)).toBeNull() + expect(SelectorEngine.getSelectorFromElement(testEl)).toBeNull() }) it('should return the anchor if a selector from a href is a url', () => { @@ -291,7 +286,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getSelectorFromElement(testEl)).toEqual('#target') + expect(SelectorEngine.getSelectorFromElement(testEl)).toEqual('#target') }) it('should return null if selector not found', () => { @@ -299,7 +294,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getSelectorFromElement(testEl)).toBeNull() + expect(SelectorEngine.getSelectorFromElement(testEl)).toBeNull() }) it('should return null if no selector', () => { @@ -307,7 +302,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('div') - expect(getSelectorFromElement(testEl)).toBeNull() + expect(SelectorEngine.getSelectorFromElement(testEl)).toBeNull() }) }) @@ -320,7 +315,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) + expect(SelectorEngine.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) }) it('should get element from href if no data-bs-target set', () => { @@ -331,7 +326,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) + expect(SelectorEngine.getElementFromSelector(testEl)).toEqual(fixtureEl.querySelector('.target')) }) it('should return null if element not found', () => { @@ -339,7 +334,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getElementFromSelector(testEl)).toBeNull() + expect(SelectorEngine.getElementFromSelector(testEl)).toBeNull() }) it('should return null if no selector', () => { @@ -347,7 +342,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('div') - expect(getElementFromSelector(testEl)).toBeNull() + expect(SelectorEngine.getElementFromSelector(testEl)).toBeNull() }) }) @@ -361,7 +356,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) + expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) }) it('should get elements in array, from href if no data-bs-target set', () => { @@ -373,7 +368,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) + expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toEqual(Array.from(fixtureEl.querySelectorAll('.target'))) }) it('should return empty array if elements not found', () => { @@ -381,7 +376,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('#test') - expect(getMultipleElementsFromSelector(testEl)).toHaveSize(0) + expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toHaveSize(0) }) it('should return empty array if no selector', () => { @@ -389,7 +384,7 @@ describe('SelectorEngine', () => { const testEl = fixtureEl.querySelector('div') - expect(getMultipleElementsFromSelector(testEl)).toHaveSize(0) + expect(SelectorEngine.getMultipleElementsFromSelector(testEl)).toHaveSize(0) }) }) }) diff --git a/js/tests/unit/util/focustrap.spec.js b/js/tests/unit/util/focustrap.spec.js index 6178f7a5c351..bedd124c9ec1 100644 --- a/js/tests/unit/util/focustrap.spec.js +++ b/js/tests/unit/util/focustrap.spec.js @@ -1,6 +1,6 @@ import FocusTrap from '../../../src/util/focustrap' import EventHandler from '../../../src/dom/event-handler' -import { SelectorEngine } from '../../../src/dom/selector-engine' +import SelectorEngine from '../../../src/dom/selector-engine' import { clearFixture, createEvent, getFixture } from '../../helpers/fixture' describe('FocusTrap', () => {