UNPKG

23.1 kBSource Map (JSON)View Raw
1{"version":3,"sources":["../src/index.ts"],"names":["Signal","Private","sender","this","prototype","connect","slot","thisArg","disconnect","emit","args","disconnectBetween","receiver","disconnectSender","disconnectReceiver","disconnectAll","object","clearData","getExceptionHandler","exceptionHandler","setExceptionHandler","handler","old","receivers","receiversForSender","get","length","each","connection","signal","scheduleCleanup","sendersForReceiver","senders","err","console","error","undefined","set","findConnection","push","i","n","invokeSlot","WeakMap","dirtySet","Set","schedule","requestAnimationFrame","setImmediate","connections","find","call","array","size","cleanupDirtySet","add","forEach","cleanupConnections","clear","ArrayExt","removeAllWhere","isDeadConnection"],"mappings":"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","sourcesContent":["// Copyright (c) Jupyter Development Team.\n// Distributed under the terms of the Modified BSD License.\n/*-----------------------------------------------------------------------------\n| Copyright (c) 2014-2017, PhosphorJS Contributors\n|\n| Distributed under the terms of the BSD 3-Clause License.\n|\n| The full license is in the file LICENSE, distributed with this software.\n|----------------------------------------------------------------------------*/\nimport { ArrayExt, each, find } from '@lumino/algorithm';\n\n/**\n * A type alias for a slot function.\n *\n * @param sender - The object emitting the signal.\n *\n * @param args - The args object emitted with the signal.\n *\n * #### Notes\n * A slot is invoked when a signal to which it is connected is emitted.\n */\nexport type Slot<T, U> = (sender: T, args: U) => void;\n\n/**\n * An object used for type-safe inter-object communication.\n *\n * #### Notes\n * Signals provide a type-safe implementation of the publish-subscribe\n * pattern. An object (publisher) declares which signals it will emit,\n * and consumers connect callbacks (subscribers) to those signals. The\n * subscribers are invoked whenever the publisher emits the signal.\n */\nexport interface ISignal<T, U> {\n /**\n * Connect a slot to the signal.\n *\n * @param slot - The slot to invoke when the signal is emitted.\n *\n * @param thisArg - The `this` context for the slot. If provided,\n * this must be a non-primitive object.\n *\n * @returns `true` if the connection succeeds, `false` otherwise.\n *\n * #### Notes\n * Slots are invoked in the order in which they are connected.\n *\n * Signal connections are unique. If a connection already exists for\n * the given `slot` and `thisArg`, this method returns `false`.\n *\n * A newly connected slot will not be invoked until the next time the\n * signal is emitted, even if the slot is connected while the signal\n * is dispatching.\n */\n connect(slot: Slot<T, U>, thisArg?: any): boolean;\n\n /**\n * Disconnect a slot from the signal.\n *\n * @param slot - The slot to disconnect from the signal.\n *\n * @param thisArg - The `this` context for the slot. If provided,\n * this must be a non-primitive object.\n *\n * @returns `true` if the connection is removed, `false` otherwise.\n *\n * #### Notes\n * If no connection exists for the given `slot` and `thisArg`, this\n * method returns `false`.\n *\n * A disconnected slot will no longer be invoked, even if the slot\n * is disconnected while the signal is dispatching.\n */\n disconnect(slot: Slot<T, U>, thisArg?: any): boolean;\n}\n\n/**\n * A concrete implementation of `ISignal`.\n *\n * #### Example\n * ```typescript\n * import { ISignal, Signal } from '@lumino/signaling';\n *\n * class SomeClass {\n *\n * constructor(name: string) {\n * this.name = name;\n * }\n *\n * readonly name: string;\n *\n * get valueChanged: ISignal<this, number> {\n * return this._valueChanged;\n * }\n *\n * get value(): number {\n * return this._value;\n * }\n *\n * set value(value: number) {\n * if (value === this._value) {\n * return;\n * }\n * this._value = value;\n * this._valueChanged.emit(value);\n * }\n *\n * private _value = 0;\n * private _valueChanged = new Signal<this, number>(this);\n * }\n *\n * function logger(sender: SomeClass, value: number): void {\n * console.log(sender.name, value);\n * }\n *\n * let m1 = new SomeClass('foo');\n * let m2 = new SomeClass('bar');\n *\n * m1.valueChanged.connect(logger);\n * m2.valueChanged.connect(logger);\n *\n * m1.value = 42; // logs: foo 42\n * m2.value = 17; // logs: bar 17\n * ```\n */\nexport class Signal<T, U> implements ISignal<T, U> {\n /**\n * Construct a new signal.\n *\n * @param sender - The sender which owns the signal.\n */\n constructor(sender: T) {\n this.sender = sender;\n }\n\n /**\n * The sender which owns the signal.\n */\n readonly sender: T;\n\n /**\n * Connect a slot to the signal.\n *\n * @param slot - The slot to invoke when the signal is emitted.\n *\n * @param thisArg - The `this` context for the slot. If provided,\n * this must be a non-primitive object.\n *\n * @returns `true` if the connection succeeds, `false` otherwise.\n */\n connect(slot: Slot<T, U>, thisArg?: any): boolean {\n return Private.connect(this, slot, thisArg);\n }\n\n /**\n * Disconnect a slot from the signal.\n *\n * @param slot - The slot to disconnect from the signal.\n *\n * @param thisArg - The `this` context for the slot. If provided,\n * this must be a non-primitive object.\n *\n * @returns `true` if the connection is removed, `false` otherwise.\n */\n disconnect(slot: Slot<T, U>, thisArg?: any): boolean {\n return Private.disconnect(this, slot, thisArg);\n }\n\n /**\n * Emit the signal and invoke the connected slots.\n *\n * @param args - The args to pass to the connected slots.\n *\n * #### Notes\n * Slots are invoked synchronously in connection order.\n *\n * Exceptions thrown by connected slots will be caught and logged.\n */\n emit(args: U): void {\n Private.emit(this, args);\n }\n}\n\n/**\n * The namespace for the `Signal` class statics.\n */\nexport namespace Signal {\n /**\n * Remove all connections between a sender and receiver.\n *\n * @param sender - The sender object of interest.\n *\n * @param receiver - The receiver object of interest.\n *\n * #### Notes\n * If a `thisArg` is provided when connecting a signal, that object\n * is considered the receiver. Otherwise, the `slot` is considered\n * the receiver.\n */\n export function disconnectBetween(sender: any, receiver: any): void {\n Private.disconnectBetween(sender, receiver);\n }\n\n /**\n * Remove all connections where the given object is the sender.\n *\n * @param sender - The sender object of interest.\n */\n export function disconnectSender(sender: any): void {\n Private.disconnectSender(sender);\n }\n\n /**\n * Remove all connections where the given object is the receiver.\n *\n * @param receiver - The receiver object of interest.\n *\n * #### Notes\n * If a `thisArg` is provided when connecting a signal, that object\n * is considered the receiver. Otherwise, the `slot` is considered\n * the receiver.\n */\n export function disconnectReceiver(receiver: any): void {\n Private.disconnectReceiver(receiver);\n }\n\n /**\n * Remove all connections where an object is the sender or receiver.\n *\n * @param object - The object of interest.\n *\n * #### Notes\n * If a `thisArg` is provided when connecting a signal, that object\n * is considered the receiver. Otherwise, the `slot` is considered\n * the receiver.\n */\n export function disconnectAll(object: any): void {\n Private.disconnectAll(object);\n }\n\n /**\n * Clear all signal data associated with the given object.\n *\n * @param object - The object for which the data should be cleared.\n *\n * #### Notes\n * This removes all signal connections and any other signal data\n * associated with the object.\n */\n export function clearData(object: any): void {\n Private.disconnectAll(object);\n }\n\n /**\n * A type alias for the exception handler function.\n */\n export type ExceptionHandler = (err: Error) => void;\n\n /**\n * Get the signal exception handler.\n *\n * @returns The current exception handler.\n *\n * #### Notes\n * The default exception handler is `console.error`.\n */\n export function getExceptionHandler(): ExceptionHandler {\n return Private.exceptionHandler;\n }\n\n /**\n * Set the signal exception handler.\n *\n * @param handler - The function to use as the exception handler.\n *\n * @returns The old exception handler.\n *\n * #### Notes\n * The exception handler is invoked when a slot throws an exception.\n */\n export function setExceptionHandler(\n handler: ExceptionHandler\n ): ExceptionHandler {\n let old = Private.exceptionHandler;\n Private.exceptionHandler = handler;\n return old;\n }\n}\n\n/**\n * The namespace for the module implementation details.\n */\nnamespace Private {\n /**\n * The signal exception handler function.\n */\n export let exceptionHandler: Signal.ExceptionHandler = (err: Error) => {\n console.error(err);\n };\n\n /**\n * Connect a slot to a signal.\n *\n * @param signal - The signal of interest.\n *\n * @param slot - The slot to invoke when the signal is emitted.\n *\n * @param thisArg - The `this` context for the slot. If provided,\n * this must be a non-primitive object.\n *\n * @returns `true` if the connection succeeds, `false` otherwise.\n */\n export function connect<T, U>(\n signal: Signal<T, U>,\n slot: Slot<T, U>,\n thisArg?: any\n ): boolean {\n // Coerce a `null` `thisArg` to `undefined`.\n thisArg = thisArg || undefined;\n\n // Ensure the sender's array of receivers is created.\n let receivers = receiversForSender.get(signal.sender);\n if (!receivers) {\n receivers = [];\n receiversForSender.set(signal.sender, receivers);\n }\n\n // Bail if a matching connection already exists.\n if (findConnection(receivers, signal, slot, thisArg)) {\n return false;\n }\n\n // Choose the best object for the receiver.\n let receiver = thisArg || slot;\n\n // Ensure the receiver's array of senders is created.\n let senders = sendersForReceiver.get(receiver);\n if (!senders) {\n senders = [];\n sendersForReceiver.set(receiver, senders);\n }\n\n // Create a new connection and add it to the end of each array.\n let connection = { signal, slot, thisArg };\n receivers.push(connection);\n senders.push(connection);\n\n // Indicate a successful connection.\n return true;\n }\n\n /**\n * Disconnect a slot from a signal.\n *\n * @param signal - The signal of interest.\n *\n * @param slot - The slot to disconnect from the signal.\n *\n * @param thisArg - The `this` context for the slot. If provided,\n * this must be a non-primitive object.\n *\n * @returns `true` if the connection is removed, `false` otherwise.\n */\n export function disconnect<T, U>(\n signal: Signal<T, U>,\n slot: Slot<T, U>,\n thisArg?: any\n ): boolean {\n // Coerce a `null` `thisArg` to `undefined`.\n thisArg = thisArg || undefined;\n\n // Lookup the list of receivers, and bail if none exist.\n let receivers = receiversForSender.get(signal.sender);\n if (!receivers || receivers.length === 0) {\n return false;\n }\n\n // Bail if no matching connection exits.\n let connection = findConnection(receivers, signal, slot, thisArg);\n if (!connection) {\n return false;\n }\n\n // Choose the best object for the receiver.\n let receiver = thisArg || slot;\n\n // Lookup the array of senders, which is now known to exist.\n let senders = sendersForReceiver.get(receiver)!;\n\n // Clear the connection and schedule cleanup of the arrays.\n connection.signal = null;\n scheduleCleanup(receivers);\n scheduleCleanup(senders);\n\n // Indicate a successful disconnection.\n return true;\n }\n\n /**\n * Remove all connections between a sender and receiver.\n *\n * @param sender - The sender object of interest.\n *\n * @param receiver - The receiver object of interest.\n */\n export function disconnectBetween(sender: any, receiver: any): void {\n // If there are no receivers, there is nothing to do.\n let receivers = receiversForSender.get(sender);\n if (!receivers || receivers.length === 0) {\n return;\n }\n\n // If there are no senders, there is nothing to do.\n let senders = sendersForReceiver.get(receiver);\n if (!senders || senders.length === 0) {\n return;\n }\n\n // Clear each connection between the sender and receiver.\n each(senders, connection => {\n // Skip connections which have already been cleared.\n if (!connection.signal) {\n return;\n }\n\n // Clear the connection if it matches the sender.\n if (connection.signal.sender === sender) {\n connection.signal = null;\n }\n });\n\n // Schedule a cleanup of the senders and receivers.\n scheduleCleanup(receivers);\n scheduleCleanup(senders);\n }\n\n /**\n * Remove all connections where the given object is the sender.\n *\n * @param sender - The sender object of interest.\n */\n export function disconnectSender(sender: any): void {\n // If there are no receivers, there is nothing to do.\n let receivers = receiversForSender.get(sender);\n if (!receivers || receivers.length === 0) {\n return;\n }\n\n // Clear each receiver connection.\n each(receivers, connection => {\n // Skip connections which have already been cleared.\n if (!connection.signal) {\n return;\n }\n\n // Choose the best object for the receiver.\n let receiver = connection.thisArg || connection.slot;\n\n // Clear the connection.\n connection.signal = null;\n\n // Cleanup the array of senders, which is now known to exist.\n scheduleCleanup(sendersForReceiver.get(receiver)!);\n });\n\n // Schedule a cleanup of the receivers.\n scheduleCleanup(receivers);\n }\n\n /**\n * Remove all connections where the given object is the receiver.\n *\n * @param receiver - The receiver object of interest.\n */\n export function disconnectReceiver(receiver: any): void {\n // If there are no senders, there is nothing to do.\n let senders = sendersForReceiver.get(receiver);\n if (!senders || senders.length === 0) {\n return;\n }\n\n // Clear each sender connection.\n each(senders, connection => {\n // Skip connections which have already been cleared.\n if (!connection.signal) {\n return;\n }\n\n // Lookup the sender for the connection.\n let sender = connection.signal.sender;\n\n // Clear the connection.\n connection.signal = null;\n\n // Cleanup the array of receivers, which is now known to exist.\n scheduleCleanup(receiversForSender.get(sender)!);\n });\n\n // Schedule a cleanup of the list of senders.\n scheduleCleanup(senders);\n }\n\n /**\n * Remove all connections where an object is the sender or receiver.\n *\n * @param object - The object of interest.\n */\n export function disconnectAll(object: any): void {\n // Remove all connections where the given object is the sender.\n disconnectSender(object);\n // Remove all connections where the given object is the receiver.\n disconnectReceiver(object);\n }\n\n /**\n * Emit a signal and invoke its connected slots.\n *\n * @param signal - The signal of interest.\n *\n * @param args - The args to pass to the connected slots.\n *\n * #### Notes\n * Slots are invoked synchronously in connection order.\n *\n * Exceptions thrown by connected slots will be caught and logged.\n */\n export function emit<T, U>(signal: Signal<T, U>, args: U): void {\n // If there are no receivers, there is nothing to do.\n let receivers = receiversForSender.get(signal.sender);\n if (!receivers || receivers.length === 0) {\n return;\n }\n\n // Invoke the slots for connections with a matching signal.\n // Any connections added during emission are not invoked.\n for (let i = 0, n = receivers.length; i < n; ++i) {\n let connection = receivers[i];\n if (connection.signal === signal) {\n invokeSlot(connection, args);\n }\n }\n }\n\n /**\n * An object which holds connection data.\n */\n interface IConnection {\n /**\n * The signal for the connection.\n *\n * A `null` signal indicates a cleared connection.\n */\n signal: Signal<any, any> | null;\n\n /**\n * The slot connected to the signal.\n */\n readonly slot: Slot<any, any>;\n\n /**\n * The `this` context for the slot.\n */\n readonly thisArg: any;\n }\n\n /**\n * A weak mapping of sender to array of receiver connections.\n */\n const receiversForSender = new WeakMap<any, IConnection[]>();\n\n /**\n * A weak mapping of receiver to array of sender connections.\n */\n const sendersForReceiver = new WeakMap<any, IConnection[]>();\n\n /**\n * A set of connection arrays which are pending cleanup.\n */\n const dirtySet = new Set<IConnection[]>();\n\n /**\n * A function to schedule an event loop callback.\n */\n const schedule = (() => {\n let ok = typeof requestAnimationFrame === 'function';\n // @ts-ignore\n return ok ? requestAnimationFrame : setImmediate;\n })();\n\n /**\n * Find a connection which matches the given parameters.\n */\n function findConnection(\n connections: IConnection[],\n signal: Signal<any, any>,\n slot: Slot<any, any>,\n thisArg: any\n ): IConnection | undefined {\n return find(\n connections,\n connection =>\n connection.signal === signal &&\n connection.slot === slot &&\n connection.thisArg === thisArg\n );\n }\n\n /**\n * Invoke a slot with the given parameters.\n *\n * The connection is assumed to be valid.\n *\n * Exceptions in the slot will be caught and logged.\n */\n function invokeSlot(connection: IConnection, args: any): void {\n let { signal, slot, thisArg } = connection;\n try {\n slot.call(thisArg, signal!.sender, args);\n } catch (err) {\n exceptionHandler(err);\n }\n }\n\n /**\n * Schedule a cleanup of a connection array.\n *\n * This will add the array to the dirty set and schedule a deferred\n * cleanup of the array contents. On cleanup, any connection with a\n * `null` signal will be removed from the array.\n */\n function scheduleCleanup(array: IConnection[]): void {\n if (dirtySet.size === 0) {\n schedule(cleanupDirtySet);\n }\n dirtySet.add(array);\n }\n\n /**\n * Cleanup the connection lists in the dirty set.\n *\n * This function should only be invoked asynchronously, when the\n * stack frame is guaranteed to not be on the path of user code.\n */\n function cleanupDirtySet(): void {\n dirtySet.forEach(cleanupConnections);\n dirtySet.clear();\n }\n\n /**\n * Cleanup the dirty connections in a connections array.\n *\n * This will remove any connection with a `null` signal.\n *\n * This function should only be invoked asynchronously, when the\n * stack frame is guaranteed to not be on the path of user code.\n */\n function cleanupConnections(connections: IConnection[]): void {\n ArrayExt.removeAllWhere(connections, isDeadConnection);\n }\n\n /**\n * Test whether a connection is dead.\n *\n * A dead connection has a `null` signal.\n */\n function isDeadConnection(connection: IConnection): boolean {\n return connection.signal === null;\n }\n}\n"]}
\No newline at end of file