...
 
Commits (4)
......@@ -37,14 +37,14 @@
<body>
<header class="header">
<h1 class="header__title">Shopping List</h1>
<h1 class="header__title">Shopping List PWA</h1>
<button id="getApp">
<p id="addText">Add to home screen</p>
</button>
</header>
<main class="main">
<button class="pushButton" id="pushButton">Enable Push Notications for your Shoppinglist</button>
<div class="card cardTemplate" >
<!-- Shopping list von https://scrimba.com/c/cZa6qA6 -->
......@@ -52,19 +52,17 @@
<div>
<header class="small-12 column">
<div class="header-wrapper">
<input type="text" placeholder="type here" id="item">
<input id="newTodoItem" type="text" placeholder="type here">
<button id="add"> <span>+</span></button>
</div>
</header>
<section class="content" id="content">
<h4>Todo</h4>
<div id="button__text">
<p>Delete Done</p>
<p>Done</p>
</div>
<ul class="todo" id="todo"></ul>
<hr>
<h4>completed</h4>
<ul class="todo" id="completed"></ul>
</section>
</div>
<p id="title__bottom" style="text-align: center">Made by Anna Kutschka
......@@ -76,7 +74,7 @@
<!-- Uncomment the line below when ready to test with fake data -->
<script src="scripts/app.js" async></script>
<script src="scripts/shopping.js" async></script>
<script src="scripts/syncAllTabs.js" async></script>
<script src="scripts/deferredPrompt.js"></script>
</body>
</html>
......@@ -16,33 +16,274 @@
(function() {
'use strict';
var app = {};
//Push Nootification
//https://developers.google.com/web/fundamentals/codelabs/push-notifications/
const applicationServerPublicKey = 'BAC5t0bQ4Mxg-ps34zqYsfIm5ni9ARdFHvPqEK1Vc53O7kYsIHcIxLxTRUZ-FLwM8fKBK4j6Ti4tgghw3b3QZiw';
const pushButton = document.getElementById('pushButton')
let serviceWorker = null;
let isSubscribed = false;
function initializeUI() {
pushButton.addEventListener('click', function() {
pushButton.disabled = true;
if (isSubscribed) {
unsubscribeUser();
} else {
subscribeUser();
}
});
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;
}
// Set the initial subscription value
serviceWorker.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 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 subscribeUser() {
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
sw.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 unsubscribeUser() {
serviceWorker.pushManager.getSubscription()
.then(function(subscription) {
if (subscription) {
return subscription.unsubscribe();
}
})
.catch(function(error) {
console.log('Error unsubscribing', error);
})
.then(function() {
updateSubscriptionOnServer(null);
console.log('User is unsubscribed.');
isSubscribed = false;
updateBtn();
});
}
function updateSubscriptionOnServer(subscription) {
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');
}
}
//Shoppinglist
let data = (localStorage.getItem('todoList')) ? JSON.parse(localStorage.getItem('todoList')):{
todo: []
};
let list = document.getElementById('buy');
renderTodoList();
// User clicked on the add button
// if there is any t ext inside the item field add that text to the todo list
document.getElementById('add').addEventListener('click', function() {
var value = document.getElementById('newTodoItem').value;
if (value) {
addItem(value);
}
});
document.getElementById('newTodoItem').addEventListener('keydown', function (e) {
var value = this.value;
if (e.code === 'Enter' && value) {
addItem(value);
}
});
function addItem (value) {
addItemToDOM(value);
document.getElementById('newTodoItem').value = '';
data.todo.push(value);
dataObjectUpdated();
}
function renderTodoList() {
if (!data.todo.length) return;
for (var i = 0; i < data.todo.length; i++) {
var value = data.todo[i];
addItemToDOM(value);
}
}
function refreshShoppingList() {
console.log('refresh')
}
function dataObjectUpdated() {
localStorage.setItem('todoList', JSON.stringify(data));
}
function removeItem() {
let item = this.parentNode.parentNode;
let value = item.innerText;
const isStriked = item.classList.contains('strike')
if (isStriked) {
data.done.splice(data.done.indexOf(value), 1);
} else {
data.buy.splice(data.buy.indexOf(value), 1);
}
dataObjectUpdated(value, 'remove');
list.removeChild(item);
}
function completeItem() {
var item = this.parentNode.parentNode
var parent = item.parentNode;
var id = parent.id;
var value = item.innerText;
if (id === 'todo') {
data.todo.splice(data.todo.indexOf(value), 1);
data.completed.push(value);
stateToServiceWorker(false, value)
}
dataObjectUpdated();
// Check if item should be added to completed or re-added to todo
var target = (id === 'todo') ? document.getElementById('completed'):document.getElementById('todo')
parent.removeChild(item);
target.insertBefore(item, target.childNodes[0]);
}
// adds new item to the todo list
function addItemToDOM(text, isCompleted = false ) {
var item = document.createElement('li');
item.innerText = text;
if (isCompleted) {
item.classList.add('strike');
}
var buttons = document.createElement('div');
buttons.classList.add('buttons');
var remove = document.createElement('button');
remove.classList.add('remove');
// add click event for removing items
remove.addEventListener('click', removeItem)
buttons.appendChild(remove);
item.appendChild(buttons);
list.appendChild(item);
list.insertBefore(item, list.childNodes[0]);
}
function createStrikedItem(item) {
item.classList.add('strike');
let buttons = item.childNodes[1];
let butDone = buttons.childNodes[1];
buttons.removeChild(butDone);
return item;
}
//Service worker
// TODO add service worker code here
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../service-worker.js')
.then(function() {
.then(function(swReg) {
console.log('Service Worker Registered');
return navigator.serviceWorker.ready;
serviceWorker = swReg;
initializeUI();
return navigator.serviceWorker.ready;
})
.then(function(reg) {
navigator.serviceWorker.addEventListener('message', function(event){
//for tab sync
if(event.data == null) console.log('Data is null')
else {
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage(event.data);
console.log(event.data)
if(todo) {
//data is in todo list
console.log('App.js Data in Todo list: ', event.data)
//addItem(event.data)
}
else {
//data is in completed list
console.log('App.js Data in Completed list: ', event.data)
//completeItem()
}
switch(event.data.action) {
case 'add':
addItemToDOM(event.data.value);
return;
case 'remove':
const itemToRemove = findElement(event.data.value);
list.removeChild(itemToRemove);
return;
default:
return;
}
}
});
......
......@@ -4,8 +4,6 @@ var btnSave = document.getElementById('getApp')
window.addEventListener('beforeinstallprompt', function(e) {
console.log('beforeinstallprompt Event fired');
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
return false;
......@@ -13,11 +11,7 @@ window.addEventListener('beforeinstallprompt', function(e) {
btnSave.addEventListener('click', function() {
if(deferredPrompt !== undefined) {
// The user has had a positive interaction with our app and Chrome
// has tried to prompt previously, so let's show the prompt.
deferredPrompt.prompt();
// Follow what the user has done with the prompt.
deferredPrompt.userChoice.then(function(choiceResult) {
console.log(choiceResult.outcome);
......@@ -28,8 +22,6 @@ btnSave.addEventListener('click', function() {
else {
console.log('User added to home screen');
}
// We no longer need the prompt. Clear it up.
deferredPrompt = null;
});
}
......
var data = (localStorage.getItem('todoList')) ? JSON.parse(localStorage.getItem('todoList')):{
todo: [],
completed: []
};
// Remove and complete icons in svg format
var removeSVG = ''
var completeSVG = ''
renderTodoList();
// User clicked on the add button
// if there is any t ext inside the item field add that text to the todo list
document.getElementById('add').addEventListener('click', function() {
var value = document.getElementById('item').value;
if (value) {
addItem(value);
stateToServiceWorker(true, value)
}
});
document.getElementById('item').addEventListener('keydown', function (e) {
var value = this.value;
if (e.code === 'Enter' && value) {
addItem(value);
}
});
function addItem (value) {
addItemToDOM(value);
document.getElementById('item').value = '';
data.todo.push(value);
dataObjectUpdated();
}
function renderTodoList() {
if (!data.todo.length && !data.completed.length) return;
for (var i = 0; i < data.todo.length; i++) {
var value = data.todo[i];
addItemToDOM(value);
}
for (var j = 0; j < data.completed.length; j++) {
var value = data.completed[i];
addItemToDOM(value, true);
}
}
function dataObjectUpdated() {
localStorage.setItem('todoList', JSON.stringify(data));
}
function removeItem() {
var item = this.parentNode.parentNode;
var parent = item.parentNode;
var id = parent.id;
var value = item.innerText;
if (id === 'todo') {
data.todo.splice(data.todo.indexOf(value), 1);
} else {
data.completed.splice(data.completed.indexOf(value), 1);
}
dataObjectUpdated();
parent.removeChild(item);
}
function completeItem() {
var item = this.parentNode.parentNode
var parent = item.parentNode;
var id = parent.id;
var value = item.innerText;
if (id === 'todo') {
data.todo.splice(data.todo.indexOf(value), 1);
data.completed.push(value);
stateToServiceWorker(false, value)
} else {
data.completed.splice(data.completed.indexOf(value), 1);
data.todo.push(value);
}
dataObjectUpdated();
// Check if item should be added to completed or re-added to todo
var target = (id === 'todo') ? document.getElementById('completed'):document.getElementById('todo')
parent.removeChild(item);
target.insertBefore(item, target.childNodes[0]);
}
// adds new item to the todo list
function addItemToDOM(text, completed) {
var list = (completed) ? document.getElementById('completed'):document.getElementById('todo');
var item = document.createElement('li');
item.innerText = text;
var buttons = document.createElement('div');
buttons.classList.add('buttons');
var remove = document.createElement('button');
remove.classList.add('remove');
remove.innerHTML = removeSVG;
// add click event for removing items
remove.addEventListener('click', removeItem)
var complete = document.createElement('button');
complete.classList.add('complete');
complete.innerHTML = completeSVG;
// add click event for completing todo items
complete.addEventListener('click', completeItem);
buttons.appendChild(remove);
buttons.appendChild(complete);
item.appendChild(buttons);
list.appendChild(item);
list.insertBefore(item, list.childNodes[0]);
}
function stateToServiceWorker(todo, data){
if(data == null) console.log('Data is null')
else {
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage(data);
console.log(data)
if(todo) {
//data is in todo list
console.log('Data in Todo list: ', data)
//addItem(data)
}
else {
//data is in completed list
console.log('Data in Completed list: ', data)
//addItem(data)
}
}
}
}
\ No newline at end of file
function stateToServiceWorker(todo, data){
if(data == null) {
console.log('Data is null')
}
else {
if (navigator.serviceWorker && navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage(data);
console.log(data)
}
}
}
function syncOnChangedList(changes){
stateToServiceWorker(changes)
}
var dataCacheName = 'weatherData-v1';
var cacheName = 'weatherPWA-final-1';
var dataCacheName = 'shoppingData-v1';
var cacheName = 'shoppingPWA-final-1';
var filesToCache = [
'/',
'/index.html',
'/scripts/app.js',
'/scripts/shopping.js',
'/scripts/deferredPrompt.js',
'/scripts/syncAllTabs.js',
'/styles/inline.css',
'/images/icons/icon.png'
];
......@@ -68,4 +69,39 @@ self.syncTabState = function(data, clientId){
}
})
})
}
\ No newline at end of file
}
//push notification
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: 'You have new Items in your Shoppinglist',
icon: 'images/icon.png',
badge: 'images/icon.png'
};
event.waitUntil(self.registration.showNotification(title, options));
});
self.addEventListener('notificationclick', function(event) {
console.log('[Service Worker] Notification click Received.');
event.notification.close();
event.waitUntil(
clients.openWindow('')
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
......@@ -322,9 +322,7 @@ body {
background-color:#ccc; }
header button#add:active {
background-color:#ccc; }
ul.todo {
}
ul.todo#todo::after, ul.todo#completed::after {
text-align: center;
width: 100%;
......@@ -428,9 +426,8 @@ body {
#getApp{
width: auto;
height: auto;
border: 0;
padding: 2px;
background: #fff;
background: white;
color: black;
font-size: 12px;
-webkit-box-align: center;
......@@ -439,4 +436,21 @@ body {
-ms-flex-pack: center;
}
#pushButton{
width: auto;
height: auto;
border: 1px;
border-color: #DB7093;
margin: 10px;
padding: 2px;
color: white;
padding: 5px;
background: #DB7093;
font-size: 12px;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
}
\ No newline at end of file