Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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); |
| OLD | NEW |