Offline strategies for HTML5 web applications - pfCongres2012

Preview:

Citation preview

Offline strategies for HTML5 web applicationsStephan Hochdörfer, bitExpert AG

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

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

What does „offline“ mean?

Offline strategies for HTML5 web applications

What does „offline“ mean?

Offline strategies for HTML5 web applications

Application Cache vs. Offline Storage

<!­­ 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 sans­serif; }

/* clock.js */setTimeout(function () {    document.getElementById('clock').value = new Date();}, 1000);

Application Cache for static resources

Offline strategies for HTML5 web applications

Application Cache for static resources

Offline strategies for HTML5 web applications

CACHE MANIFEST# 2012­09­16clock.htmlclock.cssclock.js

cache.manifest - must be served using the text/cache-manifest MIME type.

<!­­ 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>

Application Cache for static resources

Offline strategies for HTML5 web applications

CACHE MANIFEST# 2012­09­16

NETWORK:data.php

CACHE:/main/home/main/app.js/settings/home/settings/app.jshttp://myhost/logo.pnghttp://myhost/check.pnghttp://myhost/cross.png

Application Cache for static resources

Offline strategies for HTML5 web applications

CACHE MANIFEST# 2012­09­16

FALLBACK:/ /offline.html

NETWORK:*

Application Cache for static resources

Offline strategies for HTML5 web applications

Scripting the Application Cache

Offline strategies for HTML5 web applications

// events fired by window.applicationCachewindow.applicationCache.onchecking = function(e) {log("Checking for updates");}window.applicationCache.onnoupdate = function(e) {log("No updates");}window.applicationCache.onupdateready = function(e) {log("Update ready");}window.applicationCache.onobsolete = function(e) {log("Obsolete");}window.applicationCache.ondownloading = function(e) {log("Downloading");}window.applicationCache.oncached = function(e) {log("Cached");}window.applicationCache.onerror = function(e) {log("Error");}

// Log each filewindow.applicationCache.onprogress = function(e) {  log("Progress: downloaded file " + counter);  counter++;};

Scripting the Application Cache

Offline strategies for HTML5 web applications

// 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);

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

1. Files are always(!) served from the application cache.

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

2. The application cache only updates if the content of the manifest itself

has changed!

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

3. If any of the files listed in the CACHE section can't be retrieved, the

entire cache will be disregarded.

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

4. If the manifest file itself can't be retrieved, the cache will ignored!

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

5. Non-cached resources will not load on a cached page!

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

6. The page needs to be reloaded, otherwise the new resources do not

show up!

Application Cache – Some gotchas!

Offline strategies for HTML5 web applications

7. To avoid the risk of caching manifest files set expires headers!

The Data URI scheme

Offline strategies for HTML5 web applications

