Looking around on js components I found out many checks, different expressed but with same purpose.
Some of them are trying to parse string to element, others, jQuery element to js simple nodeElement etc
With this Pr, I am trying to give a standard way to parse an element
So this pr:
* Creates `getElement` helper that tries to parse an argument to element or null
* Changes `isElement` to make explicit checks and return Boolean
* fixes tests deficiencies
import {
emulateTransitionEnd,
execute,
+ getElement,
getTransitionDurationFromElement
} from './util/index'
import EventHandler from './dom/event-handler'
class BaseComponent {
constructor(element) {
- element = typeof element === 'string' ? document.querySelector(element) : element
+ element = getElement(element)
if (!element) {
return
import {
defineJQueryPlugin,
+ getElement,
getSelectorFromElement,
getElementFromSelector,
- isElement,
reflow,
typeCheckConfig
} from './util/index'
_getParent() {
let { parent } = this._config
- if (isElement(parent)) {
- // it's a jQuery object
- if (typeof parent.jquery !== 'undefined' || typeof parent[0] !== 'undefined') {
- parent = parent[0]
- }
- } else {
- parent = SelectorEngine.findOne(parent)
- }
+ parent = getElement(parent)
const selector = `${SELECTOR_DATA_TOGGLE}[data-bs-parent="${parent}"]`
import {
defineJQueryPlugin,
+ getElement,
getElementFromSelector,
isDisabled,
isElement,
if (this._config.reference === 'parent') {
referenceElement = parent
} else if (isElement(this._config.reference)) {
- referenceElement = this._config.reference
-
- // Check if it's jQuery element
- if (typeof this._config.reference.jquery !== 'undefined') {
- referenceElement = this._config.reference[0]
- }
+ referenceElement = getElement(this._config.reference)
} else if (typeof this._config.reference === 'object') {
referenceElement = this._config.reference
}
import {
defineJQueryPlugin,
findShadowRoot,
+ getElement,
getUID,
isElement,
isRTL,
const attachment = this._getAttachment(placement)
this._addAttachmentClass(attachment)
- const container = this._getContainer()
+ const { container } = this._config
Data.set(tip, this.constructor.DATA_KEY, this)
if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
return
}
- if (typeof content === 'object' && isElement(content)) {
- if (content.jquery) {
- content = content[0]
- }
+ if (isElement(content)) {
+ content = getElement(content)
// content is a DOM node or a jQuery
if (this._config.html) {
this.getTipElement().classList.add(`${CLASS_PREFIX}-${this.updateAttachment(attachment)}`)
}
- _getContainer() {
- if (this._config.container === false) {
- return document.body
- }
-
- if (isElement(this._config.container)) {
- return this._config.container
- }
-
- return SelectorEngine.findOne(this._config.container)
- }
-
_getAttachment(placement) {
return AttachmentMap[placement.toUpperCase()]
}
}
})
- if (config && typeof config.container === 'object' && config.container.jquery) {
- config.container = config.container[0]
- }
-
config = {
...this.constructor.Default,
...dataAttributes,
...(typeof config === 'object' && config ? config : {})
}
+ config.container = config.container === false ? document.body : getElement(config.container)
+
if (typeof config.delay === 'number') {
config.delay = {
show: config.delay,
+import SelectorEngine from '../dom/selector-engine'
+
/**
* --------------------------------------------------------------------------
* Bootstrap (v5.0.0): util/index.js
element.dispatchEvent(new Event(TRANSITION_END))
}
-const isElement = obj => (obj[0] || obj).nodeType
+const isElement = obj => {
+ if (!obj || typeof obj !== 'object') {
+ return false
+ }
+
+ if (typeof obj.jquery !== 'undefined') {
+ obj = obj[0]
+ }
+
+ return typeof obj.nodeType !== 'undefined'
+}
+
+const getElement = obj => {
+ if (isElement(obj)) { // it's a jQuery object or a node element
+ return obj.jquery ? obj[0] : obj
+ }
+
+ if (typeof obj === 'string' && obj.length > 0) {
+ return SelectorEngine.findOne(obj)
+ }
+
+ return null
+}
const emulateTransitionEnd = (element, duration) => {
let called = false
}
export {
+ getElement,
getUID,
getSelectorFromElement,
getElementFromSelector,
const collapseEl = fixtureEl.querySelector('div.collapse')
const myCollapseEl = fixtureEl.querySelector('.my-collapse')
const fakejQueryObject = {
- 0: myCollapseEl
+ 0: myCollapseEl,
+ jquery: 'foo'
}
const collapse = new Collapse(collapseEl, {
parent: fakejQueryObject
import { noop } from '../../src/util'
/** Test helpers */
-import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture'
+import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture'
describe('Dropdown', () => {
let fixtureEl
const btnDropdown = fixtureEl.querySelector('[data-bs-toggle="dropdown"]')
const virtualElement = {
+ nodeType: 1,
getBoundingClientRect() {
return {
width: 0,
import * as Util from '../../../src/util/index'
/** Test helpers */
-import { getFixture, clearFixture } from '../../helpers/fixture'
+import { clearFixture, getFixture } from '../../helpers/fixture'
describe('Util', () => {
let fixtureEl
})
describe('isElement', () => {
- it('should detect if the parameter is an element or not', () => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should detect if the parameter is an element or not and return Boolean', () => {
+ fixtureEl.innerHTML =
+ [
+ '<div id="foo" class="test"></div>',
+ '<div id="bar" class="test"></div>'
+ ].join('')
- const el = document.querySelector('div')
+ const el = fixtureEl.querySelector('#foo')
- expect(Util.isElement(el)).toEqual(el.nodeType)
- expect(Util.isElement({})).toEqual(undefined)
+ expect(Util.isElement(el)).toEqual(true)
+ expect(Util.isElement({})).toEqual(false)
+ expect(Util.isElement(fixtureEl.querySelectorAll('.test'))).toEqual(false)
})
it('should detect jQuery element', () => {
fixtureEl.innerHTML = '<div></div>'
- const el = document.querySelector('div')
+ const el = fixtureEl.querySelector('div')
const fakejQuery = {
- 0: el
+ 0: el,
+ jquery: 'foo'
+ }
+
+ expect(Util.isElement(fakejQuery)).toEqual(true)
+ })
+ })
+
+ describe('getElement', () => {
+ it('should try to parse element', () => {
+ fixtureEl.innerHTML =
+ [
+ '<div id="foo" class="test"></div>',
+ '<div id="bar" class="test"></div>'
+ ].join('')
+
+ const el = fixtureEl.querySelector('div')
+
+ expect(Util.getElement(el)).toEqual(el)
+ expect(Util.getElement('#foo')).toEqual(el)
+ expect(Util.getElement('#fail')).toBeNull()
+ expect(Util.getElement({})).toBeNull()
+ expect(Util.getElement([])).toBeNull()
+ expect(Util.getElement()).toBeNull()
+ expect(Util.getElement(null)).toBeNull()
+ expect(Util.getElement(fixtureEl.querySelectorAll('.test'))).toBeNull()
+
+ const fakejQueryObject = {
+ 0: el,
+ jquery: 'foo'
}
- expect(Util.isElement(fakejQuery)).toEqual(el.nodeType)
+ expect(Util.getElement(fakejQueryObject)).toEqual(el)
})
})