Index: polymer_1.0.4/bower_components/platinum-push-messaging/platinum-push-messaging.html |
diff --git a/polymer_1.0.4/bower_components/platinum-push-messaging/platinum-push-messaging.html b/polymer_1.0.4/bower_components/platinum-push-messaging/platinum-push-messaging.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7a43a73bd7eb949fdfac9e5ccf3a4f7e88e8fdff |
--- /dev/null |
+++ b/polymer_1.0.4/bower_components/platinum-push-messaging/platinum-push-messaging.html |
@@ -0,0 +1,427 @@ |
+<!-- |
+@license |
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
+Code distributed by Google as part of the polymer project is also |
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
+--> |
+<link rel="import" href="../polymer/polymer.html"> |
+ |
+<script> |
+ (function() { |
+ 'use strict'; |
+ // TODO: Doesn't work for IE or Safari, and the usual |
+ // document.getElementsByTagName('script') workaround seems to be broken by |
+ // HTML imports. Not important for now as neither of those browsers support |
+ // service worker yet. |
+ var currentScript = document.currentScript.baseURI; |
+ |
+ var SCOPE = new URL('./$$platinum-push-messaging$$/', currentScript).href; |
+ var WORKER_URL = new URL('./service-worker.js', currentScript).href; |
+ |
+ var BASE_URL = new URL('./', document.location.href).href; |
+ |
+ var SUPPORTED = 'serviceWorker' in navigator && |
+ 'PushManager' in window && |
+ 'Notification' in window; |
+ |
+ /** |
+ * @const {Number} The desired version of the service worker to use. This is |
+ * not strictly tied to anything except that it should be changed whenever |
+ * a breaking change is made to the service worker code. |
+ */ |
+ var VERSION = 1; |
+ |
+ // This allows us to use the PushSubscription attribute type in browsers |
+ // where it is not defined. |
+ if (!('PushSubscription' in window)) { |
+ window.PushSubscription = {}; |
+ } |
+ |
+ /** |
+ * `<platinum-push-messaging>` sets up a [push messaging][1] subscription |
+ * and allows you to define what happens when a push message is received. |
+ * |
+ * The element can be placed anywhere, but should only be used once in a |
+ * page. If there are multiple occurrences, only one will be active. |
+ * |
+ * # Requirements |
+ * Push messaging is currently only available in Google Chrome, which |
+ * requires you to configure Google Cloud Messaging. Chrome will check that |
+ * your page links to a manifest file that contains a `gcm_sender_id` field. |
+ * You can find full details of how to set all of this up in the [HTML5 |
+ * Rocks guide to push notifications][1]. |
+ * |
+ * # Notifcation details |
+ * The data for how a notification should be displayed can come from one of |
+ * three places. |
+ * |
+ * Firstly, you can specify a URL from which to fetch the message data. |
+ * ``` |
+ * <platinum-push-messaging |
+ * message-url="notification-data.json"> |
+ * </platinum-push-messaging> |
+ * ``` |
+ * |
+ * The second way is to send the message data in the body of |
+ * the push message from your server. In this case you do not need to |
+ * configure anything in your page: |
+ * ``` |
+ * <platinum-push-messaging></platinum-push-messaging> |
+ * ``` |
+ * **Note that this method is not currently supported by any browser**. It |
+ * is, however, defined in the |
+ * [draft W3C specification](http://w3c.github.io/push-api/#the-push-event) |
+ * and this element should use that data when it is implemented in the |
+ * future. |
+ * |
+ * If a message-url is provided then the message body will be ignored in |
+ * favor of the first method. |
+ * |
+ * Thirdly, you can manually define the attributes on the element: |
+ * ``` |
+ * <platinum-push-messaging |
+ * title="Application updated" |
+ * message="The application was updated in the background" |
+ * icon-url="icon.png" |
+ * click-url="notification.html"> |
+ * </platinum-push-messaging> |
+ * ``` |
+ * These values will also be used as defaults if one of the other methods |
+ * does not provide a value for that property. |
+ * |
+ * # Testing |
+ * If you have set up Google Cloud Messaging then you can send push messages |
+ * to your browser by following the guide in the [GCM documentation][2]. |
+ * |
+ * However, for quick client testing there are two options. You can use the |
+ * `testPush` method, which allows you to simulate a push message that |
+ * includes a payload. |
+ * |
+ * Or, at a lower level, you can open up chrome://serviceworker-internals in |
+ * Chrome and use the 'Push' button for the service worker corresponding to |
+ * your app. |
+ * |
+ * [1]: http://updates.html5rocks.com/2015/03/push-notificatons-on-the-open-web |
+ * [2]: https://developer.android.com/google/gcm/http.html |
+ * |
+ * @demo demo/ |
+ */ |
+ Polymer({ |
+ is: 'platinum-push-messaging', |
+ |
+ properties: { |
+ |
+ /** |
+ * Indicates whether the Push and Notification APIs are supported by |
+ * this browser. |
+ */ |
+ supported: { |
+ readOnly: true, |
+ type: Boolean, |
+ value: SUPPORTED |
+ }, |
+ |
+ /** |
+ * The details of the current push subscription, if any. |
+ */ |
+ subscription: { |
+ readOnly: true, |
+ type: PushSubscription, |
+ notify: true, |
+ }, |
+ |
+ /** |
+ * Indicates the status of the element. If true, push messages will be |
+ * received. |
+ */ |
+ enabled: { |
+ readOnly: true, |
+ type: Boolean, |
+ notify: true, |
+ value: false |
+ }, |
+ |
+ |
+ /** |
+ * A URL from which message information can be retrieved. |
+ * |
+ * When a push event happens that does not contain a message body this |
+ * URL will be fetched. The URL is expected to be for a JSON document in |
+ * the format: |
+ * ``` |
+ * { |
+ * "title": "The title for the notification", |
+ * "body": "The message to display in the notification", |
+ * "url": "The URL to display when the notification is clicked", |
+ * "icon": "The URL of an icon to display with the notification", |
+ * "tag": "An identifier that determines which notifications can be displayed at the same time" |
+ * } |
+ * ``` |
+ */ |
+ messageUrl: String, |
+ |
+ /** |
+ * A default notification title. |
+ */ |
+ title: String, |
+ |
+ /** |
+ * A default notification message. |
+ */ |
+ message: String, |
+ |
+ /** |
+ * A default icon for notifications. |
+ */ |
+ iconUrl: String, |
+ |
+ /** |
+ * A default URL to display when a notification is clicked. |
+ */ |
+ clickUrl: { |
+ type: String, |
+ value: document.location.href |
+ }, |
+ |
+ /** |
+ * A default tag for the notifications that will be generated by |
+ * this element. Notifications with the same tag will overwrite one |
+ * another, so that only one will be shown at once. |
+ */ |
+ tag: String |
+ }, |
+ |
+ /** |
+ * Fired when a notification is clicked that had the current page as the |
+ * click URL. |
+ * |
+ * @event platinum-push-messaging-click |
+ * @param {Object} The push message data used to create the notification |
+ */ |
+ |
+ /** |
+ * Fired when a push message is received but no notification is shown. |
+ * This happens when the click URL is for this page and the page is |
+ * visible to the user on the screen. |
+ * |
+ * @event platinum-push-messaging-push |
+ * @param {Object} The push message data that was received |
+ */ |
+ |
+ /** |
+ * Fired when an error occurs while enabling or disabling notifications |
+ * |
+ * @event platinum-push-messaging-error |
+ * @param {String} The error message |
+ */ |
+ |
+ /** |
+ * Returns a promise which will resolve to the registration object |
+ * associated with our current service worker. |
+ * |
+ * @return {Promise<ServiceWorkerRegistration>} |
+ */ |
+ _getRegistration: function() { |
+ return navigator.serviceWorker.getRegistration(SCOPE); |
+ }, |
+ |
+ /** |
+ * Returns a promise that will resolve when the given registration becomes |
+ * active. |
+ * |
+ * @param registration {ServiceWorkerRegistration} |
+ * @return {Promise<undefined>} |
+ */ |
+ _registrationReady: function(registration) { |
+ if (registration.active) { |
+ return Promise.resolve(); |
+ } |
+ |
+ var serviceWorker = registration.installing || registration.waiting; |
+ |
+ return new Promise(function(resolve, reject) { |
+ // Because the Promise function is called on next tick there is a |
+ // small chance that the worker became active already. |
+ if (serviceWorker.state === 'activated') { |
+ resolve(); |
+ } |
+ var listener = function(event) { |
+ if (serviceWorker.state === 'activated') { |
+ resolve(); |
+ } else if (serviceWorker.state === 'redundant') { |
+ reject(new Error('Worker became redundant')); |
+ } else { |
+ return; |
+ } |
+ serviceWorker.removeEventListener('statechange', listener); |
+ }; |
+ serviceWorker.addEventListener('statechange', listener); |
+ }); |
+ }, |
+ |
+ /** |
+ * Event handler for the `message` event. |
+ * |
+ * @param event {MessageEvent} |
+ */ |
+ _messageHandler: function(event) { |
+ if (event.data && event.data.source === SCOPE) { |
+ switch(event.data.type) { |
+ case 'push': |
+ this.fire('platinum-push-messaging-push', event.data); |
+ break; |
+ case 'click': |
+ this.fire('platinum-push-messaging-click', event.data); |
+ break; |
+ } |
+ } |
+ }, |
+ |
+ /** |
+ * Takes an options object and creates a stable JSON serialization of it. |
+ * This naive algorithm will only work if the object contains only |
+ * non-nested properties. |
+ * |
+ * @param options {Object.<String, ?(String|Number|Boolean)>} |
+ * @return String |
+ */ |
+ _serializeOptions: function(options) { |
+ var props = Object.keys(options); |
+ props.sort(); |
+ var parts = props.filter(function(propName) { |
+ return !!options[propName]; |
+ }).map(function(propName) { |
+ return JSON.stringify(propName) + ':' + JSON.stringify(options[propName]); |
+ }); |
+ return '{' + parts.join(',') + '}'; |
+ }, |
+ |
+ /** |
+ * Determine the URL of the worker based on the currently set parameters |
+ * |
+ * @return String the URL |
+ */ |
+ _getWorkerURL: function() { |
+ var options = this._serializeOptions({ |
+ tag: this.tag, |
+ messageUrl: this.messageUrl, |
+ title: this.title, |
+ message: this.message, |
+ iconUrl: this.iconUrl, |
+ clickUrl: this.clickUrl, |
+ version: VERSION, |
+ baseUrl: BASE_URL |
+ }); |
+ |
+ return WORKER_URL + '?' + options; |
+ }, |
+ |
+ /** |
+ * Update the subscription property, but only if the value has changed. |
+ * This prevents triggering the subscription-changed event twice on page |
+ * load. |
+ */ |
+ _updateSubscription: function(subscription) { |
+ if (JSON.stringify(subscription) !== JSON.stringify(this.subscription)) { |
+ this._setSubscription(subscription); |
+ } |
+ }, |
+ |
+ /** |
+ * Programmatically trigger a push message |
+ * |
+ * @param message {Object} the message payload |
+ */ |
+ testPush: function(message) { |
+ this._getRegistration().then(function(registration) { |
+ registration.active.postMessage({ |
+ type: 'test-push', |
+ message: message |
+ }); |
+ }); |
+ }, |
+ |
+ /** |
+ * Request push messaging to be enabled. |
+ * |
+ * @return {Promise<undefined>} |
+ */ |
+ enable: function() { |
+ if (!this.supported) { |
+ this.fire('platinum-push-messaging-error', 'Your browser does not support push notifications'); |
+ return Promise.resolve(); |
+ } |
+ |
+ return navigator.serviceWorker.register(this._getWorkerURL(), {scope: SCOPE}).then(function(registration) { |
+ return this._registrationReady(registration).then(function() { |
+ return registration.pushManager.subscribe({userVisibleOnly: true}); |
+ }); |
+ }.bind(this)).then(function(subscription) { |
+ this._updateSubscription(subscription); |
+ this._setEnabled(true); |
+ }.bind(this)).catch(function(error) { |
+ this.fire('platinum-push-messaging-error', error.message || error); |
+ }.bind(this)); |
+ }, |
+ |
+ /** |
+ * Request push messaging to be disabled. |
+ * |
+ * @return {Promise<undefined>} |
+ */ |
+ disable: function() { |
+ if (!this.supported) { |
+ return Promise.resolve(); |
+ } |
+ |
+ return this._getRegistration().then(function(registration) { |
+ if (!registration) { |
+ return; |
+ } |
+ return registration.pushManager.getSubscription().then(function(subscription) { |
+ if (subscription) { |
+ return subscription.unsubscribe(); |
+ } |
+ }).then(function() { |
+ return registration.unregister(); |
+ }).then(function() { |
+ this._updateSubscription(); |
+ this._setEnabled(false); |
+ }.bind(this)).catch(function(error) { |
+ this.fire('platinum-push-messaging-error', error.message || error); |
+ }.bind(this)); |
+ }.bind(this)); |
+ }, |
+ |
+ ready: function() { |
+ if (this.supported) { |
+ var handler = this._messageHandler.bind(this); |
+ // NOTE: We add the event listener twice because the specced and |
+ // implemented behaviors do not match. In Chrome 42, messages are |
+ // received on window. In the current spec they are supposed to be |
+ // received on navigator.serviceWorker. |
+ // TODO: Remove the non-spec code in the future. |
+ window.addEventListener('message', handler); |
+ navigator.serviceWorker.addEventListener('message', handler); |
+ |
+ this._getRegistration().then(function(registration) { |
+ if (!registration) { |
+ return; |
+ } |
+ if (registration.active && registration.active.scriptURL !== this._getWorkerURL()) { |
+ // We have an existing worker in this scope, but it is out of date |
+ return this.enable(); |
+ } |
+ return registration.pushManager.getSubscription().then(function(subscription) { |
+ this._updateSubscription(subscription); |
+ this._setEnabled(true); |
+ }.bind(this)); |
+ }.bind(this)); |
+ } |
+ } |
+ }); |
+ })(); |
+</script> |