better code: event api to preventDefault and return value at the same time

Massimo Melina committed Aug 26, 2024 at 11:45 UTC 6d53ea837006300941c303e5b9ee5390f8bfbbd1
3 files changed +18 -10
src/cross.ts
-1
@@ -403,7 +403,6 @@ export function pathEncode(s: string) {
403 }
404 //unused function pathDecode(s: string) { return decodeURI(s).replace(/%23/g, '#') }
405
406 -
406 // run at a specific point in time, also solving the limit of setTimeout, which doesn't work with +32bit delays
407 export function runAt(ts: number, cb: Callback) {
408 let cancel = false
src/events.ts
+17 -8
@@ -6,7 +6,7 @@ const LISTENERS_SUFFIX = '\0listeners'
6
7 export class BetterEventEmitter {
8 protected listeners = new Map<string, Listeners>()
9 - stop = Symbol()
9 + preventDefault = Symbol()
10 on(event: string | string[], listener: Listener, { warnAfter=10 }={}) {
11 if (typeof event === 'string')
12 event = [event]
@@ -51,19 +51,28 @@ export class BetterEventEmitter {
51 let cbs = this.listeners.get(event)
52 if (!cbs?.size) return
53 const ret: any[] = []
54 + let prevented = false
55 + const extra = {
56 + preventDefault() { prevented = true }
57 + }
58 for (const cb of cbs) {
55 - const res = cb(...args)
56 - if (res !== undefined)
59 + const res = cb(...args, extra)
60 + if (res === this.preventDefault)
61 + extra.preventDefault()
62 + else if (res !== undefined)
63 ret.push(res)
64 }
65 return Object.assign(ret, {
60 - isDefaultPrevented: () => ret.some(r => r === this.stop),
66 + isDefaultPrevented: () => prevented,
67 })
68 }
63 - emitAsync(event: string, ...args: any[]) {
64 - const ret = Promise.all(this.emit(event, ...args) || [])
65 - return Object.assign(ret, {
66 - isDefaultPrevented: async () => (await ret).some((r: any) => r === this.stop)
69 + async emitAsync(event: string, ...args: any[]) {
70 + const syncRet = this.emit(event, ...args)
71 + if (!syncRet) return
72 + const asyncRet = await Promise.all(syncRet)
73 + return Object.assign(asyncRet, {
74 + isDefaultPrevented: () => syncRet.isDefaultPrevented()
75 + || asyncRet.some((r: any) => r === this.preventDefault)
76 })
77 }
78 }
src/misc.ts
+1 -1
@@ -145,7 +145,7 @@ export async function deleteNode(ctx: Koa.Context, node: VfsNode, uri: string) {
145 if (statusCodeForMissingPerm(node, 'can_delete', ctx))
146 return ctx.status
147 try {
148 - if (await events.emitAsync('deleting', { node, ctx }).isDefaultPrevented())
148 + if ((await events.emitAsync('deleting', { node, ctx }))?.isDefaultPrevented())
149 return null // stop
150 ctx.logExtra(null, { target: decodeURI(uri) })
151 await rm(source, { recursive: true })