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

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: Response to CR 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
« no previous file with comments | « no previous file | tests/js/polyfills/notifications.polyfill.test.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 * Exported so we can override for testing.
181 *
182 * @returns {Promise} Promise resolving to the service worker registration.
183 * Rejects if no registration is available.
184 */
185 chrome.caterpillar.notifications.getRegistration = function() {
186 if (self.registration)
187 return Promise.resolve(self.registration);
188
189 if (navigator.serviceWorker &&
190 navigator.serviceWorker.getRegistration) {
191 return navigator.serviceWorker.getRegistration().then(function(reg) {
192 if (!reg)
193 return Promise.reject();
194 return Promise.resolve(reg);
195 });
196 }
197
198 return Promise.reject();
199 }
200
201
202 /**
203 * Creates a notification.
204 *
205 * Internal helper function.
206 *
207 * @param {string} title
208 * @param {object} notificationOptions Object with properties body, tag, icon,
209 * and data. All properties are expected to be defined.
210 * @returns {Promise} Promise resolving to a Notification.
211 */
212 function createNotification(title, notificationOptions) {
213 return chrome.caterpillar.notifications.getRegistration()
214 .then(function(registration) {
215 registration.showNotification(title, notificationOptions);
216 return registration.getNotifications({ tag: notificationOptions.tag });
217 }).catch(function() {
218 return Promise.resolve([new Notification(title, notificationOptions)]);
219 }).then(function(notifications) {
220 // Notifications are in creation order, so get the last notification.
221 return Promise.resolve(notifications[notifications.length - 1]);
222 });
223 }
224
225 /**
163 * Clears the specified notification. 226 * Clears the specified notification.
164 * 227 *
165 * @param {string} notificationId 228 * @param {string} notificationId
166 * @param {function} opt_callback Takes a boolean which is true iff the 229 * @param {function} opt_callback Takes a boolean which is true iff the
167 * notification was cleared successfully. 230 * notification was cleared successfully.
168 */ 231 */
169 chrome.notifications.clear = function(notificationId, opt_callback) { 232 chrome.notifications.clear = function(notificationId, opt_callback) {
170 if (!(notificationId in notifications) && opt_callback) { 233 if (!(notificationId in notifications) && opt_callback) {
171 opt_callback(false); 234 opt_callback(false);
172 return; 235 return;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 callback(e.target.tag); 286 callback(e.target.tag);
224 }; 287 };
225 288
226 for (var i in notifications) { 289 for (var i in notifications) {
227 notifications[i].addEventListener('click', callbackWrapper); 290 notifications[i].addEventListener('click', callbackWrapper);
228 } 291 }
229 292
230 onClickHandlers.push(callbackWrapper); 293 onClickHandlers.push(callbackWrapper);
231 }; 294 };
232 295
233 }).call(this); 296 }).call(this);
OLDNEW
« no previous file with comments | « no previous file | tests/js/polyfills/notifications.polyfill.test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698