diff --git a/packages/core/primitives/event-dispatch/src/dispatcher.ts b/packages/core/primitives/event-dispatch/src/dispatcher.ts
index d15efccc3e764..a08d655d97485 100644
--- a/packages/core/primitives/event-dispatch/src/dispatcher.ts
+++ b/packages/core/primitives/event-dispatch/src/dispatcher.ts
@@ -78,6 +78,10 @@ export class Dispatcher {
*/
dispatch(eventInfo: EventInfo): void {
const eventInfoWrapper = new EventInfoWrapper(eventInfo);
+ const action = eventInfoWrapper.getAction();
+ if (action && shouldPreventDefaultBeforeDispatching(action.element, eventInfoWrapper)) {
+ eventLib.preventDefault(eventInfoWrapper.getEvent());
+ }
if (eventInfoWrapper.getIsReplay()) {
if (!this.eventReplayer) {
return;
@@ -131,6 +135,24 @@ export function stopPropagation(eventInfoWrapper: EventInfoWrapper) {
event.stopPropagation();
}
+/**
+ * Returns true if the default action of this event should be prevented before
+ * this event is dispatched.
+ */
+function shouldPreventDefaultBeforeDispatching(
+ actionElement: Element,
+ eventInfoWrapper: EventInfoWrapper,
+): boolean {
+ // Prevent browser from following node links if a jsaction is present
+ // and we are dispatching the action now. Note that the targetElement may be
+ // a child of an anchor that has a jsaction attached. For that reason, we
+ // need to check the actionElement rather than the targetElement.
+ return (
+ (actionElement.tagName === 'A' && eventInfoWrapper.getEventType() === EventType.CLICK) ||
+ eventInfoWrapper.getEventType() === EventType.CLICKMOD
+ );
+}
+
/**
* Registers deferred functionality for an EventContract and a Jsaction
* Dispatcher.
diff --git a/packages/core/primitives/event-dispatch/src/eventcontract.ts b/packages/core/primitives/event-dispatch/src/eventcontract.ts
index eb6316f1b2f75..e4a95e1e79af2 100644
--- a/packages/core/primitives/event-dispatch/src/eventcontract.ts
+++ b/packages/core/primitives/event-dispatch/src/eventcontract.ts
@@ -157,13 +157,6 @@ export class EventContract implements UnrenamedEventContract {
return;
}
this.actionResolver.resolve(eventInfo);
- const action = eventInfoLib.getAction(eventInfo);
- if (action) {
- if (shouldPreventDefaultBeforeDispatching(eventInfoLib.getActionElement(action), eventInfo)) {
- eventLib.preventDefault(eventInfoLib.getEvent(eventInfo));
- }
- }
-
this.dispatcher(eventInfo);
}
@@ -386,22 +379,3 @@ export function addDeferredA11yClickSupport(eventContract: EventContract) {
a11yClickLib.populateClickOnlyAction,
);
}
-
-/**
- * Returns true if the default action of this event should be prevented before
- * this event is dispatched.
- */
-function shouldPreventDefaultBeforeDispatching(
- actionElement: Element,
- eventInfo: eventInfoLib.EventInfo,
-): boolean {
- // Prevent browser from following node links if a jsaction is present
- // and we are dispatching the action now. Note that the targetElement may be
- // a child of an anchor that has a jsaction attached. For that reason, we
- // need to check the actionElement rather than the targetElement.
- return (
- actionElement.tagName === 'A' &&
- (eventInfoLib.getEventType(eventInfo) === EventType.CLICK ||
- eventInfoLib.getEventType(eventInfo) === EventType.CLICKMOD)
- );
-}
diff --git a/packages/core/primitives/event-dispatch/test/eventcontract_test.ts b/packages/core/primitives/event-dispatch/test/eventcontract_test.ts
index 1569bc1c3a5bb..98d3f6c5ef103 100644
--- a/packages/core/primitives/event-dispatch/test/eventcontract_test.ts
+++ b/packages/core/primitives/event-dispatch/test/eventcontract_test.ts
@@ -25,6 +25,10 @@ import {OWNER} from '../src/property';
import {Restriction} from '../src/restriction';
import {safeElement, testonlyHtml} from './html';
+import {
+ Dispatcher as LateDispatcher,
+ registerDispatcher as registerLateDispatcher,
+} from '../src/dispatcher';
declare global {
interface Window extends EarlyJsactionDataContainer {}
@@ -849,17 +853,18 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('anchor-click-action-element');
const targetElement = getRequiredElementById('anchor-click-target-element');
- const dispatcher = jasmine.createSpy('dispatcher');
- createEventContract({
+ const eventContract = createEventContract({
eventContractContainerManager: new EventContractContainer(container),
eventTypes: ['click'],
- dispatcher,
});
+ const dispatch = jasmine.createSpy<(eventInfoWrapper: EventInfoWrapper) => void>('dispatch');
+ const dispatcher = new LateDispatcher(dispatch);
+ registerLateDispatcher(eventContract, dispatcher);
const clickEvent = dispatchMouseEvent(targetElement);
- expect(dispatcher).toHaveBeenCalledTimes(1);
- const eventInfoWrapper = getLastDispatchedEventInfoWrapper(dispatcher);
+ expect(dispatch).toHaveBeenCalledTimes(1);
+ const eventInfoWrapper = dispatch.calls.mostRecent().args[0];
expect(eventInfoWrapper.getEventType()).toBe('click');
expect(eventInfoWrapper.getEvent()).toBe(clickEvent);
expect(eventInfoWrapper.getTargetElement()).toBe(targetElement);
@@ -874,17 +879,18 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('anchor-clickmod-action-element');
const targetElement = getRequiredElementById('anchor-clickmod-target-element');
- const dispatcher = jasmine.createSpy('dispatcher');
- createEventContract({
+ const eventContract = createEventContract({
eventContractContainerManager: new EventContractContainer(container),
eventTypes: ['click'],
- dispatcher,
});
+ const dispatch = jasmine.createSpy<(eventInfoWrapper: EventInfoWrapper) => void>('dispatch');
+ const dispatcher = new LateDispatcher(dispatch);
+ registerLateDispatcher(eventContract, dispatcher);
const clickEvent = dispatchMouseEvent(targetElement, {shiftKey: true});
- expect(dispatcher).toHaveBeenCalledTimes(1);
- const eventInfoWrapper = getLastDispatchedEventInfoWrapper(dispatcher);
+ expect(dispatch).toHaveBeenCalledTimes(1);
+ const eventInfoWrapper = dispatch.calls.mostRecent().args[0];
expect(eventInfoWrapper.getEventType()).toBe('clickmod');
expect(eventInfoWrapper.getEvent()).toBe(clickEvent);
expect(eventInfoWrapper.getTargetElement()).toBe(targetElement);
@@ -966,17 +972,18 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('a11y-anchor-click-action-element');
const targetElement = getRequiredElementById('a11y-anchor-click-target-element');
- const dispatcher = jasmine.createSpy('dispatcher');
- createEventContract({
+ const eventContract = createEventContract({
eventContractContainerManager: new EventContractContainer(container),
eventTypes: ['click'],
- dispatcher,
});
+ const dispatch = jasmine.createSpy<(eventInfoWrapper: EventInfoWrapper) => void>('dispatch');
+ const dispatcher = new LateDispatcher(dispatch);
+ registerLateDispatcher(eventContract, dispatcher);
const keydownEvent = dispatchKeyboardEvent(targetElement, {key: 'Enter'});
- expect(dispatcher).toHaveBeenCalledTimes(1);
- const eventInfoWrapper = getLastDispatchedEventInfoWrapper(dispatcher);
+ expect(dispatch).toHaveBeenCalledTimes(1);
+ const eventInfoWrapper = dispatch.calls.mostRecent().args[0];
expect(eventInfoWrapper.getEventType()).toBe('click');
expect(eventInfoWrapper.getEvent()).toBe(keydownEvent);
expect(eventInfoWrapper.getTargetElement()).toBe(targetElement);
@@ -1095,19 +1102,20 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('a11y-anchor-click-action-element');
const targetElement = getRequiredElementById('a11y-anchor-click-target-element');
- const dispatcher = jasmine.createSpy('dispatcher');
const eventContract = createEventContract({
eventContractContainerManager: new EventContractContainer(container),
exportAddA11yClickSupport: true,
eventTypes: ['click'],
- dispatcher,
});
addDeferredA11yClickSupport(eventContract);
+ const dispatch = jasmine.createSpy<(eventInfoWrapper: EventInfoWrapper) => void>('dispatch');
+ const dispatcher = new LateDispatcher(dispatch);
+ registerLateDispatcher(eventContract, dispatcher);
const keydownEvent = dispatchKeyboardEvent(targetElement, {key: 'Enter'});
- expect(dispatcher).toHaveBeenCalledTimes(1);
- const eventInfoWrapper = getLastDispatchedEventInfoWrapper(dispatcher);
+ expect(dispatch).toHaveBeenCalledTimes(1);
+ const eventInfoWrapper = dispatch.calls.mostRecent().args[0];
expect(eventInfoWrapper.getEventType()).toBe('click');
expect(eventInfoWrapper.getEvent()).toBe(keydownEvent);
expect(eventInfoWrapper.getTargetElement()).toBe(targetElement);