UNPKG

lisn.js

Version:

Simply handle user gestures and actions. Includes widgets.

1 lines 15.3 kB
{"version":3,"file":"callback.cjs","names":["MC","_interopRequireWildcard","require","MH","_tasks","_debug","_interopRequireDefault","_Callback","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","_defineProperty","_toPropertyKey","value","enumerable","configurable","writable","_toPrimitive","Symbol","toPrimitive","TypeError","String","Number","wrapCallback","handlerOrCallback","debounceWindow","isFunction","isRemoved","callback","callablesMap","handler","args","invoke","wrapper","Callback","getDebouncedHandler","onRemove","remove","exports","constructor","logger","debug","Logger","name","logAtCreation","id","SYMBOL","newSet","debug8","rmFn","CallbackScheduler","_clear","fn","add","newPromise","resolve","reject","usageError","_push","result","err","REMOVE","newWeakMap","queues","newMap","flush","queue","lengthOf","_running","_task","shift","item","_onRemove","deleteKey","task","push"],"sources":["../../../src/ts/modules/callback.ts"],"sourcesContent":["/**\n * @module Modules/Callback\n */\n\nimport * as MC from \"@lisn/globals/minification-constants\";\nimport * as MH from \"@lisn/globals/minification-helpers\";\n\nimport { getDebouncedHandler } from \"@lisn/utils/tasks\";\n\nimport debug from \"@lisn/debug/debug\";\n\n/**\n * @typeParam Args See {@link Callback}\n */\nexport type CallbackHandler<Args extends unknown[] = []> = (\n ...args: Args\n) => CallbackReturnType | Promise<CallbackReturnType>;\n\nexport type CallbackReturnType =\n | typeof Callback.KEEP\n | typeof Callback.REMOVE\n | void;\n\n/**\n * For minification optimization. Exposed through Callback.wrap.\n *\n * @ignore\n * @internal\n */\nexport const wrapCallback = <Args extends unknown[] = []>(\n handlerOrCallback: CallbackHandler<Args> | Callback<Args>,\n debounceWindow = 0,\n): Callback<Args> => {\n const isFunction = MH.isFunction(handlerOrCallback);\n let isRemoved = () => false;\n\n if (isFunction) {\n // check if it's an invoke method\n const callback = callablesMap.get(handlerOrCallback);\n if (callback) {\n return wrapCallback(callback);\n }\n } else {\n isRemoved = handlerOrCallback.isRemoved;\n }\n\n const handler: CallbackHandler<Args> = isFunction\n ? handlerOrCallback\n : (...args: Args) => handlerOrCallback.invoke(...args);\n\n const wrapper = new Callback<Args>(\n getDebouncedHandler(debounceWindow, (...args: Args) => {\n if (!isRemoved()) {\n return handler(...args);\n }\n }),\n );\n\n if (!isFunction) {\n handlerOrCallback.onRemove(wrapper.remove);\n }\n\n return wrapper;\n};\n\n/**\n * {@link Callback} wraps user-supplied callbacks. Supports\n * - removing a callback either when calling {@link remove} or if the user\n * handler returns {@link Callback.REMOVE}\n * - calling custom {@link onRemove} hooks\n * - debouncing (via {@link wrap})\n * - awaiting on an asynchronous handler and ensuring that the handler does not\n * run concurrently to itself, i.e. subsequent {@link invoke}s will be queued\n *\n * @typeParam Args The type of arguments that the callback expects.\n */\nexport class Callback<Args extends unknown[] = []> {\n /**\n * Possible return value for the handler.\n *\n * Do not do anything. Same as not retuning anything from the function.\n */\n static readonly KEEP: unique symbol = MC.SYMBOL(\n \"KEEP\",\n ) as typeof Callback.KEEP;\n\n /**\n * Possible return value for the handler.\n *\n * Will remove this callback.\n */\n static readonly REMOVE: unique symbol = MC.SYMBOL(\n \"REMOVE\",\n ) as typeof Callback.REMOVE;\n\n /**\n * Call the handler with the given arguments.\n *\n * If the handler is asynchronous, it awaits on it. Furthermore, calls will\n * always wait for previous calls to this handler to complete first, i.e. it\n * never runs concurrently to itself. If you need multiple calls to the async\n * handler to run concurrently, then wrap it in a non-async function that\n * does not await it.\n *\n * The returned promise is rejected in two cases:\n * - If the callback throws an error or returns a rejected Promise.\n * - If the callback is removed _after_ you call {@link invoke} but before the\n * handler is actually called (while it's waiting in the queue to be called)\n * In this case, the rejection reason is {@link Callback.REMOVE}.\n *\n * @throws {@link Errors.LisnUsageError | LisnUsageError}\n * If the callback is already removed.\n */\n readonly invoke: (...args: Args) => Promise<void>;\n\n /**\n * Mark the callback as removed and call the registered {@link onRemove} hooks.\n *\n * Future attempts to call it will result in\n * {@link Errors.LisnUsageError | LisnUsageError}.\n */\n readonly remove: () => void;\n\n /**\n * Returns true if the callback has been removed and cannot be called again.\n */\n readonly isRemoved: () => boolean;\n\n /**\n * Registers the given function to be called when the callback is removed.\n *\n * You can call {@link onRemove} multiple times to register multiple hooks.\n */\n readonly onRemove: (fn: () => void) => void;\n\n /**\n * Wraps the given handler or callback as a callback, optionally debounced by\n * the given debounce window.\n *\n * If the argument is already a callback _or an invoke method of a callback_,\n * then the wrapper will call that callback and return the same value as it.\n * It will also set up the returned wrapper callback so that it is removed\n * when the original (given) callback is removed. However, removing the\n * returned wrapper callback will _not_ cause the original callback (being\n * wrapped) to be removed. If you want to do this, then do\n * `wrapper.onRemove(wrapped.remove)`.\n *\n * Note that if the argument is a callback that's already debounced by a\n * _larger_ window, then `debounceWindow` will have no effect.\n *\n * @param debounceWindow If non-0, the callback will be called at most\n * every `debounceWindow` ms. The arguments it will\n * be called with will be the last arguments the\n * wrapper was called with.\n */\n static readonly wrap = wrapCallback;\n\n /**\n * @param handler The actual function to call. This should return one of\n * the known {@link CallbackReturnType} values.\n */\n constructor(handler: CallbackHandler<Args>) {\n const logger = debug\n ? new debug.Logger({ name: \"Callback\", logAtCreation: handler })\n : null;\n\n let isRemoved = false;\n const id = MC.SYMBOL();\n\n const onRemove = MH.newSet<() => void>();\n\n this.isRemoved = () => isRemoved;\n\n this.remove = () => {\n if (!isRemoved) {\n debug: logger?.debug8(\"Removing\");\n isRemoved = true;\n\n for (const rmFn of onRemove) {\n rmFn();\n }\n\n CallbackScheduler._clear(id);\n }\n };\n\n this.onRemove = (fn) => onRemove.add(fn);\n\n this.invoke = (...args) =>\n MH.newPromise((resolve, reject) => {\n debug: logger?.debug8(\"Calling with\", args);\n if (isRemoved) {\n reject(MH.usageError(\"Callback has been removed\"));\n return;\n }\n\n CallbackScheduler._push(\n id,\n async () => {\n let result;\n try {\n result = await handler(...args);\n } catch (err) {\n reject(err);\n }\n\n if (result === Callback.REMOVE) {\n this.remove();\n }\n\n resolve();\n },\n reject,\n );\n });\n\n callablesMap.set(this.invoke, this);\n }\n}\n\n// ----------------------------------------\n\ntype CallbackSchedulerTask = () => Promise<void>;\ntype CallbackSchedulerQueueItem = {\n _task: CallbackSchedulerTask;\n _running: boolean;\n _onRemove: (reason: typeof Callback.REMOVE) => void;\n};\n\ntype CallableCallback<Args extends unknown[] = []> = (...args: Args) => void;\n\nconst callablesMap = MH.newWeakMap<CallableCallback, Callback>();\n\nconst CallbackScheduler = (() => {\n const queues = MH.newMap<symbol, CallbackSchedulerQueueItem[]>();\n\n const flush = async (queue: CallbackSchedulerQueueItem[]) => {\n // So that callbacks are always called asynchronously for consistency,\n // await here before calling 1st\n await null;\n while (MH.lengthOf(queue)) {\n // shouldn't throw anything as Callback must catch errors\n queue[0]._running = true;\n await queue[0]._task();\n\n // only remove when done\n queue.shift();\n }\n };\n\n return {\n _clear: (id: symbol) => {\n const queue = queues.get(id);\n if (queue) {\n let item: CallbackSchedulerQueueItem | undefined;\n while ((item = queue.shift())) {\n if (!item._running) {\n item._onRemove(Callback.REMOVE);\n }\n }\n\n MH.deleteKey(queues, id);\n }\n },\n\n _push: (id: symbol, task: CallbackSchedulerTask, onRemove: () => void) => {\n let queue = queues.get(id);\n if (!queue) {\n queue = [];\n queues.set(id, queue);\n }\n\n queue.push({ _task: task, _onRemove: onRemove, _running: false });\n if (MH.lengthOf(queue) === 1) {\n flush(queue);\n }\n },\n };\n})();\n"],"mappings":"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","ignoreList":[]}