Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: src/js/polyfills/notifications.polyfill.js

Issue 1646633003: Notifications work in service workers. Resolves #14. (Closed) Base URL: git@github.com:chromium/caterpillar.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 Google Inc. All Rights Reserved. 1 // Copyright 2015 Google Inc. All Rights Reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 /** 15 /**
16 * Polyfill for Chrome Apps' notifications API. 16 * Polyfill for Chrome Apps' notifications API.
17 */ 17 */
18 18
19 'use strict'; 19 'use strict';
20 20
21 // Set up a namespace for the polyfill if necessary. 21 // Set up a namespace for the polyfill if necessary.
22 if (!chrome.notifications) 22 if (!chrome.notifications)
23 chrome.notifications = {}; 23 chrome.notifications = {};
24 24
25 chrome.caterpillar.notifications = {};
26
25 (function() { 27 (function() {
26 28
27 // Private object to map notification IDs to their notification. 29 // Private object to map notification IDs to their notification.
28 var notifications = {}; 30 var notifications = {};
29 31
30 // List of event handlers for the click event. 32 // List of event handlers for the click event.
31 var onClickHandlers = []; 33 var onClickHandlers = [];
32 34
33 // Arbitrary maximum for randomly generated notification IDs. 35 // Arbitrary maximum for randomly generated notification IDs.
34 var MAX_NOTIFICATION_ID = 1000000; 36 var MAX_NOTIFICATION_ID = 1000000;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 chrome.notifications.clear(opt_notificationId); 120 chrome.notifications.clear(opt_notificationId);
119 } 121 }
120 122
121 // Generate a notification ID if necessary. 123 // Generate a notification ID if necessary.
122 if (opt_notificationId === undefined) { 124 if (opt_notificationId === undefined) {
123 // Math.random is notoriously bad at random numbers, but we don't care very 125 // Math.random is notoriously bad at random numbers, but we don't care very
124 // much about collisions. 126 // much about collisions.
125 opt_notificationId = Math.round(Math.random() * MAX_NOTIFICATION_ID) + ''; 127 opt_notificationId = Math.round(Math.random() * MAX_NOTIFICATION_ID) + '';
126 } 128 }
127 129
128 // TODO(alger): This uses a deprecated callback since the callback is 130 var title = options.title;
129 // supported on both Chrome and Firefox but the not-deprecated Promise return 131 var body = options.message;
130 // is only currently supported on Chrome. 132 if (options.contextMessage)
131 Notification.requestPermission(function() { 133 body += '\n\n' + options.contextMessage;
132 var title = options.title; 134 if (options.type === chrome.notifications.TemplateType.PROGRESS) {
133 var body = options.message; 135 body += '\n\nProgress: ' + options.progress + '%';
134 if (options.contextMessage) 136 } else if (options.type !== chrome.notifications.TemplateType.BASIC) {
135 body += '\n\n' + options.contextMessage; 137 console.warn('Notification type', options.type, 'not supported.',
136 if (options.type === chrome.notifications.TemplateType.PROGRESS) { 138 'Falling back to basic.');
137 body += '\n\nProgress: ' + options.progress + '%'; 139 }
138 } else if (options.type !== chrome.notifications.TemplateType.BASIC) { 140 var notificationOptions = {
139 console.warn('Notification type', options.type, 'not supported.', 141 'body': body,
140 'Falling back to basic.'); 142 'tag': opt_notificationId,
141 } 143 'icon': options.iconUrl,
142 var notification_options = { 144 'data': options,
143 'body': body, 145 };
144 'tag': opt_notificationId,
145 'icon': options.iconUrl,
146 'data': options,
147 };
148 146
149 var notification = new Notification(title, notification_options); 147 // Service workers can't request permission, so request permission if we can
148 // or just assume we have permission if we can't.
149 var notificationPromise;
150 if (!Notification.requestPermission) {
151 notificationPromise = createNotification(title, notificationOptions);
152 } else {
153 notificationPromise = new Promise(function(resolve, reject) {
154 // TODO(alger): This uses a deprecated callback since the callback is
155 // supported on both Chrome and Firefox but the not-deprecated Promise
156 // return is only currently supported on Chrome.
157 Notification.requestPermission(function() {
158 createNotification(title, notificationOptions)
159 .then(resolve)
160 .catch(reject);
161 });
162 });
163 }
150 164
165 notificationPromise.then(function(notification) {
151 for (var i = 0; i < onClickHandlers.length; i++) { 166 for (var i = 0; i < onClickHandlers.length; i++) {
152 notification.addEventListener('click', onClickHandlers[i]); 167 notification.addEventListener('click', onClickHandlers[i]);
153 } 168 }
154 169
155 notifications[opt_notificationId] = notification; 170 notifications[opt_notificationId] = notification;
156 171
157 if (opt_callback) 172 if (opt_callback)
158 opt_callback(opt_notificationId); 173 opt_callback(opt_notificationId);
159 }); 174 })
160 }; 175 };
161 176
162 /** 177 /**
178 * Gets the service worker registration.
179 *
180 * @returns {Promise} Promise resolving to the service worker registration.
181 * Rejects if no registration is available.
182 */
183 chrome.caterpillar.notifications.getRegistration = function() {
184 // Exported so we can override for testing.
185 if (self.registration)
186 return Promise.resolve(self.registration);
187
188 if (navigator.serviceWorker &&
189 navigator.serviceWorker.getRegistration) {
raymes 2016/01/28 04:36:56 nit: 4 space indent, or in-line with the ( on the
Matthew Alger 2016/01/28 05:18:02 Not sure what happened here - fixed!
190 return navigator.serviceWorker.getRegistration().then(function(reg) {
191 if (reg === undefined)
raymes 2016/01/28 04:36:56 if (!reg)
Matthew Alger 2016/01/28 05:18:02 Done.
192 return Promise.reject();
193 return Promise.resolve(reg);
194 });
195 }
196
197 return Promise.reject();
198 }
199
200
201 /**
202 * Creates a notification.
203 *
204 * Internal helper function.
205 *
206 * @param {string} title
207 * @param {object} notificationOptions Object with properties body, tag, icon,
208 * and data. All properties are expected to be defined.
209 * @returns {Promise} Promise resolving to a Notification.
210 */
211 var createNotification = function(title, notificationOptions) {
raymes 2016/01/28 04:36:56 function createNotification(title, ...
Matthew Alger 2016/01/28 05:18:02 Done. Is this syntax preferred?
raymes 2016/02/01 00:14:23 It's just a bit simpler
Matthew Alger 2016/02/01 00:50:42 Acknowledged.
212 return chrome.caterpillar.notifications.getRegistration()
213 .then(function(registration) {
214 registration.showNotification(title, notificationOptions);
215 return registration.getNotifications({ tag: notificationOptions.tag });
216 })
217 .catch(function() {
218 return Promise.resolve([new Notification(title, notificationOptions)]);
raymes 2016/01/28 04:36:56 Is this useful?
Matthew Alger 2016/01/28 05:18:02 Yes, I think so - new Notification was part of the
219 })
220 .then(function(notifications) {
221 // Notifications are in creation order, so get the last notification.
222 return Promise.resolve(notifications[notifications.length - 1]);
raymes 2016/01/28 04:36:56 It should be easy to inline this .then() and just
Matthew Alger 2016/01/28 05:18:02 I'm not sure how to do that without adding a .then
raymes 2016/02/01 00:14:23 Oh right, I didn't realise it returned a promise.
Matthew Alger 2016/02/01 00:50:42 Acknowledged.
223 });
224 };
225
226 /**
163 * Clears the specified notification. 227 * Clears the specified notification.
164 * 228 *
165 * @param {string} notificationId 229 * @param {string} notificationId
166 * @param {function} opt_callback Takes a boolean which is true iff the 230 * @param {function} opt_callback Takes a boolean which is true iff the
167 * notification was cleared successfully. 231 * notification was cleared successfully.
168 */ 232 */
169 chrome.notifications.clear = function(notificationId, opt_callback) { 233 chrome.notifications.clear = function(notificationId, opt_callback) {
170 if (!(notificationId in notifications) && opt_callback) { 234 if (!(notificationId in notifications) && opt_callback) {
171 opt_callback(false); 235 opt_callback(false);
172 return; 236 return;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 callback(e.target.tag); 287 callback(e.target.tag);
224 }; 288 };
225 289
226 for (var i in notifications) { 290 for (var i in notifications) {
227 notifications[i].addEventListener('click', callbackWrapper); 291 notifications[i].addEventListener('click', callbackWrapper);
228 } 292 }
229 293
230 onClickHandlers.push(callbackWrapper); 294 onClickHandlers.push(callbackWrapper);
231 }; 295 };
232 296
233 }).call(this); 297 }).call(this);
OLDNEW
« no previous file with comments | « no previous file | tests/js/polyfills/notifications.polyfill.test.html » ('j') | tests/js/polyfills/notifications.polyfill.test.js » ('J')

Powered by Google App Engine
This is Rietveld 408576698