import { getHandlers } from "./event.js" let operationGroup = null export function pushOperation(op) { if (operationGroup) { operationGroup.ops.push(op) } else { op.ownsGroup = operationGroup = { ops: [op], delayedCallbacks: [] } } } function fireCallbacksForOps(group) { // Calls delayed callbacks and cursorActivity handlers until no // new ones appear let callbacks = group.delayedCallbacks, i = 0 do { for (; i < callbacks.length; i++) callbacks[i].call(null) for (let j = 0; j < group.ops.length; j++) { let op = group.ops[j] if (op.cursorActivityHandlers) while (op.cursorActivityCalled < op.cursorActivityHandlers.length) op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } } while (i < callbacks.length) } export function finishOperation(op, endCb) { let group = op.ownsGroup if (!group) return try { fireCallbacksForOps(group) } finally { operationGroup = null endCb(group) } } let orphanDelayedCallbacks = null // Often, we want to signal events at a point where we are in the // middle of some work, but don't want the handler to start calling // other methods on the editor, which might be in an inconsistent // state or simply not expect any other events to happen. // signalLater looks whether there are any handlers, and schedules // them to be executed when the last operation ends, or, if no // operation is active, when a timeout fires. export function signalLater(emitter, type /*, values...*/) { let arr = getHandlers(emitter, type) if (!arr.length) return let args = Array.prototype.slice.call(arguments, 2), list if (operationGroup) { list = operationGroup.delayedCallbacks } else if (orphanDelayedCallbacks) { list = orphanDelayedCallbacks } else { list = orphanDelayedCallbacks = [] setTimeout(fireOrphanDelayed, 0) } for (let i = 0; i < arr.length; ++i) list.push(() => arr[i].apply(null, args)) } function fireOrphanDelayed() { let delayed = orphanDelayedCallbacks orphanDelayedCallbacks = null for (let i = 0; i < delayed.length; ++i) delayed[i]() }