aboutsummaryrefslogtreecommitdiff
path: root/files/fr/mozilla/add-ons/webextensions/your_second_webextension/index.html
blob: 896ce3b34678a5cdf8b948286674cffa9177378e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
---
title: Votre deuxième WebExtension
slug: Mozilla/Add-ons/WebExtensions/Your_second_WebExtension
tags:
  - WebExtensions
translation_of: Mozilla/Add-ons/WebExtensions/Your_second_WebExtension
---
<div>{{AddonSidebar}}
<p>Si vous avez lu l'article <a href="/fr/Add-ons/WebExtensions/Your_first_WebExtension">votre première extension</a>, vous avez déjà une idée de la manière d'écrire une extension. <span class="seoSummary">Dans cet article, nous allons écrire une extension légèrement plus complexe qui illustre un peu plus les API.</span></p>

<p>L'extension ajoute un nouveau bouton à la barre d'outils Firefox. Lorsque l'utilisateur clique sur le bouton, nous affichons une fenêtre contextuelle qui leur permet de choisir un animal. Une fois qu'ils choisissent un animal, nous remplacerons le contenu de la page actuelle par une image de l'animal choisi.</p>

<p>Pour implémenter ce module, il nous faut :</p>

<ul>
 <li><strong>définir une action du navigateur, matérialisée par un bouton dans la barre d'outils de Firefox</strong>.<br>
  Pour ce bouton, nous avons besoin de :
  <ul>
   <li>une icône, nommée "beasts-32.png"</li>
   <li>une popup qui s'ouvrira lorsque le bouton est cliqué. La popup sera constituée d'HTML, de CSS et de JavaScript.</li>
  </ul>
 </li>
 <li><strong>définir l'icône de l'extension,</strong> nommée "beasts-48.png". Elle apparaîtra dans le gestionnaire de module.</li>
 <li><strong>écrire un content script, "beastify.js" qui sera injecté dans chaque page web</strong>.<br>
  C'est le code qui va effectivement transformer les pages.</li>
 <li><strong>packager les images d'animaux, afin de remplacer les images de la page web</strong>.<br>
  Nous définirons les images comme étant des "web accessible resources" (des ressources accessible par le web) de sorte que la page web puisse y accéder.</li>
</ul>

<p>Voici une visualisation globale possible de la structure du module :</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/13671/Untitled-1.png" style="display: block; height: 1200px; margin-left: auto; margin-right: auto; width: 860px;"></p>

<p>C'est une simple extension mais qui démontre plusieurs concepts élémentaires de l'API des WebExtensions :</p>

<ul>
 <li>ajout d'un bouton à la barre d'outil</li>
 <li>définition d'une popup à l'aide de HTML, CSS et JavaScript</li>
 <li>injection des content scripts dans chaque page web</li>
 <li>communication entre les content scripts et le reste du module</li>
 <li>packager les ressources dans le module qui peuvent ensuite être utilisées par les pages web</li>
</ul>

<p>Le <a href="https://github.com/mdn/webextensions-examples/tree/master/beastify">code source complet du module est disponble sur GitHub</a>.</p>

<p>Afin d'écrire cet extension, il nous faut Firefox 45 ou plus récent.</p>

<h2 id="Ecriture_de_lextension">Ecriture de l'extension</h2>

<p>Créez un nouveau répertoire et positionnez vous dedans :</p>

<pre class="brush: bash">mkdir beastify
cd beastify</pre>

<h3 id="manifest.json">manifest.json</h3>

<p>Créez un nouveau fichier nommé "manifest.json" directement dans le répertoire "beastify" et tapez-y le contenu suivant :</p>

<pre class="brush: json">{

  "manifest_version": 2,
  "name": "Beastify",
  "version": "1.0",

  "description": "Adds a browser action icon to the toolbar. Click the button to choose a beast. The active tab's body content is then replaced with a picture of the chosen beast. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#beastify",
  "homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify",
  "icons": {
    "48": "icons/beasts-48.png"
  },

  "permissions": [
    "activeTab"
  ],

  "browser_action": {
    "default_icon": "icons/beasts-32.png",
    "default_title": "Beastify",
    "default_popup": "popup/choose_beast.html"
  },

  "web_accessible_resources": [
    "beasts/frog.jpg",
    "beasts/turtle.jpg",
    "beasts/snake.jpg"
  ]

}
</pre>

