APIs vidéo et audio
===================

* Précédent
* Aperçu : Client-side web APIs
* Suivant

HTML5 fournit des éléments pour intégrer du multimédia dans les documents — `<video>` et `<audio>` — et qui viennent avec leurs propres APIs pour contrôler la lecture, se déplacer dans le flux, etc\*.\* Cet article montre comment réaliser les tâches les plus communes, comme créer des contrôles de lectures personnalisés.

|  |  |
| --- | --- |
| Prérequis: | 
 Les bases du JavaScript (voir premiers pas en JavaScript,
 les briques Javascript,
 Introduction aux objets), Introduction aux APIs web |
| Objectif: | 
 Apprendre à utiliser les APIs du navigateur pour contrôler la lecture de
 audio et vidéo.
  |

Les balises HTML5 video et audio
--------------------------------

Les balises `<video>` et `<audio>` permettent d'intégrer des vidéos et de l'audio dans des pages web. Comme nous l'avons montré dans Contenu audio et vidéo, une implémentation habituelle ressemble à ça :


```html
<video controls>
  <source src="rabbit320.mp4" type="video/mp4" />
  <source src="rabbit320.webm" type="video/webm" />
  <p>
    Votre navigateur ne supporte pas la vidéo HTML5. Voici à la place
    <a href="rabbit320.mp4">un lien vers la vidéo</a>.
  </p>
</video>
```


Cela crée un lecteur vidéo à l'intérieur du navigateur :

Vous pouvez consulter toutes fonctionnalités HTML audio et vidéo dans l'article mentionné précédemment. Pour notre utilisation ici, l'attribut le plus intéressant est `controls`. Il permet d'activer l'ensemble des contrôles de lecture par défaut; si vous ne le spécifiez pas, vous aucun contrôle ne sera affiché :

Ce n'est pas immédiatement utile pour la lecture de vidéos, mais ça a des avantages. Les contrôles natifs des navigateurs différent complètement d'un navigateur à l'autre — ce qui est embêtant pour un support global des différents navigateurs. Un autre problème est que le contrôles natifs sont généralement assez peu accessibles au clavier.

