2. Offline strategies for HTML5 web applications
About me
Stephan Hochdörfer, bitExpert AG
Department Manager Research Labs
enjoying PHP since 1999
S.Hochdoerfer@bitExpert.de
@shochdoerfer
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13. Offline strategies for HTML5 web applications
[...] we take the next step,
announcing 2014 as the target for
Recommendation.
Jeff Jaffe, Chief Executive Officer, World Wide Web Consortium
16. Offline strategies for HTML5 web applications
What does „offline“ mean?
Application Cache vs. Offline Storage
17. Offline strategies for HTML5 web applications
Application Cache for static resources
<! clock.html >
<!DOCTYPE HTML>
<html>
<head>
<title>Clock</title>
<script src="clock.js"></script>
<link rel="stylesheet" href="clock.css">
</head>
<body>
<p>The time is: <output id="clock"></output></p>
</body>
</html>
/* clock.css */
output { font: 2em sansserif; }
/* clock.js */
setTimeout(function () {
document.getElementById('clock').value = new Date();
}, 1000);
18. Offline strategies for HTML5 web applications
Application Cache for static resources
cache.manifest - must be served using the text/cache-manifest
MIME type.
CACHE MANIFEST
# 20120916
clock.html
clock.css
clock.js
19. Offline strategies for HTML5 web applications
Application Cache for static resources
<! clock.html >
<!DOCTYPE HTML>
<html manifest="cache.manifest">
<head>
<title>Clock</title>
<script src="clock.js"></script>
<link rel="stylesheet" href="clock.css">
</head>
<body>
<p>The time is: <output id="clock"></output></p>
</body>
</html>
20. Offline strategies for HTML5 web applications
Application Cache for static resources
CACHE MANIFEST
# 20120916
NETWORK:
data.php
CACHE:
/main/home
/main/app.js
/settings/home
/settings/app.js
http://myhost/logo.png
http://myhost/check.png
http://myhost/cross.png
21. Offline strategies for HTML5 web applications
Application Cache for static resources
CACHE MANIFEST
# 20120916
FALLBACK:
/ /offline.html
NETWORK:
*
23. Offline strategies for HTML5 web applications
Scripting the Application Cache
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
window.applicationCache.addEventListener('updateready',
function(e) {
if(window.applicationCache.status ==
window.applicationCache.UPDATEREADY) {
// Browser downloaded a new app cache.
// Swap it in and reload the page
window.applicationCache.swapCache();
if (confirm('New version is available. Load it?)) {
window.location.reload();
}
} else {
// Manifest didn't changed.
}
}, false);
}, false);
25. Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
1. Files are always(!) served from the
application cache.
26. Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
2. The application cache only updates
if the content of the manifest itself
has changed!
27. Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
3. If any of the files listed in the
CACHE section can't be retrieved, the
entire cache will be disregarded.
28. Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
4. If the manifest file itself can't be
retrieved, the cache will ignored!
29. Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
5. Non-cached resources will not load
on a cached page!
30. Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
6. The page needs to be reloaded,
otherwise the new resources do not
show up!
31. Offline strategies for HTML5 web applications
Application Cache – Some gotchas!
7. To avoid the risk of caching
manifest files set expires headers!
33. Offline strategies for HTML5 web applications
The Data URI scheme
<!DOCTYPE HTML>
<html>
<head>
<title>The Data URI scheme</title>
<style type="text/css">
ul.checklist li {
marginleft: 20px;
background: white
url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAA
AFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAA
O9TXL0Y4OHwAAAABJRU5ErkJggg==') norepeat scroll left
top;
}
</style>
</head>
<body>
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAA
AFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAA
O9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">
</body>
</html>
37. Offline strategies for HTML5 web applications
Web Storage
Very convenient form of offline
storage: simple key-value store
38. Offline strategies for HTML5 web applications
Web Storage: 2 different types
localStorage vs. sessionStorage
39. Offline strategies for HTML5 web applications
Web Storage: localStorage example
var myVar = 123;
var myObj = {name: "Stephan"};
// write scalar value to localStorage
localStorage.setItem('myVar', myVar);
// read scalar value from localStorage
myVar = localStorage.getItem('myVar');
// write object to localStorage
localStorage.setItem('myObj', JSON.stringify(myObj));
// read object from localStorage
myObj = JSON.parse(localStorage.getItem('myObj'));
40. Offline strategies for HTML5 web applications
Web Storage: localStorage example
var myVar = 123;
var myObj = {name: "Stephan"};
// write scalar value to localStorage
localStorage['myVar'] = myVar;
// read scalar value from localStorage
myVar = localStorage['myVar'];
// write object to localStorage
localStorage['myObj'] = JSON.stringify(myObj);
// read object from localStorage
myObj = JSON.parse(localStorage['myObj']);
41. Offline strategies for HTML5 web applications
Web Storage: sessionStorage example
var myVar = 123;
var myObj = {name: "Stephan"};
// write scalar value to sessionStorage
sessionStorage['myVar'] = myVar;
// read scalar value from sessionStorage
myVar = sessionStorage['myVar'];
// write object to sessionStorage
sessionStorage['myObj'] = JSON.stringify(myObj);
// read object from sessionStorage
myObj = JSON.parse(sessionStorage['myObj']);
42. Offline strategies for HTML5 web applications
Web Storage: Does my browser support it?
function supports_local_storage() {
try {
return 'localStorage' in window &&
window['localStorage'] !== null;
} catch(e){
return false;
}
}
43. Offline strategies for HTML5 web applications
Web Storage: Pro
Most compatible format up to now.
44. Offline strategies for HTML5 web applications
Web Storage: Con
The data is not structured.
56. Offline strategies for HTML5 web applications
IndexedDB
A nice compromise between Web
Storage and Web SQL Database giving
you the best of both worlds.
57. Offline strategies for HTML5 web applications
Web SQL Database vs. IndexedDB
Category Web SQL IndexedDB
Location Tables contain columns and objectStore contains Javascript objects and
rows keys
Query SQL Cursor APIs, Key Range APIs, and
Mechanism Application Code
Transaction Lock can happen on Lock can happen on database
databases, tables, or rows VERSION_CHANGE transaction, on an
on READ_WRITE objectStore READ_ONLY and
transactions READ_WRITE transactions.
Transaction Transaction creation is Transaction creation is explicit. Default is to
Commits explicit. Default is to rollback commit unless we call abort or there is an
unless we call commit. error that is not caught.
58. Offline strategies for HTML5 web applications
IndexedDB – Creating an ObjectStore
indexedDB.open = function() {
var request = indexedDB.open("todos");
request.onsuccess = function(e) {
var v = "2.0 beta";
todoDB.indexedDB.db = e.target.result;
var db = todoDB.indexedDB.db;
if (v!= db.version) {
var setVrequest = db.setVersion(v);
setVrequest.onfailure = todoDB.indexedDB.onerror;
setVrequest.onsuccess = function(e) {
if (db.objectStoreNames.contains("todo")) {
db.deleteObjectStore("todo");
}
var store = db.createObjectStore("todo",
{keyPath: "timeStamp"});
todoDB.indexedDB.getAllTodoItems();
};
} else {
todoDB.indexedDB.getAllTodoItems();
}
};
request.onfailure = todoDB.indexedDB.onerror;
};
59. Offline strategies for HTML5 web applications
IndexedDB – Adding data to ObjectStore
indexedDB.addTodo = function() {
var db = todoDB.indexedDB.db;
var trans = db.transaction(['todo'],
IDBTransaction.READ_WRITE);
var store = trans.objectStore('todo');
var data = {
"text": todoText,
"timeStamp": new Date().getTime()
};
var request = store.put(data);
request.onsuccess = function(e) {
todoDB.indexedDB.getAllTodoItems();
};
request.onerror = function(e) {
console.log("Failed adding items due to: ", e);
};
};
60. Offline strategies for HTML5 web applications
IndexedDB – Retrieving data
function show() {
var request = window.indexedDB.open("todos");
request.onsuccess = function(event) {
var db = todoDB.indexedDB.db;
var trans = db.transaction(["todo"],
IDBTransaction.READ_ONLY);
var request = trans.objectStore("todo").openCursor();
var ul = document.createElement("ul");
request.onsuccess = function(event) {
var cursor = request.result || event.result;
// If cursor is null, enumeration completed
if(!cursor) {
document.getElementById("todos").appendChild(ul);
return;
}
var li = document.createElement("li");
li.textContent = cursor.value.text;
ul.appendChild(li);
cursor.continue();
}
}
}
61. Offline strategies for HTML5 web applications
IndexedDB – Deleting data
indexedDB.deleteTodo = function(id, text) {
var db = todoDB.indexedDB.db;
var trans = db.transaction(["todo"],
IDBTransaction.READ_WRITE);
var store = trans.objectStore("todo");
var request = store.delete(id);
request.onsuccess = function(e) {
todoDB.indexedDB.getAllTodoItems();
};
request.onerror = function(e) {
console.log("Error Adding: ", e);
};
};
67. Offline strategies for HTML5 web applications
File API – Creating a file
function onInitFs(fs) {
fs.root.getFile('log.txt',
{create: true, exclusive: true},
function(fileEntry) {
// fileEntry.name == 'log.txt'
// fileEntry.fullPath == '/log.txt'
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024
/*5MB*/, onInitFs, errorHandler);
68. Offline strategies for HTML5 web applications
File API – Reading a file
function onInitFs(fs) {
fs.root.getFile('log.txt', {},
function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea =
document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024
/*5MB*/, onInitFs, errorHandler);
69. Offline strategies for HTML5 web applications
File API – Writing to a file
function onInitFs(fs) {
fs.root.getFile('log.txt', {create: true},
function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.onwriteend = function(e) {
console.log('Write completed.');
};
fileWriter.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
var bb = new BlobBuilder();
bb.append('Lorem Ipsum');
fileWriter.write(bb.getBlob('text/plain'));
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024
/*5MB*/, onInitFs, errorHandler);
70. Offline strategies for HTML5 web applications
File API – Appending data to a file
function onInitFs(fs) {
fs.root.getFile('log.txt', {create: false},
function(fileEntry) {
fileEntry.createWriter(function(fileWriter) {
fileWriter.seek(fileWriter.length);
var bb = new BlobBuilder();
bb.append('Hello World');
fileWriter.write(bb.getBlob('text/plain'));
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024
/*5MB*/, onInitFs, errorHandler);
71. Offline strategies for HTML5 web applications
File API – Deleting a file
function onInitFs(fs) {
fs.root.getFile('log.txt', {create: false},
function(fileEntry) {
fileEntry.remove(function() {
console.log('File removed.');
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024
/*5MB*/, onInitFs, errorHandler);
72. Offline strategies for HTML5 web applications
File API – Creating directories
function onInitFs(fs) {
fs.root.getDirectory('MyFolder', {create: true},
function(dirEntry) {
// do stuff...
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 5*1024*1024
/*5MB*/, onInitFs, errorHandler);
73.
74. Offline strategies for HTML5 web applications
File API – Browser support?
Up to now: Chrome only
75. Offline strategies for HTML5 web applications
File API – Browser support?
But: idb.filesystem.js
77. Offline strategies for HTML5 web applications
Am I online?
document.body.addEventListener("online", function () {
// browser is online!
}
document.body.addEventListener("offline", function () {
// browser is not online!
}
78. Offline strategies for HTML5 web applications
Am I online? Another approach...
$.ajax({
dataType: 'json',
url: 'http://myappurl.com/ping',
success: function(data){
// ping worked
},
error: function() {
// ping failed > Server not reachable
}
});