...
 
Commits (2)
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
firebase-debug.log*
# Firebase cache
.firebase/
# Firebase config
# Uncomment this if you'd like others to create their own Firebase project.
# For a team working on the same Firebase project(s), it is recommended to leave
# it commented so all members can deploy to the same project(s) in .firebaserc.
# .firebaserc
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
<!--
Copyright 2016 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="canonical" href="https://weather-pwa-sample.firebaseapp.com/final/">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather PWA</title>
<link rel="stylesheet" type="text/css" href="styles/inline.css">
<link rel="manifest" href="/manifest.json">
<!--ios-->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Weather PWA">
<link rel="apple-touch-icon" href="images/icons/icon-152x152.png">
<!--windows-->
<meta name="msapplication-TileImage" content="images/icons/icon-144x144.png">
<meta name="msapplication-TileColor" content="#2F3BA2">
</head>
<body>
<header class="header">
<h1 class="header__title">Weather PWA</h1>
<button id="butRefresh" class="headerButton" aria-label="Refresh"></button>
<button id="butAdd" class="headerButton" aria-label="Add"></button>
<input onclick="showForm()" id="butAuth" class="authButton" type="button" value="login"/>
</header>
<main class="main">
<div id="dialog" class="logout">
You are logged out. You need to sign in again!
</div>
<div class="card cardTemplate weather-forecast" hidden>
<div class="city-key" hidden></div>
<div class="card-last-updated" hidden></div>
<div class="location"></div>
<div class="date"></div>
<div class="description"></div>
<div class="current">
<div class="visual">
<div class="icon"></div>
<div class="temperature">
<span class="value"></span><span class="scale">°F</span>
</div>
</div>
<div class="description">
<div class="humidity"></div>
<div class="wind">
<span class="value"></span>
<span class="scale">mph</span>
<span class="direction"></span>°
</div>
<div class="sunrise"></div>
<div class="sunset"></div>
</div>
</div>
<div class="future">
<div class="oneday">
<div class="date"></div>
<div class="icon"></div>
<div class="temp-high">
<span class="value"></span>°
</div>
<div class="temp-low">
<span class="value"></span>°
</div>
</div>
<div class="oneday">
<div class="date"></div>
<div class="icon"></div>
<div class="temp-high">
<span class="value"></span>°
</div>
<div class="temp-low">
<span class="value"></span>°
</div>
</div>
<div class="oneday">
<div class="date"></div>
<div class="icon"></div>
<div class="temp-high">
<span class="value"></span>°
</div>
<div class="temp-low">
<span class="value"></span>°
</div>
</div>
<div class="oneday">
<div class="date"></div>
<div class="icon"></div>
<div class="temp-high">
<span class="value"></span>°
</div>
<div class="temp-low">
<span class="value"></span>°
</div>
</div>
<div class="oneday">
<div class="date"></div>
<div class="icon"></div>
<div class="temp-high">
<span class="value"></span>°
</div>
<div class="temp-low">
<span class="value"></span>°
</div>
</div>
<div class="oneday">
<div class="date"></div>
<div class="icon"></div>
<div class="temp-high">
<span class="value"></span>°
</div>
<div class="temp-low">
<span class="value"></span>°
</div>
</div>
<div class="oneday">
<div class="date"></div>
<div class="icon"></div>
<div class="temp-high">
<span class="value"></span>°
</div>
<div class="temp-low">
<span class="value"></span>°
</div>
</div>
</div>
</div>
</main>
<div class="dialog-container">
<div class="dialog">
<div class="dialog-title">Add new city</div>
<div class="dialog-body">
<select id="selectCityToAdd">
<!-- Values map to Yahoo Weather API Where On Earth Identifiers (WOEIDs).
https://developer.yahoo.com/weather/documentation.html#req -->
<option value="2357536">Austin, TX</option>
<option value="2367105">Boston, MA</option>
<option value="2379574">Chicago, IL</option>
<option value="2459115">New York, NY</option>
<option value="2475687">Portland, OR</option>
<option value="2487956">San Francisco, CA</option>
<option value="2490383">Seattle, WA</option>
</select>
</div>
<div class="dialog-buttons">
<button id="butAddCity" class="button">Add</button>
<button id="butAddCancel" class="button">Cancel</button>
</div>
</div>
</div>
<div class="loader">
<svg viewBox="0 0 32 32" width="32" height="32">
<circle id="spinner" cx="16" cy="16" r="14" fill="none"></circle>
</svg>
</div>
<!-- Uncomment the line below when ready to test with fake data -->
<script src="scripts/app.js" async></script>
<script src="scripts/auth.js" async></script>
</body>
</html>
{
"name": "Weather",
"short_name": "Weather",
"icons": [{
"src": "images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
}, {
"src": "images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
}, {
"src": "images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
}, {
"src": "images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}, {
"src": "images/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
}],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#3E4EB8",
"theme_color": "#2F3BA2"
}
\ No newline at end of file
// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function() {
'use strict';
var app = {
isLoading: true,
visibleCards: {},
selectedCities: [],
spinner: document.querySelector('.loader'),
cardTemplate: document.querySelector('.cardTemplate'),
container: document.querySelector('.main'),
addDialog: document.querySelector('.dialog-container'),
daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
};
document.getElementById('butRefresh').addEventListener('click', function() {
// Refresh all of the forecasts
app.updateForecasts();
});
document.getElementById('butAdd').addEventListener('click', function() {
// Open/show the add new city dialog
app.toggleAddDialog(true);
});
document.getElementById('butAddCity').addEventListener('click', function() {
// Add the newly selected city
var select = document.getElementById('selectCityToAdd');
var selected = select.options[select.selectedIndex];
var key = selected.value;
var label = selected.textContent;
if (!app.selectedCities) {
app.selectedCities = [];
}
app.getForecast(key, label);
app.selectedCities.push({key: key, label: label});
app.saveSelectedCities();
app.toggleAddDialog(false);
});
document.getElementById('butAddCancel').addEventListener('click', function() {
// Close the add new city dialog
app.toggleAddDialog(false);
});
// TODO add service worker code here
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../service-worker.js')
.then(function() {
console.log('Service Worker Registered');
return navigator.serviceWorker.ready;
})
.then(function(reg) {
navigator.serviceWorker.addEventListener('message', function(event){
//for tab sync
console.log(event.data)
if(event.data == 0){
//user is logged in
document.getElementById("butAuth").value = "logout"
document.getElementById("dialog").style.display = "none";
console.log('you are logged in')
} else {
//user is logged out
document.getElementById("butAuth").value = "login"
document.getElementById("dialog").style.display = "inline-block";
console.log('you are logged out')
}
});
}).catch(function(error) {
console.error('Service Worker registration error : ', error);
});
}
})();
function stateToServiceWorker(data){
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage(data);
console.log(data)
if(data == 0){
//user is logged in
document.getElementById("butAuth").value = "logout"
document.getElementById("dialog").style.display = "none";
console.log('you are logged in')
} else {
//user is logged out
document.getElementById("butAuth").value = "login"
document.getElementById("dialog").style.display = "inline-block";
console.log('you are logged out')
}
}
}
if(document.getElementById("butAuth").value == "login"){
document.getElementById("dialog").style.display = "inline-block";
}
//IF U ARE LOGGED IN = 0
//IF U ARE LOGGED OUT = 1
function showForm(){
if(document.getElementById("butAuth").value == "logout"){
document.getElementById("butAuth").value = "login";
document.getElementById("dialog").style.display = "inline-block";
stateToServiceWorker(1)
} else {
document.getElementById("dialog").style.display = "none";
stateToServiceWorker(0)
}
}
var dataCacheName = 'weatherData-v1';
var cacheName = 'weatherPWA-final-1';
var filesToCache = [
'/',
'/index.html',
'/scripts/app.js',
'/styles/inline.css',
'/images/clear.png',
'/images/cloudy-scattered-showers.png',
'/images/cloudy.png',
'/images/fog.png',
'/images/ic_add_white_24px.svg',
'/images/ic_refresh_white_24px.svg',
'/images/partly-cloudy.png',
'/images/rain.png',
'/images/scattered-showers.png',
'/images/sleet.png',
'/images/snow.png',
'/images/thunderstorm.png',
'/images/wind.png'
];
self.addEventListener('install', function(e) {
console.log('[ServiceWorker] Install');
e.waitUntil(
caches.open(cacheName).then(function(cache) {
console.log('[ServiceWorker] Caching app shell');
return cache.addAll(filesToCache);
}).then(function(){
console.log("skipWaiting")
return self.skipWaiting();
})
);
});
self.addEventListener('activate', function(e) {
console.log('[ServiceWorker] Activate');
e.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (key !== cacheName && key !== dataCacheName) {
console.log('[ServiceWorker] Removing old cache', key);
return caches.delete(key);
}
}));
})
);
return self.clients.claim();
});
self.addEventListener('fetch', function(e) {
console.log('[Service Worker] Fetch', e.request.url);
var dataUrl = 'https://query.yahooapis.com/v1/public/yql';
if (e.request.url.indexOf(dataUrl) > -1) {
e.respondWith(
caches.open(dataCacheName).then(function(cache) {
return fetch(e.request).then(function(response){
cache.put(e.request.url, response.clone());
return response;
});
})
);
} else {
e.respondWith(
caches.match(e.request).then(function(response) {
return response || fetch(e.request);
})
);
}
});
//https://www.loxodrome.io/post/tab-state-service-workers/
self.addEventListener('message', function(event){
// Receive the data from the client
var data = event.data;
// The unique ID of the tab
var clientId = event.source.id
// A function that handles the message
self.syncTabState(data, clientId);
});
self.sendTabState = function(client, data){
// Post data to a specific client
client.postMessage(data);
}
self.syncTabState = function(data, clientId){
clients.matchAll().then(function(clients) {
// Loop over all available clients
clients.forEach(function(client) {
// No need to update the tab that
// sent the data
if (client.id !== clientId) {
self.sendTabState(client, data)
}
})
})
}
\ No newline at end of file
This diff is collapsed.
{
"extends": ["eslint:recommended", "google"],
"rules": {
"no-var": 2,
"no-console": 0,
"comma-dangle": 0,
"require-jsdoc": 0,
"no-useless-escape": 0
},
"parserOptions": {
"ecmaVersion": 6
}
}
*~
*.pyc
*.swp
.idea
build
.DS_Store
.sass-cache/
node_modules/
.ruby-gemset
.rvmrc
.grunt-gae-pid
src/css/styles.css
src/css/styles.min.css
dist
.tmp
npm-debug.log
sudo: required
dist: trusty
language: node_js
cache:
directories:
- node_modules
node_js:
- 'stable'
install:
- npm install
# Read more here: https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-xvfb-to-Run-Tests-That-Require-a-GUI
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start || echo \"Unable to start virtual display.\""
- sleep 3 # give xvfb some time to start
script:
- npm run test
Want to contribute? Great! First, read this page (including the small print at the end).
### Before you contribute
Before we can use your code, you must sign the
[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
(CLA), which you can do online. The CLA is necessary mainly because you own the
copyright to your changes, even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things—for instance that you'll tell us if you
know that your code infringes on other people's patents. You don't have to sign
the CLA until after you've submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase.
Before you start working on a larger contribution, you should get in touch with
us first through the issue tracker with your idea so that we can help out and
possibly guide you. Coordinating up front makes it much easier to avoid
frustration later on.
### Code reviews
All submissions, including submissions by project members, require review. We
use Github pull requests for this purpose.
### The small print
Contributions made by corporations are covered by a different agreement than
the one above, the Software Grant and Corporate Contributor License Agreement.
This diff is collapsed.
# Push Notifications codelab
Code for the Web Fundamentals [Push Notifications codelab](https://codelabs.developers.google.com/codelabs/push-notifications/).
In this codelab, you'll learn how to add Push Notifications to web applications. This will enable you to re-engage users with breaking news and information about
new content.
You'll also learn the basics of Service Workers.
## What you'll learn
* Service Worker basics: installation and event handling
* How to set up a Google Cloud Messaging (GCM) account
* How to add a web manifest
* Techniques for requesting GCM to send a notification to a web client
* Notification display
* Notification click handling
Example code for each step of the codelab is available from the [completed](completed/) directory.
## License
Copyright 2015 Google, Inc.
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
{
"rules": {
"no-unused-vars": 0
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Push Codelab</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
<script defer src="https://code.getmdl.io/1.2.1/material.min.js"></script>
<link rel="stylesheet" href="styles/index.css">
</head>
<body>
<header>
<h1>Push Codelab</h1>
</header>
<main>
<p>Welcome to the push messaging codelab. The button below needs to be
fixed to support subscribing to push.</p>
<p>
<button disabled class="js-push-btn mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Enable Push Messaging
</button>
</p>
<section class="subscription-details js-subscription-details is-invisible">
<p>Once you've subscribed your user, you'd send their subscription to your
server to store in a database so that when you want to send a message
you can lookup the subscription and send a message to it.</p>
<p>To simplify things for this code lab copy the following details
into the <a href="https://web-push-codelab.glitch.me//">Push Companion
Site</a> and it'll send a push message for you, using the application
server keys on the site - so make sure they match.</p>
<pre><code class="js-subscription-json"></code></pre>
</section>
</main>
<script src="scripts/main.js"></script>
<script src="https://code.getmdl.io/1.2.1/material.min.js"></script>
</body>
</html>
/*
*
* Push Notifications codelab
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*
*/
/* eslint-env browser, es6 */
'use strict';
const applicationServerPublicKey = 'BGlbrY1jPwGEryc_1htOBl0nmmmgy5sghKd6bLd9FJYmYPc50WhnHhI2AE5CTE7mIkWayjpWxEij6kphaq3DTH0';
const pushButton = document.querySelector('.js-push-btn');
let isSubscribed = false;
let swRegistration = null;
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
//register Service Worker
if ('serviceWorker' in navigator && 'PushManager' in window) {
console.log('Service Worker and Push is supported');
navigator.serviceWorker.register('sw.js')
.then(function(swReg) {
console.log('Service Worker is registered', swReg);
swRegistration = swReg;
initializeUI();
})
.catch(function(error) {
console.error('Service Worker Error', error);
});
} else {
console.warn('Push messaging is not supported');
pushButton.textContent = 'Push Not Supported';
}
//Subscribe User
function initializeUI() {
pushButton.addEventListener('click', function() {
pushButton.disabled = true;
if (isSubscribed) {
// TODO: Unsubscribe user
} else {
subscribeUser();
}
});
// Set the initial subscription value
swRegistration.pushManager.getSubscription()
.then(function(subscription) {
isSubscribed = !(subscription === null);
if (isSubscribed) {
console.log('User IS subscribed.');
} else {
console.log('User is NOT subscribed.');
}
updateBtn();
});
}
function updateBtn() {
if (Notification.permission === 'denied') {
pushButton.textContent = 'Push Messaging Blocked.';
pushButton.disabled = true;
updateSubscriptionOnServer(null);
return;
}
if (isSubscribed) {
pushButton.textContent = 'Disable Push Messaging';
} else {
pushButton.textContent = 'Enable Push Messaging';
}
pushButton.disabled = false;
}
function initializeUI() {
pushButton.addEventListener('click', function() {
pushButton.disabled = true;
if (isSubscribed) {
unsubscribeUser();
} else {
subscribeUser();
}
});
// Set the initial subscription value
swRegistration.pushManager.getSubscription()
.then(function(subscription) {
isSubscribed = !(subscription === null);
updateSubscriptionOnServer(subscription);
if (isSubscribed) {
console.log('User IS subscribed.');
} else {
console.log('User is NOT subscribed.');
}
updateBtn();
});
}
function subscribeUser() {
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
.then(function(subscription) {
console.log('User is subscribed.');
updateSubscriptionOnServer(subscription);
isSubscribed = true;
updateBtn();
})
.catch(function(err) {
console.log('Failed to subscribe the user: ', err);
updateBtn();
});
}
function updateSubscriptionOnServer(subscription) {
// TODO: Send subscription to application server
const subscriptionJson = document.querySelector('.js-subscription-json');
const subscriptionDetails =
document.querySelector('.js-subscription-details');
if (subscription) {
subscriptionJson.textContent = JSON.stringify(subscription);
subscriptionDetails.classList.remove('is-invisible');
} else {
subscriptionDetails.classList.add('is-invisible');
}
}
html {
height: 100%;
}
html, body {
width: 100%;
padding: 0;
margin: 0;
}
body {
min-height: auto;
box-sizing: border-box;
}
header {
padding: 115px 0 32px 0;
background-color: #00bcd4;
color: white;
}
main, header > h1 {
padding: 0 16px;
max-width: 760px;
box-sizing: border-box;
margin: 0 auto;
}
main {
margin: 24px auto;
box-sizing: border-box;
}
pre {
white-space: pre-wrap;
background-color: #EEEEEE;
padding: 16px;
}
pre code {
word-break: break-word;
}
.is-invisible {
opacity: 0;
}
.subscription-details {
transition: opacity 1s;
}
@media (max-width: 600px) {
header > h1 {
font-size: 36px;
}
}
/*
*
* Push Notifications codelab
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*
*/
/* eslint-env browser, serviceworker, es6 */
'use strict';
self.addEventListener('push', function(event) {
console.log('[Service Worker] Push Received.');
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
const title = 'Push Codelab';
const options = {
body: 'Yay it works.',
icon: 'images/icon.png',
badge: 'images/badge.png'
};
const notificationPromise = self.registration.showNotification(title, options);
event.waitUntil(notificationPromise);
});
self.addEventListener('notificationclick', function(event) {
console.log('[Service Worker] Notification click Received.');
event.notification.close();
event.waitUntil(
clients.openWindow('https://developers.google.com/web/')
);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Push Codelab</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
<script defer src="https://code.getmdl.io/1.2.1/material.min.js"></script>
<link rel="stylesheet" href="styles/index.css">
</head>
<body>
<header>
<h1>Push Codelab</h1>
</header>
<main>
<p>Welcome to the push messaging codelab. The button below needs to be
fixed to support subscribing to push.</p>
<p>
<button disabled class="js-push-btn mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Enable Push Messaging
</button>
</p>
<section class="subscription-details js-subscription-details is-invisible">
<p>Once you've subscribed your user, you'd send their subscription to your
server to store in a database so that when you want to send a message
you can lookup the subscription and send a message to it.</p>
<p>To simplify things for this code lab copy the following details
into the <a href="https://web-push-codelab.glitch.me/">Push Companion
Site</a> and it'll send a push message for you, using the application
server keys on the site - so make sure they match.</p>
<pre><code class="js-subscription-json"></code></pre>
</section>
</main>
<script src="scripts/main.js"></script>
<script src="https://code.getmdl.io/1.2.1/material.min.js"></script>
</body>
</html>
/*
*
* Push Notifications codelab
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*
*/
/* eslint-env browser, es6 */
/* eslint-disable no-unused-vars */
'use strict';
const applicationServerPublicKey = '<Your Public Key>';
const pushButton = document.querySelector('.js-push-btn');
let isSubscribed = false;
let swRegistration = null;
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
if ('serviceWorker' in navigator && 'PushManager' in window) {
console.log('Service Worker and Push is supported');
navigator.serviceWorker.register('sw.js')
.then(function(swReg) {
console.log('Service Worker is registered', swReg);
swRegistration = swReg;
})
.catch(function(error) {
console.error('Service Worker Error', error);
});
} else {
console.warn('Push messaging is not supported');
pushButton.textContent = 'Push Not Supported';
}
html {
height: 100%;
}
html, body {
width: 100%;
padding: 0;
margin: 0;
}
body {
min-height: auto;
box-sizing: border-box;
}
header {
padding: 115px 0 32px 0;
background-color: #00bcd4;
color: white;
}
main, header > h1 {
padding: 0 16px;
max-width: 760px;
box-sizing: border-box;
margin: 0 auto;
}
main {
margin: 24px auto;
box-sizing: border-box;
}
pre {
white-space: pre-wrap;
background-color: #EEEEEE;
padding: 16px;
}
pre code {
word-break: break-word;
}
.is-invisible {
opacity: 0;
}
.subscription-details {
transition: opacity 1s;
}
@media (max-width: 600px) {
header > h1 {
font-size: 36px;
}
}
/*
*
* Push Notifications codelab
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*
*/
/* eslint-env browser, serviceworker, es6 */
'use strict';
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Push Codelab</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.2.1/material.indigo-pink.min.css">
<script defer src="https://code.getmdl.io/1.2.1/material.min.js"></script>
<link rel="stylesheet" href="styles/index.css">
</head>
<body>
<header>
<h1>Push Codelab</h1>
</header>
<main>
<p>Welcome to the push messaging codelab. The button below needs to be
fixed to support subscribing to push.</p>
<p>
<button disabled class="js-push-btn mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect">
Enable Push Messaging
</button>
</p>
<section class="subscription-details js-subscription-details is-invisible">
<p>Once you've subscribed your user, you'd send their subscription to your
server to store in a database so that when you want to send a message
you can lookup the subscription and send a message to it.</p>
<p>To simplify things for this code lab copy the following details
into the <a href="https://web-push-codelab.glitch.me/">Push Companion
Site</a> and it'll send a push message for you, using the application
server keys on the site - so make sure they match.</p>
<pre><code class="js-subscription-json"></code></pre>
</section>
</main>
<script src="scripts/main.js"></script>
<script src="https://code.getmdl.io/1.2.1/material.min.js"></script>
</body>
</html>
/*
*
* Push Notifications codelab
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*
*/
/* eslint-env browser, es6 */
/* eslint-disable no-unused-vars */
'use strict';
const applicationServerPublicKey = 'BCW6JPG-T7Jx0bYKMhAbL6j3DL3VTTib7dwvBjQ' +
'C_496a12auzzKFnjgFjCsys_YtWkeMLhogfSlyM0CaIktx7o';
const pushButton = document.querySelector('.js-push-btn');
let isSubscribed = false;
let swRegistration = null;
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function updateBtn() {
if (isSubscribed) {
pushButton.textContent = 'Disable Push Messaging';
} else {
pushButton.textContent = 'Enable Push Messaging';
}
pushButton.disabled = false;
}
function initializeUI() {
// Set the initial subscription value
swRegistration.pushManager.getSubscription()
.then(function(subscription) {
isSubscribed = !(subscription === null);
if (isSubscribed) {
console.log('User IS subscribed.');
} else {
console.log('User is NOT subscribed.');
}
updateBtn();
});
}
if ('serviceWorker' in navigator && 'PushManager' in window) {
console.log('Service Worker and Push is supported');
navigator.serviceWorker.register('sw.js')
.then(function(swReg) {
console.log('Service Worker is registered', swReg);
swRegistration = swReg;
initializeUI();
})
.catch(function(error) {
console.error('Service Worker Error', error);
});
} else {
console.warn('Push messaging is not supported');
pushButton.textContent = 'Push Not Supported';
}
html {
height: 100%;
}
html, body {
width: 100%;
padding: 0;
margin: 0;
}
body {
min-height: auto;
box-sizing: border-box;
}
header {
padding: 115px 0 32px 0;
background-color: #00bcd4;
color: white;
}
main, header > h1 {
padding: 0 16px;
max-width: 760px;
box-sizing: border-box;
margin: 0 auto;
}
main {
margin: 24px auto;
box-sizing: border-box;
}
pre {
white-space: pre-wrap;
background-color: #EEEEEE;
padding: 16px;
}
pre code {
word-break: break-word;
}
.is-invisible {
opacity: 0;
}
.subscription-details {
transition: opacity 1s;
}
@media (max-width: 600px) {
header > h1 {
font-size: 36px;
}
}
/*
*
* Push Notifications codelab
* Copyright 2015 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*