feat(service-worker): close notifications and focus window on click (#25860)
- Serialize notification object before using postMessage - Close notification on click - Focus browser if it is not already focused on click PR Close #25860
This commit is contained in:
parent
f017b26e5d
commit
f5d5a3df59
|
@ -33,6 +33,10 @@ const NOTIFICATION_OPTION_NAMES = [
|
||||||
'actions', 'badge', 'body', 'dir', 'icon', 'lang', 'renotify', 'requireInteraction', 'tag',
|
'actions', 'badge', 'body', 'dir', 'icon', 'lang', 'renotify', 'requireInteraction', 'tag',
|
||||||
'vibrate', 'data'
|
'vibrate', 'data'
|
||||||
];
|
];
|
||||||
|
const NOTIFICATION_CLICK_OPTION_NAMES = [
|
||||||
|
'actions', 'badge', 'title', 'body', 'dir', 'icon', 'lang', 'renotify', 'requireInteraction',
|
||||||
|
'tag', 'vibrate', 'data'
|
||||||
|
];
|
||||||
|
|
||||||
interface LatestEntry {
|
interface LatestEntry {
|
||||||
latest: string;
|
latest: string;
|
||||||
|
@ -276,7 +280,7 @@ export class Driver implements Debuggable, UpdateSource {
|
||||||
msg.waitUntil(this.handlePush(msg.data.json()));
|
msg.waitUntil(this.handlePush(msg.data.json()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private onClick(event: NotificationClickEvent): void {
|
private onClick(event: NotificationEvent): void {
|
||||||
// Handle the click event and keep the SW alive until it's handled.
|
// Handle the click event and keep the SW alive until it's handled.
|
||||||
event.waitUntil(this.handleClick(event.notification, event.action));
|
event.waitUntil(this.handleClick(event.notification, event.action));
|
||||||
}
|
}
|
||||||
|
@ -305,10 +309,17 @@ export class Driver implements Debuggable, UpdateSource {
|
||||||
await this.scope.registration.showNotification(desc['title'] !, options);
|
await this.scope.registration.showNotification(desc['title'] !, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleClick(notification: Notification, action?: string): Promise<void> {
|
private async handleClick(notification: any, action?: string): Promise<void> {
|
||||||
await this.broadcast({
|
(notification as Notification).close();
|
||||||
|
|
||||||
|
const desc = notification as{[key: string]: string | undefined};
|
||||||
|
let options: {[key: string]: string | undefined} = {};
|
||||||
|
NOTIFICATION_CLICK_OPTION_NAMES.filter(name => desc.hasOwnProperty(name))
|
||||||
|
.forEach(name => options[name] = desc[name]);
|
||||||
|
|
||||||
|
await this.broadcastAndFocus({
|
||||||
type: 'NOTIFICATION_CLICK',
|
type: 'NOTIFICATION_CLICK',
|
||||||
data: {action, notification},
|
data: {action, notification: options},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,6 +1007,18 @@ export class Driver implements Debuggable, UpdateSource {
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async broadcastAndFocus(msg: Object): Promise<void> {
|
||||||
|
const clients = await this.scope.clients.matchAll();
|
||||||
|
clients.forEach((client: any) => {
|
||||||
|
if ('focus' in client) {
|
||||||
|
if (!client.focused) {
|
||||||
|
client.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
client.postMessage(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async broadcast(msg: Object): Promise<void> {
|
async broadcast(msg: Object): Promise<void> {
|
||||||
const clients = await this.scope.clients.matchAll();
|
const clients = await this.scope.clients.matchAll();
|
||||||
clients.forEach(client => { client.postMessage(msg); });
|
clients.forEach(client => { client.postMessage(msg); });
|
||||||
|
|
|
@ -232,7 +232,7 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context
|
||||||
if (!this.eventHandlers.has('notificationclick')) {
|
if (!this.eventHandlers.has('notificationclick')) {
|
||||||
throw new Error('No notificationclick handler registered');
|
throw new Error('No notificationclick handler registered');
|
||||||
}
|
}
|
||||||
const event = new MockNotificationClickEvent(notification, action);
|
const event = new MockNotificationEvent(notification, action);
|
||||||
this.eventHandlers.get('notificationclick') !.call(this, event);
|
this.eventHandlers.get('notificationclick') !.call(this, event);
|
||||||
return event.ready;
|
return event.ready;
|
||||||
}
|
}
|
||||||
|
@ -349,8 +349,9 @@ class MockPushEvent extends MockExtendableEvent {
|
||||||
json: () => this._data,
|
json: () => this._data,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
class MockNotificationClickEvent extends MockExtendableEvent {
|
class MockNotificationEvent extends MockExtendableEvent {
|
||||||
constructor(readonly notification: Object, readonly action?: string) { super(); }
|
constructor(private _notification: any, readonly action?: string) { super(); }
|
||||||
|
readonly notification = {...this._notification, close: () => { return; }};
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockInstallEvent extends MockExtendableEvent {}
|
class MockInstallEvent extends MockExtendableEvent {}
|
||||||
|
|
Loading…
Reference in New Issue