Skip to content
This repository was archived by the owner on Mar 13, 2018. It is now read-only.

Commit 5c17cfd

Browse files
committed
Notifications
1 parent f05450e commit 5c17cfd

8 files changed

+245
-60
lines changed

database.rules.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"rules": {
3+
"subscriptions": {
4+
"$subscription_id": {
5+
".read": false,
6+
".write": "!data.exists() && newData.exists()",
7+
".validate": "newData.hasChildren(['endpoint', 'keys']) && newData.child('keys').hasChildren(['auth', 'p256dh'])"
8+
}
9+
}
10+
}
11+
}

elements/polymer-summit.html

+50-41
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
<link rel="import" href="fancy-pages.html">
77
<link rel="import" href="service-worker.html">
8+
<link rel="import" href="push-notifications.html">
89

910
<dom-module id="polymer-summit">
1011
<template>
@@ -30,27 +31,47 @@
3031
app-header nav {
3132
background: var(--blue-theme-color);
3233
height: var(--header-height);
34+
display: flex;
3335
}
3436

35-
app-header nav a {
37+
app-header nav a,
38+
push-notifications {
3639
display: inline-block;
3740
margin: 15px;
38-
color: #000;
39-
}
40-
41-
.mobile-header-nav a {
4241
height: 30px;
42+
color: #000;
4343
}
4444

45-
.mobile-header-nav a svg {
45+
app-header nav a svg {
4646
width: 24px;
4747
height: 24px;
4848
padding: 3px;
4949
fill: #fff;
5050
}
5151

5252
.desktop-header-nav {
53-
display: none;
53+
flex: 1;
54+
font-weight: bold;
55+
text-align: center;
56+
visibility: hidden;
57+
}
58+
59+
.desktop-header-nav a:hover {
60+
text-decoration: underline;
61+
}
62+
63+
:host([path="/"]) .desktop-header-nav a[href="/"],
64+
:host([path="/schedule"]) .desktop-header-nav a[href="/schedule"],
65+
:host([path="/speakers"]) .desktop-header-nav a[href="/speakers"] {
66+
color: #fff;
67+
}
68+
69+
push-notifications {
70+
visibility: hidden;
71+
}
72+
73+
push-notifications[notifications-status] {
74+
visibility: visible;
5475
}
5576

5677
app-drawer {
@@ -79,49 +100,33 @@
79100
}
80101

81102
@media (min-width: 768px) {
82-
.mobile-header-nav {
83-
display: none;
103+
.drawer-toggle {
104+
visibility: hidden;
84105
}
85106

86107
.desktop-header-nav {
87-
display: block;
88-
font-weight: bold;
89-
text-align: center;
90-
}
91-
92-
.desktop-header-nav button {
93-
background: none;
94-
border: none;
95-
}
96-
97-
.desktop-header-nav a:hover {
98-
text-decoration: underline;
99-
}
100-
101-
:host([path="/"]) .desktop-header-nav a[href="/"],
102-
:host([path="/schedule"]) .desktop-header-nav a[href="/schedule"],
103-
:host([path="/speakers"]) .desktop-header-nav a[href="/speakers"] {
104-
color: #fff;
108+
visibility: visible;
105109
}
106110
}
107111
</style>
108112

109113
<app-header id="header" reveals effects="waterfall">
110-
<nav class="mobile-header-nav">
111-
<a href="#" on-click="_openDrawer">
114+
<nav>
115+
<a href="#" class="drawer-toggle" on-click="_openDrawer">
112116
<svg><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
113117
</a>
114-
</nav>
115-
<nav class="desktop-header-nav">
116-
<a href="/">Home</a>
117-
<a href="/schedule">Schedule</a>
118-
<a href="/speakers">Speakers</a>
119-
<a href="https://codelabs.developers.google.com/polymer-summit-2016" target="_blank" rel="noopener" data-outbound>
120-
Codelabs
121-
</a>
122-
<a href="https://events.withgoogle.com/polymer-summit-2017/registrations/new/" target="_blank" rel="noopener" data-outbound>
123-
Register
124-
</a>
118+
<div class="desktop-header-nav">
119+
<a href="/">Home</a>
120+
<a href="/schedule">Schedule</a>
121+
<a href="/speakers">Speakers</a>
122+
<a href="https://codelabs.developers.google.com/polymer-summit-2016" target="_blank" rel="noopener" data-outbound>
123+
Codelabs
124+
</a>
125+
<a href="https://events.withgoogle.com/polymer-summit-2017/registrations/new/" target="_blank" rel="noopener" data-outbound>
126+
Register
127+
</a>
128+
</div>
129+
<push-notifications notifications-status="{{notificationsStatus}}"></push-notifications>
125130
</nav>
126131
</app-header>
127132

@@ -148,7 +153,7 @@
148153
<speakers-grid path="/speakers"></speakers-grid>
149154
</fancy-pages>
150155

151-
<service-worker></service-worker>
156+
<service-worker notifications-status="{{notificationsStatus}}"></service-worker>
152157

153158
</template>
154159

@@ -165,6 +170,10 @@
165170
observer: '_pathChanged',
166171
readOnly: true,
167172
reflectToAttribute: true
173+
},
174+
175+
notificationsStatus: {
176+
type: Boolean
168177
}
169178
}
170179
}

