Skip to content

Commit

Permalink
refactor(core): Move preventDefault to Dispatcher
Browse files Browse the repository at this point in the history
This is a simple move.
  • Loading branch information
tbondwilkinson committed May 11, 2024
1 parent a6f024f commit d98963f
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 45 deletions.
22 changes: 22 additions & 0 deletions packages/core/primitives/event-dispatch/src/dispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 <a> 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.
Expand Down
26 changes: 0 additions & 26 deletions packages/core/primitives/event-dispatch/src/eventcontract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,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);
}

Expand Down Expand Up @@ -395,22 +388,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 <a> 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)
);
}
46 changes: 27 additions & 19 deletions packages/core/primitives/event-dispatch/test/eventcontract_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {Property} 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 {}
Expand Down Expand Up @@ -953,17 +957,18 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('anchor-click-action-element');
const targetElement = getRequiredElementById('anchor-click-target-element');

const dispatcher = jasmine.createSpy<Dispatcher>('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);
Expand All @@ -978,17 +983,18 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('anchor-clickmod-action-element');
const targetElement = getRequiredElementById('anchor-clickmod-target-element');

const dispatcher = jasmine.createSpy<Dispatcher>('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);
Expand Down Expand Up @@ -1070,17 +1076,18 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('a11y-anchor-click-action-element');
const targetElement = getRequiredElementById('a11y-anchor-click-target-element');

const dispatcher = jasmine.createSpy<Dispatcher>('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);
Expand Down Expand Up @@ -1199,19 +1206,20 @@ describe('EventContract', () => {
const actionElement = getRequiredElementById('a11y-anchor-click-action-element');
const targetElement = getRequiredElementById('a11y-anchor-click-target-element');

const dispatcher = jasmine.createSpy<Dispatcher>('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);
Expand Down

0 comments on commit d98963f

Please sign in to comment.