From aed785924d886a76f72dd4dbdc1ded3addb259cf Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 24 Aug 2015 16:15:48 -0600 Subject: [PATCH] Continue to dispatch CustomEvent instances in CommandRegistry This changes the approach used to synthesize an event to dispatch. Since we can no longer point to the original event as our prototype, we build a new CustomEvent instance and override select properties with Object.defineProperty. This preserves the contract with event handlers by giving them a true CustomEvent instance. --- src/command-registry.coffee | 58 +++++++++++++++---------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/src/command-registry.coffee b/src/command-registry.coffee index d2fa1c019..5543737c1 100644 --- a/src/command-registry.coffee +++ b/src/command-registry.coffee @@ -175,17 +175,8 @@ class CommandRegistry # * `commandName` {String} indicating the name of the command to dispatch. dispatch: (target, commandName, detail) -> event = new CustomEvent(commandName, {bubbles: true, detail}) - eventWithTarget = Object.create {}, - target: value: target - preventDefault: value: -> - stopPropagation: value: -> - stopImmediatePropagation: value: -> - # NOTE: In Chrome 43, Object.create doesn't work well with CustomEvent; - # However utilizing _.defaults here doesn't really do anything since all properties have been - # moved from "own" to the prototype, so we should update this to fully shadowing the properties - # from Event.prototype (+ detail property from CustomEvent). - eventWithTarget = _.defaults(eventWithTarget, event) - @handleCommandEvent(eventWithTarget) + Object.defineProperty(event, 'target', value: target) + @handleCommandEvent(event) # Public: Invoke the given callback before dispatching a command event. # @@ -213,37 +204,36 @@ class CommandRegistry @selectorBasedListenersByCommandName[commandName] = listeners.slice() return - handleCommandEvent: (originalEvent) => + handleCommandEvent: (event) => propagationStopped = false immediatePropagationStopped = false matched = false - currentTarget = originalEvent.target + currentTarget = event.target + {preventDefault, stopPropagation, stopImmediatePropagation, abortKeyBinding} = event - syntheticEvent = Object.create {}, - eventPhase: value: Event.BUBBLING_PHASE - currentTarget: get: -> currentTarget - target: value: currentTarget - preventDefault: value: -> - originalEvent.preventDefault() - stopPropagation: value: -> - originalEvent.stopPropagation() - propagationStopped = true - stopImmediatePropagation: value: -> - originalEvent.stopImmediatePropagation() - propagationStopped = true - immediatePropagationStopped = true - abortKeyBinding: value: -> - originalEvent.abortKeyBinding?() - # NOTE: See similar scenario in ::dispatch. - syntheticEvent = _.defaults(syntheticEvent, originalEvent) + dispatchedEvent = new CustomEvent(event.type, {bubbles: true, detail: event.detail}) + Object.defineProperty dispatchedEvent, 'eventPhase', value: Event.BUBBLING_PHASE + Object.defineProperty dispatchedEvent, 'currentTarget', get: -> currentTarget + Object.defineProperty dispatchedEvent, 'target', value: currentTarget + Object.defineProperty dispatchedEvent, 'preventDefault', value: -> + event.preventDefault() + Object.defineProperty dispatchedEvent, 'stopPropagation', value: -> + event.stopPropagation() + propagationStopped = true + Object.defineProperty dispatchedEvent, 'stopImmediatePropagation', value: -> + event.stopImmediatePropagation() + propagationStopped = true + immediatePropagationStopped = true + Object.defineProperty dispatchedEvent, 'abortKeyBinding', value: -> + event.abortKeyBinding?() - @emitter.emit 'will-dispatch', syntheticEvent + @emitter.emit 'will-dispatch', dispatchedEvent loop - listeners = @inlineListenersByCommandName[originalEvent.type]?.get(currentTarget) ? [] + listeners = @inlineListenersByCommandName[event.type]?.get(currentTarget) ? [] if currentTarget.webkitMatchesSelector? selectorBasedListeners = - (@selectorBasedListenersByCommandName[originalEvent.type] ? []) + (@selectorBasedListenersByCommandName[event.type] ? []) .filter (listener) -> currentTarget.webkitMatchesSelector(listener.selector) .sort (a, b) -> a.compare(b) listeners = listeners.concat(selectorBasedListeners) @@ -252,7 +242,7 @@ class CommandRegistry for listener in listeners break if immediatePropagationStopped - listener.callback.call(currentTarget, syntheticEvent) + listener.callback.call(currentTarget, dispatchedEvent) break if currentTarget is window break if propagationStopped