elements/push-notifications.html

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<link rel="import" href="../bower_components/polymer/polymer-element.html">
2+
3+
<dom-module id="push-notifications">
4+
<template>
5+
<style>
6+
:host {
7+
width: 30px;
8+
}
9+
10+
a {
11+
color: #fff;
12+
}
13+
14+
:host([disabled]) a {
15+
color: #97ccf1;
16+
pointer-events: none;
17+
}
18+
19+
svg {
20+
width: 24px;
21+
height: 24px;
22+
padding: 3px;
23+
fill: currentColor;
24+
}
25+
26+
:host([notifications-status="unsubscribed"]) .subscribed,
27+
:host([notifications-status="subscribed"]) .unsubscribed {
28+
display: none;
29+
}
30+
</style>
31+
32+
<a href="#" class="unsubscribed" on-click="_subscribe">
33+
<svg><path d="M20 18.69L7.84 6.14 5.27 3.49 4 4.76l2.8 2.8v.01c-.52.99-.8 2.16-.8 3.42v5l-2 2v1h13.73l2 2L21 19.72l-1-1.03zM12 22c1.11 0 2-.89 2-2h-4c0 1.11.89 2 2 2zm6-7.32V11c0-3.08-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68c-.15.03-.29.08-.42.12-.1.03-.2.07-.3.11h-.01c-.01 0-.01 0-.02.01-.23.09-.46.2-.68.31 0 0-.01 0-.01.01L18 14.68z"></path></svg>
34+
</a>
35+
<a href="#" class="subscribed" on-click="_unsubscribe">
36+
<svg><path d="M7.58 4.08L6.15 2.65C3.75 4.48 2.17 7.3 2.03 10.5h2c.15-2.65 1.51-4.97 3.55-6.42zm12.39 6.42h2c-.15-3.2-1.73-6.02-4.12-7.85l-1.42 1.43c2.02 1.45 3.39 3.77 3.54 6.42zM18 11c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2v-5zm-6 11c.14 0 .27-.01.4-.04.65-.14 1.18-.58 1.44-1.18.1-.24.15-.5.15-.78h-4c.01 1.1.9 2 2.01 2z"></path></svg>
37+
</a>
38+
</template>
39+
40+
<script>
41+
42+
class PushNotificationsElement extends Polymer.Element {
43+
44+
static get is() { return 'push-notifications' }
45+
46+
static get properties() {
47+
return {
48+
disabled: {
49+
type: Boolean,
50+
reflectToAttribute: true
51+
},
52+
53+
notificationsStatus: {
54+
type: Boolean,
55+
notify: true,
56+
reflectToAttribute: true
57+
}
58+
}
59+
}
60+
61+
_subscribe() {
62+
// Disable button until flow finishes.
63+
this.disabled = true;
64+
65+
Notification.requestPermission().then((permission) => {
66+
if (permission === 'granted') {
67+
navigator.serviceWorker.getRegistration()
68+
.then((registration) => {
69+
return registration.pushManager.subscribe({
70+
userVisibleOnly: true,
71+
// Bit array of base 64 encoded public key of
72+
// 'BI77qNfNf3S-lcgtLneYKuQyJ80--75XZdrvUAGN3iG3D8b1M41aqYcDcXWPEJkdHuqzZHxojyl3HKtAH1mBQNE');
73+
applicationServerKey: new Uint8Array([4,142,251,168,215,205,127,116,190,149,200,45,46,119,152,42,228,50,39,205,62,251,190,87,101,218,239,80,1,141,222,33,183,15,198,245,51,141,90,169,135,3,113,117,143,16,153,29,30,234,179,100,124,104,143,41,119,28,171,64,31,89,129,64,209])
74+
});
75+
})
76+
.then((subscription) => {
77+
return fetch('https://polymer-summit-2017.firebaseio.com/subscriptions.json', {
78+
method: 'POST',
79+
body: JSON.stringify(subscription)
80+
})
81+
})
82+
.then(() => {
83+
this.notificationsStatus = 'subscribed';
84+
this.disabled = false;
85+
})
86+
.catch((err) => {
87+
this.disabled = false;
88+
});
89+
} else if (permission === 'denied') {
90+
// Keep button permanently disabled, since user will not be prompted to re-enable again.
91+
// TODO: Tell user how to re-enable in Chrome Site Settings.
92+
} else {
93+
this.disabled = false;
94+
}
95+
});
96+
}
97+
98+
_unsubscribe() {
99+
navigator.serviceWorker.getRegistration()
100+
.then((registration) => registration.pushManager.getSubscription())
101+
.then((subscription) => subscription.unsubscribe())
102+
.then(() => {
103+
this.notificationsStatus = 'unsubscribed';
104+
});
105+
}
106+
107+
}
108+
109+
customElements.define(PushNotificationsElement.is, PushNotificationsElement);
110+
111+
</script>
112+
</dom-module>

