Override pages et utilisation des favoris

Sylvain Dangin

Un tutoriel pour vous expliquer comment modifier vos favoris au sein d'une extension et comment remplacer la page "nouvel onglet", ainsi que l'utilisation de l'API chrome.bookmarks.

Commentez

- Titre : Override pages et utilisation des favoris

- Auteur : Sylvain Dangin

- Parution : 16 décembre 2009

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2009 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- I-A. Connaissances nécessaires

- II. Override Pages

- III. Un site par défaut à l'ouverture d'un nouvel onglet.

- III-A. Le fichier manifest.json

- III-B. Le fichier newtab.html

- IV. Gestion des favoris, l'API chrome.bookmarks

- IV-A. Présentation

- IV-B. L'objet BookmarkTreeNode

- IV-D. Un premier exemple

- V. Liste des favoris

- V-A. Présentation

- V-B. Le fichier manifest.json

- V-C. Le fichier newtab.html

- V-C-1. Les fonctions nécessaires

- V-C-2. La fonction init

- V-C-3. La fonction callback

- V-C-4. Fichier complet

- V-C-5. Un peu de CSS

- VI. Conclusion

I - Introduction

Dans ce tutoriel, nous allons utiliser la fonctionnalité Override Pages qui permet de remplacer une page de Google Chrome. Nous verrons également les bases de l'utilisation de l'API chrome.bookmarks permettant la gestion des favoris.

I-A - Connaissances nécessaires

La compréhension de ce tutoriel nécessite de connaitre un minimum des langages HTML, CSS ainsi qu'une bonne notion en Javascript. Si vous n'avez jamais créé d'extension pour Google Chrome, allez lire le tutoriel d'introduction.

II - Override Pages

Actuellement, cette fonctionnalité ne peut être utilisée que sur la page de nouvel onglet. C'est pourquoi les extensions décritent par la suite se focaliseront sur cette page. Si vous cliquez sur le '+' à droite des onglets, cette page s'affichera :

Cette page vous affiche les sites les plus visités récemment. C'est bien mais, personnellement, je n'ai pas besoin que l'on me rappelle les sites pour lesquels j'ai déjà sûrement un onglet ouvert. Pour changer cela, nous allons devoir développer un plugin.

III - Un site par défaut à l'ouverture d'un nouvel onglet.

Pour notre premier exemple, nous allons changer cette page par un site de notre choix. Pour l'exemple nous allons prendre Google.

III-A - Le fichier manifest.json

Nous allons dans un premier temps indiquer à Google Chrome les informations sur notre extension.

{
"name": "New Tab Bookmarks",
"version": "1.0",
"chrome_url_overrides":
{
"newtab": "newtab.html"
}
}

Ici, la seule nouveauté se trouve être le paramètre chrome_url_overrides. La variable newtab permet de définir le fichier à ouvrir, ici newtab.html. Celui-ci fait obligatoirement partie de l'extension. En effet, il est impossible d'indiquer une URL externe directement.

III-B - Le fichier newtab.html

Comme son extension l'indique, ce fichier sera écrit en HTML. Pour charger une autre page, nous allons utiliser le javascript :

<html>
<head>
<script>
document.location.href="http://www.google.fr";
</script>
</head>
</html>

La page sera donc chargée puis directement redirigée vers Google.

IV - Gestion des favoris, l'API chrome.bookmarks

Pour gérer les favoris, Google Chrome propose une API chrome.bookmarks. Elle permet de faire toutes les manipulations possibles "facilement".

IV-A - Présentation

Une structure en arbre a été utilisée pour gérer les favoris. Pour ceux qui ne connaissent pas ce type de structure, on peut la comparer avec vos répertoires. Voici un schéma qui pourra vous aider à comprendre :

Ici, nous pouvons voir en jaune les répertoire et en bleu les liens. Le nœud principal ne peut être atteint. Le répertoire "Barre de favoris" possède l'identifiant 1, "Autres favoris" le 2.

IV-B - L'objet BookmarkTreeNode

Cet objet est utilisé dans quasiment toutes les fonctions de l'API. C'est pourquoi il est nécessaire de connaitre un minimum de ses attributs :

- id : Identifiant de l'élément.

- parentId : Identifiant du nœud parent. (facultatif)

- index : Ordre des éléments. (facultatif)

- url : URL. (facultatif)

- title : Nom affiché.

- dateAdded : Date d'ajout du favori. (facultatif)

- dateGroupModified : Date de la dernière modification au sein du groupe. (facultatif)

- children : Tableau contenant les nœuds enfants. (facultatif)

IV-D - Un premier exemple

La fonction chrome.bookmarks.create permet d'ajouter un favori. Pour l'exemple, nous allons l'ajouter à la barre de favoris ayant pour identifiant 1. Elle prend en paramètre un objet de type bookmark dont voici les attributs :

- parentId : Identifiant du nœud parent.

- index : Position. (facultatif)

- title : Titre affiché. (facultatif)

- url : URL. (facultatif)

Elle prend également une fonction callback en paramètre. Celle-ci sera étudiée par la suite. Voici maintenant comment appeler cette fonction :

