Giter Club home page Giter Club logo

event-target-shim's Introduction

event-target-shim

npm version Downloads/month Build Status Coverage Status Dependency Status

An implementation of WHATWG EventTarget interface and WHATWG Event interface. This implementation supports constructor, passive, once, and signal.

This implementation is designed ...

  • Working fine on both browsers and Node.js.
  • TypeScript friendly.

Native Support Information:

Feature IE Edge Firefox Chrome Safari Node.js
Event constructor 12 11 15 6 15.4.0
EventTarget constructor 87 84 87 14 15.4.0
passive option 16 49 51 10 15.4.0
once option 16 50 55 10 15.4.0
signal option

💿 Installation

Use npm or a compatible tool.

npm install event-target-shim

📖 Getting started

import { EventTarget, Event } from "event-target-shim";

// constructor (was added to the standard on 8 Jul 2017)
const myNode = new EventTarget();

// passive flag (was added to the standard on 6 Jan 2016)
myNode.addEventListener(
  "hello",
  (e) => {
    e.preventDefault(); // ignored and print warning on console.
  },
  { passive: true }
);

// once flag (was added to the standard on 15 Apr 2016)
myNode.addEventListener("hello", listener, { once: true });
myNode.dispatchEvent(new Event("hello")); // remove the listener after call.

// signal (was added to the standard on 4 Dec 2020)
const ac = new AbortController();
myNode.addEventListener("hello", listener, { signal: ac.signal });
ac.abort(); // remove the listener.
  • For browsers, there are two ways:
    • use a bundler such as Webpack to bundle. If you want to support IE11, use import {} from "event-target-shim/es5" instead. It's a transpiled code by babel. It depends on @baebl/runtime (^7.12.0) package.
    • use CDN such as unpkg.com. For example, <script src="https://unpkg.com/[email protected]"></script> will define EventTargetShim global variable.
  • The AbortController class was added to the standard on 14 Jul 2017. If you want the shim of that, use abort-controller package.

Runnable Examples

📚 API Reference

See docs/reference.md.

💥 Migrating to v6

See docs/migrating-to-v6.md.

📰 Changelog

See GitHub 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 watch:mocha runs tests on each file change.

event-target-shim's People

Contributors

eddiemoore avatar fadomire avatar frogthefrog avatar liqi0816 avatar marcoscaceres avatar mysticatea avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

event-target-shim's Issues

Rollup is emitting non-ES5 build for `dist/event-target-shim.js`

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.

Infinite recursion "'this' is expected an EventTarget object, but got [object Object]'

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..

image

`EventTarget` (and the `Event` type) are incompatible with typescript's `CustomEvent` type

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.

Event-target-shim breaks Create React App builds

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.

index.d.ts produces errors in Typescript

$ 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

Can't console.log() event instance in Node

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);

export event?

thinking it could be useful for stuff like extending the default event so that one can implement own events like CustomEvent, MessageEvent, etc

constructor should take a single array of strings

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.

`EventTarget.removeEventListener` called from within listener callback results in index out of bounds access

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:

for (let i = 0; i < listeners.length; ++i) {
const listener = listeners[i]
// Skip if removed.
if (isRemoved(listener)) {
continue
}
// Remove this listener if has the `once` flag.
if (isOnce(listener) && removeListenerAt(list, i, !cow)) {
// Because this listener was removed, the next index is the
// same as the current value.
i -= 1
}
// Call this listener with the `passive` flag.
eventData.inPassiveListenerFlag = isPassive(listener)
invokeCallback(listener, this, event)
eventData.inPassiveListenerFlag = false
// Stop if the `event.stopImmediatePropagation()` method was called.
if (eventData.stopImmediatePropagationFlag) {
break
}
}

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:

connectrpc/connect-es#749

Insights

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.

Possible solution

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.

Feature request: make defineEventAttribute variadic

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);

Add support for event propagation

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.

Please remove extra comma in console.xxx() arguments

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.

Missing dependency on @babel/runtime

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).

CustomEvents not working

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 }

Implement `legacyOutputDidListenersThrowFlag`

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.

console.assert is not a function

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.

check for on + event_name before dispatching event listener

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?

Webpack breaking change: The extension in the request is mandatory

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.

process: "process/browser",

Support for CustomEvent

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 🤔

EventTarget breaks on IE

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?

Uncaught TypeError: EventTarget.dispatchEvent: Argument 1 does not implement interface Event.

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.