elements/service-worker.html

+15
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@
5252

5353
static get is() { return 'service-worker' }
5454

55+
static get properties() {
56+
return {
57+
notificationsStatus: {
58+
type: Boolean,
59+
notify: true
60+
}
61+
}
62+
}
63+
5564
ready() {
5665
super.ready();
5766

@@ -68,6 +77,12 @@
6877
}
6978
});
7079
});
80+
81+
if ('PushManager' in window && 'Notification' in window) {
82+
registration.pushManager.getSubscription().then((subscription) => {
83+
this.notificationsStatus = subscription ? 'subscribed' : 'unsubscribed';
84+
});
85+
}
7186
});
7287

7388
// Check to see if the service worker controlling the page at initial load

firebase.json

+38-18
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,52 @@
1515
"headers": [
1616
{
1717
"source": "/",
18-
"headers": [{
19-
"key": "Link",
20-
"value": "</bower_components/webcomponentsjs/webcomponents-loader.js>;rel=preload;as=script,</elements/polymer-summit.html>;rel=preload;as=document"
21-
}]
18+
"headers": [
19+
{
20+
"key": "Link",
21+
"value": "</bower_components/webcomponentsjs/webcomponents-loader.js>;rel=preload;as=script,</elements/polymer-summit.html>;rel=preload;as=document"
22+
}
23+
]
2224
},
2325
{
2426
"source": "/schedule",
25-
"headers": [{
26-
"key": "Link",
27-
"value": "</bower_components/webcomponentsjs/webcomponents-loader.js>;rel=preload;as=script,</elements/polymer-summit.html>;rel=preload;as=document,</elements/schedule-grid.html>;rel=preload;as=document,</data/schedule.json>;rel=preload"
28-
}]
27+
"headers": [
28+
{
29+
"key": "Link",
30+
"value": "</bower_components/webcomponentsjs/webcomponents-loader.js>;rel=preload;as=script,</elements/polymer-summit.html>;rel=preload;as=document,</elements/schedule-grid.html>;rel=preload;as=document,</data/schedule.json>;rel=preload"
31+
}
32+
]
2933
},
3034
{
3135
"source": "/speakers",
32-
"headers": [{
33-
"key": "Link",
34-
"value": "</bower_components/webcomponentsjs/webcomponents-loader.js>;rel=preload;as=script,</elements/polymer-summit.html>;rel=preload;as=document,</elements/speakers-grid.html>;rel=preload;as=document,</data/speakers.json>;rel=preload"
35-
}]
36+
"headers": [
37+
{
38+
"key": "Link",
39+
"value": "</bower_components/webcomponentsjs/webcomponents-loader.js>;rel=preload;as=script,</elements/polymer-summit.html>;rel=preload;as=document,</elements/speakers-grid.html>;rel=preload;as=document,</data/speakers.json>;rel=preload"
40+
}
41+
]
3642
},
3743
{
38-
"source" : "/service-worker.js",
39-
"headers" : [{
40-
"key": "Cache-Control",
41-
"value": "max-age=0"
42-
}]
44+
"source": "/service-worker.js",
45+
"headers": [
46+
{
47+
"key": "Cache-Control",
48+
"value": "max-age=0"
49+
}
50+
]
51+
},
52+
{
53+
"source": "/sw-imported.js",
54+
"headers": [
55+
{
56+
"key": "Cache-Control",
57+
"value": "max-age=0"
58+
}
59+
]
4360
}
4461
]
62+
},
63+
"database": {
64+
"rules": "database.rules.json"
4565
}
46-
}
66+
}

polymer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"data/**/*",
99
"images/**/*",
1010
"code-of-conduct.html",
11-
"manifest.json"
11+
"manifest.json",
12+
"sw-imported.js"
1213
],
1314
"builds": [{
1415
"bundle": true,

0 commit comments

Comments
 (0)