chrome.bookmarks.create({"parentId": "1", "titre": "Développez.com", "url": "http://www.developpez.com"});

Si vous essayez cette ligne de code, un favori pointant vers Développez.com s'ajoutera à votre barre d'outils.

V - Liste des favoris

V-A - Présentation

Le deuxième exemple de ce tutoriel sera de modifier la page Nouvel onglet par votre liste des favoris affichée sous forme de liste à plusieurs niveaux.

V-B - Le fichier manifest.json

Ce sera le même que dans l'exemple précédent sauf l'ajout d'une ligne donnant la permission de gérer les favoris avec l'extension :

{
"name": "New Tab Bookmarks",
"version": "1.0",
"chrome_url_overrides":
{
"newtab": "newtab.html"
},
"permissions": ["bookmarks"]
}

V-C - Le fichier newtab.html

Celui-ci sera plus compliqué que pour les autres tutoriels. Le parcours d'un arbre se fait en général avec la récursivité. Pour faire simple, une fonction récursive est une fonction qui va s'appeler elle-même. Ainsi nous écrirons une fonction qui aura pour but de parcourir un répertoire (en partant du nœud donné). Puis lorsqu'elle tombera sur un répertoire, elle se rappellera elle-même pour parcourir ce répertoire, etc...

V-C-1 - Les fonctions nécessaires

Nous aurons besoin de deux fonctions pour réaliser cette extension dont voici les prototypes :

- chrome.bookmarks.getTree(function callback) : Permet l'accès à l'arbre complet.

- chrome.bookmarks.getChildren(string id, function callback) : Donne la liste des enfants sous forme de tableau.

De nombreuses fonctionnalités des APIs de Google Chrome utilisent les fonctions callback. En français, nous les appelons les fonctions de rappel. Elles sont passées en paramètre à une autre fonction qui pourra alors les appeler par la suite. Ici, elles nous permettent d'accéder aux données de cette façon :

chrome.bookmarks.getTree(function (tree)
{
// Dans cette partie, nous avons accès au données de l'arbre de favoris

// Affichage de l'identifiant du premier élément
console.log(tree[0].id);
})

La fonction console.log(string) permet d'afficher du texte dans la console de debuggage. Souvent très pratique.

V-C-2 - La fonction init

La première étape va être de créer la fonction d'initialisation :

function init()
{
// Récupération de l'arbre des favoris
chrome.bookmarks.getTree(function (tree)
{
// On commence du nœud principal
chrome.bookmarks.getChildren(tree[0].id, callback_show);
})
}

Dans un premier temps nous récupérons l'arbre des favoris puis nous lançons son parcours. La fonction callback est désignée par la variable callback_show. Cette fonction sera par l'évènement "onload". Voici le code HTML :

<body onload="init()">
<h1>Vos favoris</h1>
<div id="level0">
</div>
</body>

Le conteneur div a l'identifiant level0 qui sera utilisé par la fonction callback pour insérer la liste de base.

V-C-3 - La fonction callback

Nous allons déjà commencer par une version pseudo-algorithmique de cette fonction pour faciliter la compréhension :

FONCTION affichage_arbre(arbre)
{
Création de la liste

BOUCLE sur les enfants de l'arbre
{
Création d'un élément de la liste

SI le nœud est un url ALORS
{
Ecriture des données dans l'élément
Insertion de l'élément à la liste
}
SINON
{
Création d'un élément de la liste
Ecriture du titre du répertoire
Insertion de l'élément à la liste
Lancer la fonction affichage_arbre(arbre.enfant)
}
}

Insertion de la liste dans celle de niveau supérieur
}

Voici maintenant la fonction principale de l'extension. Elle pourra paraitre complexe pour certains mais il est surtout important de se focaliser sur l'API Google Chrome :

var callback_show = function show_tree(tree)
{
// Création d'une nouvelle liste
var list = document.createElement("ul");
// Parcours de l'arbre
for (var i = 0; i < tree.length; ++i)
{
// Création d'un nouvel élément
var item = document.createElement("li");
// Test si c'est un lien
if (tree[i].url != null)
{
// Création du lien
var alink = document.createElement("a");
var alink_text = document.createTextNode(tree[i].title);
alink.href = tree[i].url;
alink.appendChild(alink_text);
// Ajoute le lien à l'élément de la liste
item.appendChild(alink);
// Ajoute l'élément à la liste
list.appendChild(item);
}
// Si ce n'est pas un lien, c'est un répertoire
else
{
// Création de l'élément pour la sous-liste
var sublist = document.createElement("li");
var sublist_title = document.createTextNode(tree[i].title);
// L'identifiant de la sous-liste sera l'identifiant du nœud
sublist.id = "level"+tree[i].id;
sublist.appendChild(sublist_title);
// Ajoute la sous-liste à la liste
list.appendChild(sublist);
// Parcours du répertoire par appel récursif
chrome.bookmarks.getChildren(tree[i].id, callback_show);
}
}
// Ajoute la liste à la liste de niveau supérieure (identifiant égale à l'identifiant du nœud parent)
var parent = document.getElementById("level"+tree[0].parentId);
parent.appendChild(list);
}