<!DOCTYPE HTML><html> <head>  <title>The Data URI scheme</title>  <style type="text/css">  ul.checklist li {    margin­left: 20px;    background: white url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==') no­repeat scroll left top;}  </style> </head> <body>  <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot"> </body></html>

The Data URI scheme

Offline strategies for HTML5 web applications

Storing dynamic data locally (in HTML5)

Offline strategies for HTML5 web applications

Storing dynamic data locally (in HTML5)

Offline strategies for HTML5 web applications

Web Storage, Web SQL Database, IndexedDB, File API

Web Storage

Offline strategies for HTML5 web applications

Web Storage

Offline strategies for HTML5 web applications

Very convenient form of offline storage: simple key-value store

Web Storage: 2 different types

Offline strategies for HTML5 web applications

localStorage vs. sessionStorage

var myVar = 123;var myObj = {name: "Stephan"};

// write scalar value to localStoragelocalStorage['myVar'] = myVar;

// read scalar value from localStoragemyVar = localStorage['myVar'];

// write object to localStoragelocalStorage['myObj'] = JSON.stringify(myObj);

// read object from localStoragemyObj = JSON.parse(localStorage['myObj']);

Web Storage: localStorage example

Offline strategies for HTML5 web applications

var myVar = 123;var myObj = {name: "Stephan"};

// write scalar value to sessionStoragesessionStorage['myVar'] = myVar;

// read scalar value from sessionStoragemyVar = sessionStorage['myVar'];

// write object to sessionStoragesessionStorage['myObj'] = JSON.stringify(myObj);

// read object from sessionStoragemyObj = JSON.parse(sessionStorage['myObj']);

Web Storage: sessionStorage example

Offline strategies for HTML5 web applications

function supports_local_storage() {  try {    return 'localStorage' in window &&               window['localStorage'] !== null;  } catch(e){    return false;  }}

Web Storage: Does my browser support it?

Offline strategies for HTML5 web applications

Web Storage: Pro

Offline strategies for HTML5 web applications

Most compatible format up to now.

Web Storage: Con

Offline strategies for HTML5 web applications

The data is not structured.

Web Storage: Con

Offline strategies for HTML5 web applications

No transaction support!

Web SQL Database

Offline strategies for HTML5 web applications

Web SQL Database

Offline strategies for HTML5 web applications

An offline SQL database based on SQLite, an general-purpose SQL engine.

Web SQL Database

Offline strategies for HTML5 web applications

function prepareDatabase(ready, error) {  return openDatabase('documents', '1.0',     'Offline document storage', 5*1024*1024, function (db) {    db.changeVersion('', '1.0', function (t) {      t.executeSql('CREATE TABLE docids (id, name)');    }, error);  });}

function showDocCount(db, span) {  db.readTransaction(function (t) {    t.executeSql('SELECT COUNT(*) AS c FROM docids', [],       function (t, r) {         span.textContent = r.rows[0].c;      }, function (t, e) {         // couldn't read database         span.textContent = '(unknown: ' + e.message + ')';    });  });}

Web SQL Database: Pro

Offline strategies for HTML5 web applications

It`s a SQL database within the browser!

Web SQL Database: Con

Offline strategies for HTML5 web applications

It`s a SQL database within the browser!

Web SQL Database: Con

Offline strategies for HTML5 web applications

SQLite is slooooow!

Web SQL Database: Con

Offline strategies for HTML5 web applications

The specification is no longer part of HTML5!

IndexedDB

Offline strategies for HTML5 web applications

IndexedDB

Offline strategies for HTML5 web applications

A nice compromise between Web Storage and Web SQL Database giving

you the best of both worlds.

Web SQL Database vs. IndexedDB

Offline strategies for HTML5 web applications

Category Web SQL IndexedDB

Location Tables contain columns and rows

objectStore contains Javascript objects and keys

Query Mechanism

SQL Cursor APIs, Key Range APIs, and Application Code

Transaction Lock can happen on databases, tables, or rows on READ_WRITE transactions

Lock can happen on database VERSION_CHANGE transaction, on an objectStore READ_ONLY and READ_WRITE transactions.

Transaction Commits

Transaction creation is explicit. Default is to rollback unless we call commit.

Transaction creation is explicit. Default is to commit unless we call abort or there is an error that is not caught.

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;};

IndexedDB – Creating an ObjectStore

Offline strategies for HTML5 web applications

IndexedDB – Adding data to ObjectStore

Offline strategies for HTML5 web applications

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);  };};

IndexedDB – Retrieving data

Offline strategies for HTML5 web applications

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();    }  }}

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);  };};

IndexedDB – Deleting data

Offline strategies for HTML5 web applications

File API

Offline strategies for HTML5 web applications

File API

Offline strategies for HTML5 web applications

FileReader API and FileWriter API

function onInitFs(fs) {  console.log('Opened file system: ' + fs.name);}

function errorHandler(e) {  console.log('Error: ' + e.code);}

window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);

File API – Requesting access

Offline strategies for HTML5 web applications

window.webkitStorageInfo.requestQuota(    PERSISTENT,     5*1024*1024 /*5MB*/,     function(grantedBytes) {      window.requestFileSystem(PERSISTENT, grantedBytes,          onInitFs, errorHandler);    },     function(e) {      console.log('Error', e);});

File API – Requesting quota

Offline strategies for HTML5 web applications

Offline strategies for HTML5 web applications

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);

File API – Creating a file

Offline strategies for HTML5 web applications

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);

File API – Reading a file

Offline strategies for HTML5 web applications

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);

File API – Writing to a file

Offline strategies for HTML5 web applications

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);

File API – Appending data to a file

Offline strategies for HTML5 web applications

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);

File API – Deleting a file

Offline strategies for HTML5 web applications

File API – Creating directories

Offline strategies for HTML5 web applications

function onInitFs(fs) {   fs.root.getDirectory('MyFolder', {create: true},    function(dirEntry) {    // do stuff...    }, errorHandler);}

window.requestFileSystem(window.TEMPORARY, 5*1024*1024 /*5MB*/, onInitFs, errorHandler);

File API – Browser support?

Offline strategies for HTML5 web applications

Up to now: Chrome only

File API – Browser support?

Offline strategies for HTML5 web applications

But: idb.filesystem.js

Am I online?

Offline strategies for HTML5 web applications

document.body.addEventListener("online", function () {  // browser is online!}

document.body.addEventListener("offline", function () {  // browser is not online!}

Am I online?

Offline strategies for HTML5 web applications

$.ajax({  dataType: 'json',  url: 'http://myappurl.com/ping',  success: function(data){    // ping worked  },  error: function() {    // ping failed ­> Server not reachable  }});

Am I online? Another approach...

Offline strategies for HTML5 web applications

Thank you!

http://joind.in/7073

Recommended