From 78859b167ec5fd5c5d21e2d63b6585e8786ec07b Mon Sep 17 00:00:00 2001 From: David Arenas Date: Thu, 11 Apr 2024 21:31:53 +0200 Subject: [PATCH] Interactivity API: Allow multiple event handlers for the same type with `data-wp-on`. (#60661) * Allow multiple event handlers for the same type * Add simple test Co-authored-by: DAreRodz Co-authored-by: felixarntz Co-authored-by: luisherranz --- .../directive-on/render.php | 20 +++++++++++++++ .../interactive-blocks/directive-on/view.js | 12 +++++++++ packages/interactivity/src/directives.js | 15 ++++++++--- .../specs/interactivity/directive-on.spec.ts | 25 +++++++++++++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php index edb081922fc0e4..eb2de94ab58eea 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on/render.php @@ -51,4 +51,24 @@ data-wp-on--click="actions.clickHandler" >Click me! +
+

false

+

0

+

true

+ +
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js index 69378b53e14c0a..8b0bcc0e115eca 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-on/view.js @@ -26,5 +26,17 @@ const { state } = store( 'directive-on', { const context = getContext(); context.customEvents += 1; }, + setClicked: () => { + const context = getContext(); + context.clicked = true; + }, + countClick: () => { + const context = getContext(); + context.clickCount += 1; + }, + toggle: () => { + const context = getContext(); + context.isOpen = ! context.isOpen; + }, }, } ); diff --git a/packages/interactivity/src/directives.js b/packages/interactivity/src/directives.js index b19067bdc1ad9a..c20ea3aec722d3 100644 --- a/packages/interactivity/src/directives.js +++ b/packages/interactivity/src/directives.js @@ -270,13 +270,22 @@ export default () => { // data-wp-on--[event] directive( 'on', ( { directives: { on }, element, evaluate } ) => { + const events = new Map(); on.filter( ( { suffix } ) => suffix !== 'default' ).forEach( ( entry ) => { - element.props[ `on${ entry.suffix }` ] = ( event ) => { - evaluate( entry, event ); - }; + const event = entry.suffix.split( '--' )[ 0 ]; + if ( ! events.has( event ) ) events.set( event, new Set() ); + events.get( event ).add( entry ); } ); + + events.forEach( ( entries, eventType ) => { + element.props[ `on${ eventType }` ] = ( event ) => { + entries.forEach( ( entry ) => { + evaluate( entry, event ); + } ); + }; + } ); } ); // data-wp-on-window--[event] diff --git a/test/e2e/specs/interactivity/directive-on.spec.ts b/test/e2e/specs/interactivity/directive-on.spec.ts index 03dfe64462c567..886f74335e7aee 100644 --- a/test/e2e/specs/interactivity/directive-on.spec.ts +++ b/test/e2e/specs/interactivity/directive-on.spec.ts @@ -51,4 +51,29 @@ test.describe( 'data-wp-on', () => { .click( { clickCount: 3, delay: 100 } ); await expect( counter ).toHaveText( '3' ); } ); + + test( 'should work with multiple event handlers on the same event type', async ( { + page, + } ) => { + const button = page.getByTestId( 'multiple handlers button' ); + const isOpen = page.getByTestId( 'multiple handlers isOpen' ); + const clicked = page.getByTestId( 'multiple handlers clicked' ); + const clickCount = page.getByTestId( 'multiple handlers clickCount' ); + + await expect( clicked ).toHaveText( 'false' ); + await expect( clickCount ).toHaveText( '0' ); + await expect( isOpen ).toHaveText( 'true' ); + + await button.click(); + + await expect( clicked ).toHaveText( 'true' ); + await expect( clickCount ).toHaveText( '1' ); + await expect( isOpen ).toHaveText( 'false' ); + + await button.click(); + + await expect( clicked ).toHaveText( 'true' ); + await expect( clickCount ).toHaveText( '2' ); + await expect( isOpen ).toHaveText( 'true' ); + } ); } );