Add familiar, standard JavaScript event handling methods for custom objects based on EventTarget.
Based on original code from mrdoob and ShareIt-project.
Supports stricter API requirements and a number of additional methods to mimic
EventTarget
.
<script src="node_modules/eventtargeter/EventTarget.js"></script>
const {
EventTargetFactory, ShimEventTarget,
ShimEvent, ShimCustomEvent,
ShimDOMException, setPrototypeOfCustomEvent
} = EventTargeter;
or just:
import {
EventTargetFactory, ShimEventTarget,
ShimEvent, ShimCustomEvent,
ShimDOMException, setPrototypeOfCustomEvent
} from './node_modules/eventtargeter/EventTarget-es6.js';
npm install
const EventTarget = require('eventtarget');
<script>
// Adding events to custom object
const Car = function () {
this.start = function () {
this.dispatchEvent({type: 'start', message: 'vroom vroom!'});
};
};
Object.assign(Car.prototype, EventTarget.prototype);
// Using events
const car = new Car();
car.addEventListener('start', function (ev) {
alert(ev.message);
});
car.start();
</script>
If you inherit from EventTarget
, you can invoke the (non-standard)
constructor with options. See __setOptions
.
The following behave as with the standard EventTarget
methods
(as possible). Options supported include the standard options, capture
(including expressed as a boolean), as well as once
(which auto-removes
the listener after execution) and passive
(which prevents the listener
from using preventDefault
even if the event passed to the target was
cancelable
).
-
addEventListener(type, listener, options)
- These standard methods cannot prevent execution of the non-standardaddDefaultEventListener
/addLateEventListener
-added methods. -
removeEventListener(type, listener, options)
-
dispatchEvent(ev)
- Will check as appropriate the event'stype
,bubbles
orcancelable
(which can all be set with invocation of the constructor,Event
) or the readonlyeventPhase
anddefaultPrevented
. The propertiestarget
,currentTarget
,eventPhase
, anddefaultPrevented
will be set as appropriate. -
on* = function (ev) {};
(e.g.,onclick
) - Can usereturn false
to prevent the default (but this will not stop propagation or stop immediate propagation as per regular JavaScript behavior (unlike jQuery which stops propagation)).
Note that if an error throws within one of the listeners, an ErrorEvent
will
be dispatched to window
as expected, or, if on Node, you can listen instead
for uncaughtException
. Alternatively, you may implement your own
__userErrorEventHandler
method (see below).
The following are non-standard methods:
-
__setOptions(optsObject)
- Set custom options. Currently limited todefaultSync
which can be set totrue
to execute the default behaviors even before late listeners and beforedispatchEvent
returns. Default listeners will otherwise be triggered aftersetTimeout(..., 0)
. -
hasEventListener(type, listener, options)
- Detects whether a given event listener exists -
<add/remove/has>EarlyEventListener
- Allows maintenance of functions which execute prior to all other event listeners. These should generally not stop propagation or prevent the default behavior since that should normally be left up to the consumer. Note that capturing and bubbling do not occur for early listeners. -
<add/remove/has>DefaultEventListener
- Allows maintenance of functions which execute subsequent to all normal event listeners and which can be prevented viapreventDefault
(or checked viadefaultPrevented
) unless the event dispatched to the target is not cancelable. These events will not be stopped bystopPropagation
orstopImmediatePropagation
alone. (You can check thedefaultPrevented
property in these methods to determine whether the user has callede.preventDefault()
and thus to decide whether to continue on with some default behavior.) These cannot usestopPropagation
to stop execution of late event listeners (though they can usestopImmediatePropagation
to prevent further execution of other default listeners). Note that capturing and bubbling do not occur for default listeners. -
<add/remove/has>LateEventListener
- Allows maintenance of functions which execute subsequent to all event listeners (unless default behaviors are set to run asynchronously) and which cannot be stopped. Should be used within implementations only to avoid unexpected behavior by consumers. If default event listeners fire after late listeners (whendefaultSync
is true), late listeners can prevent default event execution. Note that capturing and bubbling do not occur for late listeners.stopPropagation
has no relevance (even if occurring before default listeners) (thoughstopImmediatePropagation
may be used to prevent further execution of other late listeners). -
__getParent
- This method can be implemented by consumers to support hierarchical events (those with bubbling and/or capturing). Should itself return anEventTarget
object. -
__userErrorEventHandler(errorObj, triggerGlobalErrorEventCb)
- This method can be implemented by consumers to override the default behavior relating to triggering of a globalErrorEvent
upon encountering exceptions within handlers. Will be passed an object representing the thrown error and a callback which can be invoked to trigger the usual globalErrorEvent
behavior. An example usage is for an IndexedDB transaction object which must abort a transaction upon encountering an error in a user event handler. This method could be used to implement the aborting or it could merely rethrow the error object passed to it and allow the internal consuming code to catch it and abort the transaction. If using this handler, you should ideally use a flag in your calling code and utilize that in this handler in order to distinguish between your own specific internal error events and those dispatched by users in their owndispatchEvent
calls (which shouldn't ever throw as that would be non-standard for the realEventTarget
).
Because Object.setPrototypeOf
is not supported in all environments (e.g.,
React-Native currently) and it comes at a cost for performance without
much strong of a benefit (besides introspecting on the prototype chain),
these calls to associate ShimCustomEvent
with ShimEvent
no longer occur
automatically. If desired (e.g., for passing IDL tests), they can be set
using setPrototypeOfCustomEvent
.
ShimEvent
, ShimCustomEvent
, and ShimDOMException
should generally
follow the standard API for the objects they are shimming.
-
See
todo
's' within code. -
Align with new standard.
-
Option to set global
event
(Does this redefine or alter the object for capturing, bubbling, etc.?) -
Support
worker.onerror
-
Allow
__getParent
to return a promise to allow async bubbling -
Consider refactoring so that all methods (as with properties) are private and all early/late/default listeners, parent retrieval, and option setting are done dynamically at class creation time or, alternatively, at any time via ES6 Symbols (Babel) which are somewhat more "safely" namespaced. Remove
hasEventListener
as it is necessarily run-time and non-standard. -
Add
getEventHandler
andsetEventHandler
methods (ala Mozilla)? -
Provide option for early, late, and default listeners to capture and bubble (will need to propagate independently of normal listeners)?
-
Add another type of late listener or config which executes even after async default?
-
Demo
click()
(for capturing/bubbling/propagation) andsubmit()
(for default and default prevention) on implementations on JSON.