Vous pouvez régler ces deux problèmes en cachant les contrôles natifs (en supprimant l'attribut `controls`) et en les remplaçant par les votres en HTML, CSS et JavaScript. Dans la prochaine section, nous verrons les outils de base à notre disposition pour faire ça.

L'API HTMLMediaElement
----------------------

L'API `HTMLMediaElement`, spécifiée dans HTML5, fournit des fonctionnalités qui permettent de controller des lecteurs audio et vidéo avec JavaScript — avec par exemple `HTMLMediaElement.play()` ou encore `HTMLMediaElement.pause()` (en-US). Cette interface est disponible à la fois pour les balises `<audio>` et `<video>`, les fonctionnalités utiles pour les deux étant quasiment identiques. Voyons un exemple pour découvrir ces fonctionnalités.

Notre exemple final ressemblera (et fonctionnera) comme ceci :

### Débuter

Pour commencer avec cet exemple, télechargez notre media-player-start.zip et décompressez-le dans un nouveau dossier sur votre disque dur. Si vous avez téléchargé notre dépôt d'exemples, vous le trouverez dans `javascript/apis/video-audio/start/`.

Si vous ouvrez la page HTML, vous devriez voir un lecteur HTML5 utilisant les contrôles natifs.

#### Exploration du HTML

Ouvrez le fichier HTML d'index. Vous allez voir que le HTML contient majoritairement du code pour le lecteur et ses contrôles:


```html
<div class="player">
  <video controls>
    <source src="video/sintel-short.mp4" type="video/mp4" />
    <source src="video/sintel-short.mp4" type="video/webm" />
    <!-- fallback contenu ici -->
  </video>
  <div class="controls">
    <button
 class="play"
 data-icon="P"
 aria-label="bascule lecture pause"></button>
    <button class="stop" data-icon="S" aria-label="stop"></button>
    <div class="timer">
      <div></div>
      <span aria-label="timer">00:00</span>
    </div>
    <button class="rwd" data-icon="B" aria-label="retour arrière"></button>
    <button class="fwd" data-icon="F" aria-label="avance rapide"></button>
  </div>
</div>
```


* Le lecteur complet est englobé dans une balise `<div>` pour pouvoir appliquer du style sur le bloc complet si nécessaire.
* La balise `<video>` contient deux éléments `<source>` pour permettre la lecture du média selon les capacités de chaque navigateur.
* La partie *controls* du HTML est la plus intéressante :
    + Il contient 4 `<button>` : lecture/mise en pause, stop, retour arrière et avance rapide.
    + Chaque `<button>` a un nom de classe, un attribut `data-icon` (pour définir l'icône affichée), et un attribut `aria-label` (qui fournit une description de chaque bouton pour le rendre accessible). Le contenu d'un attribut `aria-label` est lu par les lecteurs d'écran quand l'élément sur lequel il se situe prend le focus.
    + Il y a également un élément `<div>`, qui affiche le temps écoulé quand la vidéo est en cours de lecture. Pour s'amuser, nous avons mis deux mécanismes en place — un `<span>` qui affiche le temps écoulé en minutes/secondes, et un autre `<div>` pour afficher une barre de progrès. Pour vous faire une idée du produit final, vous pouvez jeter un d'oeil à la version finie.

#### Exploration du CSS

Maintenant, ouvrez le fichier CSS et jetez-y un coup d'oeil. Le CSS pour cet exemple n'est pas très compliqué, mais nous allons voir les éléments les plus intéressants ici. Tout d'abord, le style de `.controls` :


```css
.controls {
  visibility: hidden;
  opacity: 0.5;
  width: 400px;
  border-radius: 10px;
  position: absolute;
  bottom: 20px;
  left: 50%;
  margin-left: -200px;
  background-color: black;
  box-shadow: 3px 3px 5px black;
  transition: 1s all;
  display: flex;
}

.player:hover .controls,
player:focus .controls {
  opacity: 1;
}
```


* Nous commençons par définir la propriété `visibility` à `hidden`. Plus tard dans notre JavaScript, nous le rendrons `visible`, et supprimerons l'attribut `controls` de l'élément `<video>`. Ainsi, si pour une raison quelconque le JavaScript ne se charge pas, les utilisateurs peuvent toujours utiliser la vidéo avec les contrôles natifs.
* Nous donnons aux propriétés une `opacity` de 0.5 par défaut, pour qu'ils ne soient pas génants lorsqu'on veut regarder la vidéo. Ce n'est qu'en passant la souris sur le lecteur que les contrôles sont affichés en pleine opacité.
* Ne plaçons les boutons à l'intérieur du div en utilisant Flexbox (`display`: flex), c'est plus simple comme ça.

Ensuite, voyons les icônes des boutons:


```css
@font-face {
  font-family: "HeydingsControlsRegular";
  src: url("fonts/heydings\_controls-webfont.eot");
  src:
    url("fonts/heydings\_controls-webfont.eot?#iefix") format("embedded-opentype"),
    url("fonts/heydings\_controls-webfont.woff") format("woff"),
    url("fonts/heydings\_controls-webfont.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
}

button:before {
  font-family: HeydingsControlsRegular;
  font-size: 20px;
  position: relative;
  content: attr(data-icon);
  color: #aaa;
  text-shadow: 1px 1px 0px black;
}
```


Tout d'abord, en haut du CSS, nous utilisons un bloc `@font-face` pour importer une police web personnalisée. Il s'agit d'une police d'icônes — tous les caractères de l'alphabet correspondent à des icônes que vous pouvez utiliser dans votre application.

Ensuite, nous générons du contenu pour afficher une icône sur chaque bouton :

* Nous utilisons le sélecteur `::before` pour afficher le contenu au début de chaque élément `<button>`.
* Nous utilisons la propriété `content` pour que le contenu à afficher soit égal au contenu de l'attribut `data-icon`. Dans le cas du bouton play par exemple, `data-icon` contient un "P" majuscule.
* Nous apliquons la police web personnalisée au bouton en utilisant `font-family`. Dans cette police, "P" est une icône "play", donc le bouton play a une icône "play" affichée dedans.

Les polices d'icônes sont très cool pour de nombreuses raisons: réduire les requêtes HTTP (puisque vous n'avez pas besoin de télécharger des icônes sous forme de fichiers image), bonne scalabilité, et le fait que vous pouvez utiliser les propriétés de texte pour les formatter — comme `color` et `text-shadow`.

Dernier point mais non des moindres, le CSS du décompte :


```css
.timer {
  line-height: 38px;
  font-size: 10px;
  font-family: monospace;
  text-shadow: 1px 1px 0px black;
  color: white;
  flex: 5;
  position: relative;
}

.timer div {
  position: absolute;
  background-color: rgba(255, 255, 255, 0.2);
  left: 0;
  top: 0;
  width: 0;
  height: 38px;
  z-index: 2;
}

.timer span {
  position: absolute;
  z-index: 3;
  left: 19px;
}
```


* Nous donnons au `<div>` `.timer` la propriété `flex: 5`, pour qu'il occupe la plus grande partie de la barre de contrôle en largeur. Nous ajoutons également `position``: relative`, pour que les éléments à l'intérieur puissent être positionnés relativement à ses dimensions et non à celles de l'élément `<body>`.
* Le `<div>` interne est positionné en absolu pour être situé au-dessus du `<div>` externe. On lui donne également une largeur initiale de 0, de sorte qu'on ne le voie pas du tout. Au fur et à mesure de la lecture de la vidéo, la largeur sera augmentée via JavaScript.
* Le `<span>` est également positionné en absolu pour être situé sur le côté gauche de la barre de progrès.
* Nous donnons au `<div>` et au `<span>` le `z-index` approprié pour que les données soient visibles — qu'un élément n'en cache pas un autre.
### Implémenter le JavaScript

Nous avons déjà une interface HTML et CSS assez complète; nous avons maintenant besoin de gérer les boutons pour que les contrôles fonctionnent.

1. Créez un nouveau fichier JavaScript dans le même répertoire que votre fichier index.html. Nous l'appelerons `custom-player.js`.
2. En haut de ce fichier, insérez le code suivant :

```js
var media = document.querySelector("video");
var controls = document.querySelector(".controls");

var play = document.querySelector(".play");
var stop = document.querySelector(".stop");
var rwd = document.querySelector(".rwd");
var fwd = document.querySelector(".fwd");

var timerWrapper = document.querySelector(".timer");
var timer = document.querySelector(".timer span");
var timerBar = document.querySelector(".timer div");
```

Ici, nous créons des variables pour stocker les références de tous les objets que nous voulons manipuler. Nous avons trois groupes :
    * L'élément `<video>`, et la barre de contrôle.
    * Les boutons play/pause, stop, retour arrière, et avance rapide.
    * Le `<div>` externe, le `<span>` qui décompte le temps écoulé, et le `<div>` interne qui affiche le progrès de la vidéo.
3. Ensuite, insérez ce qui suit en bas de votre code :

```js
media.removeAttribute("controls");
controls.style.visibility = "visible";
```

Ces deux lignes suppriment les contrôles par défaut du navigateur sur la vidéo, et rendent nos contrôles personnalisés visibles.

#### Lecture et pause de la vidéo

Imlémentons le contrôle le plus important — le bouton play/pause.

1. Tout d'abord, ajoutez ce qui suit au bas de votre code, pour que la fonction `playPauseMedia()` soit invoquée quand le bouton play est cliqué :

```js
play.addEventListener("click", playPauseMedia);
```

2. Maintenant, définissons `playPauseMedia()` — ajoutez ce qui suit, toujours au bas de votre code :

```js
function playPauseMedia() {
  if (media.paused) {
    play.setAttribute("data-icon", "u");
    media.play();
  } else {
    play.setAttribute("data-icon", "P");
    media.pause();
  }
}
```

Ici, nous utilisons une instruction `if` pour vérifier si la vidéo est en pause. La propriété `HTMLMediaElement.paused` (en-US) retourne vrai si le média est en pause — c'est le cas quand la vidéo n'est pas en cours de lecture, y compris quand la vidéo est au début après son chargement. Si elle est en pause, nous définissons la valeur de l'attribut `data-icon` à "u", qui est une icône "en pause", et invoquons la méthode `HTMLMediaElement.play()` pour jouer le média.
 Au second clic, le bouton sera de nouveau alterné — l'icône "play" sera affiché, et la vidéo sera mise en pause avec `HTMLMediaElement.paused()` (en-US).

#### Stopper la vidéo

1. Ajoutons la possibilité d'arrêter la vidéo. Ajoutez les lignes `addEventListener()` suivantes au-dessous de vos ajouts précédents :

```js
stop.addEventListener("click", stopMedia);
media.addEventListener("ended", stopMedia);
```

L'événement `click` est explicite — nous voulons stopper la vidéo en appelant la fonction `stopMedia()` quand le bouton stop est cliqué. Cependant, nous voulons également stopper la vidéo quand elle a fini de jouer — signalé par l'événement `ended`, nous pouvons donc mettre en place un gestionnaire d'événement pour exécuter la fonction quand cet évènement se produit.
2. Ensuite, définissons `stopMedia()` — ajoutez ce qui suit après la fonction `playPauseMedia()` :

```js
function stopMedia() {
  media.pause();
  media.currentTime = 0;
  play.setAttribute("data-icon", "P");
}
```

Il n'y a pas de méthode `stop()` dans l'API HTMLMediaElement — l'équivalent du stop est de mettre `pause()` sur la vidéo, et de définir la propriété `currentTime` (en-US) à 0. Définir une valeur à `currentTime` (en secondes) change immédiatement la position du temps du média.
 Tout ce qui nous reste à faire après ça est d'afficher l'icône "play". Que la vidéo ait été en train de jouer ou en pause, quand le bouton stop est pressé, vous voulez qu'elle doit prête à être lue.

#### Retour arrière et avance rapide

Il y a différentes manières d'implémenter le retour arrière et l'avance rapide; ici, nous vous montrons une manière relativement complexe de le faire, qui n'a pas de comportement inattendu quand différents boutons sont pressés dans un ordre aléatoire.

1. Tout d'abord, ajoutez les lignes `addEventListener()` suivantes à la suite des précédentes :

```js
rwd.addEventListener("click", mediaBackward);
fwd.addEventListener("click", mediaForward);
```

2. Maintenant, occupons-nous des fonctions des gestionnaires d'évènement — ajoutez le code suivant à la suite des fonctions précédentes pour définir `mediaBackward()` et `mediaForward()` :

```js
var intervalFwd;
var intervalRwd;

function mediaBackward() {
  clearInterval(intervalFwd);
  fwd.classList.remove("active");

  if (rwd.classList.contains("active")) {
    rwd.classList.remove("active");
    clearInterval(intervalRwd);
    media.play();
  } else {
    rwd.classList.add("active");
    media.pause();
    intervalRwd = setInterval(windBackward, 200);
  }
}

function mediaForward() {
  clearInterval(intervalRwd);
  rwd.classList.remove("active");

  if (fwd.classList.contains("active")) {
    fwd.classList.remove("active");
    clearInterval(intervalFwd);
    media.play();
  } else {
    fwd.classList.add("active");
    media.pause();
    intervalFwd = setInterval(windForward, 200);
  }
}
```

Vous remarquerez que nous commençons par initialiser deux variables — `intervalFwd` et `intervalRwd` — vous verrez à quoi elles servent plus tard.
 Voyons pas à pas `mediaBackward()` (`mediaForward()` fait la même chose, mais dans l'autre sens) :
    1. Nous effaçons les classes et intervales qui sont définits sur la fonctionnalité d'avance rapide — de cette manière, si on presse le bouton `rwd` après avoir pressé le bouton `fwd`, on annule l'avance rapide et la remplaçons avec le retour arrière. Si on essayait de faire les deux à la fois, le lecteur échouerait.
    2. Nous utilisons une instruction `if` pour vérifier si la classe `active` a été définie sur le bouton `rwd`, ce qui indique qu'il a déjà été pressé. La propriété `classList` est une propriété plutôt pratique qui existe sur chaque élément — elle contient une liste de toutes les classes définies sur l'élément, ainsi que des méthodes pour en ajouter/supprimer, etc. Nous utilisons la méthode `classList.contains()` pour vérifier si la liste contient la classe `active`. Cela retourne un booléen `true`/`false` en résultat.
    3. Si la classe `active` a été définie sur le bouton `rwd`, nous la supprimons avec `classList.remove()`, effaçons l'intervale qui a été définit sur le bouton quand il a été pressé (voir ci-dessous pour plus d'explication), et utilisons `HTMLMediaElement.play()` pour annuler le retour arrière et démarrer la vidéo normalement.
    4. Sinon, nous ajoutons la classe `active` sur le bouton `rwd` avec `classList.add()`, mettons la vidéo en pause en utilisant `HTMLMediaElement.pause()` (en-US), puis définissons la variable `intervalRwd` en appelant `setInterval()` (en-US). Quand elle invoquée, la fonction `setInterval()` créé un intervale actif, ce qui signifie qu'une fonction donnée en paramètre est exécutée toutes les x millisecondes — x est la valeur du 2ème paramètre. Ainsi, nous exécutons ici la fonction `windBackward()` toutes les 200 millisecondes — nous utiliserons cette fonction pour retourner la fonction en arrière de manière constante. Pour stopper un intervale actif, vous devez appeler `clearInterval()` en lui donnant l'intervale à arrêter en paramètre, dans notre cas il est stocké dans la variable `intervalRwd` (voir l'appel à `clearInterval()` effectué plus tôt dans la fonction).
3. Pour en finir avec cette section, nous devons définir les fonctions `windBackward()` et `windForward()` invoquées dans les appels `setInterval()`. Ajoutez ce qui suit après les deux fonctions précédentes :

```js
function windBackward() {
  if (media.currentTime <= 3) {
    rwd.classList.remove("active");
    clearInterval(intervalRwd);
    stopMedia();
  } else {
    media.currentTime -= 3;
  }
}

function windForward() {
  if (media.currentTime >= media.duration - 3) {
    fwd.classList.remove("active");
    clearInterval(intervalFwd);
    stopMedia();
  } else {
    media.currentTime += 3;
  }
}
```

Encore une fois, nous allons voir pas à pas la première fonction, puisque les deux fonctions font la même chose mais dans le sens inverse. Dans `windBackward()`, nous faisons comme suit — gardez à l'esprit que la fonction est exécutée toutes les 200 millisecondes.
    1. Nous commençons avec une instruction `if` qui vérifie si le temps en cours est inférieur à 3 secondes, c'est à dire si le retour arrière nous ramènerait avant le début de la vidéo. Cela provoquerait un comportement étrange. Ainsi, si c'est le cas, nous arrêtons la vidéo en appelant `stopMedia()`, supprimons la classe `active` du bouton, et stoppons l'intervale `intervalRwd` pour stopper le retour arrière. Si nous n'avions pas ajouté cette dernière étape, la vidéo continuerait de se remboniner éternellement.
    2. Si le temps en cours n'est pas inférieur à 3 secondes, nous retournons en arrière de 3 secondes en exécutant `media.currentTime -= 3`. Dans les faits, on rembobine donc la vidéo de 3 secondes toutes les 200 millisecondes.

#### Mettre à jour le temps écoulé

La dernière chose à implémenter pour notre lecteur multimédia est l'affichage du temps écoulé. Pour ce faire, nous allons exécuter une fonction pour mettre à jour le temps affiché à chaque fois que l'événement `timeupdate` est déclenché sur l'élément `<video>`. La fréquence à laquelle cet événement se déclenche dépend de votre navigateur, de la puissance de votre CPU, etc (voir post stackoverflow).

Ajoutez la ligne `addEventListener()` suivante à la suite des autres :


```js
media.addEventListener("timeupdate", setTime);
```


Maintenant, ajoutez la fonction `setTime()` :


```js
function setTime() {
  var minutes = Math.floor(media.currentTime / 60);
  var seconds = Math.floor(media.currentTime - minutes \* 60);
  var minuteValue;
  var secondValue;

  if (minutes < 10) {
    minuteValue = "0" + minutes;
  } else {
    minuteValue = minutes;
  }

  if (seconds < 10) {
    secondValue = "0" + seconds;
  } else {
    secondValue = seconds;
  }

  var mediaTime = minuteValue + ":" + secondValue;
  timer.textContent = mediaTime;

  var barLength =
    timerWrapper.clientWidth \* (media.currentTime / media.duration);
  timerBar.style.width = barLength + "px";
}
```


C'est une fonction assez longue, alors allons-y étape par étape :

1. Tout d'abord, nous récupérons le nombre de minutes et de secondes à partir de `HTMLMediaElement.currentTime` (en-US).
2. Ensuite, on initialise deux variables supplémentaires — `minuteValue` et `secondValue`.
3. Les deux instructions `if` qui suivent déterminent si le nombre de minutes et secondes est inférieur à 10. Si c'est le cas, on ajoute un zéro à gauche pour afficher le numéro sur deux chiffres — comme sur une horloge digitale.
4. Le temps est au final la concaténation de `minuteValue`, un caractère deux-points, et `secondValue`.
5. Le temps qu'on vient de définir devient la valeur `Node.textContent` du décompte, pour qu'il s'affiche dans l'interface utilisateur.
6. La largeur que nous devons donner `<div>` intérieur est calculée en récupérant la largeur du `<div>` externe (la propriété `clientWidth` retourne la largeur de l'élément), et en la multipliant par `HTMLMediaElement.currentTime` (en-US) divisé par le total `HTMLMediaElement.duration` (en-US) du média.
7. Nous assignons la largeur du `<div>` intérieur à la valeur calculée, plus "px", il sera donc fixé à ce nombre de pixels.

#### Corriger play et pause

Il nous reste un problème à régler. Si on presse les boutons play/pause ou stop pendant que le retour arrière ou l'avance rapide sont actifs, alors ça ne marchera pas. Comment corriger le code pour qu'ils annulent l'action `rwd`/`fwd` et joue/stoppe la vidéo comme on s'y attendrait? C'est relativement simple.

Tout d'abord, ajoutez les lignes qui suivent à l'intérieur de la fonction `stopMedia()` — n'importe où :


```js
rwd.classList.remove("active");
fwd.classList.remove("active");
clearInterval(intervalRwd);
clearInterval(intervalFwd);
```


Maintenant, ajoutez ces mêmes lignes une fois de plus, au début de la fonction `playPauseMedia()` (juste avant le début de l'instruction `if`).

À ce stade, vous pouvez supprimer les lignes équivalentes des fonctions `windBackward()` et `windForward()`, puisqu'elles ont été ajoutées à la fonction `stopMedia()` à la place.

**Note :** Vous pouvez améliorer votre code en créant une fonction séparée qui exécute ces lignes, et l'appeler aux endroits où vous en avez besoin plutôt que de répéter ces lignes à de multiples endroits du code. Mais nous vous laissons vous en occuper.

**Note :** Le code terminé est disponible sur Github (le voir en direct).

Sommaire
--------

Je pense que nous vous en avons suffisamment appris dans cet article. L'API `HTMLMediaElement` offre une multitude de fonctionnalités pour la création de lecteurs audio et vidéo simples, et ce n'est que le sommet de l'iceberg. La section "Voir aussi" ci-dessous vous fournirea des liens vers des fonctionnalités plus complexes et plus intéressantes.

Voici quelques suggestions de modifications à apporter à l'exemple que nous avons construit :

1. Si la vidéo dure plus d'une heure, le temps écoulé va bien afficher les minutes et les secondes mais pas les heures. Changez l'exemple pour lui faire afficher les heures.
2. Parce que les éléments `<audio>` ont la même fonctionnalité `HTMLMediaElement` de disponible, vous pouvez faire fonctionner ce lecteur avec un élément `<audio>`. Essayez de le faire.
3. Trouvez un moyen de transformer le `<div>` interne en une véritable barre de progrès — quand vous cliquez quelque part sur la barre, vous vous déplacez à la position relative dans la vidéo. Un indice: vous pouvez trouver les valeurs X et Y des côtés gauche/droite et haut/bas d'un l'élément via la méthode `getBoundingClientRect()`, et vous pouvez trouver les coordonnées de la souris au moment du clic à l'intérieur de l'objet `event` du clic, appelé sur l'objet `Document`. Par exemple :

```js
document.onclick = function (e) {
  console.log(e.x) + "," + console.log(e.y);
};
```

Voir aussi
----------

* `HTMLMediaElement`
* Contenu audio et vidéo — simple guide aux `<video>` et `<audio>` HTML.
* Intégration audio et vidéo — guide détaillé sur l'intégration de média dans le navigateur, avec de nombreux conseils, astuces et liens vers des tutoriels plus avancés.
* Manipulation audio et vidéo — guide détaillé pour manipuler l'audio et vidéo avec Canvas API, Web Audio API, et plus encore.
* Les pages référence `<video>` et `<audio>`.
* Formats pris en charge par les éléments HTML audio et vidéo.
* Précédent
* Aperçu : Client-side web APIs
* Suivant