Socket
Socket
Sign inDemoInstall

event-target-shim

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

event-target-shim - npm Package Compare versions

Comparing version 2.0.0 to 3.0.0

dist/event-target-shim.js.map

1113

dist/event-target-shim.js

@@ -1,597 +0,756 @@

(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.eventTargetShim = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* @author Toru Nagashima
* @author Toru Nagashima <https://github.com/mysticatea>
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
"use strict"
'use strict';
/**
* Creates a unique key.
*
* @param {string} name - A name to create.
* @returns {symbol|string} Generated unique key.
* @private
*/
var createUniqueKey = module.exports.createUniqueKey = (
typeof Symbol !== "undefined" ? Symbol : //eslint-disable-line no-undef
/* otherwise */ function createUniqueKey(name) {
return "[[" + name + "_" + Math.random().toFixed(8).slice(2) + "]]"
}
)
Object.defineProperty(exports, '__esModule', { value: true });
/**
* Checks whether the given value is a non-null object or not.
*
* @param {any} x - The value to be check.
* @returns {boolean} `true` if the value is a non-null object.
* @typedef {object} PrivateData
* @property {EventTarget} eventTarget The event target.
* @property {{type:string}} event The original event object.
* @property {number} eventPhase The current event phase.
* @property {EventTarget|null} currentTarget The current event target.
* @property {boolean} canceled The flag to prevent default.
* @property {boolean} stopped The flag to stop propagation immediately.
* @property {Function|null} passiveListener The listener if the current listener is passive. Otherwise this is null.
* @property {number} timeStamp The unix time.
* @private
*/
var isObject = module.exports.isObject = function isObject(x) {
return typeof x === "object" && x !== null
}
/**
* The key of listeners.
*
* @type {symbol|string}
* Private data for event wrappers.
* @type {WeakMap<Event, PrivateData>}
* @private
*/
module.exports.LISTENERS = createUniqueKey("listeners")
const privateData = new WeakMap();
/**
* A value of kind for listeners which are registered in the capturing phase.
*
* @type {number}
* Cache for wrapper classes.
* @type {WeakMap<Object, Function>}
* @private
*/
module.exports.CAPTURE = 1
const wrappers = new WeakMap();
/**
* A value of kind for listeners which are registered in the bubbling phase.
*
* @type {number}
* Get private data.
* @param {Event} event The event object to get private data.
* @returns {PrivateData} The private data of the event.
* @private
*/
module.exports.BUBBLE = 2
function pd(event) {
const retv = privateData.get(event);
console.assert(retv != null, "'this' is expected an Event object, but got", event);
return retv
}
/**
* A value of kind for listeners which are registered as an attribute.
*
* @type {number}
* @see https://dom.spec.whatwg.org/#interface-event
* @private
*/
module.exports.ATTRIBUTE = 3
/**
* @typedef object ListenerNode
* @property {function} listener - A listener function.
* @property {number} kind - The kind of the listener.
* @property {ListenerNode|null} next - The next node.
* If this node is the last, this is `null`.
* The event wrapper.
* @constructor
* @param {EventTarget} eventTarget The event target of this dispatching.
* @param {Event|{type:string}} event The original event to wrap.
*/
function Event(eventTarget, event) {
privateData.set(this, {
eventTarget,
event,
eventPhase: 2,
currentTarget: eventTarget,
canceled: false,
stopped: false,
passiveListener: null,
timeStamp: event.timeStamp || Date.now(),
});
/**
* Creates a node of singly linked list for a list of listeners.
*
* @param {function} listener - A listener function.
* @param {number} kind - The kind of the listener.
* @param {object} [options] - The option object.
* @param {boolean} [options.once] - The flag to remove the listener at the first call.
* @param {boolean} [options.passive] - The flag to ignore `event.preventDefault` method.
* @returns {ListenerNode} The created listener node.
*/
module.exports.newNode = function newNode(listener, kind, options) {
var obj = isObject(options)
// https://heycam.github.io/webidl/#Unforgeable
Object.defineProperty(this, "isTrusted", { value: false, enumerable: true });
return {
listener: listener,
kind: kind,
once: obj && Boolean(options.once),
passive: obj && Boolean(options.passive),
next: null,
// Define accessors
const keys = Object.keys(event);
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
if (!(key in this)) {
Object.defineProperty(this, key, defineRedirectDescriptor(key));
}
}
}
},{}],2:[function(require,module,exports){
/**
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
"use strict"
// Should be enumerable, but class methods are not enumerable.
Event.prototype = {
/**
* The type of this event.
* @type {string}
*/
get type() {
return pd(this).event.type
},
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
/**
* The target of this event.
* @type {EventTarget}
*/
get target() {
return pd(this).eventTarget
},
var Commons = require("./commons")
var LISTENERS = Commons.LISTENERS
var ATTRIBUTE = Commons.ATTRIBUTE
var newNode = Commons.newNode
/**
* The target of this event.
* @type {EventTarget}
*/
get currentTarget() {
return pd(this).currentTarget
},
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
/**
* @returns {EventTarget[]} The composed path of this event.
*/
composedPath() {
const currentTarget = pd(this).currentTarget;
if (currentTarget == null) {
return []
}
return [currentTarget]
},
/**
* Gets a specified attribute listener from a given EventTarget object.
*
* @param {EventTarget} eventTarget - An EventTarget object to get.
* @param {string} type - An event type to get.
* @returns {function|null} The found attribute listener.
*/
function getAttributeListener(eventTarget, type) {
var node = eventTarget[LISTENERS][type]
while (node != null) {
if (node.kind === ATTRIBUTE) {
return node.listener
/**
* Constant of NONE.
* @type {number}
*/
get NONE() {
return 0
},
/**
* Constant of CAPTURING_PHASE.
* @type {number}
*/
get CAPTURING_PHASE() {
return 1
},
/**
* Constant of AT_TARGET.
* @type {number}
*/
get AT_TARGET() {
return 2
},
/**
* Constant of BUBBLING_PHASE.
* @type {number}
*/
get BUBBLING_PHASE() {
return 3
},
/**
* The target of this event.
* @type {number}
*/
get eventPhase() {
return pd(this).eventPhase
},
/**
* Stop event bubbling.
* @returns {void}
*/
stopPropagation() {
const data = pd(this);
if (typeof data.event.stopPropagation === "function") {
data.event.stopPropagation();
}
node = node.next
}
return null
}
},
/**
* Sets a specified attribute listener to a given EventTarget object.
*
* @param {EventTarget} eventTarget - An EventTarget object to set.
* @param {string} type - An event type to set.
* @param {function|null} listener - A listener to be set.
* @returns {void}
*/
function setAttributeListener(eventTarget, type, listener) {
if (typeof listener !== "function" && typeof listener !== "object") {
listener = null // eslint-disable-line no-param-reassign
}
/**
* Stop event bubbling.
* @returns {void}
*/
stopImmediatePropagation() {
const data = pd(this);
var prev = null
var node = eventTarget[LISTENERS][type]
while (node != null) {
if (node.kind === ATTRIBUTE) {
// Remove old value.
if (prev == null) {
eventTarget[LISTENERS][type] = node.next
}
else {
prev.next = node.next
}
data.stopped = true;
if (typeof data.event.stopImmediatePropagation === "function") {
data.event.stopImmediatePropagation();
}
else {
prev = node
}
},
node = node.next
}
/**
* The flag to be bubbling.
* @type {boolean}
*/
get bubbles() {
return Boolean(pd(this).event.bubbles)
},
// Add new value.
if (listener != null) {
if (prev == null) {
eventTarget[LISTENERS][type] = newNode(listener, ATTRIBUTE)
/**
* The flag to be cancelable.
* @type {boolean}
*/
get cancelable() {
return Boolean(pd(this).event.cancelable)
},
/**
* Cancel this event.
* @returns {void}
*/
preventDefault() {
const data = pd(this);
if (data.passiveListener != null) {
console.warn("Event#preventDefault() was called from a passive listener:", data.passiveListener);
return
}
else {
prev.next = newNode(listener, ATTRIBUTE)
if (!data.event.cancelable) {
return
}
}
}
//-----------------------------------------------------------------------------
// Public Interface
//-----------------------------------------------------------------------------
data.canceled = true;
if (typeof data.event.preventDefault === "function") {
data.event.preventDefault();
}
},
/**
* Defines an `EventTarget` implementation which has `onfoobar` attributes.
*
* @param {EventTarget} EventTargetBase - A base implementation of EventTarget.
* @param {string[]} types - A list of event types which are defined as attribute listeners.
* @returns {EventTarget} The defined `EventTarget` implementation which has attribute listeners.
*/
module.exports.defineCustomEventTarget = function(EventTargetBase, types) {
/**
* The constructor of custom event target.
* @constructor
* The flag to indicate cancellation state.
* @type {boolean}
*/
function EventTarget() {
EventTargetBase.call(this)
}
get defaultPrevented() {
return pd(this).canceled
},
var descripter = {
constructor: {
value: EventTarget,
configurable: true,
writable: true,
},
}
/**
* The flag to be composed.
* @type {boolean}
*/
get composed() {
return Boolean(pd(this).event.composed)
},
types.forEach(function(type) {
descripter["on" + type] = {
get: function() {
return getAttributeListener(this, type)
},
set: function(listener) {
setAttributeListener(this, type, listener)
},
configurable: true,
enumerable: true,
}
})
/**
* The unix time of this event.
* @type {number}
*/
get timeStamp() {
return pd(this).timeStamp
},
};
EventTarget.prototype = Object.create(EventTargetBase.prototype, descripter)
// `constructor` is not enumerable.
Object.defineProperty(Event.prototype, "constructor", { value: Event, configurable: true, writable: true });
return EventTarget
// Ensure `event instanceof window.Event` is `true`.
if (typeof window !== "undefined" && typeof window.Event !== "undefined") {
Object.setPrototypeOf(Event.prototype, window.Event.prototype);
// Make association for wrappers.
wrappers.set(window.Event.prototype, Event);
}
},{"./commons":1}],3:[function(require,module,exports){
/**
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
* Get the property descriptor to redirect a given property.
* @param {string} key Property name to define property descriptor.
* @returns {PropertyDescriptor} The property descriptor to redirect the property.
* @private
*/
"use strict"
function defineRedirectDescriptor(key) {
return {
get() {
return pd(this).event[key]
},
set(value) {
pd(this).event[key] = value;
},
configurable: true,
enumerable: true,
}
}
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
/*globals window */
var Commons = require("./commons")
var CustomEventTarget = require("./custom-event-target")
var EventWrapper = require("./event-wrapper")
var isObject = Commons.isObject
var LISTENERS = Commons.LISTENERS
var CAPTURE = Commons.CAPTURE
var BUBBLE = Commons.BUBBLE
var ATTRIBUTE = Commons.ATTRIBUTE
var newNode = Commons.newNode
var defineCustomEventTarget = CustomEventTarget.defineCustomEventTarget
var createEventWrapper = EventWrapper.createEventWrapper
var STOP_IMMEDIATE_PROPAGATION_FLAG = EventWrapper.STOP_IMMEDIATE_PROPAGATION_FLAG
var PASSIVE_LISTENER_FLAG = EventWrapper.PASSIVE_LISTENER_FLAG
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
/**
* A flag which shows there is the native `EventTarget` interface object.
*
* @type {boolean}
* Get the property descriptor to call a given method property.
* @param {string} key Property name to define property descriptor.
* @returns {PropertyDescriptor} The property descriptor to call the method property.
* @private
*/
var HAS_EVENTTARGET_INTERFACE = (
typeof window !== "undefined" &&
typeof window.EventTarget !== "undefined"
)
function defineCallDescriptor(key) {
return {
value() {
const event = pd(this).event;
return event[key].apply(event, arguments)
},
configurable: true,
enumerable: true,
}
}
//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------
/**
* An implementation for `EventTarget` interface.
*
* @constructor
* @public
* Define new wrapper class.
* @param {Function} BaseEvent The base wrapper class.
* @param {Object} proto The prototype of the original event.
* @returns {Function} The defined wrapper class.
* @private
*/
var EventTarget = module.exports = function EventTarget() {
if (this instanceof EventTarget) {
// this[LISTENERS] is a Map.
// Its key is event type.
// Its value is ListenerNode object or null.
//
// interface ListenerNode {
// var listener: Function
// var kind: CAPTURE|BUBBLE|ATTRIBUTE
// var next: ListenerNode|null
// }
Object.defineProperty(this, LISTENERS, {value: Object.create(null)})
function defineWrapper(BaseEvent, proto) {
const keys = Object.keys(proto);
if (keys.length === 0) {
return BaseEvent
}
else if (arguments.length === 1 && Array.isArray(arguments[0])) {
return defineCustomEventTarget(EventTarget, arguments[0])
}
else if (arguments.length > 0) {
var types = Array(arguments.length)
for (var i = 0; i < arguments.length; ++i) {
types[i] = arguments[i]
}
// To use to extend with attribute listener properties.
// e.g.
// class MyCustomObject extends EventTarget("message", "error") {
// //...
// }
return defineCustomEventTarget(EventTarget, types)
/** CustomEvent */
function CustomEvent(eventTarget, event) {
BaseEvent.call(this, eventTarget, event);
}
else {
throw new TypeError("Cannot call a class as a function")
}
}
EventTarget.prototype = Object.create(
(HAS_EVENTTARGET_INTERFACE ? window.EventTarget : Object).prototype,
{
constructor: {
value: EventTarget,
writable: true,
configurable: true,
},
CustomEvent.prototype = Object.create(BaseEvent.prototype, {
constructor: { value: CustomEvent, configurable: true, writable: true },
});
addEventListener: {
value: function addEventListener(type, listener, options) {
if (listener == null) {
return false
}
if (typeof listener !== "function" && typeof listener !== "object") {
throw new TypeError("\"listener\" is not an object.")
}
// Define accessors.
for (let i = 0; i < keys.length; ++i) {
const key = keys[i];
if (!(key in BaseEvent.prototype)) {
const descriptor = Object.getOwnPropertyDescriptor(proto, key);
const isFunc = (typeof descriptor.value === "function");
Object.defineProperty(
CustomEvent.prototype,
key,
isFunc ? defineCallDescriptor(key) : defineRedirectDescriptor(key)
);
}
}
var capture = isObject(options) ? Boolean(options.capture) : Boolean(options)
var kind = (capture ? CAPTURE : BUBBLE)
var node = this[LISTENERS][type]
if (node == null) {
this[LISTENERS][type] = newNode(listener, kind, options)
return true
}
return CustomEvent
}
var prev = null
while (node != null) {
if (node.listener === listener && node.kind === kind) {
// Should ignore a duplicated listener.
return false
}
prev = node
node = node.next
}
/**
* Get the wrapper class of a given prototype.
* @param {Object} proto The prototype of the original event to get its wrapper.
* @returns {Function} The wrapper class.
* @private
*/
function getWrapper(proto) {
if (proto == null || proto === Object.prototype) {
return Event
}
prev.next = newNode(listener, kind, options)
return true
},
configurable: true,
writable: true,
},
removeEventListener: {
value: function removeEventListener(type, listener, options) {
if (listener == null) {
return false
}
var capture = isObject(options) ? Boolean(options.capture) : Boolean(options)
var kind = (capture ? CAPTURE : BUBBLE)
var prev = null
var node = this[LISTENERS][type]
while (node != null) {
if (node.listener === listener && node.kind === kind) {
if (prev == null) {
this[LISTENERS][type] = node.next
}
else {
prev.next = node.next
}
return true
}
prev = node
node = node.next
}
return false
},
configurable: true,
writable: true,
},
dispatchEvent: {
value: function dispatchEvent(event) {
// If listeners aren't registered, terminate.
var type = event.type
var node = this[LISTENERS][type]
if (node == null) {
return true
}
// Since we cannot rewrite several properties, so wrap object.
var wrapped = createEventWrapper(event, this)
// This doesn't process capturing phase and bubbling phase.
// This isn't participating in a tree.
var prev = null
while (node != null) {
// Remove this listener if it's once
if (node.once) {
if (prev == null) {
this[LISTENERS][type] = node.next
}
else {
prev.next = node.next
}
}
else {
prev = node
}
// Call this listener
wrapped[PASSIVE_LISTENER_FLAG] = node.passive
if (typeof node.listener === "function") {
node.listener.call(this, wrapped)
}
else if (node.kind !== ATTRIBUTE && typeof node.listener.handleEvent === "function") {
node.listener.handleEvent(wrapped)
}
// Break if `event.stopImmediatePropagation` was called.
if (wrapped[STOP_IMMEDIATE_PROPAGATION_FLAG]) {
break
}
node = node.next
}
return !wrapped.defaultPrevented
},
configurable: true,
writable: true,
},
let wrapper = wrappers.get(proto);
if (wrapper == null) {
wrapper = defineWrapper(getWrapper(Object.getPrototypeOf(proto)), proto);
wrappers.set(proto, wrapper);
}
)
return wrapper
}
},{"./commons":1,"./custom-event-target":2,"./event-wrapper":4}],4:[function(require,module,exports){
/**
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
* Wrap a given event to management a dispatching.
* @param {EventTarget} eventTarget The event target of this dispatching.
* @param {Object} event The event to wrap.
* @returns {Event} The wrapper instance.
* @private
*/
"use strict"
function wrapEvent(eventTarget, event) {
const Wrapper = getWrapper(Object.getPrototypeOf(event));
return new Wrapper(eventTarget, event)
}
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
/**
* Get the stopped flag of a given event.
* @param {Event} event The event to get.
* @returns {boolean} The flag to stop propagation immediately.
* @private
*/
function isStopped(event) {
return pd(event).stopped
}
var createUniqueKey = require("./commons").createUniqueKey
/**
* Set the current event phase of a given event.
* @param {Event} event The event to set current target.
* @param {number} eventPhase New event phase.
* @returns {void}
* @private
*/
function setEventPhase(event, eventPhase) {
pd(event).eventPhase = eventPhase;
}
//-----------------------------------------------------------------------------
// Constsnts
//-----------------------------------------------------------------------------
/**
* Set the current target of a given event.
* @param {Event} event The event to set current target.
* @param {EventTarget|null} currentTarget New current target.
* @returns {void}
* @private
*/
function setCurrentTarget(event, currentTarget) {
pd(event).currentTarget = currentTarget;
}
/**
* The key of the flag which is turned on by `stopImmediatePropagation` method.
*
* @type {symbol|string}
* Set a passive listener of a given event.
* @param {Event} event The event to set current target.
* @param {Function|null} passiveListener New passive listener.
* @returns {void}
* @private
*/
var STOP_IMMEDIATE_PROPAGATION_FLAG =
createUniqueKey("stop_immediate_propagation_flag")
function setPassiveListener(event, passiveListener) {
pd(event).passiveListener = passiveListener;
}
/**
* The key of the flag which is turned on by `preventDefault` method.
*
* @type {symbol|string}
* @typedef {object} ListenerNode
* @property {Function} listener
* @property {1|2|3} listenerType
* @property {boolean} passive
* @property {boolean} once
* @property {ListenerNode|null} next
* @private
*/
var CANCELED_FLAG = createUniqueKey("canceled_flag")
/**
* The key of the flag that it cannot use `preventDefault` method.
*
* @type {symbol|string}
* @type {WeakMap<object, Map<string, ListenerNode>>}
* @private
*/
var PASSIVE_LISTENER_FLAG = createUniqueKey("passive_listener_flag")
const listenersMap = new WeakMap();
// Listener types
const CAPTURE = 1;
const BUBBLE = 2;
const ATTRIBUTE = 3;
/**
* The key of the original event object.
*
* @type {symbol|string}
* Check whether a given value is an object or not.
* @param {any} x The value to check.
* @returns {boolean} `true` if the value is an object.
*/
function isObject(x) {
return x !== null && typeof x === "object" //eslint-disable-line no-restricted-syntax
}
/**
* Get listeners.
* @param {EventTarget} eventTarget The event target to get.
* @returns {Map<string, ListenerNode>} The listeners.
* @private
*/
var ORIGINAL_EVENT = createUniqueKey("original_event")
function getListeners(eventTarget) {
const listeners = listenersMap.get(eventTarget);
console.assert(listeners != null, "'this' is expected an EventTarget object, but got", eventTarget);
return listeners || new Map()
}
/**
* Method definitions for the event wrapper.
*
* @type {object}
* Get the property descriptor for the event attribute of a given event.
* @param {string} eventName The event name to get property descriptor.
* @returns {PropertyDescriptor} The property descriptor.
* @private
*/
var wrapperPrototypeDefinition = Object.freeze({
stopPropagation: Object.freeze({
value: function stopPropagation() {
var e = this[ORIGINAL_EVENT]
if (typeof e.stopPropagation === "function") {
e.stopPropagation()
function defineEventAttributeDescriptor(eventName) {
return {
get() {
const listeners = getListeners(this);
let node = listeners.get(eventName);
while (node != null) {
if (node.listenerType === ATTRIBUTE) {
return node.listener
}
node = node.next;
}
return null
},
writable: true,
configurable: true,
}),
stopImmediatePropagation: Object.freeze({
value: function stopImmediatePropagation() {
this[STOP_IMMEDIATE_PROPAGATION_FLAG] = true
var e = this[ORIGINAL_EVENT]
if (typeof e.stopImmediatePropagation === "function") {
e.stopImmediatePropagation()
set(listener) {
if (typeof listener !== "function" && !isObject(listener)) {
listener = null; // eslint-disable-line no-param-reassign
}
},
writable: true,
configurable: true,
}),
const listeners = getListeners(this);
preventDefault: Object.freeze({
value: function preventDefault() {
if (this[PASSIVE_LISTENER_FLAG]) {
return
// Traverse to the tail while removing old value.
let prev = null;
let node = listeners.get(eventName);
while (node != null) {
if (node.listenerType === ATTRIBUTE) {
// Remove old value.
if (prev !== null) {
prev.next = node.next;
}
else if (node.next !== null) {
listeners.set(eventName, node.next);
}
else {
listeners.delete(eventName);
}
}
else {
prev = node;
}
node = node.next;
}
if (this.cancelable === true) {
this[CANCELED_FLAG] = true
}
var e = this[ORIGINAL_EVENT]
if (typeof e.preventDefault === "function") {
e.preventDefault()
// Add new value.
if (listener !== null) {
const newNode = {
listener,
listenerType: ATTRIBUTE,
passive: false,
once: false,
next: null,
};
if (prev === null) {
listeners.set(eventName, newNode);
}
else {
prev.next = newNode;
}
}
},
writable: true,
configurable: true,
}),
defaultPrevented: Object.freeze({
get: function defaultPrevented() {
return this[CANCELED_FLAG]
},
enumerable: true,
configurable: true,
}),
})
}
}
//-----------------------------------------------------------------------------
// Public Interface
//-----------------------------------------------------------------------------
/**
* Define an event attribute (e.g. `eventTarget.onclick`).
* @param {Object} eventTargetPrototype The event target prototype to define an event attrbite.
* @param {string} eventName The event name to define.
* @returns {void}
*/
function defineEventAttribute(eventTargetPrototype, eventName) {
Object.defineProperty(eventTargetPrototype, `on${eventName}`, defineEventAttributeDescriptor(eventName));
}
module.exports.STOP_IMMEDIATE_PROPAGATION_FLAG = STOP_IMMEDIATE_PROPAGATION_FLAG
module.exports.PASSIVE_LISTENER_FLAG = PASSIVE_LISTENER_FLAG
/**
* Creates an event wrapper.
*
* We cannot modify several properties of `Event` object, so we need to create the wrapper.
* Plus, this wrapper supports non `Event` objects.
*
* @param {Event|{type: string}} event - An original event to create the wrapper.
* @param {EventTarget} eventTarget - The event target of the event.
* @returns {Event} The created wrapper. This object is implemented `Event` interface.
* Define a custom EventTarget with event attributes.
* @param {string[]} eventNames Event names for event attributes.
* @returns {EventTarget} The custom EventTarget.
* @private
*/
module.exports.createEventWrapper = function createEventWrapper(event, eventTarget) {
var timeStamp = (
typeof event.timeStamp === "number" ? event.timeStamp : Date.now()
)
var propertyDefinition = {
type: {value: event.type, enumerable: true},
target: {value: eventTarget, enumerable: true},
currentTarget: {value: eventTarget, enumerable: true},
eventPhase: {value: 2, enumerable: true},
bubbles: {value: Boolean(event.bubbles), enumerable: true},
cancelable: {value: Boolean(event.cancelable), enumerable: true},
timeStamp: {value: timeStamp, enumerable: true},
isTrusted: {value: false, enumerable: true},
function defineCustomEventTarget(eventNames) {
/** CustomEventTarget */
function CustomEventTarget() {
EventTarget.call(this);
}
propertyDefinition[STOP_IMMEDIATE_PROPAGATION_FLAG] = {value: false, writable: true}
propertyDefinition[CANCELED_FLAG] = {value: false, writable: true}
propertyDefinition[PASSIVE_LISTENER_FLAG] = {value: false, writable: true}
propertyDefinition[ORIGINAL_EVENT] = {value: event}
// For CustomEvent.
if (typeof event.detail !== "undefined") {
propertyDefinition.detail = {value: event.detail, enumerable: true}
CustomEventTarget.prototype = Object.create(EventTarget.prototype, {
constructor: { value: CustomEventTarget, configurable: true, writable: true },
});
for (let i = 0; i < eventNames.length; ++i) {
defineEventAttribute(CustomEventTarget.prototype, eventNames[i]);
}
return Object.create(
Object.create(event, wrapperPrototypeDefinition),
propertyDefinition
)
return CustomEventTarget
}
},{"./commons":1}]},{},[3])(3)
});
/**
* EventTarget.
*
* - This is constructor if no arguments.
* - This is a function which returns a CustomEventTarget constructor if there are arguments.
*
* For example:
*
* class A extends EventTarget {}
* class B extends EventTarget("message") {}
* class C extends EventTarget("message", "error") {}
* class D extends EventTarget(["message", "error"]) {}
*/
function EventTarget() {
/*eslint-disable consistent-return */
if (this instanceof EventTarget) {
listenersMap.set(this, new Map());
return
}
if (arguments.length === 1 && Array.isArray(arguments[0])) {
return defineCustomEventTarget(arguments[0])
}
if (arguments.length > 0) {
const types = new Array(arguments.length);
for (let i = 0; i < arguments.length; ++i) {
types[i] = arguments[i];
}
return defineCustomEventTarget(types)
}
throw new TypeError("Cannot call a class as a function")
/*eslint-enable consistent-return */
}
// Should be enumerable, but class methods are not enumerable.
EventTarget.prototype = {
/**
* Add a given listener to this event target.
* @param {string} eventName The event name to add.
* @param {Function} listener The listener to add.
* @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener.
* @returns {boolean} `true` if the listener was added actually.
*/
addEventListener(eventName, listener, options) {
if (listener == null) {
return false
}
if (typeof listener !== "function" && !isObject(listener)) {
throw new TypeError("'listener' should be a function or an object.")
}
const listeners = getListeners(this);
const optionsIsObj = isObject(options);
const capture = optionsIsObj ? Boolean(options.capture) : Boolean(options);
const listenerType = (capture ? CAPTURE : BUBBLE);
const newNode = {
listener,
listenerType,
passive: optionsIsObj && Boolean(options.passive),
once: optionsIsObj && Boolean(options.once),
next: null,
};
// Set it as the first node if the first node is null.
let node = listeners.get(eventName);
if (node === undefined) {
listeners.set(eventName, newNode);
return true
}
// Traverse to the tail while checking duplication..
let prev = null;
while (node != null) {
if (node.listener === listener && node.listenerType === listenerType) {
// Should ignore duplication.
return false
}
prev = node;
node = node.next;
}
// Add it.
prev.next = newNode;
return true
},
/**
* Remove a given listener from this event target.
* @param {string} eventName The event name to remove.
* @param {Function} listener The listener to remove.
* @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener.
* @returns {boolean} `true` if the listener was removed actually.
*/
removeEventListener(eventName, listener, options) {
if (listener == null) {
return false
}
const listeners = getListeners(this);
const capture = isObject(options) ? Boolean(options.capture) : Boolean(options);
const listenerType = (capture ? CAPTURE : BUBBLE);
let prev = null;
let node = listeners.get(eventName);
while (node != null) {
if (node.listener === listener && node.listenerType === listenerType) {
if (prev !== null) {
prev.next = node.next;
}
else if (node.next !== null) {
listeners.set(eventName, node.next);
}
else {
listeners.delete(eventName);
}
return true
}
prev = node;
node = node.next;
}
return false
},
/**
* Dispatch a given event.
* @param {Event|{type:string}} event The event to dispatch.
* @returns {boolean} `false` if canceled.
*/
dispatchEvent(event) {
if (event == null || typeof event.type !== "string") {
throw new TypeError("\"event.type\" should be a string.")
}
// If listeners aren't registered, terminate.
const listeners = getListeners(this);
const eventName = event.type;
let node = listeners.get(eventName);
if (node == null) {
return true
}
// Since we cannot rewrite several properties, so wrap object.
const wrappedEvent = wrapEvent(this, event);
// This doesn't process capturing phase and bubbling phase.
// This isn't participating in a tree.
let prev = null;
while (node != null) {
// Remove this listener if it's once
if (node.once) {
if (prev !== null) {
prev.next = node.next;
}
else if (node.next !== null) {
listeners.set(eventName, node.next);
}
else {
listeners.delete(eventName);
}
}
else {
prev = node;
}
// Call this listener
setPassiveListener(wrappedEvent, (node.passive ? node.listener : null));
if (typeof node.listener === "function") {
node.listener.call(this, wrappedEvent);
}
else if (node.listenerType !== ATTRIBUTE && typeof node.listener.handleEvent === "function") {
node.listener.handleEvent(wrappedEvent);
}
// Break if `event.stopImmediatePropagation` was called.
if (isStopped(wrappedEvent)) {
break
}
node = node.next;
}
setPassiveListener(wrappedEvent, null);
setEventPhase(wrappedEvent, 0);
setCurrentTarget(wrappedEvent, null);
return !wrappedEvent.defaultPrevented
},
};
// `constructor` is not enumerable.
Object.defineProperty(EventTarget.prototype, "constructor", { value: EventTarget, configurable: true, writable: true });
// Ensure `eventTarget instanceof window.EventTarget` is `true`.
if (typeof window !== "undefined" && typeof window.EventTarget !== "undefined") {
Object.setPrototypeOf(EventTarget.prototype, window.EventTarget.prototype);
}
exports.defineEventAttribute = defineEventAttribute;
exports.EventTarget = EventTarget;
exports['default'] = EventTarget;
module.exports = EventTarget
module.exports.EventTarget = module.exports["default"] = EventTarget
module.exports.defineEventAttribute = defineEventAttribute
//# sourceMappingURL=event-target-shim.js.map
{
"name": "event-target-shim",
"version": "2.0.0",
"version": "3.0.0",
"description": "An implementation of W3C EventTarget interface.",
"main": "lib/event-target.js",
"main": "dist/event-target-shim",
"files": [
"dist",
"lib"
"dist"
],
"engines": {
"code": ">=4"
},
"scripts": {

@@ -14,25 +16,28 @@ "preversion": "npm test",

"postversion": "git push && git push --tags",
"clean": "rimraf coverage",
"lint": "if-node-version \">=4\" eslint lib test",
"build": "rimraf dist && run-s build:*",
"build:dist": "mkdirp dist && browserify lib/event-target.js --standalone event-target-shim > dist/event-target-shim.js",
"build:dist-min": "uglifyjs dist/event-target-shim.js --compress --mangle > dist/event-target-shim.min.js",
"test": "run-s clean lint && karma start karma.conf.js --single-run",
"watch": "karma start karma.conf.js --watch",
"travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- test/**/*.js --require scripts/power-assert",
"clean": "rimraf .nyc_output coverage",
"coverage": "nyc report --reporter lcov && opener coverage/lcov-report/index.html",
"lint": "eslint src test scripts",
"build": "run-p build:*",
"build:cjs": "node scripts/build-cjs.js",
"build:mjs": "node scripts/build-mjs.js",
"build:umd": "node scripts/build-umd.js",
"pretest": "npm run lint",
"test": "run-s test:*",
"test:mocha": "nyc --require ./scripts/babel-register.js mocha test/index.mjs",
"test:karma": "karma start scripts/karma.conf.js --single-run",
"watch": "run-p watch:*",
"watch:mocha": "mocha test/index.mjs --compilers mjs:babel-register --watch --growl",
"watch:karma": "karma start scripts/karma.conf.js --watch",
"codecov": "codecov"
},
"devDependencies": {
"browserify": "^13.1.1",
"browserify-istanbul": "^2.0.0",
"codecov": "^1.0.1",
"eslint": "^3.11.0",
"eslint-config-mysticatea": "^7.0.1",
"espower-loader": "^1.0.0",
"espowerify": "^1.0.0",
"if-node-version": "^1.1.1",
"istanbul": "^0.4.1",
"karma": "^1.3.0",
"karma-browserify": "^5.1.0",
"karma-chrome-launcher": "^2.0.0",
"babel-core": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-register": "^6.26.0",
"chai": "^4.1.2",
"codecov": "^2.3.0",
"eslint": "^4.7.2",
"eslint-config-mysticatea": "^12.0.0",
"karma": "^1.7.1",
"karma-chrome-launcher": "^2.2.0",
"karma-coverage": "^1.1.1",

@@ -43,10 +48,16 @@ "karma-firefox-launcher": "^1.0.0",

"karma-mocha": "^1.3.0",
"mkdirp": "^0.5.1",
"mocha": "^3.2.0",
"npm-run-all": "^3.1.1",
"power-assert": "^1.2.0",
"rimraf": "^2.3.4",
"spy": "^0.1.3",
"uglify-js": "^2.6.1",
"watchify": "^3.7.0"
"karma-rollup-preprocessor": "^5.0.1",
"mocha": "^3.5.3",
"npm-run-all": "^4.1.1",
"nyc": "^11.2.1",
"opener": "^1.4.3",
"rimraf": "^2.6.2",
"rollup": "^0.50.0",
"rollup-plugin-babel": "^3.0.2",
"rollup-plugin-babel-minify": "^3.1.2",
"rollup-plugin-commonjs": "^8.2.1",
"rollup-plugin-json": "^2.3.0",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-watch": "^4.3.1",
"spy": "^1.0.0"
},

@@ -53,0 +64,0 @@ "repository": {

@@ -15,177 +15,201 @@ # event-target-shim

```js
// The prototype of this class has getters and setters of `onmessage` and `onerror`.
class Foo extends EventTarget("message", "error") {
//...
import {EventTarget, defineEventAttribute} from "event-target-shim"
class Foo extends EventTarget {
// ...
}
// Define `foo.onhello` property.
defineEventAttribute(Foo.prototype, "hello")
// Use
const foo = new Foo()
foo.addEventListener("hello", e => console.log("hello", e))
foo.onhello = e => console.log("onhello:", e)
foo.dispatchEvent(new CustomEvent("hello"))
```
## Installation
## 💿 Installation
Use [npm](https://www.npmjs.com/) to install then use a bundler.
```
npm install --save event-target-shim
npm install event-target-shim
```
Or download from `dist` directory.
Or download from [`dist` directory](./dist).
## Usage
- [dist/event-target-shim.mjs](dist/event-target-shim.mjs) ... ES modules version.
- [dist/event-target-shim.js](dist/event-target-shim.js) ... Common JS version.
- [dist/event-target-shim.umd.js](dist/event-target-shim.umd.js) ... UMD (Universal Module Definition) version. This is transpiled by [Babel](https://babeljs.io/) for IE 11.
### Basic
## 📖 Usage
```js
//-----------------------------------------------------------------------------
// import (with browserify, webpack, etc...).
const EventTarget = require("event-target-shim");
import {EventTarget, defineEventAttribute} from "event-target-shim"
// or
const {EventTarget, defineEventAttribute} = require("event-target-shim")
//-----------------------------------------------------------------------------
// define a custom type.
class Foo extends EventTarget {
}
// or UMD version defines a global variable:
const {EventTarget, defineEventAttribute} = window.EventTargetShim
```
//-----------------------------------------------------------------------------
// add event listeners.
let foo = new Foo();
foo.addEventListener("foo", event => {
console.log(event.hello);
});
foo.addEventListener("foo", event => {
if (event.hello !== "hello") {
// event implements Event interface.
event.preventDefault();
}
});
### EventTarget
//-----------------------------------------------------------------------------
// dispatch an event.
let event = document.createEvent("CustomEvent");
event.initCustomEvent("foo", /*bubbles*/ false, /*cancelable*/ false, /*detail*/ null);
event.hello = "hello";
foo.dispatchEvent(event);
> https://dom.spec.whatwg.org/#interface-eventtarget
//-----------------------------------------------------------------------------
// dispatch an event simply (non standard).
foo.dispatchEvent({type: "foo", hello: "hello"});
#### eventTarget.addEventListener(type, callback, options)
//-----------------------------------------------------------------------------
// dispatch a cancelable event.
if (!foo.dispatchEvent({type: "foo", cancelable: true, hello: "hey"})) {
console.log("defaultPrevented");
}
Register an event listener.
//-----------------------------------------------------------------------------
// If `window.EventTarget` exists, `EventTarget` inherits from `window.EventTarget`.
if (foo instanceof window.EventTarget) {
console.log("yay!");
}
```
- `type` is a string. This is the event name to register.
- `callback` is a function. This is the event listener to register.
- `options` is a boolean or an object `{ capture?: boolean, passive?: boolean, once?: boolean }`. If this is a boolean, it's same meaning as `{ capture: options }`.
- `capture` is the flag to register the event listener for capture phase.
- `passive` is the flag to ignore `event.preventDefault()` method in the event listener.
- `once` is the flag to remove the event listener automatically after the first call.
### The Extension for Attribute Listeners
#### eventTarget.removeEventListener(type, callback, options)
```js
//-----------------------------------------------------------------------------
// import (with browserify, webpack, etc...).
const EventTarget = require("event-target-shim");
Unregister an event listener.
//-----------------------------------------------------------------------------
// define a custom type with attribute listeners.
class Foo extends EventTarget("message", "error") {
}
// or non-variadic
class Foo extends EventTarget(["message", "error"]) {
}
- `type` is a string. This is the event name to unregister.
- `callback` is a function. This is the event listener to unregister.
- `options` is a boolean or an object `{ capture?: boolean }`. If this is a boolean, it's same meaning as `{ capture: options }`.
- `capture` is the flag to register the event listener for capture phase.
//-----------------------------------------------------------------------------
// add event listeners.
let foo = new Foo();
foo.onmessage = event => {
console.log(event.data);
};
foo.onerror = event => {
console.log(event.message);
};
foo.addEventListener("message", event => {
console.log(event.data);
});
#### eventTarget.dispatchEvent(event)
//-----------------------------------------------------------------------------
// dispatch a event simply (non standard).
foo.dispatchEvent({type: "message", data: "hello"});
foo.dispatchEvent({type: "error", message: "an error"});
```
Dispatch an event.
### Use in ES5
- `event` is a [Event](https://dom.spec.whatwg.org/#event) object or an object `{ type: string, [key: string]: any }`. The latter is non-standard but useful. In both cases, listeners receive the event as implementing [Event](https://dom.spec.whatwg.org/#event) interface.
- Basic.
### defineEventAttribute(proto, type)
```js
function Foo() {
EventTarget.call(this);
}
Define an event attribute (e.g. `onclick`) to `proto`. This is non-standard.
Foo.prototype = Object.create(EventTarget.prototype, {
constructor: {
value: Foo,
configurable: true,
writable: true
},
- `proto` is an object (assuming it's a prototype object). This function defines a getter/setter pair for the event attribute.
- `type` is a string. This is the event name to define.
//....
});
```
For example:
- With attribute listeners.
```js
class AbortSignal extends EventTarget {
constructor() {
this.aborted = false
}
}
// Define `onabort` property.
defineEventAttribute(AbortSignal.prototype, "abort")
```
```js
function Foo() {
EventTarget.call(this);
}
### EventTarget(types)
Foo.prototype = Object.create(EventTarget("message", "error").prototype, {
// or
// Foo.prototype = Object.create(EventTarget(["message", "error"]).prototype, {
constructor: {
value: Foo,
configurable: true,
writable: true
},
Define a custom `EventTarget` class with event attributes. This is non-standard.
//....
});
```
- `types` is a string or an array of strings. This is the event name to define.
### Use with RequireJS
For example:
```js
require(["https://cdn.rawgit.com/mysticatea/event-target-shim/v2.0.0/dist/event-target-shim.min.js"], function(EventTarget) {
//...
});
// This has `onabort` property.
class AbortSignal extends EventTarget("abort") {
constructor() {
this.aborted = false
}
}
```
## API
## 📚 Examples
```ts
declare class EventTarget {
constructor();
addEventListener(type: string, listener?: (event: Event) => void, options?: boolean | AddEventListenerOptions): void;
removeEventListener(type: string, listener?: (event: Event) => void, options?: boolean | EventListenerOptions): void;
dispatchEvent(event: Event | EventLike): boolean;
### ES2015 and later
> https://jsfiddle.net/636vea92/
```js
const {EventTarget, defineEventAttribute} = EventTargetShim
// Define a derived class.
class Foo extends EventTarget {
// ...
}
// Define EventTarget type with attribute listeners.
declare function EventTarget(...types: string[]): EventTarget;
declare function EventTarget(types: string[]): EventTarget;
// Define `foo.onhello` property.
defineEventAttribute(Foo.prototype, "hello")
// Options
interface EventListenerOptions {
capture?: boolean;
// Register event listeners.
const foo = new Foo()
foo.addEventListener("hello", (e) => {
console.log("hello", e)
})
foo.onhello = (e) => {
console.log("onhello", e)
}
interface AddEventListenerOptions extends EventListenerOptions {
once?: boolean;
passive?: boolean;
// Dispatching events
foo.dispatchEvent(new CustomEvent("hello", { detail: "detail" }))
```
### ES5
> https://jsfiddle.net/522zc9de/
```js
// Define a derived class.
function Foo() {
EventTarget.call(this)
}
Foo.prototype = Object.create(EventTarget.prototype, {
constructor: { value: Foo, configurable: true, writable: true }
// ...
})
// Non-standard.
interface EventLike {
type: string;
cancelable?: boolean;
// Define `foo.onhello` property.
defineEventAttribute(Foo.prototype, "hello")
// Register event listeners.
var foo = new Foo()
foo.addEventListener("hello", function(e) {
console.log("hello", e)
})
foo.onhello = function(e) {
console.log("onhello", e)
}
// Dispatching events
function isSupportEventConstrucor() { // IE does not support.
try {
new CusomEvent("hello")
return true
} catch (_err) {
return false
}
}
if (isSupportEventConstrucor()) {
foo.dispatchEvent(new CustomEvent("hello", { detail: "detail" }))
} else {
var e = document.createEvent("CustomEvent")
e.initCustomEvent("hello", false, false, "detail")
foo.dispatchEvent(e)
}
```
## 📰 Changelog
- See [GitHub releases](https://github.com/mysticatea/event-target-shim/releases).
## 🍻 Contributing
Contributing is welcome ❤️
Please use GitHub issues/PRs.
### Development tools
- `npm install` installs dependencies for development.
- `npm test` runs tests and measures code coverage.
- `npm run clean` removes temporary files of tests.
- `npm run coverage` opens code coverage of the previous test with your default browser.
- `npm run lint` runs ESLint.
- `npm run build` generates `dist` codes.
- `npm run watch` runs tests on each file change.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc