aboutsummaryrefslogtreecommitdiff
path: root/js/src/dom
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/dom')
-rw-r--r--js/src/dom/data.js2
-rw-r--r--js/src/dom/eventHandler.js105
-rw-r--r--js/src/dom/manipulator.js20
3 files changed, 102 insertions, 25 deletions
diff --git a/js/src/dom/data.js b/js/src/dom/data.js
index 655706fbc..68908d8f2 100644
--- a/js/src/dom/data.js
+++ b/js/src/dom/data.js
@@ -21,7 +21,7 @@ const mapData = (() => {
id++
},
get(element, key) {
- if (typeof element.key === 'undefined') {
+ if (typeof element === 'undefined' || typeof element.key === 'undefined') {
return null
}
diff --git a/js/src/dom/eventHandler.js b/js/src/dom/eventHandler.js
index 746f84bcb..a69ab6136 100644
--- a/js/src/dom/eventHandler.js
+++ b/js/src/dom/eventHandler.js
@@ -63,6 +63,7 @@ if (!window.Event || typeof window.Event !== 'function') {
const namespaceRegex = /[^.]*(?=\..*)\.|.*/
const stripNameRegex = /\..*/
const keyEventRegex = /^key/
+const stripUidRegex = /::\d+$/
// Events storage
const eventRegistry = {}
@@ -110,10 +111,10 @@ function bootstrapHandler(element, fn) {
}
}
-function bootstrapDelegationHandler(selector, fn) {
+function bootstrapDelegationHandler(element, selector, fn) {
return function (event) {
event = fixEvent(event)
- const domElements = document.querySelectorAll(selector)
+ const domElements = element.querySelectorAll(selector)
for (let target = event.target; target && target !== this; target = target.parentNode) {
for (let i = domElements.length; i--;) {
if (domElements[i] === target) {
@@ -126,6 +127,26 @@ function bootstrapDelegationHandler(selector, fn) {
}
}
+function removeHandler(element, events, typeEvent, handler) {
+ const uidEvent = handler.uidEvent
+ const fn = events[typeEvent][uidEvent]
+ element.removeEventListener(typeEvent, fn, fn.delegation)
+ delete events[typeEvent][uidEvent]
+}
+
+function removeNamespacedHandlers(element, events, typeEvent, namespace) {
+ const storeElementEvent = events[typeEvent] || {}
+ for (const handlerKey in storeElementEvent) {
+ if (!Object.prototype.hasOwnProperty.call(storeElementEvent, handlerKey)) {
+ continue
+ }
+
+ if (handlerKey.indexOf(namespace) > -1) {
+ removeHandler(element, events, typeEvent, storeElementEvent[handlerKey].originalHandler)
+ }
+ }
+}
+
const EventHandler = {
on(element, originalTypeEvent, handler, delegationFn) {
if (typeof originalTypeEvent !== 'string' ||
@@ -155,7 +176,7 @@ const EventHandler = {
return
}
- const fn = !delegation ? bootstrapHandler(element, handler) : bootstrapDelegationHandler(handler, delegationFn)
+ const fn = !delegation ? bootstrapHandler(element, handler) : bootstrapDelegationHandler(element, handler, delegationFn)
fn.isDelegation = delegation
handlers[uid] = fn
originalHandler.uidEvent = uid
@@ -179,43 +200,49 @@ const EventHandler = {
const events = getEvent(element)
let typeEvent = originalTypeEvent.replace(stripNameRegex, '')
+
const inNamespace = typeEvent !== originalTypeEvent
const custom = customEvents[typeEvent]
if (custom) {
typeEvent = custom
}
+
const isNative = nativeEvents.indexOf(typeEvent) > -1
if (!isNative) {
typeEvent = originalTypeEvent
}
- if (typeof handler === 'undefined') {
+ if (typeof handler !== 'undefined') {
+ // Simplest case: handler is passed, remove that listener ONLY.
+ if (!events || !events[typeEvent]) {
+ return
+ }
+
+ removeHandler(element, events, typeEvent, handler)
+ return
+ }
+
+ const isNamespace = originalTypeEvent.charAt(0) === '.'
+ if (isNamespace) {
for (const elementEvent in events) {
if (!Object.prototype.hasOwnProperty.call(events, elementEvent)) {
continue
}
- const storeElementEvent = events[elementEvent]
- for (const keyHandlers in storeElementEvent) {
- if (!Object.prototype.hasOwnProperty.call(storeElementEvent, keyHandlers)) {
- continue
- }
- // delete all the namespaced listeners
- if (inNamespace && keyHandlers.indexOf(originalTypeEvent) > -1) {
- const handlerFn = events[elementEvent][keyHandlers]
- EventHandler.off(element, elementEvent, handlerFn.originalHandler)
- }
- }
+ removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.substr(1))
}
- } else {
- if (!events || !events[typeEvent]) {
- return
+ }
+
+ const storeElementEvent = events[typeEvent] || {}
+ for (const keyHandlers in storeElementEvent) {
+ if (!Object.prototype.hasOwnProperty.call(storeElementEvent, keyHandlers)) {
+ continue
}
- const uidEvent = handler.uidEvent
- const fn = events[typeEvent][uidEvent]
- element.removeEventListener(typeEvent, fn, fn.delegation)
- delete events[typeEvent][uidEvent]
+ const handlerKey = keyHandlers.replace(stripUidRegex, '')
+ if (!inNamespace || originalTypeEvent.indexOf(handlerKey) > -1) {
+ removeHandler(element, events, typeEvent, storeElementEvent[keyHandlers].originalHandler)
+ }
}
},
@@ -226,7 +253,25 @@ const EventHandler = {
}
const typeEvent = event.replace(stripNameRegex, '')
+ const inNamespace = event !== typeEvent
const isNative = nativeEvents.indexOf(typeEvent) > -1
+
+ const $ = Util.jQuery
+ let jQueryEvent
+
+ let bubbles = true
+ let nativeDispatch = true
+ let defaultPrevented = false
+
+ if (inNamespace && typeof $ !== 'undefined') {
+ jQueryEvent = new $.Event(event, args)
+
+ $(element).trigger(jQueryEvent)
+ bubbles = !jQueryEvent.isPropagationStopped()
+ nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()
+ defaultPrevented = jQueryEvent.isDefaultPrevented()
+ }
+
let evt = null
if (isNative) {
@@ -234,7 +279,7 @@ const EventHandler = {
evt.initEvent(typeEvent, true, true)
} else {
evt = new CustomEvent(event, {
- bubbles: true,
+ bubbles,
cancelable: true
})
}
@@ -243,7 +288,19 @@ const EventHandler = {
if (typeof args !== 'undefined') {
evt = Util.extend(evt, args)
}
- element.dispatchEvent(evt)
+
+ if (defaultPrevented) {
+ evt.preventDefault()
+ }
+
+ if (nativeDispatch) {
+ element.dispatchEvent(evt)
+ }
+
+ if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') {
+ jQueryEvent.preventDefault()
+ }
+
return evt
}
}
diff --git a/js/src/dom/manipulator.js b/js/src/dom/manipulator.js
index c12480234..b8136dda1 100644
--- a/js/src/dom/manipulator.js
+++ b/js/src/dom/manipulator.js
@@ -1,3 +1,5 @@
+import Util from '../util'
+
/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-beta): dom/manipulator.js
@@ -18,6 +20,24 @@ const Manipulator = {
return input.bsChecked || input.checked
}
throw new Error('INPUT parameter is not an HTMLInputElement')
+ },
+
+ setDataAttribute(element, key, value) {
+ const $ = Util.jQuery
+ if (typeof $ !== 'undefined') {
+ $(element).data(key, value)
+ }
+
+ element.setAttribute(`data-${key.replace(/[A-Z]/g, (chr) => `-${chr.toLowerCase()}`)}`, value)
+ },
+
+ removeDataAttribute(element, key) {
+ const $ = Util.jQuery
+ if (typeof $ !== 'undefined') {
+ $(element).removeData(key)
+ }
+
+ element.removeAttribute(`data-${key.replace(/[A-Z]/g, (chr) => `-${chr.toLowerCase()}`)}`)
}
}