<ul>
 <li>Les trois premières clés : <code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/manifest_version">manifest_version</a></code>, <code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/name">name</a></code>, et <code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/version">version</a></code>, sont obligatoires et contiennent les métadatas élémentaires nécessaires à l'extension.</li>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/description">description</a></code> and <code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/homepage_url">homepage_url</a></code> sont optionnelles mais recommandées : elles apportent de l'information utile à propos de l'extension.</li>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/icons">icons</a></code> est optionnelle mais recommandée : elle permet de spécifier l'icône du module qui s'affichera dans le gestionnaire d'extension.</li>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/permissions">permissions</a></code> liste les permissions nécessaires à cet extension. Ici, uniquement  <a href="/fr/Add-ons/WebExtensions/manifest.json/permissions#activeTab_permission"><code>la permission activeTab</code> </a>est demandée.</li>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_action">browser_action</a></code> spécifie le bouton de la barre d'outil. Nous fournissons trois informations :
  <ul>
   <li><code>default_icon</code> est obligatoire et référence l'icône du bouton</li>
   <li><code>default_title</code> est optionelle et s'affichera dans une bulle d'aide</li>
   <li><code>default_popup</code> est nécessaire si vous souhaitez qu'une popup s'affiche lorsque l'utilisateur clique sur le bouton. C'est notre cas, nous avons donc défini cette clé et l'avons faites pointer sur un fichier HTML inclus dans le module.</li>
  </ul>
 </li>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/manifest.json/web_accessible_resources">web_accessible_resources</a></code> liste les fichiers qui doivent être accessibles aux pages web. Comme cette extension remplace le contenu de la page web par les images inclues dans cette extension, il faut les rendre accessibles à la page.</li>
</ul>

<p>Il est à noter que tous les chemins sont relatifs au fichier manifest.json.</p>

<h3 id="Licône">L'icône</h3>

<p>L'extension doit posséder une icône qui sera affichée à côté de la liste des extensions du gestionnaire des Add-ons module (vous pouvez afficher le gestionnaire en ouvrant l'URL "about:addons").  Le fichier manifest.json a déclaré une icône pour la barre d'outil, "icons/beasts-48.png".</p>

<p>Créer le répertoire "icons" et enregistrez-y une icône nommée "beasts-48.png".  Il vous est possible d'en utiliser <a href="https://github.com/mdn/webextensions-examples/raw/master/beastify/icons/beasts-48.png">une de notre exemple</a>, provenant du jeu d'icônes de <a href="https://www.iconfinder.com/iconsets/free-retina-icon-set">Aha-Soft’s Free Retina</a> et utilisable selon les termes de sa <a href="http://www.aha-soft.com/free-icons/free-retina-icon-set/">license</a>.</p>

<p>Si vous décidez de fournir votre propre icône, sa taille devra être de 48 pixels par 48 pixels. Il vous est aussi possible de fournir une icône de taille 96 pixels par 96 pixels, adpatée aux affichages hautes résolutions, et, devra dans ce cas, être spécifiée par la propriété <code>96</code> de l'objet icon du manifest.json :</p>

<pre class="brush: json line-numbers  language-json"><code class="language-json">"icons": {
  "48": "icons/beasts-48.png",
  "96": "icons/beasts-96.png"
}</code></pre>

<h3 id="Le_bouton_de_la_barre_doutils">Le bouton de la barre d'outils</h3>

<p>Une icône est nécessaire pour le bouton de la barre d'outils et le manifest.json déclare une icône "icons/beasts-32.png" pour la barre d'outils.</p>

<p>Enregistrez une icône nommée "beasts-32.png" dans le répertoire "icons". Il vous est possible d'en utiliser <a href="https://github.com/mdn/webextensions-examples/blob/master/beastify/icons/beasts-32.png">une de notre exemple</a>, provenant du jeu d'icône <a href="http://www.iconbeast.com/free">IconBeast Lite icon</a> et utilisable selon les termes de sa <a href="http://www.iconbeast.com/faq/">license</a>.</p>

<p>Si vous ne mettez pas à disposition une popup, alors un événement "click" est propagé au module lorque l'utilisateur clique le bouton. Si vous mettez à disposition une popup l'évenement "click" n'est pas propagé, mais la popup s'ouvre à la place. Nous souhaitons une popup, alors créons là.</p>

<h3 id="La_popup">La popup</h3>

<p>La but de la popup est de permettre à l'utilisateur de choisir une des trois bêtes.</p>

<p>Créez un nouveau répertoire nommé popup à la racine de l'extension. Ce sera l'emplacement du code de la popup. La popup sera constituée de trois fichiers :</p>

<ul>
 <li><strong><code>choose_beast.html</code></strong> qui définit le contenu du panneau</li>
 <li><strong><code>choose_beast.css</code></strong> qui stylise le contenu</li>
 <li><strong><code>choose_beast.js</code></strong> qui gére le choix de l'utilisateur en exécutant un content script dans l'onglet actif</li>
</ul>

<h4 id="choose_beast.html">choose_beast.html</h4>

<p>Voici le contenu du fichier HTML :</p>

<pre class="brush: html">&lt;!DOCTYPE html&gt;

&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;link rel="stylesheet" href="choose_beast.css"/&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;div class="beast"&gt;Frog&lt;/div&gt;
    &lt;div class="beast"&gt;Turtle&lt;/div&gt;
    &lt;div class="beast"&gt;Snake&lt;/div&gt;

    &lt;script src="choose_beast.js"&gt;&lt;/script&gt;
  &lt;/body&gt;

&lt;/html&gt;</pre>

<p>Un seul élément est défini pour chaque animal. Il est à noter que le ficher CSS et le fichier JS sont inclus depuis ce fichier, tout comme une page web normale.</p>

<h4 id="choose_beast.css">choose_beast.css</h4>

<p>Le CSS fixe la taille de la popup, s'assure que les trois choix remplissent l'espace et les stylise de façon élémentaire :</p>

<pre class="brush: css">html, body {
  width: 100px;
}

.beast {
  margin: 3% auto;
  padding: 4px;
  text-align: center;
  font-size: 1.5em;
  background-color: #E5F2F2;
  cursor: pointer;
}

.beast:hover {
  background-color: #CFF2F2;
}
</pre>

<h4 id="choose_beast.js">choose_beast.js</h4>

<p>Dans le JavaScript de la popup, nous écoutons les événements click. Si le click se produit sur un de nos trois choix d'animaux, nous injectons un content script dans l'onglet actif. Une fois le content script chargé, nous lui envoyons un message contenant le choix de l'animal :</p>

<pre class="brush: js">/*
Given the name of a beast, get the URL to the corresponding image.
*/
function beastNameToURL(beastName) {
  switch (beastName) {
    case "Frog":
      return browser.extension.getURL("beasts/frog.jpg");
    case "Snake":
      return browser.extension.getURL("beasts/snake.jpg");
    case "Turtle":
      return browser.extension.getURL("beasts/turtle.jpg");
  }
}

/*
Listen for clicks in the popup.

If the click is on one of the beasts:
  Inject the "beastify.js" content script in the active tab.

  Then get the active tab and send "beastify.js" a message
  containing the URL to the chosen beast's image.

If it's on a button wich contains class "clear":
  Reload the page.
  Close the popup. This is needed, as the content script malfunctions after page reloads.
*/

// execute the script now so it can listen to the messages sent by the code below
browser.tabs.executeScript(null, { file: "/content_scripts/beastify.js" });


document.addEventListener("click", (e) =&gt; {
  if (e.target.classList.contains("beast")) {
    var chosenBeast = e.target.textContent;
    var chosenBeastURL = beastNameToURL(chosenBeast);



    var gettingActiveTab = browser.tabs.query({active: true, currentWindow: true});
    gettingActiveTab.then((tabs) =&gt; {
      browser.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
    });
  }
  else if (e.target.classList.contains("clear")) {
    browser.tabs.reload();
    window.close();
  }
});
</pre>

<p>Ce script utilise trois fonctions de l'API WebExtension :</p>

<ul>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/API/tabs/executeScript">browser.tabs.executeScript</a></code> qui injecte le content script, de chemin  "content_scripts/beastify.js" dans l'onglet actif</li>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/API/tabs/query">browser.tabs.query</a></code> pour récupérer l'onglet actif</li>
 <li><code><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/API/tabs/sendMessage">browser.tabs.sendMessage</a></code> pour envoyer un message au content scripts s'exécutant dans l'onglet actif. Le message contient l'URL pointant vers l'image de la bête choisie.</li>
</ul>

<h3 id="Le_content_script">Le content script</h3>

<p>Créez un nouveau répertoire sous la racine du module nommé "content_scripts" et créez un nouveau fichier nommé "beastify.js", contenant :</p>

