aboutsummaryrefslogtreecommitdiffstats
path: root/node_modules/rxjs/src/internal/observable/fromEvent.ts
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2025-06-28 17:26:46 -0700
committerPinapelz <yukais@pinapelz.com>2025-06-28 17:43:56 -0700
commite4fa1e69e7ebfb627c7198fd1a9881e9327ec4d4 (patch)
tree06284a538a6008eca75051399e47db4e5d50301c /node_modules/rxjs/src/internal/observable/fromEvent.ts
initial commit: scaffolding
Diffstat (limited to 'node_modules/rxjs/src/internal/observable/fromEvent.ts')
-rw-r--r--node_modules/rxjs/src/internal/observable/fromEvent.ts339
1 files changed, 339 insertions, 0 deletions
diff --git a/node_modules/rxjs/src/internal/observable/fromEvent.ts b/node_modules/rxjs/src/internal/observable/fromEvent.ts
new file mode 100644
index 0000000..ef15431
--- /dev/null
+++ b/node_modules/rxjs/src/internal/observable/fromEvent.ts
@@ -0,0 +1,339 @@
+import { innerFrom } from '../observable/innerFrom';
+import { Observable } from '../Observable';
+import { mergeMap } from '../operators/mergeMap';
+import { isArrayLike } from '../util/isArrayLike';
+import { isFunction } from '../util/isFunction';
+import { mapOneOrManyArgs } from '../util/mapOneOrManyArgs';
+
+// These constants are used to create handler registry functions using array mapping below.
+const nodeEventEmitterMethods = ['addListener', 'removeListener'] as const;
+const eventTargetMethods = ['addEventListener', 'removeEventListener'] as const;
+const jqueryMethods = ['on', 'off'] as const;
+
+export interface NodeStyleEventEmitter {
+ addListener(eventName: string | symbol, handler: NodeEventHandler): this;
+ removeListener(eventName: string | symbol, handler: NodeEventHandler): this;
+}
+
+export type NodeEventHandler = (...args: any[]) => void;
+
+// For APIs that implement `addListener` and `removeListener` methods that may
+// not use the same arguments or return EventEmitter values
+// such as React Native
+export interface NodeCompatibleEventEmitter {
+ addListener(eventName: string, handler: NodeEventHandler): void | {};
+ removeListener(eventName: string, handler: NodeEventHandler): void | {};
+}
+
+// Use handler types like those in @types/jquery. See:
+// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/847731ba1d7fa6db6b911c0e43aa0afe596e7723/types/jquery/misc.d.ts#L6395
+export interface JQueryStyleEventEmitter<TContext, T> {
+ on(eventName: string, handler: (this: TContext, t: T, ...args: any[]) => any): void;
+ off(eventName: string, handler: (this: TContext, t: T, ...args: any[]) => any): void;
+}
+
+export interface EventListenerObject<E> {
+ handleEvent(evt: E): void;
+}
+
+export interface HasEventTargetAddRemove<E> {
+ addEventListener(
+ type: string,
+ listener: ((evt: E) => void) | EventListenerObject<E> | null,
+ options?: boolean | AddEventListenerOptions
+ ): void;
+ removeEventListener(
+ type: string,
+ listener: ((evt: E) => void) | EventListenerObject<E> | null,
+ options?: EventListenerOptions | boolean
+ ): void;
+}
+
+export interface EventListenerOptions {
+ capture?: boolean;
+ passive?: boolean;
+ once?: boolean;
+}
+
+export interface AddEventListenerOptions extends EventListenerOptions {
+ once?: boolean;
+ passive?: boolean;
+}
+
+export function fromEvent<T>(target: HasEventTargetAddRemove<T> | ArrayLike<HasEventTargetAddRemove<T>>, eventName: string): Observable<T>;
+export function fromEvent<T, R>(
+ target: HasEventTargetAddRemove<T> | ArrayLike<HasEventTargetAddRemove<T>>,
+ eventName: string,
+ resultSelector: (event: T) => R
+): Observable<R>;
+export function fromEvent<T>(
+ target: HasEventTargetAddRemove<T> | ArrayLike<HasEventTargetAddRemove<T>>,
+ eventName: string,
+ options: EventListenerOptions
+): Observable<T>;
+export function fromEvent<T, R>(
+ target: HasEventTargetAddRemove<T> | ArrayLike<HasEventTargetAddRemove<T>>,
+ eventName: string,
+ options: EventListenerOptions,
+ resultSelector: (event: T) => R
+): Observable<R>;
+
+export function fromEvent(target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>, eventName: string): Observable<unknown>;
+/** @deprecated Do not specify explicit type parameters. Signatures with type parameters that cannot be inferred will be removed in v8. */
+export function fromEvent<T>(target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>, eventName: string): Observable<T>;
+export function fromEvent<R>(
+ target: NodeStyleEventEmitter | ArrayLike<NodeStyleEventEmitter>,
+ eventName: string,
+ resultSelector: (...args: any[]) => R
+): Observable<R>;
+
+export function fromEvent(
+ target: NodeCompatibleEventEmitter | ArrayLike<NodeCompatibleEventEmitter>,
+ eventName: string
+): Observable<unknown>;
+/** @deprecated Do not specify explicit type parameters. Signatures with type parameters that cannot be inferred will be removed in v8. */
+export function fromEvent<T>(target: NodeCompatibleEventEmitter | ArrayLike<NodeCompatibleEventEmitter>, eventName: string): Observable<T>;
+export function fromEvent<R>(
+ target: NodeCompatibleEventEmitter | ArrayLike<NodeCompatibleEventEmitter>,
+ eventName: string,
+ resultSelector: (...args: any[]) => R
+): Observable<R>;
+
+export function fromEvent<T>(
+ target: JQueryStyleEventEmitter<any, T> | ArrayLike<JQueryStyleEventEmitter<any, T>>,
+ eventName: string
+): Observable<T>;
+export function fromEvent<T, R>(
+ target: JQueryStyleEventEmitter<any, T> | ArrayLike<JQueryStyleEventEmitter<any, T>>,
+ eventName: string,
+ resultSelector: (value: T, ...args: any[]) => R
+): Observable<R>;
+
+/**
+ * Creates an Observable that emits events of a specific type coming from the
+ * given event target.
+ *
+ * <span class="informal">Creates an Observable from DOM events, or Node.js
+ * EventEmitter events or others.</span>
+ *
+ * ![](fromEvent.png)
+ *
+ * `fromEvent` accepts as a first argument event target, which is an object with methods
+ * for registering event handler functions. As a second argument it takes string that indicates
+ * type of event we want to listen for. `fromEvent` supports selected types of event targets,
+ * which are described in detail below. If your event target does not match any of the ones listed,
+ * you should use {@link fromEventPattern}, which can be used on arbitrary APIs.
+ * When it comes to APIs supported by `fromEvent`, their methods for adding and removing event
+ * handler functions have different names, but they all accept a string describing event type
+ * and function itself, which will be called whenever said event happens.
+ *
+ * Every time resulting Observable is subscribed, event handler function will be registered
+ * to event target on given event type. When that event fires, value
+ * passed as a first argument to registered function will be emitted by output Observable.
+ * When Observable is unsubscribed, function will be unregistered from event target.
+ *
+ * Note that if event target calls registered function with more than one argument, second
+ * and following arguments will not appear in resulting stream. In order to get access to them,
+ * you can pass to `fromEvent` optional project function, which will be called with all arguments
+ * passed to event handler. Output Observable will then emit value returned by project function,
+ * instead of the usual value.
+ *
+ * Remember that event targets listed below are checked via duck typing. It means that
+ * no matter what kind of object you have and no matter what environment you work in,
+ * you can safely use `fromEvent` on that object if it exposes described methods (provided
+ * of course they behave as was described above). So for example if Node.js library exposes
+ * event target which has the same method names as DOM EventTarget, `fromEvent` is still
+ * a good choice.
+ *
+ * If the API you use is more callback then event handler oriented (subscribed
+ * callback function fires only once and thus there is no need to manually
+ * unregister it), you should use {@link bindCallback} or {@link bindNodeCallback}
+ * instead.
+ *
+ * `fromEvent` supports following types of event targets:
+ *
+ * **DOM EventTarget**
+ *
+ * This is an object with `addEventListener` and `removeEventListener` methods.
+ *
+ * In the browser, `addEventListener` accepts - apart from event type string and event
+ * handler function arguments - optional third parameter, which is either an object or boolean,
+ * both used for additional configuration how and when passed function will be called. When
+ * `fromEvent` is used with event target of that type, you can provide this values
+ * as third parameter as well.
+ *
+ * **Node.js EventEmitter**
+ *
+ * An object with `addListener` and `removeListener` methods.
+ *
+ * **JQuery-style event target**
+ *
+ * An object with `on` and `off` methods
+ *
+ * **DOM NodeList**
+ *
+ * List of DOM Nodes, returned for example by `document.querySelectorAll` or `Node.childNodes`.
+ *
+ * Although this collection is not event target in itself, `fromEvent` will iterate over all Nodes
+ * it contains and install event handler function in every of them. When returned Observable
+ * is unsubscribed, function will be removed from all Nodes.
+ *
+ * **DOM HtmlCollection**
+ *
+ * Just as in case of NodeList it is a collection of DOM nodes. Here as well event handler function is
+ * installed and removed in each of elements.
+ *
+ *
+ * ## Examples
+ *
+ * Emit clicks happening on the DOM document
+ *
+ * ```ts
+ * import { fromEvent } from 'rxjs';
+ *
+ * const clicks = fromEvent(document, 'click');
+ * clicks.subscribe(x => console.log(x));
+ *
+ * // Results in:
+ * // MouseEvent object logged to console every time a click
+ * // occurs on the document.
+ * ```
+ *
+ * Use `addEventListener` with capture option
+ *
+ * ```ts
+ * import { fromEvent } from 'rxjs';
+ *
+ * const div = document.createElement('div');
+ * div.style.cssText = 'width: 200px; height: 200px; background: #09c;';
+ * document.body.appendChild(div);
+ *
+ * // note optional configuration parameter which will be passed to addEventListener
+ * const clicksInDocument = fromEvent(document, 'click', { capture: true });
+ * const clicksInDiv = fromEvent(div, 'click');
+ *
+ * clicksInDocument.subscribe(() => console.log('document'));
+ * clicksInDiv.subscribe(() => console.log('div'));
+ *
+ * // By default events bubble UP in DOM tree, so normally
+ * // when we would click on div in document
+ * // "div" would be logged first and then "document".
+ * // Since we specified optional `capture` option, document
+ * // will catch event when it goes DOWN DOM tree, so console
+ * // will log "document" and then "div".
+ * ```
+ *
+ * @see {@link bindCallback}
+ * @see {@link bindNodeCallback}
+ * @see {@link fromEventPattern}
+ *
+ * @param target The DOM EventTarget, Node.js EventEmitter, JQuery-like event target,
+ * NodeList or HTMLCollection to attach the event handler to.
+ * @param eventName The event name of interest, being emitted by the `target`.
+ * @param options Options to pass through to the underlying `addListener`,
+ * `addEventListener` or `on` functions.
+ * @param resultSelector A mapping function used to transform events. It takes the
+ * arguments from the event handler and should return a single value.
+ * @return An Observable emitting events registered through `target`'s
+ * listener handlers.
+ */
+export function fromEvent<T>(
+ target: any,
+ eventName: string,
+ options?: EventListenerOptions | ((...args: any[]) => T),
+ resultSelector?: (...args: any[]) => T
+): Observable<T> {
+ if (isFunction(options)) {
+ resultSelector = options;
+ options = undefined;
+ }
+ if (resultSelector) {
+ return fromEvent<T>(target, eventName, options as EventListenerOptions).pipe(mapOneOrManyArgs(resultSelector));
+ }
+
+ // Figure out our add and remove methods. In order to do this,
+ // we are going to analyze the target in a preferred order, if
+ // the target matches a given signature, we take the two "add" and "remove"
+ // method names and apply them to a map to create opposite versions of the
+ // same function. This is because they all operate in duplicate pairs,
+ // `addListener(name, handler)`, `removeListener(name, handler)`, for example.
+ // The call only differs by method name, as to whether or not you're adding or removing.
+ const [add, remove] =
+ // If it is an EventTarget, we need to use a slightly different method than the other two patterns.
+ isEventTarget(target)
+ ? eventTargetMethods.map((methodName) => (handler: any) => target[methodName](eventName, handler, options as EventListenerOptions))
+ : // In all other cases, the call pattern is identical with the exception of the method names.
+ isNodeStyleEventEmitter(target)
+ ? nodeEventEmitterMethods.map(toCommonHandlerRegistry(target, eventName))
+ : isJQueryStyleEventEmitter(target)
+ ? jqueryMethods.map(toCommonHandlerRegistry(target, eventName))
+ : [];
+
+ // If add is falsy, it's because we didn't match a pattern above.
+ // Check to see if it is an ArrayLike, because if it is, we want to
+ // try to apply fromEvent to all of it's items. We do this check last,
+ // because there are may be some types that are both ArrayLike *and* implement
+ // event registry points, and we'd rather delegate to that when possible.
+ if (!add) {
+ if (isArrayLike(target)) {
+ return mergeMap((subTarget: any) => fromEvent(subTarget, eventName, options as EventListenerOptions))(
+ innerFrom(target)
+ ) as Observable<T>;
+ }
+ }
+
+ // If add is falsy and we made it here, it's because we didn't
+ // match any valid target objects above.
+ if (!add) {
+ throw new TypeError('Invalid event target');
+ }
+
+ return new Observable<T>((subscriber) => {
+ // The handler we are going to register. Forwards the event object, by itself, or
+ // an array of arguments to the event handler, if there is more than one argument,
+ // to the consumer.
+ const handler = (...args: any[]) => subscriber.next(1 < args.length ? args : args[0]);
+ // Do the work of adding the handler to the target.
+ add(handler);
+ // When we finalize, we want to remove the handler and free up memory.
+ return () => remove!(handler);
+ });
+}
+
+/**
+ * Used to create `add` and `remove` functions to register and unregister event handlers
+ * from a target in the most common handler pattern, where there are only two arguments.
+ * (e.g. `on(name, fn)`, `off(name, fn)`, `addListener(name, fn)`, or `removeListener(name, fn)`)
+ * @param target The target we're calling methods on
+ * @param eventName The event name for the event we're creating register or unregister functions for
+ */
+function toCommonHandlerRegistry(target: any, eventName: string) {
+ return (methodName: string) => (handler: any) => target[methodName](eventName, handler);
+}
+
+/**
+ * Checks to see if the target implements the required node-style EventEmitter methods
+ * for adding and removing event handlers.
+ * @param target the object to check
+ */
+function isNodeStyleEventEmitter(target: any): target is NodeStyleEventEmitter {
+ return isFunction(target.addListener) && isFunction(target.removeListener);
+}
+
+/**
+ * Checks to see if the target implements the required jQuery-style EventEmitter methods
+ * for adding and removing event handlers.
+ * @param target the object to check
+ */
+function isJQueryStyleEventEmitter(target: any): target is JQueryStyleEventEmitter<any, any> {
+ return isFunction(target.on) && isFunction(target.off);
+}
+
+/**
+ * Checks to see if the target implements the required EventTarget methods
+ * for adding and removing event handlers.
+ * @param target the object to check
+ */
+function isEventTarget(target: any): target is HasEventTargetAddRemove<any> {
+ return isFunction(target.addEventListener) && isFunction(target.removeEventListener);
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage