mysticatea / event-target-shim Goto Github PK
View Code? Open in Web Editor NEWAn implementation of WHATWG EventTarget interface, plus few extensions.
License: MIT License
An implementation of WHATWG EventTarget interface, plus few extensions.
License: MIT License
This code (in src/event.mjs
) fails in Node 6 (parsing error) due to the extra comma in the argument list :
console.error(
"Unable to preventDefault inside passive event listener invocation.",
data.passiveListener, // <-- this comma
)
I've forked the project to remove those commas (there are 2 in total in src/event.mjs
) and indeed it works in Node 6. But then, when running npm run lint
it fails with:
/Users/ibc/src/forks/event-target-shim/src/event.mjs
40:14 error Insert `,` @mysticatea/prettier
57:37 error Insert `,` @mysticatea/prettier
Well, no idea how to reset such a eslint rule. But please, remove it so this good library can be used in Node 6.
As a curiosity, I'd like to experiment with the native variant of an event emitter, as described in
https://medium.com/@zandaqo/eventtarget-the-future-of-javascript-event-systems-205ae32f5e6b
and
https://css-tricks.com/lets-create-a-lightweight-native-event-bus-in-javascript/
It works in all modern browsers today and Deno - but not Node!
Running new CustomEvent()
results in ReferenceError: CustomEvent is not defined
in the latest version (currently 15.5.1)
I'm not sure if it's in scope for this project to support it, or if a custom-event-shim
is more fitting π€
Hi,
when compiling with Webpack(Laravel Mix 6.14.11), I am getting this error:
ERROR in ./node_modules/event-target-shim/index.mjs 62:24-31
Module not found: Error: Can't resolve 'process/browser' in '/Users/medhi/Sites/forma/node_modules/event-target-shim'
Did you mean 'browser.js'?
BREAKING CHANGE: The request 'process/browser' failed to resolve only because it was resolved as fully specified
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
event-target-shim/scripts/test.ts
Line 201 in 71b37d1
If you try to log an event instance in Node, an error is thrown: Value of "this" must be of type EventTarget
repro:
import {Event as EventShim} from 'event-target-shim';
const event = new EventShim('test');
console.log(event);
Overview
I have a react native app which I am running on android.
I have event-target-shim as a dependency.
Issue
The app was working fine with react-native version 0.59.
But when I upgraded it to react-native version 0.60, I started seeing an error
"console.assert is not a function"
When I remove console.assert statement from line 46 of event-target-shim.js, everything works fine.
If EventTarget.removeEventListener
is called from within the listeners callback, this may result in an access to an array index which does not exist any more when calling listeners in a loop:
event-target-shim/src/lib/event-target.ts
Lines 243 to 267 in a37993c
As this library is used as a ponyfill in vercel's edge-runtime this becomes evident when using libraries which rely on removing event listeners in the listener callback. One instance of this case is documented in the following issue:
When calling dispatchEvent
, the list of listeners consists of two items:
listeners = [
{ callback: [function onAbort], flags: 0 },
{ callback: [function onAbort], flags: 4 }
]
In the first iteration, the callback removes the first listener from list.listeners
. However, the local, deconstructed listeners
still points to the old list with 2 items. This becomes a problem in the second iteration, as it's a "once" listener, which the code tries to remove from list.listeners
. As the list only contains one listener, the operation fails as it's working on a undefined
value.
I don't know if this case should work, or this library is still maintained. However, it's used by nextjs and I'm surprised it did not become evident before.
I did not dig too deep, but one thing I've noticed is when always referencing the listeners list by list.listeners
the issue does not arise. However, I don't know if this messes up other parts of the listener invoke logic.
right now, one has to do:
defineEventAttribute(Foo, "bar");
defineEventAttribute(Foo, "baz");
// or
["bar", "baz"].forEach( name => defineEventAttribute(Foo, name));
Which is kinda ugly...
What would be nice is a variadic function:
defineEventAttribute(Foo, "bar", "baz" /*, ...and so on*/);
// or
const attributes = ["bar", "baz"]
defineEventAttribute(Foo, ...attributes);
There's an argument to dispatchEvent
that, if given, will set a legacyOutputDidListenersThrowFlag
if a user given callback raises an exception. It was added for IndexedDB which had been monkey patching the event mechanism to determine if a user given callback raised an exception in order to roll back a transaction if it did. This feature is only used by IndexedDB, so it makes sense that no one has implemented it in their event shims, but I'm having a go at implementing IndexedDB and it would be nice to have.
I believe it would be as simple as setting the property in the catch
block of the try
block where you invoke the user given callback for an event target. I'll be running tests agains the W3C integration suite for IndexedDB and will be able to report on whether or not the implementation in target-event-shim
works correctly. I'm willing to submit a patch if you're pressed for time.
The discussion of legacyOutputDidListenersThrowFlag
begins here with "If an exception was propagated out from any event handler" is not a thing. The description of the algorithm can be found in the DOM standard under 2.9. Dispatching events.
Additional points of reference the discussion under Add legacyOutputDidListenersThrowFlag to event dispatch for IDB at the repo for the DOM spec. The PR that updated the IndexedDB spec for legacyOutputDidListenersThrowFlag
. Tests for the proper behavior are part of the IndexedDB integration test suite.
The CustomEvent
type, which inherits the Event
interface, are both present in the typescript standard library definitions. However they appear to be incompatible with the types this library exports; meaning if you define:
type ArbitraryDetail = {
cool: boolean
}
type ArbitraryEvent = CustomEvent<ArbitraryDetail>
class MyClass extends EventTarget<{arbitrary: ArbitraryEvent}> {
// β¦
this will not compile, as the CustomEvent
class is not seen as fulfilling Event
as provided by event-target-shim
. Before version 6 of this library, this worked as (although the generic wasn't really being enforced while emitting events):
class MyClass extends EventTarget<{arbitrary: ArbitraryEvent}, {}> {
// β¦
In looking through the library, I didn't see anywhere that seemed to support this "events plus arbitrary data" pattern that CustomEvent
allows. I can replicate it by creating an actual event definition, something like:
class ArbitraryEvent extends Event<'arbitrary'> {
constructor(public readonly detail: ArbitraryDetail) {
super('arbitrary')
}
}
β¦and that's not half bad, but I was wondering if there were any plans to provide interoperability with the types the stdlib already provides, or if there was methods already and I had missed them, or misunderstood some usage.
thinking it could be useful for stuff like extending the default event so that one can implement own events like CustomEvent, MessageEvent, etc
In a similar issue to #12, Sentry's browser library patches console.assert
with a function which includes accessing an Event
's type
, which, combined with the assertion in pd
, results in infinite recursion.
It's not entirely clear whose responsibility it is to fix, so I've deferred to precedent, and fixed this in the same way #12 was fixed in #27.
they could also be objects with the handleEvent
method defined on their prototype chain. This check is preventing a consumer of this lib from passing an object to addEventListener
.
eventTarget.on('click', e => {
// will throw illegal invocation
e.relatedTarget;
})
eventTarget.dispatchEvent(new MouseEvent('click'));
window.EventTarget = EventTargetShim.EventTarget;
window.Event = EventTargetShim.Event;
window.getEventAttributeValue = EventTargetShim.getEventAttributeValue;
window.setEventAttributeValue = EventTargetShim.setEventAttributeValue;
// ---
const input = document.createElement('input');
input.dispatchEvent(new Event('change', { bubbles: true }));
I do the first part in my site, overriding native with shim for have a homogeneous behavior in all devices.
Most things works as expected, but the second part of code throws
Uncaught TypeError: EventTarget.dispatchEvent: Argument 1 does not implement interface Event.
Maybe EventTargetShim.Event can be a instance of native Event if its is defined for fix this problem?
Seems like this package has a dependency on @babel/runtime
that's missing from the package.json, which causes some issues during webpack with package managers like pnpm. Suggest adding it as an optional or peer dependency. (Take a look at the es5.js
file).
$ tsc
node_modules/event-target-shim/index.d.ts:377:34 - error TS1005: ']' expected.
377 [P in string & keyof TEventMap as `on${P}`]: EventTarget.CallbackFunction<TEventTarget, TEventMap[P]> | null;
~~
node_modules/event-target-shim/index.d.ts:377:45 - error TS1005: ';' expected.
377 [P in string & keyof TEventMap as `on${P}`]: EventTarget.CallbackFunction<TEventTarget, TEventMap[P]> | null;
~
node_modules/event-target-shim/index.d.ts:377:46 - error TS1128: Declaration or statement expected.
377 [P in string & keyof TEventMap as `on${P}`]: EventTarget.CallbackFunction<TEventTarget, TEventMap[P]> | null;
~
node_modules/event-target-shim/index.d.ts:377:105 - error TS1005: '(' expected.
377 [P in string & keyof TEventMap as `on${P}`]: EventTarget.CallbackFunction<TEventTarget, TEventMap[P]> | null;
~
node_modules/event-target-shim/index.d.ts:377:111 - error TS1005: ')' expected.
377 [P in string & keyof TEventMap as `on${P}`]: EventTarget.CallbackFunction<TEventTarget, TEventMap[P]> | null;
~
node_modules/event-target-shim/index.d.ts:379:1 - error TS1128: Declaration or statement expected.
379 }
~
Typescript version ^3.8.3
I need to emulate part of the DOM along with event dispatch and propagation. While the DOM EventTarget class doesn't support this as a public interface, it would be great to be able to use this shim and provide the EventTarget class with a parent reference so that the dispatch algorithm could be implemented.
To keep from creating a non-standard interface on EventTarget itself there could be a utility function like setEventTargetParent()
which sets an internal field.
Browser: IE 11
Version: 11.719.18362.0
Update Versions: 11.0.180
I have a project written in TypeScript. I had a sample class which extends EventTarget it did not work.
Has anyone experience the same issue?
I'm curious if this library could change the way .oneventname
methods are handled, rather than passing strings to the EventTarget function. For example:
function X () {
EventTarget.call(this);
};
X.prototype = new EventTarget;
x.onhello = function y () {};
x.dispatchEvent({ type: 'hello' });
So right now, that should not work, since I didn't pass the string hello to EventTarget. addEventListener would work. Could it be possible that dispatch event check's first for this['on' + eventName]
before checking the list of event listeners added with addEventListener?
I have an app bootstrapped with create-react-app and decided to use abort-controller with github's fetch polyfil.
As you know, abort-controller has this package as it's only dependency. When I attempt to build my package (Equivalent with .babelrc { "presets": ["react-app"]}
) I get the following:
Failed to compile.
Failed to minify the code from this file:
./node_modules/event-target-shim/dist/event-target-shim.js:61
I'd really like to use abort controller.
EventTarget
should trigger the global uncaught exception error (such as window.onerror
) if a listener threw an error because it ignores the error to call the rest listeners.
Spec:
https://dom.spec.whatwg.org/#interface-eventtarget
const obj = new EventTarget()
obj.addEventListener("test", () => console.log("hello"), {once: true})
obj.dispatchEvent({type: "test"}) // β "hello"
obj.dispatchEvent({type: "test"}) // β
After rollup build, dist/event-target-shim.js
is not a ES5 build.
This is verified by looking at https://unpkg.com/[email protected]/dist/event-target-shim.js. Excerpt from the code:
privateData.set(this, {
eventTarget,
event,
eventPhase: 2,
currentTarget: eventTarget,
canceled: false,
stopped: false,
immediateStopped: false,
passiveListener: null,
timeStamp: event.timeStamp || Date.now(),
});
You can clearly see eventTarget
and event
is emitted in non-ES5 mode and it requires the caller environment to support rest operator. And rest operator is not supported in pure ES5 environment.
All JS files referenced through package.json/main
field should be ES5. If not, it will break apps that use Webpack in pure ES5 environment, such as create-react-app
. This is because Webpack assume everything under node_modules
are precompiled to ES5. For JS files that are not precompiled (ES6+), they are referenced through package.json/module
field instead.
Should use @babel/preset-env
with forceAllTransforms: true
to force the output build as ES5.
I am getting an error on my app, but it targets an infinite recursion on:
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()
}
At least on IE11, the console.assert when trying display my bogus eventTarget
calls again the getListeners, which calls assert again.. and so on..
Specifically, in the case form the README:
class Foo extends EventTarget("message", "error") {
}
This is a problem because what if I have a large number of strings to pass in? I'm probably going to put them in an array in a previous statement, then pass that array in. I'll have to use Function.prototype.apply
in es5, which will break a constructor function! ex:
var events = [
'negotiationneeded',
'icecandidate',
'icecandidateerror',
'signalingstatechange',
'iceconnectionstatechange',
'icegatheringstatechange',
'connectionstatechange'
];
// oops! this subtly breaks the prototype chain!
RTCPeerConnection.prototype = new EventTarget.apply({}, events);
A simple forward compatible change would be to first check if the constructor's if (arguments.length === 1 && Array.isArray(arguments[0]) { // don't construct a new array
.
I'm trying to dispatch a custom event but currently it's not working.
dispatcher
const evt = new CustomEvent('testevent', { detail: 'details' })
this.dispatchEvent(evt)
listener
dispatcher.addEventListener('testevent', e => {
console.log(e)
})
output from console.log
{ type: 'testevent',
target: { _uri: 'http://example.com' },
currentTarget: { _uri: 'http://example.com' },
eventPhase: 2,
bubbles: false,
cancelable: false,
timeStamp: 1432690145315,
isTrusted: false }
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.