Skip to content

Commit

Permalink
Rewritten modal without jquery (#23955)
Browse files Browse the repository at this point in the history
* Trigger jquery events if available in event handler

* Rewritten modal without jquery
  • Loading branch information
alekitto authored and Johann-S committed Sep 17, 2017
1 parent 28301cd commit ef8a002
Show file tree
Hide file tree
Showing 10 changed files with 551 additions and 169 deletions.
2 changes: 1 addition & 1 deletion js/src/carousel.js
Expand Up @@ -205,7 +205,7 @@ const Carousel = (() => {
}

dispose() {
EventHandler.off(this._element, DATA_KEY)
EventHandler.off(this._element, EVENT_KEY)
Data.removeData(this._element, DATA_KEY)

this._items = null
Expand Down
2 changes: 1 addition & 1 deletion js/src/dom/data.js
Expand Up @@ -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
}

Expand Down
105 changes: 81 additions & 24 deletions js/src/dom/eventHandler.js
Expand Up @@ -70,6 +70,7 @@ if (!window.Event || typeof window.Event !== 'function') {
const namespaceRegex = /[^.]*(?=\..*)\.|.*/
const stripNameRegex = /\..*/
const keyEventRegex = /^key/
const stripUidRegex = /::\d+$/

// Events storage
const eventRegistry = {}
Expand Down Expand Up @@ -117,10 +118,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) {
Expand All @@ -133,6 +134,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'
Expand Down Expand Up @@ -162,7 +183,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
Expand All @@ -186,43 +207,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)
}
}
},

Expand All @@ -233,15 +260,33 @@ 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) {
evt = document.createEvent('HTMLEvents')
evt.initEvent(typeEvent, true, true)
} else {
evt = new CustomEvent(event, {
bubbles: true,
bubbles,
cancelable: true
})
}
Expand All @@ -250,7 +295,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
},

Expand Down
20 changes: 20 additions & 0 deletions js/src/dom/manipulator.js
@@ -1,3 +1,5 @@
import Util from '../util'

/**
* --------------------------------------------------------------------------
* Bootstrap (v4.0.0-beta): dom/manipulator.js
Expand All @@ -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()}`)}`)
}
}

Expand Down

0 comments on commit ef8a002

Please sign in to comment.