<pre class="brush: js">/*
beastify():
* removes every node in the document.body,
* then inserts the chosen beast
* then removes itself as a listener
*/
function beastify(request, sender, sendResponse) {
  removeEverything();
  insertBeast(request.beastURL);
  browser.runtime.onMessage.removeListener(beastify);
}

/*
Remove every node under document.body
*/
function removeEverything() {
  while (document.body.firstChild) {
    document.body.firstChild.remove();
  }
}

/*
Given a URL to a beast image, create and style an IMG node pointing to
that image, then insert the node into the document.
*/
function insertBeast(beastURL) {
  var beastImage = document.createElement("img");
  beastImage.setAttribute("src", beastURL);
  beastImage.setAttribute("style", "width: 100vw");
  beastImage.setAttribute("style", "height: 100vh");
  document.body.appendChild(beastImage);
}

/*
Assign beastify() as a listener for messages from the extension.
*/
browser.runtime.onMessage.addListener(beastify);
</pre>

<p>Le content script ajoute un listener sur les messages émis depuis le module (et spécifiquement depuis "choose_beast.js" ci-dessus). Dans le listener, il :</p>

<ul>
 <li>supprime tous les éléments dans le <code>document.body</code></li>
 <li>crée un élément <code>&lt;img&gt;</code> pointant sur l'URL définie et l'insère dans le DOM</li>
 <li>supprime le listener du message.</li>
</ul>

<h3 id="Les_bêtes">Les bêtes</h3>

<p>Enfin, nous devons inclure les images d'animaux.</p>

<p>Créez un nouveau répertoire nommé "beasts", et ajoutez-y les trois images, nommées de façon appropriée. Vous pouvez récuperer les images du <a href="https://github.com/mdn/webextensions-examples/tree/master/beastify/beasts">dépôt GitHub</a>, ou bien ci-après :</p>

<p><img alt="" src="https://mdn.mozillademos.org/files/11459/frog.jpg" style="display: inline-block; height: 200px; margin: 20px; width: 200px;"><img alt="" src="https://mdn.mozillademos.org/files/11461/snake.jpg" style="display: inline-block; height: 200px; margin: 20px; width: 200px;"><img alt="" src="https://mdn.mozillademos.org/files/11463/turtle.jpg" style="display: inline-block; height: 200px; margin: 20px; width: 200px;"></p>

<h2 id="Test">Test</h2>

<p>D'abord, vérifiez de nouveau que les bons fichiers sont au bon endroit :</p>

<pre>beastify/

    beasts/
        frog.jpg
        snake.jpg
        turtle.jpg

    content_scripts/
        beastify.js

    icons/
        beasts-32.png
        beasts-48.png

    popup/
        choose_beast.css
        choose_beast.html
        choose_beast.js

    manifest.json</pre>

<p>A partir de Firefox version 45, il est possible d'installer les WebExtensions temporairement.</p>

<p>Ouvrez "about:debugging" dans Firefox, cliquez sur "Load Temporary Add-on", et choisissez le fichier manifest.json. Vous devriez voir apparaitre l'icône du module dans la barre d'outils de Firefox :</p>

<p>{{EmbedYouTube("sAM78GU4P34")}}</p>

<p>Ouvrez une page web et cliquez sur l'icône, sélectionnez une bête et observez la page web se modifier :</p>

<p>{{EmbedYouTube("YMQXyAQSiE8")}}</p>

<h2 id="Développement_depuis_la_ligne_de_commande">Développement depuis la ligne de commande</h2>

<p>Il est possible d'automatiser l'installation temporaire de modules, étape par étape en utilisant l'outil <a href="/fr/Add-ons/WebExtensions/Getting_started_with_web-ext">web-ext</a> tool. Essayez ainsi :</p>

<pre class="brush: bash">cd beastify
web-ext run</pre>
</div>

<h2 id="Quelle_est_la_prochaine_étape">Quelle est la prochaine étape ?</h2>

<p>Vous avez maintenant créé une extension Web avancée pour Firefox :</p>

<ul>
 <li><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension">lisez l'anatomie d'une extension</a></li>
 <li><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/Examples">explorer les exemples d'extension</a></li>
 <li><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/que_faire_ensuite">découvrir ce dont vous avez besoin pour développer, tester et publier votre extension</a></li>
 <li><a href="/fr/docs/Mozilla/Add-ons/WebExtensions/que_faire_ensuite#Continuez_votre_expérience_d'apprentissage">approfondir votre apprentissage</a>.</li>
</ul>