1. Présentation et enjeux

Le mode de consultation des pages hors connexion est pris en charge par l'API Offline Application Caching mais on retrouvera sur la toile des expressions comme Application Cache ou AppCache.

Le Html5 a élaboré un dispositif afin de pouvoir consulter des applications du navigateur et l'application reste consultable même lorsque l'utilisateur est déconnecté. Si une page ou une applic ation Web a été mise offline, grâce à cette API le navigateur peut alors utiliser (de façon transparente) la copie en cache.

Tous les navigateurs offrent une certaine forme de mise en cache, mais le fonctionnement de l'API AppCache est différent du processus normal de mise en cache du navigateur. Le cache du navigateur contient normalement les pages et leurs ressources associées qui ont été précédemment visitées. L'API AppCache permet au développeur de spécifier quelles pages et quelles ressources (fichiers js ou css, images, etc.) doivent être mises en cache.

Des applications Web qui continue nt à fonctionner même quand la connexion Internet est coupée n'ont pas beaucoup de sens avec la qualité de connexions actuelles lors de vos visites sur la toile à votre domicile. Par contre, si vous consultez le net à partir de vo tre smartphone, la traversée d'un tunnel, un trajet en métro, la prise d'un ascenseur ou un voyage dans une zone sans couverture 3G risquent de couper beaucoup plus fréquemment votre connexion et donc l'application que vous êtes en trai n de consulter. Cette API offline est donc principalement destin ée aux téléphones portables, qui sont susceptibles de subir plus régulièrem ent des problèmes de déconnexion. On est donc en quelque sorte face à des ap plications "hybrides" qui fonctionnent à la fois en ligne (online) et hors connexion (offline).

Cette navigation offline présente les avantages :
  • De toujours être disponible, qu'il y ait ou non une connexion Internet.
  • D'être rapide car les fichiers, localement en cache, se chargent plus rapidement.
  • De réduire la charge du serveur en réduisant les requêtes à celui-ci.

Sécurité

Seul Firefox demande votre autorisation pour mettre en cache des données en cas d'utilisation hors connexion.

Image non disponible
Autorisation Firefox

Les autres navigateurs n'avertissent pas de la mise en cache des fichiers et le font de façon automatique et transparente pour l'utilisateur.

Débogage

Lorsque l'on débugue et teste une application Web utilisant la mise en cache, il n'est pas inutile de démarrer à partir d'une situation saine. Pour ce faire, il est conseillé de vider le cache au départ ou en cours de mise au point.

Image non disponible
Firefox : Options - Avancé - onglet Réseau
Image non disponible

Chrome : Outil Image non disponible - Outils - Effacer les données de navigation

Pour Chrome, il est possible de ne supprimer que des applications mises en cache spécifiques en encodant chrome://appcache-internals dans la barre d'adresse.

Image non disponible

Safari: Outil Image non disponible Réinitialiser Safari

Image non disponible

Opera :Outils - Supprimer les données privées - Effacer tout le cache

Image non disponible

Les exemples et vos essais ne fonctionneront que par l'intermédiaire d'un serveur local ou en ligne.

2. Disponibilité de l'API

Cette API est reconnue par les navigateurs suivants :
  • Internet Explorer 10+
  • Firefox 3.6+
  • Safari 4+
  • Google Chrome 5+
  • Opera 10.6+
Concernant les smartphones ou tablettes, l'API est disponible pour les navigateurs suivants :
  • iOS Safari 3.2+
  • Android 2.1+
  • Opera Mobile 11+

Pour tester la disponibilité de l'API, on vérifie la présence de l'objet applicationCache de window. Ce qui peut donner le code suivant:

 
Sélectionnez
if(window.applicationCache) {
// Le navigateur supporte les applications offline 
}

ou

 
Sélectionnez
if (!window.applicationCache){
alert("Votre navigateur ne prend pas en charge les applications
offline");
}

Exemple

Testons la disponibilité sous Internet Explorer 8.

Image non disponible
Le code
Sélectionnez
<!DOCTYPE html>
<html lang="fr">
<head>
<title>Les API JavaScript du Html5</title>
<meta charset=utf-8>
<style type="text/css">
#box { border: 1px solid black;
    background-color: rgb(195,215,235);
    padding-left: 3px;
    text-align: center;}
</style>
<script type="text/javascript">
function init(){
if (!window.applicationCache){
msg = "L'API Offline n'est pas prise en charge";
document.querySelector('#box').innerHTML =  msg;
}
else {
msg = "L'API Offline est prise en charge";
document.querySelector('#box').innerHTML =  msg;
} 
}
</script>
</head>
<body onload="init();">
<h2>applicationCache</h2>  
<div id="box">&nbsp;</div>
</body>
</html>

