Commit 6e1416ed authored by Anna Kutschka's avatar Anna Kutschka

hosting

parent e1364c43
{
"projects": {
"default": "shoppinglist-db187"
}
}
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page Not Found</title>
<style media="screen">
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px 16px; border-radius: 3px; }
#message h3 { color: #888; font-weight: normal; font-size: 16px; margin: 16px 0 12px; }
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
@media (max-width: 600px) {
body, #message { margin-top: 0; background: white; box-shadow: none; }
body { border-top: 16px solid #ffa100; }
}
</style>
</head>
<body>
<div id="message">
<h2>404</h2>
<h1>Page Not Found</h1>
<p>The specified file was not found on this website. Please check the URL for mistakes and try again.</p>
<h3>Why am I seeing this?</h3>
<p>This page was generated by the Firebase Command-Line Interface. To modify it, edit the <code>404.html</code> file in your project's configured <code>public</code> directory.</p>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Welcome to Firebase Hosting</title>
<!-- update the version number as needed -->
<script defer src="/__/firebase/6.0.2/firebase-app.js"></script>
<!-- include only the Firebase features as you need -->
<script defer src="/__/firebase/6.0.2/firebase-auth.js"></script>
<script defer src="/__/firebase/6.0.2/firebase-database.js"></script>
<script defer src="/__/firebase/6.0.2/firebase-messaging.js"></script>
<script defer src="/__/firebase/6.0.2/firebase-storage.js"></script>
<!-- initialize the SDK after all desired features are loaded -->
<script defer src="/__/firebase/init.js"></script>
<style media="screen">
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px; border-radius: 3px; }
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
@media (max-width: 600px) {
body, #message { margin-top: 0; background: white; box-shadow: none; }
body { border-top: 16px solid #ffa100; }
}
</style>
</head>
<body>
<div id="message">
<h2>Welcome</h2>
<h1>Firebase Hosting Setup Complete</h1>
<p>You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!</p>
<a target="_blank" href="https://firebase.google.com/docs/hosting/">Open Hosting Documentation</a>
</div>
<p id="load">Firebase SDK Loading&hellip;</p>
<script>
document.addEventListener('DOMContentLoaded', function() {
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
// // The Firebase SDK is initialized and available here!
//
// firebase.auth().onAuthStateChanged(user => { });
// firebase.database().ref('/path/to/ref').on('value', snapshot => { });
// firebase.messaging().requestPermission().then(() => { });
// firebase.storage().ref('/path/to/ref').getDownloadURL().then(() => { });
//
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
try {
let app = firebase.app();
let features = ['auth', 'database', 'messaging', 'storage'].filter(feature => typeof app[feature] === 'function');
document.getElementById('load').innerHTML = `Firebase SDK loaded with ${features.join(', ')}`;
} catch (e) {
console.error(e);
document.getElementById('load').innerHTML = 'Error loading the Firebase SDK, check the console.';
}
});
</script>
</body>
</html>
{
"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>Shoppinglist 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">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 -->
<div>
<header class="small-12 column">
<div class="header-wrapper">
<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>Done</p>
</div>
<ul class="todo" id="todo"></ul>
<hr>
</section>
</div>
<p id="title__bottom" style="text-align: center">Made by Anna Kutschka
second child of four, Sandwichkind a lifetime, Queen of Graz,
Master of Beachvolleyballscores, Sprengerin der Hundefesthaltung,
Rechntmäßige Erbin vom Reinerkogel Throne.</p>
</div>
</main>
<!-- Uncomment the line below when ready to test with fake data -->
<script src="scripts/app.js" async></script>
<script src="scripts/syncAllTabs.js" async></script>
<script src="scripts/deferredPrompt.js"></script>
</body>
</html>
{
"name": "ShoppingList",
"short_name": "ShoppingList",
"icons": [{
"src": "images/icons/icon32x32.png",
"sizes": "128x128",
"type": "image/png"
}, {
"src": "images/icons/icon64x64.png",
"sizes": "144x144",
"type": "image/png"
},{
"src": "images/icons/icon.png",
"sizes": "256x256",
"type": "image/png"
}],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#3E4EB8",
"theme_color": "#DB7093"
}
\ 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';
//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
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('../service-worker.js')
.then(function(swReg) {
console.log('Service Worker Registered');
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 {
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;
}
}
});
}).catch(function(error) {
console.error('Service Worker registration error : ', error);
});
}
})();
var deferredPrompt;
var btnSave = document.getElementById('getApp')
window.addEventListener('beforeinstallprompt', function(e) {
console.log('beforeinstallprompt Event fired');
e.preventDefault();
deferredPrompt = e;
return false;
});
btnSave.addEventListener('click', function() {
if(deferredPrompt !== undefined) {
deferredPrompt.prompt();
deferredPrompt.userChoice.then(function(choiceResult) {
console.log(choiceResult.outcome);
if(choiceResult.outcome == 'dismissed') {
console.log('User cancelled home screen install');
}
else {
console.log('User added to home screen');
}
deferredPrompt = null;
});
}
});
\ 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 = 'shoppingData-v1';
var cacheName = 'shoppingPWA-final-1';
var filesToCache = [
'/',
'/index.html',
'/scripts/app.js',
'/scripts/deferredPrompt.js',
'/scripts/syncAllTabs.js',
'/styles/inline.css',
'/images/icons/icon.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();
});
//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)
}
})
})
}
//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();