Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use a Map instead of an Object in dom/data #32180

Merged
merged 10 commits into from
Mar 2, 2021
2 changes: 1 addition & 1 deletion .bundlewatch.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
},
{
"path": "./dist/js/bootstrap.bundle.min.js",
"maxSize": "21.75 kB"
"maxSize": "22 kB"
},
{
"path": "./dist/js/bootstrap.esm.js",
Expand Down
2 changes: 1 addition & 1 deletion js/src/alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class Alert extends BaseComponent {

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)
Expand Down
6 changes: 3 additions & 3 deletions js/src/base-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ class BaseComponent {
}

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() {
Expand Down
4 changes: 2 additions & 2 deletions js/src/button.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Button extends BaseComponent {

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)
Expand All @@ -75,7 +75,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {

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)
}
Expand Down
6 changes: 3 additions & 3 deletions js/src/carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ class Carousel extends BaseComponent {
// 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)
Expand Down Expand Up @@ -586,7 +586,7 @@ class Carousel extends BaseComponent {
Carousel.carouselInterface(target, config)

if (slideIndex) {
Data.getData(target, DATA_KEY).to(slideIndex)
Data.get(target, DATA_KEY).to(slideIndex)
}

event.preventDefault()
Expand All @@ -605,7 +605,7 @@ EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
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))
}
})

Expand Down
8 changes: 4 additions & 4 deletions js/src/collapse.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class Collapse extends BaseComponent {
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
Expand All @@ -166,7 +166,7 @@ class Collapse extends BaseComponent {
}

if (!activesData) {
Data.setData(elemActive, DATA_KEY, null)
Data.set(elemActive, DATA_KEY, null)
}
})
}
Expand Down Expand Up @@ -332,7 +332,7 @@ class Collapse extends BaseComponent {
// 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),
Expand Down Expand Up @@ -380,7 +380,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
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
Expand Down
80 changes: 35 additions & 45 deletions js/src/dom/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,47 @@
* ------------------------------------------------------------------------
*/

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
4 changes: 2 additions & 2 deletions js/src/dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class Dropdown extends BaseComponent {
// 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) {
Expand Down Expand Up @@ -387,7 +387,7 @@ class Dropdown extends BaseComponent {
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]
}
Expand Down
4 changes: 2 additions & 2 deletions js/src/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ class Modal extends BaseComponent {

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),
Expand Down Expand Up @@ -556,7 +556,7 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
})
})

let data = Data.getData(target, DATA_KEY)
let data = Data.get(target, DATA_KEY)
if (!data) {
const config = {
...Manipulator.getDataAttributes(target),
Expand Down
4 changes: 2 additions & 2 deletions js/src/popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class Popover extends Tooltip {

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)) {
Expand All @@ -145,7 +145,7 @@ class Popover extends Tooltip {

if (!data) {
data = new Popover(this, _config)
Data.setData(this, DATA_KEY, data)
Data.set(this, DATA_KEY, data)
}

if (typeof config === 'string') {
Expand Down
2 changes: 1 addition & 1 deletion js/src/scrollspy.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ class ScrollSpy extends BaseComponent {

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) {
Expand Down
4 changes: 2 additions & 2 deletions js/src/tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ class Tab extends BaseComponent {

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') {
Expand All @@ -204,7 +204,7 @@ class Tab extends BaseComponent {
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()
})

Expand Down
2 changes: 1 addition & 1 deletion js/src/toast.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class Toast extends BaseComponent {

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) {
Expand Down
8 changes: 4 additions & 4 deletions js/src/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class Tooltip extends BaseComponent {
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)
Expand Down Expand Up @@ -465,11 +465,11 @@ class Tooltip extends BaseComponent {

_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
Expand Down Expand Up @@ -761,7 +761,7 @@ class Tooltip extends BaseComponent {

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)) {
Expand Down
Loading