import { id } from "tsafe/id"; import { assert } from "tsafe/assert"; import { typeGuard } from "tsafe/typeGuard"; import { mergeImpl } from "./Evt.merge"; import { importProxy } from "./importProxy"; import type { dom, Evt, NonPostableEvtLike } from "./types"; import type { EventTargetLike } from "./types"; import * as nsEventTargetLike from "./types/EventTargetLike"; const { EventTargetLike: EventTargetLikeAsValue } = nsEventTargetLike; import type { ObserverConstructor } from "./types/Observer"; type OneOrMany = T | ArrayLike; type CtxLike = import("./types").CtxLike & { evtDoneOrAborted: NonPostableEvtLike & { postCount: number; attachOnce(callback: () => void): void; }; }; function fromImplForTargetEventLike( ctx: CtxLike | undefined, target: OneOrMany> | PromiseLike, eventName?: string, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt { const matchEventTargetLike = (target_: typeof target): target_ is EventTargetLike => EventTargetLikeAsValue.canBe(target_); if (!matchEventTargetLike(target)) { if ("then" in target) { const evt = new importProxy.Evt(); const isCtxDone = (() => { const getEvtDonePostCount = () => ctx?.evtDoneOrAborted.postCount; const n = getEvtDonePostCount(); return () => n !== getEvtDonePostCount(); })(); target.then(data => { if (isCtxDone()) { return; } evt.post(data); }); return evt; } return mergeImpl>( ctx, Array.from(target).map( target => fromImplForTargetEventLike(ctx, target, eventName, options) ) ); } type ProxyMethod = ( listener: (data: T) => void, eventName: string, options?: EventTargetLike.HasEventTargetAddRemove.Options ) => void; let proxy: { on: ProxyMethod; off: ProxyMethod; }; if (EventTargetLikeAsValue.HasEventTargetAddRemove.match(target)) { proxy = { "on": (listener, eventName, options) => target.addEventListener(eventName, listener, options), "off": (listener, eventName, options) => target.removeEventListener(eventName, listener, options) }; } else if (EventTargetLikeAsValue.NodeStyleEventEmitter.match(target)) { proxy = { "on": (listener, eventName) => target.addListener(eventName, listener), "off": (listener, eventName) => target.removeListener(eventName, listener) }; } else if (EventTargetLikeAsValue.JQueryStyleEventEmitter.match(target)) { proxy = { "on": (listener, eventName) => target.on(eventName, listener), "off": (listener, eventName) => target.off(eventName, listener) }; } else if (EventTargetLikeAsValue.RxJSSubject.match(target)) { let subscription: EventTargetLike.RxJSSubject.Subscription; proxy = { "on": listener => subscription = target.subscribe(data => listener(data)), "off": () => subscription.unsubscribe() }; } else { id(target); assert(false); } const evt = new importProxy.Evt(); const listener = (data: T) => evt.post(data); ctx?.evtDoneOrAborted.attachOnce( () => proxy.off( listener, eventName!, options ) ); proxy.on(listener, eventName!, options); return evt; } function fromImplForObserver( ctx: CtxLike | undefined, ObserverConstructor: ObserverConstructor, target: Target ): Evt { const evt = importProxy.Evt.create(); const listener = ([entry]: Entry[]) => evt.post(entry); const observer = new ObserverConstructor(listener); observer.observe(target); ctx?.evtDoneOrAborted.attachOnce( () => observer.disconnect() ); return evt; } /** https://docs.evt.land/api/evt/from */ export function from( ctx: CtxLike, target: EventTargetLike.HTMLElement, eventName: K, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( ctx: CtxLike, target: EventTargetLike.Window, eventName: K, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( ctx: CtxLike, target: EventTargetLike.Document, eventName: K, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( ctx: CtxLike, target: OneOrMany< EventTargetLike.NodeStyleEventEmitter | EventTargetLike.JQueryStyleEventEmitter >, eventName: string ): Evt; export function from( ctx: CtxLike, target: OneOrMany< EventTargetLike.HasEventTargetAddRemove >, eventName: string, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( ctx: CtxLike, target: OneOrMany> ): Evt; export function from( ctx: CtxLike, target: PromiseLike ): Evt; export function from( ctx: CtxLike, ObserverConstructor: ObserverConstructor, target: Target ): Evt; export function from( target: EventTargetLike.HTMLElement, eventName: K, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( target: EventTargetLike.Window, eventName: K, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( target: EventTargetLike.Document, eventName: K, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( target: OneOrMany< EventTargetLike.NodeStyleEventEmitter | EventTargetLike.JQueryStyleEventEmitter >, eventName: string ): Evt; export function from( target: OneOrMany< EventTargetLike.HasEventTargetAddRemove >, eventName: string, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt; export function from( target: OneOrMany> ): Evt; export function from( target: PromiseLike ): Evt; export function from( ObserverConstructor: ObserverConstructor, target: Target ): Evt; /* /^[A-Z]/.test(targetOrEventNameOrObserverConstructorOrObserverTarget.name */ export function from( ctxOrTargetOrObserverConstructor: CtxLike | OneOrMany> | PromiseLike | ObserverConstructor, targetOrEventNameOrObserverConstructorOrObserverTarget?: OneOrMany> | string | PromiseLike | ObserverConstructor | ObserverTarget, eventNameOrOptionsOrObserverTarget?: string | EventTargetLike.HasEventTargetAddRemove.Options | ObserverTarget, options?: EventTargetLike.HasEventTargetAddRemove.Options ): Evt { if ("evtDoneOrAborted" in ctxOrTargetOrObserverConstructor) { assert( typeGuard> | PromiseLike | ObserverConstructor>(targetOrEventNameOrObserverConstructorOrObserverTarget, true) && typeGuard(eventNameOrOptionsOrObserverTarget, true) && typeGuard(options, true) ); if (typeof targetOrEventNameOrObserverConstructorOrObserverTarget === "function") { assert( typeGuard(eventNameOrOptionsOrObserverTarget, true) && typeGuard(options, true) ); return fromImplForObserver( ctxOrTargetOrObserverConstructor, targetOrEventNameOrObserverConstructorOrObserverTarget, eventNameOrOptionsOrObserverTarget ); } else { assert( typeGuard>(eventNameOrOptionsOrObserverTarget, true) ); return fromImplForTargetEventLike( ctxOrTargetOrObserverConstructor, targetOrEventNameOrObserverConstructorOrObserverTarget, eventNameOrOptionsOrObserverTarget, options ); } } else { assert( typeGuard>>(ctxOrTargetOrObserverConstructor, true) && typeGuard(targetOrEventNameOrObserverConstructorOrObserverTarget, true) && typeGuard(eventNameOrOptionsOrObserverTarget, true) ); if (typeof ctxOrTargetOrObserverConstructor === "function") { assert( typeGuard(targetOrEventNameOrObserverConstructorOrObserverTarget, true) && typeGuard(eventNameOrOptionsOrObserverTarget, true) ); return fromImplForObserver( undefined, ctxOrTargetOrObserverConstructor, targetOrEventNameOrObserverConstructorOrObserverTarget ); } else { assert( typeGuard>( targetOrEventNameOrObserverConstructorOrObserverTarget, true ) ); return fromImplForTargetEventLike( undefined, ctxOrTargetOrObserverConstructor, targetOrEventNameOrObserverConstructorOrObserverTarget, eventNameOrOptionsOrObserverTarget ); } } }