Pour cette API, il peut aussi être utile de tester la disponibilité de la connexion.Connecté :

Image non disponible

Hors ligne :

Image non disponible

Pour tester hors ligne une application si tuée sur un serveur distant, il suffit de débrancher votre connexion Internet et de recharger ou d'actualiser la page.

Si vous testez une application située sur un serveur local, il faut arrêter le fonctionnement du serveur local et recharger la page

Image non disponible
Le code
Sélectionnez
 <!DOCTYPE html>
            <html lang="fr">
            <head>
            <title>Les API JavaScript du Html5</title>
            <meta charset=utf-8>
            <style type="text/css">
            #box { width: 80px;
            border: 1px solid black;
            text-align: center;
            margin : auto;}
            .offline { background: #c00;}
            .online { background: #0c0;}
            </style>
            <script type="text/javascript">
            function init(){
            if (!window.applicationCache){
            msg = "L'API Offline n'est pas prise en charge";
            document.querySelector('#box').innerHTML =  msg;
            }
            if (window.navigator.onLine) {
            document.querySelector('#box').className= 'online';
            msg = "Connecté";
            document.querySelector('#box').innerHTML =  msg;
            } else {
            document.querySelector('#box').className= 'offline';
            msg = "Déconnecté";
            document.querySelector('#box').innerHTML =  msg;
            }
            } 
            </script>
            </head>
            <body onload="init();">
            <h2>applicationCache</h2>  
            <div id="box">&nbsp;</div>
            </body>
            </html>

            

Commentaire On aurait également pu utiliser des gestionnaires d'événements DOM 2.

 
Sélectionnez
 window.addEventListener("offline", function(e) {
            alert("offline");
            }, false);
            window.addEventListener("online", function(e) {
            alert("online");
            }, false);
            

3. Le fichier de mise en cache (manifest)

La gestion de la mise en cache des fichiers est prise en charge par un fichier appelé manifeste ( manifest) qui est un simple fichier de texte brut en UTF-8.Il permet au développeur de spécifier les fichiers et ressources qui doivent être mis en cache par le navigateur. Une fois mis en cache, l'utilisateur retrouvera ces fichiers en local sans dépendre du serveur ou de la connexion.

Le navigateur télécharge les ressources seulement lorsqu'elles sont modifiées ou mises à jour.

Précisons que ce fichier manifeste :
  • Comporte l'extension .appcache (text/cache-manifest). Cette extension est recommandée par le W3C depuis le 15 ju in 2011. Vous risquez de retrouver sur la toile des tutoriels utilisant l'ancienne dénomination, .manifest.
  • Il faudra vous assurer que votre serveur ou le serveur de votre hébergeur reconnaisse ce Mime-Type.
  • Le fichier manifeste commence toujours par la mention CACHE MANIFEST (obligatoirement en majuscules).
  • Les commentaires éventuels sont précédés par le signe #.
  • Pour qu'il soit fonctionnel, ce manife ste doit être déclaré dans le fichier Html : html manifest= "nom du fichier.appcache"
  • Il est possible d'ajouter des lignes vides pour la lisibilité du fichier.

Le manifeste comporte trois sectio ns : CACHE, NETWORK et FALLBACK.

CACHE Liste les fichiers et ressources à mettre en cache.
NETWORK Liste les ressources qui ne sont disponibles qu'en ligne (par exemple un fichier PHP). Ces fichiers ne seront pas mis en cache.
FALLBACK Fichiers à afficher dans le cas où des ressources demandées ne sont pas disponibles. La syntaxe en est :url_fichier_original url_fichier_fallback Un joker avec la notation / url_fichier_fallback renvoie tous les fichiers non disponibles vers le fichier indiqué.

Notons que les URL utilisées dans le ma nifeste peuvent être relatives ou absolues et que rien n'empêche de mettre en cache des ressources situées sur un autre domaine que celui de la pa ge qui déclare le manifeste.

Y a-t-il des limites sur la quantité d'in formations qui peut être mise en cache ? Différents navigateurs imposent des restrictions de taille très différentes sur les applications hors ligne.

D'abord, les navigateurs mobiles ont tendance à être avares de leur mise en cache pour des raisons d'espace limité sur ce genre de périphériques. À ce jour, la version de Safari qui fonctionne sur l' iPad et l'iPhone limite chaque applica-tion offline à 5 Mo.

Les navigateurs de bureau sont, eux, étonnamment contradictoires.

Dans Firefox, une application mise en cache peut occuper jusqu'à 50 Mo d'espace avec les paramètres par défaut et l'utilisateur peut augmenter cette limite. Pour appliquer des paramètres de cache personnalisés, dans le menu Firefox, choisissez - onglet Avancé - onglet Réseau.

Image non disponible

Pour Google Chrome, la limite reste (pour l'instant ?) de 5 Mo.

Ce manque de cohérence entre les navigateurs pose problème. Si vous développez dès à présent une application de plus de 5 Mo de données, elle fonctionnera correctement sous Firefox mais pas dans Chrome. N'oublions pas que l'implémentation des API JavaScript du Html5 est évolutive, voire expérimentale. À n'en pas douter, ces applications hors ligne auront probablement dans le futur de plus grandes quantité s d'espace à leur disposition.

Un fichier de manifeste peut prendre la forme suivante :

 
Sélectionnez
CACHE MANIFEST
# version 1.0
CACHE: 
index.html 
fallback.html 
style.css 
images/1.png 
images/2.png 
images/3.png 
images/4.png
FALLBACK: 
/ fallback.html
NETWORK: 
network.html
 

Configurer IIS

Il faudra configurer le serveur (local) pour qu'il reconnai sse ce nouveau Type MIME. Ouvrez IIS Manager (inetmgr dans la ligne de texte de recherche de Windows 7). Dans l'écran qui se présente, choisissez Types MIME.

Image non disponible

Dans le nouvel écran, effectuez un clic droit et sélectionnez Ajouter

Image non disponible

Encodez comme extension de fichier .appcache et comme type MIME text/cache-manifest.

Image non disponible

Exemple

Appliquons tout ceci avec l'exemple suivant :

Image non disponible
Le fichier JavaScript externe (script.js)
Sélectionnez
function init(){
if (!window.applicationCache){
msg = "L'API offline n'est pas prise en charge";
document.querySelector('#box').innerHTML =  msg;
}
if (window.navigator.onLine) {
document.querySelector('#boite').className= 'online';
msg = "Connecté";
document.querySelector('#boite').innerHTML =  msg;
} else {
document.querySelector('#boite').className= 'offline';
msg = "Déconnecté";
document.querySelector('#boite').innerHTML =  msg;
}
}
La feuille de style CSS externe (style.css)
Sélectionnez
a { color: black; }
body {background: #f5f5f5;}
#box{ margin: 0 auto;
   background: white;
   width: 340px;
   border:5px solid rgb(195,215,235);
   padding-left:5px;
   -webkit-border-radius: 10px;
   -moz-border-radius: 10px;
   border-radius: 10px;}
#boite { width: 80px;
         border: 1px solid black;
     text-align: center;
     margin : auto;}
.paragraphe { margin-top: 8px;
       margin-bottom: 8px;}
.offline { background: #c00;}
.online { background: #0c0;}
Le fichier Html proprement dit (index.html)
Sélectionnez
<!DOCTYPE html>
<html lang="en" manifest="offline.appcache">
<head>
<title>Les API JavaScript du Html5</title>
<meta charset=utf-8>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script> 
</head>
<body onload="init()">
<h2>Application Offline</h2>
<div id="boite">&nbsp;</div>
<p>
<div id="box">
<p class="paragraphe">Un bouquet pour les lectrices</p>
<img src="bouquet1.jpg" alt="Flower">
<img src="bouquet2.jpg" alt="Flower">
<img src="bouquet3.jpg" alt="Flower">
<img src="bouquet4.jpg" alt="Flower">
</div>
</p>
<footer>
<p class="paragraphe">
<a href=
"http://www.editions-eni.fr/">Editions Eni</a></p>
</footer>
</body>
</html>
Le fichier de fallback (fallback.html)
Sélectionnez
<!DOCTYPE html>
<html lang="fr" manifest="offline.appcache">
<head>
<title>Les API JavaScript du Html5</title>
<meta charset=utf-8>
<style>
div { margin-top: 40px;
   margin-left: 40px;
   padding: 4px;
   width: 220px;
   border: 1px solid black;
   background: rgb(195,215,235)}
</style>
</head>
<body>
<h2>Application Offline</h2>
<div>
Désolé, cette page n'est pas prévue pour une consultation offline.
</div>
</body>
</html>

Le fichier de manifeste (offline.appcache)

Nous souhaitons que soient disponibles hors connexion les fichier index.html, fallback.html, style.css, script.js et les images bouquet1.jpg bouquet2.jpg, bouquet3.jpg et bouquet4.jpg. Le fichier de manifeste offline.appcache devient :

 
Sélectionnez
CACHE MANIFEST
# version 1.0
CACHE:
index.html
fallback.html
style.css 
script.js
bouquet1.jpg
bouquet2.jpg
bouquet3.jpg
bouquet4.jpg
FALLBACK:
/ fallback.html
NETWORK:
*

L'astérisque qui accompagne la rubriq ue NETWORK signifie que toutes les ressources qui ne sont pas mises en cache réclament une connexion.

Au chargement de la page, ces fichiers seront mis en cache pour une exploitation hors connexion.

Un coup d'œil aux outils de développement de Chrome permet de s'en convaincre.

En activant l'onglet Console :

Image non disponible

Et avec l'onglet Resources :

Image non disponible

Firefox nous fournit également des informations en encodant about:cache dans la barre d'adresse.

Image non disponible

Ne quittons pas cet exemple sans illustrer le rôle du fichier fallback lors d'une consultation hors ligne. Si l'on clique sur le lien Editions Eni qui n'est pas dispoible offline, le fichier fallback s'affiche.

Image non disponible

4. Gérer le cache

4.1. Les statuts

Chaque cache a un statut qui indique la condition actuelle de celui-ci. Les caches qui partagent la même URL de manifeste partagent le même statut, qui est un des suivants :

0 UNCACHED Une valeur spéciale qui indique qu'un objet application cache n'est pas complètement initialisé et que la mise en cache a échoué
1 IDLE Le cache n'est pas en cours de mise à jour.
2 CHECKING Le manifeste est en train d'être contrôlé pour d'éventuelles mises à jour.
3 DOWNLOADING Des ressources sont en train d'être téléchargées pour être ajoutées au cache suite à un changement du manifeste.
4 UPDATEREADY Une nouvelle version du cache est disponible. Il y a un événement updateready correspondant qui est lancé au lieu de l'événement cached quand une nou- velle mise à jour a été téléchargée mais pas encore activée via la méthode swapCache() (voir plus loin).
5 OBSOLETE Le groupe mis en cache est maintenant obsolète.

4.2. Les événements

Certains événements se produisent selon ce qui se passe avec l'AppCache.

checking Se produit lorsque le navigateur cherche à télécharger le manifeste pour la première fois ou vérifie si une mise à jour du manifeste est disponible.
noupdate Se produit s'il n'y a pas de version mise à jour du manifeste disponible sur le serveur.
downloading Se produit lorsque le navigateur télécharge le manifeste pour la première fois ou un e mise à jour de celui-ci.
progress Se produit lorsque chaque fichier mentionné dans le mani-feste est téléchargé dans le cache
cached Se produit lorsque toutes les ressources ont été téléchargées et sont présentes dans le cache.
updateready Se produit une fois que tous les fichiers mentionnés dans une mise à jour du manifeste ont été (re)téléchargés. La méthode swapCache() peut alors être utilisée pour rendre ces fichiers utilisables par le navigateur.
obsolete Se produit lorsque le fichier manifeste ne peut être trouvé (erreur 404 ou 401).
error Se déclenche lorsqu'une erreur s'est produite, par exemple le fichier de manifeste n'a pas été trouvé ou un problème a eu lieu lors du téléchargeme nt d'un fichier ou d'une ressource.

Ces événements seront parfois précédés du préfixe on : onchecking, onnoupdate, ondownloading, onprogress, etc.

Il faut noter qu'au moment de l'écriture de cet ouvrage, les navigateurs ne supportent pas les événements de cache d'une façon égale. Ainsi, Firefox ignore des événements comme checking et updateready mais reconnaît noupdate et error.

4.3. Application

À partir d'un nouvel exemple, illustrons ces propriétés.

Image non disponible

Le script relatif aux statuts et événements nous retourne événement : cached. Toutes les ressources signalées dans le manifeste ont donc été chargées et sont présentes dans le cache. Avec statut : idle, il nous signale que toutes les ressources ont été téléchargées et qu'il n'y a pas de mise à jour en cours de mise en cache.

Les images comme les fichiers des exempl es sont disponible s dans l'espace de téléchargement associé à cet ouvrage.

Le fichier de base (index.html)
Sélectionnez
<!DOCTYPE html>
<html lang="en" manifest="offline.appcache">
<head>
<title>Les API JavaScript du Html5</title>
<meta charset=utf-8>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script> 
</head>
<body onload="init()">
<h2>Application Offline</h2>
<img src="on.png" alt="online">     
<img src="off.png" alt="offline" style="margin-left: 50px;">
<div id="boite">&nbsp;</div>
</body>
</html>
Le script externe (script.js
Sélectionnez
function init(){
var cacheStatusValues = [];
cacheStatusValues[0] = 'uncached';
cacheStatusValues[1] = 'idle';
cacheStatusValues[2] = 'checking';
cacheStatusValues[3] = 'downloading';
cacheStatusValues[4] = 'updateready';
cacheStatusValues[5] = 'obsolete';
var cache = window.applicationCache;
cache.addEventListener('cached', logEvent, false);
cache.addEventListener('checking', logEvent, false);
cache.addEventListener('downloading', logEvent, false);
cache.addEventListener('error', logEvent, false);
cache.addEventListener('noupdate', logEvent, false);
cache.addEventListener('obsolete', logEvent, false);
cache.addEventListener('progress', logEvent, false);
cache.addEventListener('updateready', logEvent, false);
function logEvent(e) {
var message, online, status, type;
online = (navigator.onLine) ? 'oui' : 'non';
status = cacheStatusValues[cache.status];
type = e.type;
message = 'online : ' + online;
message+= ', événement : ' + type;
message+= ', statut : ' + status;
document.querySelector('#boite').innerHTML =  message;
}
}
Commentaire
Sélectionnez
var cacheStatusValues = [];
				cacheStatusValues[0] = 'uncached
				cacheStatusValues[1] = 'idle';

Avec la variable Array cacheStatusValues, chaque valeur de statut est associée avec son intitulé.

 
Sélectionnez
var cache = window.applicationCache;

La variable cache récupère toutes les informations de l'objet applicationCache.

 
Sélectionnez
cache.addEventListener('cached', logEvent, false);

Un gestionnaire d'événements DOM 2 "écoute" l'événement cached et, s'il seproduit, passe la main à la fonction logEvent(). Il en est de même pour les autres événements.

 
Sélectionnez
online = (navigator.onLine) ? 'oui' : 'non';

La variable online teste (navigator.onLine ) si la page est en ligne ou non.

 
Sélectionnez
type = e.type;

La variable type capture les événements.

 
Sélectionnez
status = cacheStatusValues[cache.status];

Le statut est fourni par cacheStatusValues[cache.status] . La suite est du JavaScript classique.

La feuille de style externe (style.css)
Sélectionnez
 #boite { width: 300px;
border: 1px solid bla
text-align: center;
margin-top: 15px;}
Le fichier de manifeste
Sélectionnez
CACHE MANIFEST
CACHE:
index.html
style.css
script.js
on.png
off.png
FALLBACK:
NETWORK:

5. Mise à jour des données en cache

5.1. La méthode update

La méthode update() vérifie simplement s'il y a une nouvelle version du fi-chier de manifeste disponible. Si celle-ci existe, elle démarre le téléchargement de la nouvelle version.

Le navigateur vérifie l'existence d'un timestamp plus récent du fichier de mani-feste ainsi qu'une modification de contenu de celui-ci.

Si un navigateur télécharge un fichier de manifeste mis à jour et découvre que le contenu est inchangé, il arrête le processus de téléchargement et garde les fichiers précédemment mis en cache. Ceci pour épargner la bande passante du réseau.

En phase d'apprentissage ou de développement, une astuce consiste à changer le numéro de la version (par exemple 1. 0.1. au lieu de 1.0) ou d'ajouter une ligne de commentaires.

Bien que le navigateur vérifie auto matiquement l'existence d'un nouveau fichier de manifeste, il est possible de fo rcer ce processus de mise à jour si vous pensez que le fichier de manifeste a changé depuis la première visite de l'utilisateur, en aj outant au script :

setInterval(function () {window.applicationCache.update();}, 3600000);

Ce bout de script vérifie toutes les 60 minutes s'il existe une nouvelle version du manifeste. Si c'est le cas, les fichiers et ressources définis dans le nouveau manifeste seront téléchargés.

5.2. La méthode swapCache

La méthode swapCache() indique au navigateur de commencer à utiliser le nouveau contenu mis en cache, si bien entendu une mise à jour a été téléchargée. Il est important de noter que même s'il y a une nouvelle version du manifeste, l'application continuera à utiliser les anciens fichiers du cache (comme spécifié dans l'ancienne version du manifeste). Une fois la fonction swapcache() appelée, alors seulement les nouveaux fichiers du cache seront utilisés.

Exemple de code à utiliser
Sélectionnez
<!DOCTYPE html>
<html lang="en" manifest="demo.appcache">
<head>
<title>Les API JavaScript du Html5</title>
<meta charset=utf-8>
<script type="text/javascript">
window.applicationCache.addEventListener('updateready',
function(){
window.applicationCache.swapCache();
}, false);
</script>
</head>
<body>
 ...
</body>
</html>