blob: a33ff0f38b196881a978057aedb91c2f5037c564 [file] [log] [blame]
// Deep-copies the attributes of |notification|. Note that the
// robustness of this function (and also |assert_object_equals| in
// testharness.js) affects the types of possible testing can be done.
// TODO(peter): change this to a structured clone algorithm.
function cloneNotification(notification) {
function deepCopy(src) {
if (typeof src !== 'object' || src === null)
return src;
var dst = Array.isArray(src) ? [] : {};
for (var property in src) {
if (typeof src[property] === 'function')
continue;
dst[property] = deepCopy(src[property]);
}
return dst;
}
return deepCopy(notification);
}
// Deserializes a trigger object sent via postMessage.
function deserializeTrigger(trigger) {
if (trigger && trigger.timestamp)
return new TimestampTrigger(trigger.timestamp);
return trigger;
}
// Deserializes notification options sent via postMessage.
function deserializeOptions(options) {
return {
...options,
showTrigger: deserializeTrigger(options.showTrigger),
};
}
// Allows a document to exercise the Notifications API within a service worker by sending commands.
var messagePort = null;
// All urls of requests that have been routed through the fetch event handler.
var fetchHistory = [];
addEventListener('install', event => {
event.waitUntil(skipWaiting());
});
addEventListener('activate', event => {
event.waitUntil(clients.claim());
});
addEventListener('message', workerEvent => {
messagePort = workerEvent.data;
// Listen to incoming commands on the message port.
messagePort.onmessage = event => {
if (typeof event.data != 'object' || !event.data.command)
return;
switch (event.data.command) {
case 'permission':
messagePort.postMessage({ command: event.data.command,
value: Notification.permission });
break;
case 'show':
registration.showNotification(event.data.title, deserializeOptions(event.data.options)).then(() => {
messagePort.postMessage({ command: event.data.command,
success: true });
}, error => {
messagePort.postMessage({ command: event.data.command,
success: false,
message: error.message });
});
break;
case 'get-fetch-history':
messagePort.postMessage({ command: event.data.command,
fetchHistory: fetchHistory });
break;
case 'get':
var filter = {};
if (typeof (event.data.filter) !== 'undefined')
filter = event.data.filter;
registration.getNotifications(filter).then(notifications => {
var clonedNotifications = [];
for (var notification of notifications)
clonedNotifications.push(cloneNotification(notification));
messagePort.postMessage({ command: event.data.command,
success: true,
notifications: clonedNotifications });
}, error => {
messagePort.postMessage({ command: event.data.command,
success: false,
message: error.message });
});
break;
case 'request-permission-exists':
messagePort.postMessage({ command: event.data.command,
value: 'requestPermission' in Notification });
break;
default:
messagePort.postMessage({ command: 'error', message: 'Invalid command: ' + event.data.command });
break;
}
};
// Notify the controller that the worker is now available.
messagePort.postMessage('ready');
});
addEventListener('notificationclick', event => {
var notificationCopy = cloneNotification(event.notification);
// Notifications containing "ACTION:CLOSE" in their message will be closed
// immediately by the Service Worker.
if (event.notification.body.indexOf('ACTION:CLOSE') != -1)
event.notification.close();
// Notifications containing "ACTION:OPENWINDOW" in their message will attempt
// to open a new window for an example URL.
if (event.notification.body.indexOf('ACTION:OPENWINDOW') != -1)
event.waitUntil(clients.openWindow('https://example.com/'));
messagePort.postMessage({ command: 'click',
notification: notificationCopy,
action: event.action,
reply: event.reply });
});
addEventListener('notificationclose', event => {
var notificationCopy = cloneNotification(event.notification);
messagePort.postMessage({ command: 'close',
notification: notificationCopy });
});
addEventListener('fetch', event => {
fetchHistory.push(event.request.url);
event.respondWith(fetch(event.request));
});