Socket
Socket
Sign inDemoInstall

event-target-shim

Package Overview
Dependencies
0
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.1 to 0.1.0

src/EventWrapper.js

4

package.json
{
"name": "event-target-shim",
"version": "0.0.1",
"version": "0.1.0",
"description": "A polyfill for W3C EventTarget Constructor.",
"main": "lib/index.js",
"main": "lib/EventTarget.js",
"directories": {

@@ -7,0 +7,0 @@ "test": "test"

@@ -10,10 +10,7 @@ # event-target-shim

~~This module uses native implementation of EventTarget if it exists.~~
~~otherwise, defines shim.~~
This module provides `EventTarget` constructor that can inherit for your custom object.
And this module provides an utility to define properties for attribute listeners (e.g. `obj.onclick`).
Ummm, occured `Illegal constructor` exception at native.
This module always defines shim.
If `window.EventTarget` exists, `EventTarget` is inherit from `window.EventTarget`.
And this provides an utility to define properties for attribute listeners (e.g. `obj.onclick`).
```ts

@@ -39,3 +36,3 @@ declare class EventTarget {

This module has been desined that uses together [Browserify](http://browserify.org/).
This module has been designed that uses together [Browserify](http://browserify.org/).

@@ -42,0 +39,0 @@ ```js

"use strict";
import {createEventWrapper, STOP_IMMEDIATE_PROPAGATION_FLAG, DISPATCH_FLAG,
CANCELED_FLAG} from "./EventWrapper";
let EventTarget;
if (false/*typeof window !== "undefined" && typeof window.EventTarget !== "undefined"*/) {
// Occored `Illegal constructor` exception when called.
EventTarget = window.EventTarget;
const LISTENERS = Symbol("listeners");
const SET_ATTRIBUTE_LISTENER = Symbol("setAttributeListener");
const GET_ATTRIBUTE_LISTENER = Symbol("getAttributeListener");
const CAPTURE = 1;
const BUBBLE = 2;
const ATTRIBUTE = 3;
// Return definition of an attribute listener.
function defineAttributeListener(type) {
type = type.replace(/"/g, "\\\"");
return `
"on${type}": {
get: function() { return this[GET_ATTRIBUTE_LISTENER]("${type}"); },
set: function(value) { this[SET_ATTRIBUTE_LISTENER]("${type}", value); },
configurable: true
},
`;
}
else {
// Event's private members.
const STOP_IMMEDIATE_PROPAGATION_FLAG = Symbol("stop immediate propagation flag");
const CANCELED_FLAG = Symbol("canceled flag");
const DISPATCH_FLAG = Symbol("dispatch flag");
// EventTarget's private members.
const LISTENERS = Symbol("listeners");
// Create a LinkedList structure for EventListener.
function newNode(listener, capture) {
return {listener, capture, next: null};
// Create a LinkedList structure for EventListener.
function newNode(listener, kind) {
return {listener, kind, next: null};
}
//
// Class Definition.
//
let ET = function EventTarget(...types) {
if (this instanceof EventTarget) {
// this[LISTENERS] is a Map.
// Its key is event type.
// Its value is ListenerNode object or null.
//
// interface ListenerNode {
// let listener: Function
// let kind: CAPTURE|BUBBLE|ATTRIBUTE
// let next: ListenerNode|null
// }
this[LISTENERS] = Object.create(null);
}
else if (types.length > 0) {
// To use to extend with attribute listener properties.
// e.g.
// class MyCustomObject extends EventTarget("message", "error") {
// //...
// }
return Function(
"EventTargetBase",
"GET_ATTRIBUTE_LISTENER",
"SET_ATTRIBUTE_LISTENER",
`
function EventTarget() {
EventTargetBase.call(this);
}
EventTarget.prototype = Object.create(EventTargetBase.prototype, {
${types.map(defineAttributeListener).join()}
constructor: {
value: EventTarget,
writable: true,
configurable: true
}
});
return EventTarget;
`
)(EventTarget, GET_ATTRIBUTE_LISTENER, SET_ATTRIBUTE_LISTENER);
}
else {
throw new TypeError("Cannot call a class as a function");
}
};
// Create a Event wrapper to rewrite readonly properties.
function newEventWrapper(event, eventTarget) {
let timeStamp = (typeof event.timeStamp === "number"
? event.timeStamp
: Date.now());
ET.prototype = Object.create(
(typeof EventTarget === "function" ? EventTarget : Object).prototype,
{
constructor: {
value: ET,
writable: true,
configurable: true
},
return Object.create(event, {
type: {value: event.type, enumerable: true},
target: {value: eventTarget, enumerable: true},
currentTarget: {value: eventTarget, enumerable: true},
eventPhase: {value: 2, enumerable: true},
stopPropagation: {value: function stopPropagation() {}},
stopImmediatePropagation: {value: function stopImmediatePropagation() {
this[STOP_IMMEDIATE_PROPAGATION_FLAG] = true;
}},
bubbles: {value: Boolean(event.bubbles), enumerable: true},
cancelable: {value: Boolean(event.cancelable), enumerable: true},
preventDefault: {value: function preventDefault() {
if (this.cancelable === true) {
this[CANCELED_FLAG] = true;
addEventListener: {
value: function addEventListener(type, listener, capture = false) {
if (listener == null) {
return false;
}
}},
defaultPrevented: {
get: function() { return this[CANCELED_FLAG]; },
enumerable: true
},
isTrusted: {value: false, enumerable: true},
timeStamp: {value: timeStamp, enumerable: true},
[STOP_IMMEDIATE_PROPAGATION_FLAG]: {value: false, writable: true},
[CANCELED_FLAG]: {value: false, writable: true},
[DISPATCH_FLAG]: {value: true}
});
}
if (typeof listener !== "function") {
throw TypeError("listener should be a function.");
}
// Define EventTarget.
// See Also: https://dom.spec.whatwg.org/#interface-eventtarget
EventTarget = class EventTarget {
constructor() {
// This object is a Map.
// Its key is event type.
// Its value is ListenerNode object or null.
//
// interface ListenerNode {
// let listener: Function
// let capture: boolean
// let next: ListenerNode|null
// }
this[LISTENERS] = Object.create(null);
}
let kind = (capture ? CAPTURE : BUBBLE);
let node = this[LISTENERS][type];
if (node == null) {
this[LISTENERS][type] = newNode(listener, kind);
return true;
}
addEventListener(type, listener, capture = false) {
if (listener == null) {
return false;
}
capture = Boolean(capture);
let prev = null;
while (node != null) {
if (node.listener === listener && node.kind === kind) {
// Should ignore a duplicated listener.
return false;
}
prev = node;
node = node.next;
}
let node = this[LISTENERS][type];
if (node == null) {
this[LISTENERS][type] = newNode(listener, capture);
prev.next = newNode(listener, kind);
return true;
}
},
writable: true,
configurable: true
},
let prev = null;
while (node != null) {
if (node.listener === listener && node.capture === capture) {
// Should ignore a duplicated listener.
removeEventListener: {
value: function removeEventListener(type, listener, capture = false) {
if (listener == null) {
return false;
}
prev = node;
node = node.next;
}
prev.next = newNode(listener, capture);
return true;
}
let kind = (capture ? CAPTURE : BUBBLE);
let prev = null;
let 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;
}
removeEventListener(type, listener, capture = false) {
if (listener == null) {
prev = node;
node = node.next;
}
return false;
}
capture = Boolean(capture);
},
writable: true,
configurable: true
},
let prev = null;
let node = this[LISTENERS][type];
while (node != null) {
if (node.listener === listener && node.capture === capture) {
if (prev == null) {
this[LISTENERS][type] = node.next;
}
else {
prev.next = node.next;
}
dispatchEvent: {
value: function dispatchEvent(event) {
// Should check initialized flag, but impossible.
if (event[DISPATCH_FLAG]) {
throw Error("InvalidStateError");
}
// If listeners aren't registered, terminate.
let node = this[LISTENERS][event.type];
if (node == null) {
return true;
}
prev = node;
node = node.next;
}
// Since we cannot rewrite several properties, so wrap object.
event = createEventWrapper(event, this);
return false;
}
// This doesn't process capturing phase and bubbling phase.
// This isn't participating in a tree.
while (node != null) {
node.listener.call(this, event);
if (event[STOP_IMMEDIATE_PROPAGATION_FLAG]) {
break;
}
node = node.next;
}
dispatchEvent(event) {
// Should check initialized flag, but impossible.
if (event[DISPATCH_FLAG]) {
throw Error("InvalidStateError");
}
return !event[CANCELED_FLAG];
},
writable: true,
configurable: true
},
// If listeners aren't registered, terminate.
let node = this[LISTENERS][event.type];
if (node == null) {
return true;
}
[GET_ATTRIBUTE_LISTENER]: {
value: function getAttributeListener(type) {
let node = this[LISTENERS][type];
while (node != null) {
if (node.kind === ATTRIBUTE) {
return node.listener;
}
node = node.next;
}
return null;
},
writable: true,
configurable: true
},
// Since we cannot rewrite several properties, so wrap object.
event = newEventWrapper(event, this);
[SET_ATTRIBUTE_LISTENER]: {
value: function setAttributeListener(type, listener) {
if (listener != null && typeof listener !== "function") {
throw TypeError("listener should be a function.");
}
// This doesn't process capturing phase and bubbling phase.
// This isn't participating in a tree.
while (node != null) {
node.listener.call(this, event);
if (event[STOP_IMMEDIATE_PROPAGATION_FLAG]) {
break;
let prev = null;
let node = this[LISTENERS][type];
while (node != null) {
if (node.kind === ATTRIBUTE) {
// Remove old value.
if (prev == null) {
this[LISTENERS][type] = node.next;
}
else {
prev.next = node.next;
}
}
else {
prev = node;
}
node = node.next;
}
node = node.next;
}
return !event[CANCELED_FLAG];
// Add new value.
if (listener != null) {
if (prev == null) {
this[LISTENERS][type] = newNode(listener, ATTRIBUTE);
}
else {
prev.next = newNode(listener, ATTRIBUTE);
}
}
},
writable: true,
configurable: true
}
};
}
}
);
export default EventTarget;
export default ET;

@@ -5,3 +5,3 @@ "use strict";

import spies from "chai-spies";
import EventTarget from "../src/index";
import EventTarget from "../src/EventTarget";

@@ -37,2 +37,12 @@ chai.use(spies);

if (typeof window !== "undefined" && typeof window.EventTarget !== "undefined") {
it("should be instanceof `window.EventTarget`.", () => {
expect(target).to.be.instanceof(window.EventTarget);
});
it("should not equal `EventTarget` and `window.EventTarget`.", () => {
expect(EventTarget).to.not.equal(window.EventTarget);
});
}
it("should call registered listeners on called `dispatchEvent()`.", () => {

@@ -192,2 +202,6 @@ let lastEvent = null;

it("should properties of attribute listener are null by default.", () => {
expect(target.ontest).to.be.null;
});
it("should call attribute listeners when called `dispatchEvent()`.", () => {

@@ -199,2 +213,3 @@ let listener = chai.spy();

expect(target.ontest).to.equal(listener);
expect(listener).to.have.been.called.once;

@@ -210,2 +225,3 @@ });

expect(target.ontest).to.be.null;
expect(listener).to.not.have.been.called();

@@ -221,4 +237,5 @@ });

expect(target.ontest).to.equal(listener);
expect(listener).to.have.been.called.once;
});
});
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc