/** * @module seng-event */ import SengDisposable from 'seng-disposable'; import EventListenerData from './EventListenerData'; import AbstractEvent from './AbstractEvent'; import { EventHandlerForEvent, EventListenerMap, TypesForEvent, ExtractEventOfType } from './EventTypings'; /** * Base class that adds the ability to dispatch events and attach handlers that should be * called when such events are triggered. * * This EventDispatcher also supports event capturing and bubbling phases, heavily inspired * by existing event dispatching systems like the functionality described in the * [DOM Event W3 spec](https://www.w3.org/TR/DOM-Level-2-Events/events.html) * * @typeparam TEvent The type of the events that this EventDispatcher is expected to dispatch. To * allow for multiple event classes, use a union type here. If you don't specify an event type, * any event that `extends` [[AbstractEvent]] can be dispatched, but you won't get automatic typing * for event handlers. */ export default class EventDispatcher extends SengDisposable { /** * The parent EventDispatcher instance. If this instance has no parent, this value will be * set to `null`. The parent is used in the bubbling and capturing phases of events. * @see [[dispatchEvent]] for more information on the bubbling and capturing chain */ parent: EventDispatcher | null; /** * An object containing all event listeners by [[AbstractEvent.type|event type]]. Each value * on this object is an Array of [[EventListenerData]] objects for each event listener * added with that type. */ protected listeners: EventListenerMap; /** * The value that will be set as [[AbstractEvent.target|target]] on events that are dispatched * by this EventDispatcher instance. Set to the value passed to the constructor */ protected target: EventDispatcher; /** * Creates an EventDispatcher instance. * @param parent If set, registers the given EventDispatcher instance as parent. This * child-parent relationship is used in the event chain during the capture phase of * events and the bubbling phase of bubbling events. For more information on event * bubbling and capturing, see [[dispatchEvent]] * @param target If set, will set the [[AbstractEvent.target|target]] attribute of all events * dispatched by this EventDispatcher to the given object. If not set, will use this instance * as a target for dispatched events. * @example You can use the `target` parameter to proxy the EventDispatcher instead of extending * it directly. * ```ts * class Foo { * public dispatcher:EventDispatcher; * * constructor() { * this.dispatcher = new EventDispatcher(null, this); * } * * ... * }; * ``` */ constructor(parent?: EventDispatcher | null, target?: EventDispatcher); /** * Dispatches the given event. The dispatch consists of three phases: * 1. The capture phase. We walk through all ancestors of this EventDispatcher, with the * top-most instance first and the direct parent of this EventDispatcher last. On each * ancestor, we call all event handlers that are added with the `useCapture` argument * set to `true` and the `eventType` set to the same [[AbstractEvent.type|type]] as * the given event. * If this EventDispatcher has no parent, this phase will be skipped. * 2. The target phase. In this phase we call all event handlers on this EventDispatcher * instance that listen for the same [[AbstractEvent.type|type]] as the given event. * 3. The bubbling phase. This phase will only be executed if the given event has the * [[AbstractEvent.bubbles|bubbles]] property set to `true`. If so, we will again walk through * all ancestors of this EventDispatcher, but in the reverse order: the direct parent * of this instance first and the top-most parent last. On every ancestor, we will call * all event handlers that are added with the `useCapture` argument set to `false` and the * `eventType` set to the same [[AbstractEvent.type|type]] as the given event. * * If any of the event handlers call [[AbstractEvent.stopPropagation|stopPropagation()]], we will * skip all event handlers that occur on a target later in the event chain. If an event handler * calls [[AbstractEvent.stopImmediatePropagation|stopImmediatePropagation()]], we will also skip * any event handlers on the same target in the event chain. * @param event The event to dispatch * @returns If one of the handlers that have been called during this dispatch * called [[AbstractEvent.preventDefault|event.preventDefault()]], this method will return `false`. * If no handlers have been called or none of the handlers have called * [[AbstractEvent.preventDefault|event.preventDefault()]], this method will return `true`. * * > Please note: [[AbstractEvent.preventDefault|preventDefault()]] can only be called on * > events that have their [[AbstractEvent.cancelable|cancelable]] property set to `true` */ dispatchEvent(event: TEvent): boolean; /** * Adds a new event listener. The given handler function will be called in the following cases: * - An event with a [[AbstractEvent.type|type]] that is equal to the given `eventType` is dispatched * on this EventDispatcher instance. * - An event with a [[AbstractEvent.type|type]] that is equal to the given `eventType` is dispatched * on a child EventDispatcher, and the `useCapture` parameter is set to `true` * - An event with [[AbstractEvent.bubbles|bubbles]] set to `true` and a [[AbstractEvent.type|type]] that * is equal to the given `eventType` is dispatched on a child EventDispatcher, and the * `useCapture` parameter is set to `false` * * @see [[dispatchEvent]] for more info on the which event listeners are called during * capturing and bubbling * @param eventType The eventType to listen for * @param handler The handler function that will be called when a matching event is dispatched. * This function will retrieve the dispatched [[AbstractEvent|event]] as a parameter * @param useCapture Indicates if this handler should be called during the capturing phase * of an event chain. If and only if this is set to `false` will this handler be called * during the bubbling phase of an event chain. * @param priority A number that indicates the priority of this event listener relative * to other event listeners of the same type on this EventDispatcher instance. A higher number * indicates that this listener will be called earlier. * @returns An object describing the listener that has a [[EventListenerData.dispose|dispose()]] * method to remove the listener. */ addEventListener>(eventType: TType, handler: EventHandlerForEvent>, useCapture?: boolean, priority?: number): EventListenerData; /** * Checks if an event listener matching the given parameters exists on this EventDispatcher * instance. * @param eventType Will only look for event listeners with this `eventType` * @param handler If set, will only match event listeners that have the same handler function * @param useCapture If set, will only match event listeners that have the same `useCapture` * argument. * > Please note: if no `useCapture` argument was provided to [[addEventListener]], it * is set to `false` by default * @returns {boolean} True if one or more event listeners exist */ hasEventListener>(eventType: TType, handler?: EventHandlerForEvent>, useCapture?: boolean): boolean; /** * Checks if an event listener with a [[EventListenerData.type|type]] of the given `eventType` exists * on this EventDispatcher or any ancestor EventDispatcher instance. * @param eventType The event type to check for * @returns `true` if a matching listener is found */ willTrigger(eventType: TypesForEvent): boolean; /** * Removes all event listeners that match the given parameters from this EventDispatcher * instance. * * _Please note: if you remove an event listener during the dispatch of an event it will * not be called anymore, even if it was supposed to be called in the same event chain_ * @param eventType Only event listeners of that have this `eventType` are removed * @param handler Only event listeners that have this handler function will be removed * @param useCapture Only event listeners that have been added with the same `useCapture` * parameter will be removed. _Please note: if no useCapture argument is provided, only * event listeners that have useCapture set to false will be removed._ */ removeEventListener>(eventType: TType, handler: EventHandlerForEvent, useCapture?: boolean): void; /** * Removes all event listeners that have a [[AbstractEvent.type|type]] of the given `eventType` * from this EventDispatcher instance, regardless of their [[EventListenerData.handler|handler]] or * [[EventListenerData.useCapture|useCapture]] property. * * _Please note: if you remove an event listener during the dispatch of an event it will * not be called anymore, even if it was supposed to be called in the same event chain_ * @param eventType The [[AbstractEvent.type|type]] of event to remove. If not provided, all event listeners * will be removed regardless of their type. */ removeAllEventListeners(eventType?: TypesForEvent): void; /** * Cleans up this EventListener instance. No event handlers on this EventDispatcher will be called * and future calls to [[EventDispatcher.dispatchEvent|dispatchEvent()]] will be ignored. */ dispose(): void; /** * Method that is used to sort arrays of event listeners based on their [[EventListenerData.priority|priority]] * property. Higher priority will be sorted before lower priority values. * @param e1 The first event listener to compare * @param e2 The other event listener to compare to * @returns A number that indicates the sorting according to the JS sort() method. */ protected listenerSorter(e1: EventListenerData, e2: EventListenerData): number; } /** * Helper function for [[EventDispatcher.removeEventListener]] and [[EventDispatcher.removeAllEventListeners]]. * Will remove all event listeners that match the given parameters from the given event listener map object. * This function differs from [[EventDispatcher.removeEventListener|removeEventListener()]] in that it does not * use default values when you emit one of the parameters. Instead, it will remove event listeners of all * possible values for that parameter. * @hidden * @param listeners A map of listeners to remove from. See [[EventDispatcher.listeners]] * @param eventType If set, will only remove listeners added with this `eventType` * @param handler If set, will only remove listeners with this _handler_ * @param useCapture If set, will only remove listeners with the same value for `useCapture` */ export declare const removeListenersFrom: (listeners: EventListenerMap, eventType?: TEvent["type"] | null | undefined, handler?: EventHandlerForEvent | null | undefined, useCapture?: boolean | undefined) => void; /** * Gets an array of all parent EventDispatcher instances of the given EventDispatcher. The direct * parent (if it has one) will be first in the Array, and the most top-level parent will be last. * @hidden * @param target The instance to get parents for * @returns {Array} The array of parents */ export declare const getParents: (target: EventDispatcher) => EventDispatcher[]; /** * Gets an array that represents the entire call tree when an event is dispatched on the given target. * See [[EventDispatcher.dispatchEvent]] for more information on the event phases * @hidden * @param target The target to get the call tree for * @param bubbles If true, will also include the target instances of the _bubbling_ phase. If false, will * only include the _capture_ and target_ phases. * @returns An array of EventDispatcher instances in the order that an event will travel during dispatch * on the given target. */ export declare const getCallTree: (target: EventDispatcher, bubbles: boolean) => EventDispatcher[]; /** * Calls all listeners on the given event listener map that should be called when the given event is * dispatched. If no matching listeners are present, this function has no effect * @hidden * @param listeners The object that contains listeners to call. Has the same format as the * [[EventDispatcher.listeners|listeners]] property on [[EventDispatcher]] * @param event The event that may trigger listeners in the map * @returns True if any of the listeners call [[AbstractEvent.stopPropagation|stopPropagation()]] or * [[AbstractEvent.stopImmediatePropagation|stopImmediatePropagation]]. False if no listeners are called or none * of them call [[AbstractEvent.stopPropagation|stopPropagation()]] or * [[AbstractEvent.stopImmediatePropagation|stopImmediatePropagation]] */ export declare const callListeners: (listeners: EventListenerMap, event: TEvent) => boolean;