source: trip-planner-front/node_modules/rxjs/src/internal/observable/fromEvent.ts@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 10.4 KB
Line 
1import { Observable } from '../Observable';
2import { isArray } from '../util/isArray';
3import { isFunction } from '../util/isFunction';
4import { Subscriber } from '../Subscriber';
5import { map } from '../operators/map';
6
7const toString: Function = (() => Object.prototype.toString)();
8
9export interface NodeStyleEventEmitter {
10 addListener: (eventName: string | symbol, handler: NodeEventHandler) => this;
11 removeListener: (eventName: string | symbol, handler: NodeEventHandler) => this;
12}
13
14export type NodeEventHandler = (...args: any[]) => void;
15
16// For APIs that implement `addListener` and `removeListener` methods that may
17// not use the same arguments or return EventEmitter values
18// such as React Native
19export interface NodeCompatibleEventEmitter {
20 addListener: (eventName: string, handler: NodeEventHandler) => void | {};
21 removeListener: (eventName: string, handler: NodeEventHandler) => void | {};
22}
23
24export interface JQueryStyleEventEmitter {
25 on: (eventName: string, handler: Function) => void;
26 off: (eventName: string, handler: Function) => void;
27}
28
29export interface HasEventTargetAddRemove<E> {
30 addEventListener(type: string, listener: ((evt: E) => void) | null, options?: boolean | AddEventListenerOptions): void;
31 removeEventListener(type: string, listener?: ((evt: E) => void) | null, options?: EventListenerOptions | boolean): void;
32}
33
34export type EventTargetLike<T> = HasEventTargetAddRemove<T> | NodeStyleEventEmitter | NodeCompatibleEventEmitter | JQueryStyleEventEmitter;
35
36export type FromEventTarget<T> = EventTargetLike<T> | ArrayLike<EventTargetLike<T>>;
37
38export interface EventListenerOptions {
39 capture?: boolean;
40 passive?: boolean;
41 once?: boolean;
42}
43
44export interface AddEventListenerOptions extends EventListenerOptions {
45 once?: boolean;
46 passive?: boolean;
47}
48
49/* tslint:disable:max-line-length */
50export function fromEvent<T>(target: FromEventTarget<T>, eventName: string): Observable<T>;
51/** @deprecated resultSelector no longer supported, pipe to map instead */
52export function fromEvent<T>(target: FromEventTarget<T>, eventName: string, resultSelector: (...args: any[]) => T): Observable<T>;
53export function fromEvent<T>(target: FromEventTarget<T>, eventName: string, options: EventListenerOptions): Observable<T>;
54/** @deprecated resultSelector no longer supported, pipe to map instead */
55export function fromEvent<T>(target: FromEventTarget<T>, eventName: string, options: EventListenerOptions, resultSelector: (...args: any[]) => T): Observable<T>;
56/* tslint:enable:max-line-length */
57
58/**
59 * Creates an Observable that emits events of a specific type coming from the
60 * given event target.
61 *
62 * <span class="informal">Creates an Observable from DOM events, or Node.js
63 * EventEmitter events or others.</span>
64 *
65 * ![](fromEvent.png)
66 *
67 * `fromEvent` accepts as a first argument event target, which is an object with methods
68 * for registering event handler functions. As a second argument it takes string that indicates
69 * type of event we want to listen for. `fromEvent` supports selected types of event targets,
70 * which are described in detail below. If your event target does not match any of the ones listed,
71 * you should use {@link fromEventPattern}, which can be used on arbitrary APIs.
72 * When it comes to APIs supported by `fromEvent`, their methods for adding and removing event
73 * handler functions have different names, but they all accept a string describing event type
74 * and function itself, which will be called whenever said event happens.
75 *
76 * Every time resulting Observable is subscribed, event handler function will be registered
77 * to event target on given event type. When that event fires, value
78 * passed as a first argument to registered function will be emitted by output Observable.
79 * When Observable is unsubscribed, function will be unregistered from event target.
80 *
81 * Note that if event target calls registered function with more than one argument, second
82 * and following arguments will not appear in resulting stream. In order to get access to them,
83 * you can pass to `fromEvent` optional project function, which will be called with all arguments
84 * passed to event handler. Output Observable will then emit value returned by project function,
85 * instead of the usual value.
86 *
87 * Remember that event targets listed below are checked via duck typing. It means that
88 * no matter what kind of object you have and no matter what environment you work in,
89 * you can safely use `fromEvent` on that object if it exposes described methods (provided
90 * of course they behave as was described above). So for example if Node.js library exposes
91 * event target which has the same method names as DOM EventTarget, `fromEvent` is still
92 * a good choice.
93 *
94 * If the API you use is more callback then event handler oriented (subscribed
95 * callback function fires only once and thus there is no need to manually
96 * unregister it), you should use {@link bindCallback} or {@link bindNodeCallback}
97 * instead.
98 *
99 * `fromEvent` supports following types of event targets:
100 *
101 * **DOM EventTarget**
102 *
103 * This is an object with `addEventListener` and `removeEventListener` methods.
104 *
105 * In the browser, `addEventListener` accepts - apart from event type string and event
106 * handler function arguments - optional third parameter, which is either an object or boolean,
107 * both used for additional configuration how and when passed function will be called. When
108 * `fromEvent` is used with event target of that type, you can provide this values
109 * as third parameter as well.
110 *
111 * **Node.js EventEmitter**
112 *
113 * An object with `addListener` and `removeListener` methods.
114 *
115 * **JQuery-style event target**
116 *
117 * An object with `on` and `off` methods
118 *
119 * **DOM NodeList**
120 *
121 * List of DOM Nodes, returned for example by `document.querySelectorAll` or `Node.childNodes`.
122 *
123 * Although this collection is not event target in itself, `fromEvent` will iterate over all Nodes
124 * it contains and install event handler function in every of them. When returned Observable
125 * is unsubscribed, function will be removed from all Nodes.
126 *
127 * **DOM HtmlCollection**
128 *
129 * Just as in case of NodeList it is a collection of DOM nodes. Here as well event handler function is
130 * installed and removed in each of elements.
131 *
132 *
133 * ## Examples
134 * ### Emits clicks happening on the DOM document
135 * ```ts
136 * import { fromEvent } from 'rxjs';
137 *
138 * const clicks = fromEvent(document, 'click');
139 * clicks.subscribe(x => console.log(x));
140 *
141 * // Results in:
142 * // MouseEvent object logged to console every time a click
143 * // occurs on the document.
144 * ```
145 *
146 * ### Use addEventListener with capture option
147 * ```ts
148 * import { fromEvent } from 'rxjs';
149 *
150 * const clicksInDocument = fromEvent(document, 'click', true); // note optional configuration parameter
151 * // which will be passed to addEventListener
152 * const clicksInDiv = fromEvent(someDivInDocument, 'click');
153 *
154 * clicksInDocument.subscribe(() => console.log('document'));
155 * clicksInDiv.subscribe(() => console.log('div'));
156 *
157 * // By default events bubble UP in DOM tree, so normally
158 * // when we would click on div in document
159 * // "div" would be logged first and then "document".
160 * // Since we specified optional `capture` option, document
161 * // will catch event when it goes DOWN DOM tree, so console
162 * // will log "document" and then "div".
163 * ```
164 *
165 * @see {@link bindCallback}
166 * @see {@link bindNodeCallback}
167 * @see {@link fromEventPattern}
168 *
169 * @param {FromEventTarget<T>} target The DOM EventTarget, Node.js
170 * EventEmitter, JQuery-like event target, NodeList or HTMLCollection to attach the event handler to.
171 * @param {string} eventName The event name of interest, being emitted by the
172 * `target`.
173 * @param {EventListenerOptions} [options] Options to pass through to addEventListener
174 * @return {Observable<T>}
175 * @name fromEvent
176 */
177export function fromEvent<T>(
178 target: FromEventTarget<T>,
179 eventName: string,
180 options?: EventListenerOptions | ((...args: any[]) => T),
181 resultSelector?: ((...args: any[]) => T)
182): Observable<T> {
183
184 if (isFunction(options)) {
185 // DEPRECATED PATH
186 resultSelector = options;
187 options = undefined;
188 }
189 if (resultSelector) {
190 // DEPRECATED PATH
191 return fromEvent<T>(target, eventName, <EventListenerOptions | undefined>options).pipe(
192 map(args => isArray(args) ? resultSelector(...args) : resultSelector(args))
193 );
194 }
195
196 return new Observable<T>(subscriber => {
197 function handler(e: T) {
198 if (arguments.length > 1) {
199 subscriber.next(Array.prototype.slice.call(arguments));
200 } else {
201 subscriber.next(e);
202 }
203 }
204 setupSubscription(target, eventName, handler, subscriber, options as EventListenerOptions);
205 });
206}
207
208function setupSubscription<T>(sourceObj: FromEventTarget<T>, eventName: string,
209 handler: (...args: any[]) => void, subscriber: Subscriber<T>,
210 options?: EventListenerOptions) {
211 let unsubscribe: () => void;
212 if (isEventTarget(sourceObj)) {
213 const source = sourceObj;
214 sourceObj.addEventListener(eventName, handler, options);
215 unsubscribe = () => source.removeEventListener(eventName, handler, options);
216 } else if (isJQueryStyleEventEmitter(sourceObj)) {
217 const source = sourceObj;
218 sourceObj.on(eventName, handler);
219 unsubscribe = () => source.off(eventName, handler);
220 } else if (isNodeStyleEventEmitter(sourceObj)) {
221 const source = sourceObj;
222 sourceObj.addListener(eventName, handler as NodeEventHandler);
223 unsubscribe = () => source.removeListener(eventName, handler as NodeEventHandler);
224 } else if (sourceObj && (sourceObj as any).length) {
225 for (let i = 0, len = (sourceObj as any).length; i < len; i++) {
226 setupSubscription(sourceObj[i], eventName, handler, subscriber, options);
227 }
228 } else {
229 throw new TypeError('Invalid event target');
230 }
231
232 subscriber.add(unsubscribe);
233}
234
235function isNodeStyleEventEmitter(sourceObj: any): sourceObj is NodeStyleEventEmitter {
236 return sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function';
237}
238
239function isJQueryStyleEventEmitter(sourceObj: any): sourceObj is JQueryStyleEventEmitter {
240 return sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function';
241}
242
243function isEventTarget(sourceObj: any): sourceObj is HasEventTargetAddRemove<any> {
244 return sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function';
245}
Note: See TracBrowser for help on using the repository browser.