================================================
FILE: js/app.js
================================================
// Registering ServiceWorker
if ( 'serviceWorker' in navigator ) {
navigator.serviceWorker.register( 'sw.js' ).then(function(registration) {
// Registration was successful
console.log( 'ServiceWorker registration successful. Scope: ' + registration.scope )
}).catch(function(err) {
// Registration failed with error
console.log( 'ServiceWorker registration failed. Error: ' + err);
});
}
================================================
FILE: js/cache-polyfill.js
================================================
/**
* 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
*
* 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() {
var nativeAddAll = Cache.prototype.addAll;
var userAgent = navigator.userAgent.match(/(Firefox|Chrome)\/(\d+\.)/);
// Has nice behavior of `var` which everyone hates
if (userAgent) {
var agent = userAgent[1];
var version = parseInt(userAgent[2]);
}
if (
nativeAddAll && (!userAgent ||
(agent === 'Firefox' && version >= 46) ||
(agent === 'Chrome' && version >= 50)
)
) {
return;
}
Cache.prototype.addAll = function addAll(requests) {
var cache = this;
// Since DOMExceptions are not constructable:
function NetworkError(message) {
this.name = 'NetworkError';
this.code = 19;
this.message = message;
}
NetworkError.prototype = Object.create(Error.prototype);
return Promise.resolve().then(function() {
if (arguments.length < 1) throw new TypeError();
// Simulate sequence<(Request or USVString)> binding:
var sequence = [];
requests = requests.map(function(request) {
if (request instanceof Request) {
return request;
}
else {
return String(request); // may throw TypeError
}
});
return Promise.all(
requests.map(function(request) {
if (typeof request === 'string') {
request = new Request(request);
}
var scheme = new URL(request.url).protocol;
if (scheme !== 'http:' && scheme !== 'https:') {
throw new NetworkError("Invalid scheme");
}
return fetch(request.clone());
})
);
}).then(function(responses) {
// If some of the responses has not OK-eish status,
// then whole operation should reject
if (responses.some(function(response) {
return !response.ok;
})) {
throw new NetworkError('Incorrect response status');
}
// TODO: check that requests don't overwrite one another
// (don't think this is possible to polyfill due to opaque responses)
return Promise.all(
responses.map(function(response, i) {
return cache.put(requests[i], response);
})
);
}).then(function() {
return undefined;
});
};
Cache.prototype.add = function add(request) {
return this.addAll([request]);
};
}());
================================================
FILE: js/note-list.js
================================================
$(document).ready(function () {
var noteList = function() {
var $notepad = $(' .notepad' ),
$noteList = $(' .notepad__list' ),
$noteListItem = $( '.notepad__list-item' ),
$noteForm = $( '.notepad__form' ),
$noteFormInput = $( '.notepad__form-input' ),
$clearList = $( '.notepad__clear' ),
clearListDisplay = 'notepad__clear--display',
noteCount = 0;
function displayNotes() {
for (noteCount = 0; noteCount < localStorage.length; noteCount++) {
var noteID = 'task-' + noteCount;
// Build note list
$noteList.append("
" + localStorage.getItem(noteID) + "
");
// Show reset button
$clearList.addClass( clearListDisplay );
}
}
function storeNote() {
if ( $noteFormInput.val() !== '' ) {
var noteID = 'task-' + noteCount,
task = $( '#' + noteID ),
taskMessage = $noteFormInput.val();
localStorage.setItem( noteID, taskMessage );
// Add to note list
$noteList.append( "
" + taskMessage + "
" );
// Display reset button
if ( !$clearList.hasClass( clearListDisplay ) ) {
$clearList.addClass( clearListDisplay );
}
// Reset
$noteFormInput.val('');
noteCount++;
}
}
function clearNotes() {
// Update DOM
$noteList.empty();
$clearList.removeClass( clearListDisplay );
// Clear storage
localStorage.clear();
noteCount = 0;
}
function bindEvents() {
// Show any existing notes from localStorage
displayNotes();
// Create new note
$noteForm.on( 'submit', function () {
storeNote();
return false;
});
// Reset notes
$clearList.on( 'click', function () {
clearNotes();
});
}
bindEvents();
};
noteList();
});
================================================
FILE: manifest.json
================================================
{
"short_name": "notes",
"name": "notes",
"description" : "An offline-capable notes app, using localStorage and ServiceWorker",
"display": "standalone",
"orientation": "portrait",
"start_url": "index.html",
"theme_color": "#ffffff",
"background_color": "#ffffff",
"icons": [
{
"src": "img/icon-60.png",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "img/icon-114.png",
"sizes": "114x114",
"type": "image/png"
},
{
"src": "img/icon-152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "img/icon-558.png",
"sizes": "558x558",
"type": "image/png"
}
]
}
================================================
FILE: sw.js
================================================
// Polyfill for Chrome caching
importScripts('js/cache-polyfill.js');
// Install the ServiceWorker
self.addEventListener('install', function(event) {
event.waitUntil(
// Open a cache
caches.open('v1').then(function(cache) {
// Define what we want to cache
return cache.addAll([
'/',
'index.html',
'js/app.js',
'js/jquery.min.js',
'js/note-list.js',
'css/style.css',
'favicon.ico',
'manifest.json',
'img/icon-60.png',
'img/icon-114.png',
'img/icon-152.png',
'img/icon-558.png'
]);
})
);
});
// Use ServiceWorker (or not) to fetch data
self.addEventListener('fetch', function(event) {
event.respondWith(
// Look for something in the cache that matches the request
caches.match(event.request).then(function(response) {
// If we find something, return it
// Otherwise, use the network instead
return response || fetch(event.request);
})
);
});