Skip to content

Commit

Permalink
feat: add client message to notify host of click events
Browse files Browse the repository at this point in the history
COMUI-201
  • Loading branch information
thomas-c-dillon committed Nov 23, 2022
1 parent 5a835fd commit 4a7768f
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 17 deletions.
2 changes: 1 addition & 1 deletion packages/iframe-coordinator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"lint.format": "prettier --check **/*.ts **/*.tsx",
"lint": "tslint --project tsconfig.json && npm run lint.format",
"start": "webpack --watch",
"start-client-example": "cd ./client-app-example && npm start",
"start-client-example": "cd ../../apps/ifc-example-client && npm start",
"test": "karma start --single-run",
"test.watch": "karma start",
"test.watch.chrome": "karma start --browsers=Chrome"
Expand Down
30 changes: 15 additions & 15 deletions packages/iframe-coordinator/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export interface ClientConfigOptions {
*/
export class Client {
private _isStarted: boolean;
private _isInterceptingLinksStarted: boolean;
private _clientWindow: Window;
private _environmentData: EnvData;
private _envDataEmitter: InternalEventEmitter<EnvData>;
Expand All @@ -67,6 +66,7 @@ export class Client {
private _publishExposedEmitter: EventEmitter<Publication>;
private _registeredKeys: KeyData[];
private _assignedRoute: string | null;
private _shouldInterceptLinks: boolean;

/**
* Creates a new client.
Expand Down Expand Up @@ -187,6 +187,14 @@ export class Client {
};

private _onWindowClick = (event: MouseEvent) => {
this._sendToHost({ msgType: 'clickFired', msg: {} });

if (this._shouldInterceptLinks) {
this._interceptLink(event);
}
};

private _interceptLink = (event: MouseEvent) => {
const target = event.target as HTMLElement;
if (target.tagName.toLowerCase() === 'a' && event.button === 0) {
event.preventDefault();
Expand Down Expand Up @@ -355,34 +363,25 @@ bad input into one of the iframe-coordinator client methods.

this._clientWindow.addEventListener('message', this._onWindowMessage);
this._clientWindow.addEventListener('keydown', this._onKeyDown);
this._clientWindow.addEventListener('click', this._onWindowClick);
this._sendToHost(Lifecycle.startedMessage);
}

/**
* Adds a global click handler to the client window that intercepts clicks on anchor elements
* Allows the click handler on the client window to intercept clicks on anchor elements
* and makes a nav request to the host based on the element's href. This should be
* avoided for complex applications as it can interfere with things like download
* links that you may not want to intercept.
*/
public startInterceptingLinks(): void {
if (this._isInterceptingLinksStarted) {
return;
}

this._isInterceptingLinksStarted = true;
this._clientWindow.addEventListener('click', this._onWindowClick);
this._shouldInterceptLinks = true;
}

/**
* Removes the global click handler that intercepts clicks on anchor elements.
* Turns off the behavior of intercepting link clicks in the client window click handler.
*/
public stopInterceptingLinks(): void {
if (!this._isInterceptingLinksStarted) {
return;
}

this._isInterceptingLinksStarted = false;
this._clientWindow.removeEventListener('click', this._onWindowClick);
this._shouldInterceptLinks = true;
}

/**
Expand All @@ -407,6 +406,7 @@ bad input into one of the iframe-coordinator client methods.
this._isStarted = false;
this._clientWindow.removeEventListener('message', this._onWindowMessage);
this._clientWindow.removeEventListener('keydown', this._onKeyDown);
this._clientWindow.removeEventListener('click', this._onWindowClick);
this.stopInterceptingLinks();
}

Expand Down
18 changes: 18 additions & 0 deletions packages/iframe-coordinator/src/messages/Click.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { constant, Decoder, object } from 'decoders';
import { labeledDecoder, LabeledMsg } from './LabeledMsg';

/**
* A message used to notify the host that a click (mousedown followed by mouseup)
* occurred in the client application.
*/
export interface LabeledClick extends LabeledMsg<'clickFired', {}> {
/** Message identifier */
msgType: 'clickFired';
}

const decoder: Decoder<LabeledClick> = labeledDecoder(
constant<'clickFired'>('clickFired'),
object({})
);

export { decoder };
3 changes: 3 additions & 0 deletions packages/iframe-coordinator/src/messages/ClientToHost.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { dispatch, guard } from 'decoders';
import { decoder as clickDecoder, LabeledClick } from './Click';
import { decoder as keyDownDecoder, LabeledKeyDown } from './KeyDown';
import { LabeledStarted, startedDecoder } from './Lifecycle';
import { decoder as modalDecoder, LabeledModalRequest } from './ModalRequest';
Expand All @@ -16,6 +17,7 @@ import {
export type ClientToHost =
| LabeledPublication
| LabeledNotification
| LabeledClick
| LabeledNavRequest
| LabeledStarted
| LabeledKeyDown
Expand All @@ -32,6 +34,7 @@ export function validate(msg: any): ClientToHost {
publish: publicationDecoder,
registeredKeyFired: keyDownDecoder,
client_started: startedDecoder,
clickFired: clickDecoder,
navRequest: navRequestDecoder,
notifyRequest: notifyDecoder,
toastRequest: notifyDecoder,
Expand Down
27 changes: 26 additions & 1 deletion packages/iframe-coordinator/src/specs/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ describe('client', () => {
let mockElement;
describe('when click event target is an anchor', () => {
beforeEach(() => {
client.start();
client.startInterceptingLinks();
mockElement = document.createElement('a');
mockElement.setAttribute('href', 'http://www.example.com/');
Expand All @@ -447,10 +448,21 @@ describe('client', () => {
'https://example.com'
);
});

it('should notify host of a click event', () => {
expect(mockFrameWindow.parent.postMessage).toHaveBeenCalledWith(
applyClientProtocol({
msgType: 'clickFired',
msg: {}
}),
'https://example.com'
);
});
});

describe('when click event target is not an anchor', () => {
beforeEach(() => {
client.start();
client.startInterceptingLinks();
mockFrameWindow.parent.postMessage.calls.reset();
mockElement = document.createElement('div');
Expand All @@ -464,7 +476,20 @@ describe('client', () => {
});

it('should not notify host of navigation request', () => {
expect(mockFrameWindow.parent.postMessage).not.toHaveBeenCalled();
expect(mockFrameWindow.parent.postMessage).not.toHaveBeenCalledWith(
jasmine.objectContaining({ msgType: 'navRequest' }),
jasmine.anything()
);
});

it('should notify host of a click event', () => {
expect(mockFrameWindow.parent.postMessage).toHaveBeenCalledWith(
applyClientProtocol({
msgType: 'clickFired',
msg: {}
}),
'https://example.com'
);
});
});

Expand Down

0 comments on commit 4a7768f

Please sign in to comment.