diff options
Diffstat (limited to 'js/src/dom')
| -rw-r--r-- | js/src/dom/data.js | 82 | ||||
| -rw-r--r-- | js/src/dom/event-handler.js | 41 | ||||
| -rw-r--r-- | js/src/dom/manipulator.js | 2 | ||||
| -rw-r--r-- | js/src/dom/selector-engine.js | 15 |
4 files changed, 72 insertions, 68 deletions
diff --git a/js/src/dom/data.js b/js/src/dom/data.js index 0a47a58d7..41ad08ab3 100644 --- a/js/src/dom/data.js +++ b/js/src/dom/data.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0-alpha3): dom/data.js + * Bootstrap (v5.0.0-beta3): dom/data.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ @@ -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 diff --git a/js/src/dom/event-handler.js b/js/src/dom/event-handler.js index ceb6a6e6e..3293f397d 100644 --- a/js/src/dom/event-handler.js +++ b/js/src/dom/event-handler.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0-alpha3): dom/event-handler.js + * Bootstrap (v5.0.0-beta3): dom/event-handler.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ @@ -22,6 +22,7 @@ const customEvents = { mouseenter: 'mouseover', mouseleave: 'mouseout' } +const customEventsRegex = /^(mouseenter|mouseleave)/i const nativeEvents = new Set([ 'click', 'dblclick', @@ -112,7 +113,8 @@ function bootstrapDelegationHandler(element, selector, fn) { event.delegateTarget = target if (handler.oneOff) { - EventHandler.off(element, event.type, fn) + // eslint-disable-next-line unicorn/consistent-destructuring + EventHandler.off(element, event.type, selector, fn) } return fn.apply(target, [event]) @@ -143,14 +145,7 @@ function normalizeParams(originalTypeEvent, handler, delegationFn) { const delegation = typeof handler === 'string' const originalHandler = delegation ? delegationFn : handler - // allow to get the native events from namespaced events ('click.bs.button' --> 'click') - let typeEvent = originalTypeEvent.replace(stripNameRegex, '') - const custom = customEvents[typeEvent] - - if (custom) { - typeEvent = custom - } - + let typeEvent = getTypeEvent(originalTypeEvent) const isNative = nativeEvents.has(typeEvent) if (!isNative) { @@ -170,6 +165,24 @@ function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) { delegationFn = null } + // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position + // this prevents the handler from being dispatched the same way as mouseover or mouseout does + if (customEventsRegex.test(originalTypeEvent)) { + const wrapFn = fn => { + return function (event) { + if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) { + return fn.call(this, event) + } + } + } + + if (delegationFn) { + delegationFn = wrapFn(delegationFn) + } else { + handler = wrapFn(handler) + } + } + const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn) const events = getEvent(element) const handlers = events[typeEvent] || (events[typeEvent] = {}) @@ -218,6 +231,12 @@ function removeNamespacedHandlers(element, events, typeEvent, namespace) { }) } +function getTypeEvent(event) { + // allow to get the native events from namespaced events ('click.bs.button' --> 'click') + event = event.replace(stripNameRegex, '') + return customEvents[event] || event +} + const EventHandler = { on(element, event, handler, delegationFn) { addHandler(element, event, handler, delegationFn, false) @@ -271,7 +290,7 @@ const EventHandler = { } const $ = getjQuery() - const typeEvent = event.replace(stripNameRegex, '') + const typeEvent = getTypeEvent(event) const inNamespace = event !== typeEvent const isNative = nativeEvents.has(typeEvent) diff --git a/js/src/dom/manipulator.js b/js/src/dom/manipulator.js index ed74e0ce2..73b409f7e 100644 --- a/js/src/dom/manipulator.js +++ b/js/src/dom/manipulator.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0-alpha3): dom/manipulator.js + * Bootstrap (v5.0.0-beta3): dom/manipulator.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ diff --git a/js/src/dom/selector-engine.js b/js/src/dom/selector-engine.js index b42c30c3f..116b02741 100644 --- a/js/src/dom/selector-engine.js +++ b/js/src/dom/selector-engine.js @@ -1,6 +1,6 @@ /** * -------------------------------------------------------------------------- - * Bootstrap (v5.0.0-alpha3): dom/selector-engine.js + * Bootstrap (v5.0.0-beta3): dom/selector-engine.js * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) * -------------------------------------------------------------------------- */ @@ -14,10 +14,6 @@ const NODE_TEXT = 3 const SelectorEngine = { - matches(element, selector) { - return element.matches(selector) - }, - find(selector, element = document.documentElement) { return [].concat(...Element.prototype.querySelectorAll.call(element, selector)) }, @@ -27,9 +23,8 @@ const SelectorEngine = { }, children(element, selector) { - const children = [].concat(...element.children) - - return children.filter(child => child.matches(selector)) + return [].concat(...element.children) + .filter(child => child.matches(selector)) }, parents(element, selector) { @@ -38,7 +33,7 @@ const SelectorEngine = { let ancestor = element.parentNode while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) { - if (this.matches(ancestor, selector)) { + if (ancestor.matches(selector)) { parents.push(ancestor) } @@ -66,7 +61,7 @@ const SelectorEngine = { let next = element.nextElementSibling while (next) { - if (this.matches(next, selector)) { + if (next.matches(selector)) { return [next] } |
