},
{
"path": "./dist/js/bootstrap.bundle.min.js",
- "maxSize": "21.75 kB"
+ "maxSize": "22 kB"
},
{
"path": "./dist/js/bootstrap.esm.js",
static jQueryInterface(config) {
return this.each(function () {
- let data = Data.getData(this, DATA_KEY)
+ let data = Data.get(this, DATA_KEY)
if (!data) {
data = new Alert(this)
}
this._element = element
- Data.setData(this._element, this.constructor.DATA_KEY, this)
+ Data.set(this._element, this.constructor.DATA_KEY, this)
}
dispose() {
- Data.removeData(this._element, this.constructor.DATA_KEY)
+ Data.remove(this._element, this.constructor.DATA_KEY)
this._element = null
}
/** Static */
static getInstance(element) {
- return Data.getData(element, this.DATA_KEY)
+ return Data.get(element, this.DATA_KEY)
}
static get VERSION() {
static jQueryInterface(config) {
return this.each(function () {
- let data = Data.getData(this, DATA_KEY)
+ let data = Data.get(this, DATA_KEY)
if (!data) {
data = new Button(this)
const button = event.target.closest(SELECTOR_DATA_TOGGLE)
- let data = Data.getData(button, DATA_KEY)
+ let data = Data.get(button, DATA_KEY)
if (!data) {
data = new Button(button)
}
// Static
static carouselInterface(element, config) {
- let data = Data.getData(element, DATA_KEY)
+ let data = Data.get(element, DATA_KEY)
let _config = {
...Default,
...Manipulator.getDataAttributes(element)
Carousel.carouselInterface(target, config)
if (slideIndex) {
- Data.getData(target, DATA_KEY).to(slideIndex)
+ Data.get(target, DATA_KEY).to(slideIndex)
}
event.preventDefault()
const carousels = 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))
+ Carousel.carouselInterface(carousels[i], Data.get(carousels[i], DATA_KEY))
}
})
const container = SelectorEngine.findOne(this._selector)
if (actives) {
const tempActiveData = actives.find(elem => container !== elem)
- activesData = tempActiveData ? Data.getData(tempActiveData, DATA_KEY) : null
+ activesData = tempActiveData ? Data.get(tempActiveData, DATA_KEY) : null
if (activesData && activesData._isTransitioning) {
return
}
if (!activesData) {
- Data.setData(elemActive, DATA_KEY, null)
+ Data.set(elemActive, DATA_KEY, null)
}
})
}
// Static
static collapseInterface(element, config) {
- let data = Data.getData(element, DATA_KEY)
+ let data = Data.get(element, DATA_KEY)
const _config = {
...Default,
...Manipulator.getDataAttributes(element),
const selectorElements = SelectorEngine.find(selector)
selectorElements.forEach(element => {
- const data = Data.getData(element, DATA_KEY)
+ const data = Data.get(element, DATA_KEY)
let config
if (data) {
// update parent attribute
* ------------------------------------------------------------------------
*/
-const mapData = (() => {
- const storeData = {}
- let id = 1
- return {
- set(element, key, data) {
- if (typeof element.bsKey === 'undefined') {
- element.bsKey = {
- key,
- id
- }
- id++
- }
+const elementMap = new Map()
- storeData[element.bsKey.id] = data
- },
- get(element, key) {
- if (!element || typeof element.bsKey === 'undefined') {
- return null
- }
-
- const keyProperties = element.bsKey
- if (keyProperties.key === key) {
- return storeData[keyProperties.id]
- }
+export default {
+ set(element, key, instance) {
+ if (!elementMap.has(element)) {
+ elementMap.set(element, new Map())
+ }
- return null
- },
- delete(element, key) {
- if (typeof element.bsKey === 'undefined') {
- return
- }
+ const instanceMap = elementMap.get(element)
- const keyProperties = element.bsKey
- if (keyProperties.key === key) {
- delete storeData[keyProperties.id]
- delete element.bsKey
- }
+ // make it clear we only want one instance per element
+ // can be removed later when multiple key/instances are fine to be used
+ if (!instanceMap.has(key) && instanceMap.size !== 0) {
+ // eslint-disable-next-line no-console
+ console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)
+ return
}
- }
-})()
-const Data = {
- setData(instance, key, data) {
- mapData.set(instance, key, data)
+ instanceMap.set(key, instance)
},
- getData(instance, key) {
- return mapData.get(instance, key)
+
+ get(element, key) {
+ if (elementMap.has(element)) {
+ return elementMap.get(element).get(key) || null
+ }
+
+ return null
},
- removeData(instance, key) {
- mapData.delete(instance, key)
+
+ remove(element, key) {
+ if (!elementMap.has(element)) {
+ return
+ }
+
+ const instanceMap = elementMap.get(element)
+
+ instanceMap.delete(key)
+
+ // free up element references if there are no instances left for an element
+ if (instanceMap.size === 0) {
+ elementMap.delete(element)
+ }
}
}
-
-export default Data
// Static
static dropdownInterface(element, config) {
- let data = Data.getData(element, DATA_KEY)
+ let data = Data.get(element, DATA_KEY)
const _config = typeof config === 'object' ? config : null
if (!data) {
const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)
for (let i = 0, len = toggles.length; i < len; i++) {
- const context = Data.getData(toggles[i], DATA_KEY)
+ const context = Data.get(toggles[i], DATA_KEY)
const relatedTarget = {
relatedTarget: toggles[i]
}
static jQueryInterface(config, relatedTarget) {
return this.each(function () {
- let data = Data.getData(this, DATA_KEY)
+ let data = Data.get(this, DATA_KEY)
const _config = {
...Default,
...Manipulator.getDataAttributes(this),
})
})
- let data = Data.getData(target, DATA_KEY)
+ let data = Data.get(target, DATA_KEY)
if (!data) {
const config = {
...Manipulator.getDataAttributes(target),
static jQueryInterface(config) {
return this.each(function () {
- let data = Data.getData(this, DATA_KEY)
+ let data = Data.get(this, DATA_KEY)
const _config = typeof config === 'object' ? config : null
if (!data && /dispose|hide/.test(config)) {
if (!data) {
data = new Popover(this, _config)
- Data.setData(this, DATA_KEY, data)
+ Data.set(this, DATA_KEY, data)
}
if (typeof config === 'string') {
static jQueryInterface(config) {
return this.each(function () {
- let data = Data.getData(this, DATA_KEY)
+ let data = Data.get(this, DATA_KEY)
const _config = typeof config === 'object' && config
if (!data) {
static jQueryInterface(config) {
return this.each(function () {
- const data = Data.getData(this, DATA_KEY) || new Tab(this)
+ const data = Data.get(this, DATA_KEY) || new Tab(this)
if (typeof config === 'string') {
if (typeof data[config] === 'undefined') {
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault()
- const data = Data.getData(this, DATA_KEY) || new Tab(this)
+ const data = Data.get(this, DATA_KEY) || new Tab(this)
data.show()
})
static jQueryInterface(config) {
return this.each(function () {
- let data = Data.getData(this, DATA_KEY)
+ let data = Data.get(this, DATA_KEY)
const _config = typeof config === 'object' && config
if (!data) {
this._addAttachmentClass(attachment)
const container = this._getContainer()
- Data.setData(tip, this.constructor.DATA_KEY, this)
+ Data.set(tip, this.constructor.DATA_KEY, this)
if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
container.appendChild(tip)
_initializeOnDelegatedTarget(event, context) {
const dataKey = this.constructor.DATA_KEY
- context = context || Data.getData(event.delegateTarget, dataKey)
+ context = context || Data.get(event.delegateTarget, dataKey)
if (!context) {
context = new this.constructor(event.delegateTarget, this._getDelegateConfig())
- Data.setData(event.delegateTarget, dataKey, context)
+ Data.set(event.delegateTarget, dataKey, context)
}
return context
static jQueryInterface(config) {
return this.each(function () {
- let data = Data.getData(this, DATA_KEY)
+ let data = Data.get(this, DATA_KEY)
const _config = typeof config === 'object' && config
if (!data && /dispose|hide/.test(config)) {
import { getFixture, clearFixture } from '../../helpers/fixture'
describe('Data', () => {
+ const TEST_KEY = 'bs.test'
+ const UNKNOWN_KEY = 'bs.unknown'
+ const TEST_DATA = {
+ test: 'bsData'
+ }
+
let fixtureEl
+ let div
beforeAll(() => {
fixtureEl = getFixture()
})
+ beforeEach(() => {
+ fixtureEl.innerHTML = '<div></div>'
+ div = fixtureEl.querySelector('div')
+ })
+
afterEach(() => {
+ Data.remove(div, TEST_KEY)
clearFixture()
})
- describe('setData', () => {
- it('should set data in an element by adding a bsKey attribute', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
- expect(div.bsKey).toBeDefined()
- })
+ it('should return null for unknown elements', () => {
+ const data = { ...TEST_DATA }
- it('should change data if something is already stored', () => {
- fixtureEl.innerHTML = '<div></div>'
+ Data.set(div, TEST_KEY, data)
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
-
- Data.setData(div, 'test', data)
-
- data.test = 'bsData2'
- Data.setData(div, 'test', data)
-
- expect(div.bsKey).toBeDefined()
- })
+ expect(Data.get(null)).toBeNull()
+ expect(Data.get(undefined)).toBeNull()
+ expect(Data.get(document.createElement('div'), TEST_KEY)).toBeNull()
})
- describe('getData', () => {
- it('should return stored data', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
+ it('should return null for unknown keys', () => {
+ const data = { ...TEST_DATA }
- Data.setData(div, 'test', data)
- expect(Data.getData(div, 'test')).toEqual(data)
- })
+ Data.set(div, TEST_KEY, data)
- it('should return null on undefined element', () => {
- expect(Data.getData(null)).toEqual(null)
- expect(Data.getData(undefined)).toEqual(null)
- })
-
- it('should return null when an element have nothing stored', () => {
- fixtureEl.innerHTML = '<div></div>'
-
- const div = fixtureEl.querySelector('div')
-
- expect(Data.getData(div, 'test')).toEqual(null)
- })
-
- it('should return null when an element have nothing stored with the provided key', () => {
- fixtureEl.innerHTML = '<div></div>'
+ expect(Data.get(div, null)).toBeNull()
+ expect(Data.get(div, undefined)).toBeNull()
+ expect(Data.get(div, UNKNOWN_KEY)).toBeNull()
+ })
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
+ it('should store data for an element with a given key and return it', () => {
+ const data = { ...TEST_DATA }
- Data.setData(div, 'test', data)
+ Data.set(div, TEST_KEY, data)
- expect(Data.getData(div, 'test2')).toEqual(null)
- })
+ expect(Data.get(div, TEST_KEY)).toBe(data)
})
- describe('removeData', () => {
- it('should do nothing when an element have nothing stored', () => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should overwrite data if something is already stored', () => {
+ const data = { ...TEST_DATA }
+ const copy = { ...data }
- const div = fixtureEl.querySelector('div')
+ Data.set(div, TEST_KEY, data)
+ Data.set(div, TEST_KEY, copy)
- Data.removeData(div, 'test')
- expect().nothing()
- })
+ expect(Data.get(div, TEST_KEY)).not.toBe(data)
+ expect(Data.get(div, TEST_KEY)).toBe(copy)
+ })
- it('should should do nothing if it\'s not a valid key provided', () => {
- fixtureEl.innerHTML = '<div></div>'
+ it('should do nothing when an element have nothing stored', () => {
+ Data.remove(div, TEST_KEY)
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
+ expect().nothing()
+ })
- Data.setData(div, 'test', data)
+ it('should remove nothing for an unknown key', () => {
+ const data = { ...TEST_DATA }
- expect(div.bsKey).toBeDefined()
+ Data.set(div, TEST_KEY, data)
+ Data.remove(div, UNKNOWN_KEY)
- Data.removeData(div, 'test2')
+ expect(Data.get(div, TEST_KEY)).toBe(data)
+ })
- expect(div.bsKey).toBeDefined()
- })
+ it('should remove data for a given key', () => {
+ const data = { ...TEST_DATA }
- it('should remove data if something is stored', () => {
- fixtureEl.innerHTML = '<div></div>'
+ Data.set(div, TEST_KEY, data)
+ Data.remove(div, TEST_KEY)
- const div = fixtureEl.querySelector('div')
- const data = {
- test: 'bsData'
- }
+ expect(Data.get(div, TEST_KEY)).toBeNull()
+ })
- Data.setData(div, 'test', data)
+ it('should console.error a message if called with multiple keys', () => {
+ /* eslint-disable no-console */
+ console.error = jasmine.createSpy('console.error')
- expect(div.bsKey).toBeDefined()
+ const data = { ...TEST_DATA }
+ const copy = { ...data }
- Data.removeData(div, 'test')
+ Data.set(div, TEST_KEY, data)
+ Data.set(div, UNKNOWN_KEY, copy)
- expect(div.bsKey).toBeUndefined()
- })
+ expect(console.error).toHaveBeenCalled()
+ expect(Data.get(div, UNKNOWN_KEY)).toBe(null)
})
})