diff --git a/src/blockdom/events.ts b/src/blockdom/events.ts index 47d31745..4f663bcb 100644 --- a/src/blockdom/events.ts +++ b/src/blockdom/events.ts @@ -47,14 +47,18 @@ function createElementHandler(evName: string, capture: boolean = false): EventHa // Synthetic handler: a form of event delegation that allows placing only one // listener per event type. +let nextSyntheticEventId = 1; function createSyntheticHandler(evName: string, capture: boolean = false): EventHandlerCreator { let eventKey = `__event__synthetic_${evName}`; if (capture) { eventKey = `${eventKey}_capture`; } setupSyntheticEvent(evName, eventKey, capture); + const currentId = nextSyntheticEventId++; function setup(this: HTMLElement, data: any) { - (this as any)[eventKey] = data; + const _data = (this as any)[eventKey] || {}; + _data[currentId] = data; + (this as any)[eventKey] = _data; } return { setup, update: setup }; } @@ -62,10 +66,12 @@ function createSyntheticHandler(evName: string, capture: boolean = false): Event function nativeToSyntheticEvent(eventKey: string, event: Event) { let dom = event.target; while (dom !== null) { - const data = (dom as any)[eventKey]; - if (data) { - const stopped = config.mainEventHandler(data, event, dom); - if (stopped) return; + const _data = (dom as any)[eventKey]; + if (_data) { + for (const data of Object.values(_data)) { + const stopped = config.mainEventHandler(data, event, dom); + if (stopped) return; + } } dom = (dom as any).parentNode; } diff --git a/tests/blockdom/block_event_handling.test.ts b/tests/blockdom/block_event_handling.test.ts index a791c7a8..781356e0 100644 --- a/tests/blockdom/block_event_handling.test.ts +++ b/tests/blockdom/block_event_handling.test.ts @@ -123,6 +123,40 @@ test("two same block nodes with different handlers (synthetic)", async () => { expect(steps).toEqual(["1", "2"]); }); +test("two event handlers on same event", async () => { + const block = createBlock('
'); + let n = 0; + let m = 0; + const tree = block([() => m++, () => n++]); + + mount(tree, fixture); + expect(fixture.innerHTML).toBe("
"); + + expect(m).toBe(0); + expect(n).toBe(0); + (fixture.firstChild as HTMLDivElement).click(); + expect(m).toBe(1); + expect(n).toBe(1); +}); + +test("two synthetic event handlers on same event", async () => { + const block = createBlock( + '
' + ); + let n = 0; + let m = 0; + const tree = block([() => m++, () => n++]); + + mount(tree, fixture); + expect(fixture.innerHTML).toBe("
"); + + expect(m).toBe(0); + expect(n).toBe(0); + (fixture.firstChild as HTMLDivElement).click(); + expect(m).toBe(1); + expect(n).toBe(1); +}); + test("synthetic and native handlers can cohabitate", async () => { const block = createBlock( '
' @@ -180,7 +214,7 @@ test("synthetic and native handlers can cohabitate (3)", async () => { expect(steps).toEqual(["1", "0", "0", "2"]); }); -test("synthetic and native handlers can cohabitate (5)", async () => { +test("synthetic and native handlers can cohabitate (4)", async () => { const parent = createBlock(`
`); const block = createBlock('
'); const blockSynth = createBlock('
'); @@ -203,3 +237,37 @@ test("synthetic and native handlers can cohabitate (5)", async () => { (children[1] as HTMLElement).click(); expect(steps).toEqual(["1", "0", "0"]); }); + +test("synthetic and native handlers can cohabitate (5)", async () => { + const block = createBlock('
'); + let steps: string[] = []; + let handler1 = () => steps.push("1"); + let handler2 = () => steps.push("2"); + const tree = block([handler1, handler2]); + + mount(tree, fixture); + expect(fixture.innerHTML).toBe("
"); + + (fixture.firstChild as HTMLDivElement).click(); + expect(steps).toEqual(["2", "1"]); +}); + +test("synthetic and native handlers can cohabitate (6)", async () => { + const block = createBlock(`
`); + let steps: string[] = []; + const handler1 = () => steps.push("1"); + const handler2 = () => steps.push("2"); + const handler3 = () => steps.push("3"); + const handler4 = () => steps.push("4"); + const tree = block([handler1, handler2, handler3, handler4]); + mount(tree, fixture); + expect(fixture.innerHTML).toBe("
"); + + (fixture.firstChild as HTMLDivElement).click(); + expect(steps).toEqual(["2", "4", "1", "3"]); +});