L'utilisation du DOM ne facilite pas la lecture du code, mais il y a un autre point plus important. En javascript, lorsqu'une fonction callback est appelée, cet appel est "stocké" tant que la fonction appelante n'a pas fini son traitement. Une fois ce traitement fini, elle sera éxécutée et pourra elle-mêmes en rajouter. Voici un exemple, sur l'arbre vu précédemment à la section IV-A, d'exécution de l'algorithme effectué avec un interpréteur Javascript :

Barre de favoris
Autres favoris
- Moteurs de recherche
- Développez.com
-- Google
-- Bing
-- Yahoo

Sauf que nous voulons faire un affichage de ce type :

Barre de favoris
- Moteurs de recherche
-- Google
-- Bing
-- Yahoo
- Développez.com
Autres favoris

Les fonctions callback s'exécutant à la fin du traitement d'une itération, il va être nécessaire de faire attention lors de l'insertion des données dans l'arbre. Une façon simple de faire va être d'utiliser les identifiants des nœuds de Google Chrome pour les réutiliser dans notre arbre au sein des listes.

V-C-4 - Fichier complet

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<script>

var callback_show = function show_tree(tree)
{
// Création d'une nouvelle liste
var list = document.createElement("ul");
// Parcours de l'arbre
for (var i = 0; i < tree.length; ++i)
{
// Création d'un nouvel élément
var item = document.createElement("li");
// Test si c'est un lien
if (tree[i].url != null)
{
// Création du lien
var alink = document.createElement("a");
var alink_text = document.createTextNode(tree[i].title);
alink.href = tree[i].url;
alink.appendChild(alink_text);
// Ajoute le lien à l'élément de la liste
item.appendChild(alink);
// Ajoute l'élément à la liste
list.appendChild(item);
}
// Si ce n'est pas un lien, c'est un répertoire
else
{
// Création de l'élément pour la sous-liste
var sublist = document.createElement("li");
var sublist_title = document.createTextNode(tree[i].title);
// L'identifiant de la sous-liste sera l'identifiant du nœud
sublist.id = "level"+tree[i].id;
sublist.appendChild(sublist_title);
// Ajoute la sous-liste à la liste
list.appendChild(sublist);
// Parcours du répertoire par appel récursif
chrome.bookmarks.getChildren(tree[i].id, callback_show);
}
}
// Ajoute la liste à la liste de niveau supérieure (identifiant égale à l'identifiant du nœud parent)
var parent = document.getElementById("level"+tree[0].parentId);
parent.appendChild(list);
}

function init()
{
// Récupération de l'arbre des favoris
chrome.bookmarks.getTree(function (tree)
{
// On commence du nœud principal
chrome.bookmarks.getChildren(tree[0].id, callback_show);
})
}
</script>
</head>
<body onload="init()">
<h1>Vos favoris</h1>
<div id="level0">
</div>
</body>
</html>

V-C-5 - Un peu de CSS

Une pointe de CSS rendra la chose plus agréable surtout avec Webkit. Voici un code CSS que vous pourriez ajouter :

h1
{
background-color: #9292ff;
text-align: center;
width: 300px;
margin-left: auto;
margin-right: auto;
-webkit-border-radius: 25px;
}

a
{
text-decoration: none;
color: black;
background-color: #c0c0ff;
-webkit-border-radius: 10px;
padding-left: 5px;
width: 500px;
display: block;
margin-bottom: 3px;
}

a:hover
{
background-color: #e36d6d;
margin-left: 30px;
-webkit-transition: margin-left 0.5s;
}

ul, li
{
list-style: none;
padding-left: 10px;
}

.directory
{
background-color: #4ef685;
-webkit-border-radius: 10px;
padding-left: 5px;
width: 500px;
display: block;
font-weight: bold;
}

Une légère modification dans le code javascript :

// Création de l'élément pour la sous-liste
var sublist = document.createElement("li");
var sublist_div = document.createElement("div");
var sublist_title = document.createTextNode(tree[i].title);
// L'identifiant de la sous-liste sera l'identifiant du nœud
sublist.id = "level"+tree[i].id;
sublist_div.className = "directory";
sublist_div.appendChild(sublist_title);
sublist.appendChild(sublist_div);
// Ajoute la sous-liste à la liste
list.appendChild(sublist);

C'est tout de même plus joli :

VI - Conclusion

Ce tutoriel était bien plus compliqué que tous les autres à cause de l'intégration de différents concepts. Je vous conseille de faire différents essais pour mieux comprendre l'utilisation de l'API de gestion des favoris pour être plus à l'aise par la suite. N'hésitez pas à me transmettre vos suggestions pour enrichir et améliorer ce document, notamment si vous trouvez des explications peu claires, des passages de code non optimisés, ou toute autre remarque. Elles seront les bienvenues.

Tous mes remerciements à gorgonite et jacques_jean pour la relecture de ce tutoriel.