Common patterns when handling promises

Promises are becoming a top feature of JavaScript. They’re already part of most libraries and frameworks (jQuery, WinJS and AngularJS among others) and will soon be included natively in all browsers with the upcoming delivery of ECMAScript 6 (the standard behind JavaScript). They are heavily used every time you have to deal with asynchronous calls, like in Ajax, or in Single Page Applications which rely a lot on them.

I’ve been using them proficiently for different projects, and I noticed there are common patterns that keep popping in my code, and are not necessarily well known for the time being. I propose we take a look at three of them. Lire la suite

Retour sur la conférence NCRAFTS 2014

Pendant que certains de mes collègues participaient au hackaton organisé par Microsoft pour l’évènement //publish, j’ai pour ma part eu le plaisir de me rendre à la première édition de la conférence NCRAFTS organisée le 16 mai dernier par l’association ALT.NET. Cette association promeut les solutions alternatives en .NET et une vision du développement informatique axée autant sur l’artisanat que sur l’ingénierie. Je vous propose donc un compte-rendu de ce que j’ai pu glaner au cours des session auxquelles j’ai pu assister. Lire la suite

Les blogs pour faire de la veille technologique en .NET

Les équipes de MCNEXT espèrent que ce blog vous permet d’améliorer toujours un peu plus vos connaissances des technologies Microsoft. Il existe néanmoins d’autres blogs qui valent le détour sur ce sujet. En l’occurrence, je vais vous parler des blogs que je consulte régulièrement – via leur flux RSS – pour me tenir au courant des dernières avancées en matière de développement en .NET.

Les auteurs de ces différents blogs, lorsqu’ils ne travaillent pas pour Microsoft, sont généralement des MVPs reconnus par la communauté pour leur expertise technique et leurs capacités à partager leurs connaissances. Par ailleurs ils ont tous un point commun : c’est un vrai plaisir de les lire.

Croyez bien que c’est tout à fait involontaire de ma part, mais tous ces blogs sont en anglais. J’espère donc que vous maîtrisez la langue de Shakespeare.

Scott Guthrie est le directeur de toute la stack web chez Microsoft, et même plus encore. Son blog lui sert à annoncer régulièrement les nouveautés dans le monde d’ASP.NET et d’Azure. Ses articles sont généralement pointus mais très bien expliqués, et il en publie de nouveaux à intervalle très régulier. Je lui reprocherais juste un côté un peu « corporate », et le fait que les sujets ont tendance à s’entrechoquer. En fonction de vos affinités, tout ne vous intéressera pas, mais cela reste néanmoins une source d’information incontournable si vous êtes du métier.

Scott Hanselman est le pendant plus « geek » de Scott Guthrie. Lui aussi travaille pour la stack web, à un degré de hiérarchie moindre, et lui aussi publie très régulièrement de nouveaux articles. Mais il est par ailleurs très drôle, a un don pour savoir mettre en avant des connaissances vraiment utiles, et il n’hésite pas à parler de sujets très variés tout en réunissant à les connecter au monde du développement informatique. A lire absolument : ses réflexions sur sa condition de diabétique de niveau 1 et l’état de la technologie dans ce domaine.

Ayende Rahien, de son vrai nom Oren Eini, est une sommité dans le monde Microsoft. Spécialiste du développement .NET, il publie au minimum un article par jour, et ceux-ci sont souvent passionnants. Il a la particularité de publier des articles à suivre sous forme de feuilleton, autour d’un sujet bien précis : NHibernate, le développement de son propre moteur de stockage de données (VORON), ou plus récemment le fonctionnement de Lucene.NET. Au fil des ans il est devenu de plus en plus pointu, et j’avoue avoir parfois du mal à suivre lorsqu’il explique les algorithmes à l’œuvre dans certains produits que commercialise sa société (Hibernating Rhinos), mais c’est aussi un très bon moyen de se remuer les méninges.

Rick Strahl est aussi un auteur très prolifique. Il n’est d’ailleurs pas rare de tomber sur son blog au détour d’une recherche depuis Google sur le monde ASP.NET. Cette technologie est sa grande spécialité et ses articles sont une vraie mine d’or en matière de bonnes pratiques, astuces diverses et solutions aux nombreux problèmes auxquels il a pu lui-même été confronté. Un gros défaut cependant : ce salaud habite à Hawaï.

Jeff Atwood et son blog Coding Horror. Jeff Atwood n’est autre que l’un des fondateurs de Stackoverflow que je ne vous ferai pas l’insulte de présenter. Son blog est moins technique et parle d’avantage de choses comme la motivation, comment recruter les bons collaborateurs, comment s’organiser, et c’est tout aussi passionnant, surtout sous sa plume.

K. Scott Allen est un vieux briscard du monde .NET qui partage ses astuces et réflexions en matière de développement informatique. Ses connaissances épousent tout un pan de la galaxie .NET, et il est n’est pas avare en exemples de code que vous passerez de nombreuses heures à étudier.

Kraig Brockschmidt est l’auteur du très bon livre Programming Windows Store Apps With HTML CSS and JavaScript, disponible gratuitement au téléchargement chez Microsoft Press, dont la seconde édition vient juste de sortir. Ce grand spécialiste de WinJS profite de son blog pour distiller des connaissances de base sur son sujet de prédilection, ou aborder des aspects qui ne trouvaient par leur place dans l’ebook.

Troy Hunt est une découverte récente pour ma part. Spécialiste d’Azure et de sécurité informatique (en particulier autour de la stack web .NET), Troy publie très régulièrement des articles longs et très détaillés. Il a par exemple abordé les bonnes pratiques à appliquer en matière de mot de passe informatique, de quelle manière selon lui une grande compagnie américaine s’est faite pirater sa base de comptes clients. Dans un billet plus récent, il explique avec brio comment fonctionne le bug qui frappe actuellement OpenSSL, pourquoi il faut s’en émouvoir, comment s’en protéger, et quels impacts celui-ci peut avoir sur un système informatique. A lire absolument.

La trousse à outils du développeur HTML5

Le monde du web est en pleine effervescence avec la mise au point en parallèle des normes HTML5, CSS3 et ECMAScript 6. Dans le même temps, les développements web se font plus diverses, intégrant maintenant des notions telles que le responsive design, la mobilité, ou l’hypermedia.

Les frontières bougeant rapidement, il devient parfois difficile de suivre l’actualité et de se former efficacement sur les nouveautés et sur l’utilisation des nouveaux outils, à moins d’avoir le courage d’aller lire le document de normalisation.

C’est pourquoi je vous propose aujourd’hui une liste de ressources qui vous permettront de vous tenir à jour, et peut-être de découvrir de quoi sera fait le monde HTML5 de demain.

Les sites web pour se documenter

Que vous vouliez vérifier la syntaxe d’une fonction JavaScript ou simplement apprendre à utiliser de nouvelles fonctionnalités, le web est maintenant riche de ressources qui vous permettront de creuser en profondeur aussi bien les anciens sujets que les toutes dernières nouveautés de la norme HTML5.

  • W3Schools, qu’on ne présente plus tant il a permis de mettre le pied à l’étrier de toute une génération de développeurs web. Le site propose toute une section consacrée à HTML5, qui parle essentiellement des éléments de la norme qui sont d’ores et déjà stabilisés. Pour l’anecdote, contrairement à ce que croient beaucoup de développeurs, le site W3Schools n’est en aucun cas associé au W3C, l’organisme qui régit la norme HTML5. Il s’agit d’une entité totalement indépendante.
  • Mozilla Developper Network (MDN), un effort de la fondation Mozilla, bien connue pour son navigateur Firefox. Ce site propose une documentation riche et très complète sur tout ce qui touche au HTML5, y compris ses aspects toujours en cours de normalisation. De nombreux tutoriaux permettent de mettre directement les mains dans le cambouis, avec des exemples de code clairs et pédagogiques, ce qui est toujours appréciable. MDN a par ailleurs le bon goût de ne pas se limiter aux fonctionnalités supportées par Firefox, mais au contraire de proposer pour chacune d’entre elles un tableau établissant quel navigateur les supporte, et les éventuels cas particuliers (fonctionnalité supportée partiellement).
  • HTML5 Rocks, un site supporté par Google qui propose des articles sur différents sujets autour du HTML5. Le site est conçu sur un principe de communauté ouverte où chacun est libre de proposer de nouveaux articles ou de corriger les articles plus anciens, par le biais d’un repo GitHub. On trouve quelques belles plumes sur ce site, comme Paul Irish ou Paul Lewis.

Les sites pour juger la compatibilité

Le principal problème avec lequel le développeur HTML5 doit composer, est la notion de compatibilité des navigateurs avec les fonctionnalités HTML5. De cette compatibilité va dépendre la nécessité d’utiliser ou non des polyfills, et d’appliquer les principes de graceful degradation et d’amélioration progressive.

  • Can I Use propose une matrice des fonctionnalités du monde HTML5, et des différents navigateurs du marché. Il vous permet donc d’un seul coup d’œil de savoir quel navigateur supporte quelles fonctionnalités. Ce site est rapidement devenu un incontournable, car nous sommes dans une période de transition où il est très important de faire attention à ce que les aspects de la norme HTML5 (ou de ses cousines CSS3 et ECMAScript 5) que nous souhaitons utiliser dans nos développements sont bien supportés par le parc de navigateurs visé. Dans ce domaine, Can I Use est la référence absolue. Il est très clair, facile à utiliser avec son moteur de recherche, et surtout il a le mérite d’être très régulièrement mis à jour, aussi bien avec de nouvelles fonctionnalités en cours de normalisation, qu’avec les nouvelles versions des navigateurs mises sur le marché.
  • QuirksMode est un bon complément à Can I Use. Le site existe depuis plus longtemps, et s’avère parfois plus précis pour expliquer comment sont supportées certaines vieilles fonctionnalités par de non moins anciens navigateurs. Le site est aussi très bavard pour qui s’intéresse à l’histoire du web. Par contre son interface commence à se faire vieillissante, et le site ne semble plus être mis à jour qu’épisodiquement.
  • Les matrices des fonctionnalités ECMAScript 5 et le futur ECMAScript 6 présentent les nouvelles fonctionnalités introduites dans ces deux normes du langage JavaScript, et indiquent quels navigateurs les supportent. Ces tableaux sont tout d’abord très utile d’un point de vue éducatif, car ils permettent de se faire une bonne idée des nouveautés du langage JavaScript. En terme de compatibilité, tous les nouveaux navigateurs supportent maintenant ECMAScript 5, mais il est intéressant de pouvoir déterminer lesquels ont commencé à supporter ECMAScript 6 (qui est toujours en cours de normalisation) et quelles nouvelles solutions cette norme va nous apporter.
  • Modernizr n’est pas à proprement parler un site, mais une librairie à la fois CSS et JavaScript, permettant de faire de la détection de fonctionnalités. Côté CSS, Modernizr ajoute automatiquement dans la balise <html> des classes qui vont indiquer si le navigateur courant supporte ou non, par exemple les coins arrondis (les classes borderradius et no-borderradius). Côté JavaScript, Modernizr propose une API permettant d’effectuer les mêmes tests, cette fois-ci déclarativement, pour s’en servir comme condition dans notre code. Tout cela permet d’appliquer les principes d’amélioration progressive dont nous avons parlé plus haut. Personnellement, j’évite généralement de charger cette librairie, en préférant en extraire simplement le morceau de code correspondant au test que j’ai besoin d’effectuer.

Les outils de développement

L’époque où l’on devait presser Ctrl+F5 toutes les 10 secondes est maintenant révolue. L’écosystème du développement web est maintenant riche de très nombreuses applications et plugins qui peuvent vous faire gagner un temps phénoménal.

  • Firebug a longtemps été un pionnier du débugage dans les navigateurs, mais aujourd’hui, ils disposent tous d’un tel outil. Quel que soit le choix que vous avez fait, il y a forcément une console qui accompagne votre navigateur préféré. De nos jours, elles permettent toutes, à minima, d’ausculter et de modifier à la volée le code HTML et styles CSS de la page, ainsi que de débuguer le code JavaScript (avec des points d’arrêt, des espions et l’accès à la stack) et d’afficher les requêtes HTTP. Firebug permet aussi d’examiner les cookies liés à la page courante. Chrome nécessitera pour se faire une autre extension : Edit this cookie.
  • YSlow est un très bon outil conçu par les développeurs web de Yahoo!, disponible sous forme de plugin pour la plupart des navigateurs (à l’exception notable d’Internet Explorer). Il vous permet de jauger la rapidité de rendu de vos pages web, et vous suggère différentes optimisations que vous pourriez effectuer afin d’améliorer votre score. Il dispose aussi d’outils complémentaires comme JSLint, un parser JavaScript permettant d’analyser votre code afin d’y décéler les mauvais usages, ou de Smush.it, un outil permettant d’optimiser la compression des images utilisées par votre site.
  • Autre très bonne extension pour Firefox, Tamper Data permet d’intercepter les formulaires POST et de les modifier à la volée. Très utile pour se retrouver plus rapidement en tête des highscores de votre jeu préféré. 🙂
  • Dans le même ordre d’idée, l’extension Postman pour Chrome permet de fabriquer vos propres requêtes HTTP, chose très utile pour tester des services REST.
  • Bien connu des développeurs web, racheté en 2012 par Telerik mais toujours gratuit, Fiddler est un outil de plus haut niveau que les consoles de développement. Il permet de sniffer le trafic HTTP qui circule sur votre machine, y compris sur la boucle Localhost, et de l’analyser, voire le modifier. C’est un incontournable, extrêmement complet (au point que je ne pense pas connaître les trois quart de ses fonctionnalités) qui se révèlera être votre meilleur ami lorsque vous aurez tôt ou tard besoin de débuguer au plus près les requêtes HTTP.
  • Encore plus haut niveau, WireShark (ex-Ethereal) est plutôt un outil pour administrateur réseau, mais il s’avère parfois nécessaire d’en arriver à cette extrémité lorsque le problème dépasse la seule couche applicative (où se trouve le protocole HTTP). Je vous souhaite d’avoir rarement à vous en servir car son utilisation est généralement synonyme d’un problème de réseau assez compliqué à résoudre pour un humble développeur web.
  • Il y a malheureusement encore beaucoup de vieilles versions d’Internet Explorer en circulation, ce qui implique la nécessité de tester nos sites web pour s’assurer de leur bon fonctionnement sur celles-ci. Pour se faire, vous pouvez utiliser les dernières versions de ce navigateur qui dispose d’émulateurs pour les versions antérieures. Malheureusement, ça ne marche pas toujours très bien. La meilleure alternative que j’ai pu trouver, en dehors de créer une machine virtuelle avec une vieille version de Windows (seule solution 100% fiable), est de passer par IETester, qui propose de reproduire le comportement des anciennes versions d’Internet Explorer, en réutilisant les moteurs originaux, gage de fidélité dans le comportement. Cet outil semble néanmoins sujet à de nombreux bugs, mais pour du débugage rapide c’est la meilleure solution que je connaisse.

Conclusion

Cette liste ne se veut pas exhaustive. Aussi, n’hésitez pas à partager vos propres recommandations dans les commentaires si le cœur vous en dit.

JavaScript, un langage single-thread

JavaScript, il faut le savoir, est un langage single-thread. Cela signifie que le code d’une page s’exécute sur un seul et unique thread, et qu’aucun appel n’est dispatché.

Prenons un exemple concret (on utilise jQuery pour simplifier) et essayons de déterminer dans quel ordre va s’exécuter le code suivant :

// 1. Code principal
console.log("Code principal");
var element = $("#mon-element");
element.on("click", onClick);

alert("Coucou!");

element.trigger("click");

someFunction();

// 2. Gestionnaire d'évènement
function onClick() {
  console.log("Gestionnaire d'évènement");
}

// 3. Méthode arbitraire
function someFunction() {
  console.log("Fonction arbitraire");
}

Et le résultat :

Capture console single-thread

On pouvait à priori s’y attendre, pourtant cet exemple mérite quelques commentaires.

Tout d’abord, l’appel à la fonction alert() a pour effet de bloquer l’exécution du code JavaScript. Tant que l’utilisateur n’aura pas cliqué sur le bouton de la fenêtre modale qui va s’afficher, le reste du code ne sera pas traité. On peut le voir facilement en mettant un point d’arrêt après la fonction.

Ensuite, il est intéressant de noter que le gestionnaire d’évènement sera exécuté dès l’appel à trigger(), et non pas mis en file d’attente comme on aurait pu le croire.

Une conséquence importante de la nature single-thread du JavaScript est que le code s’exécute sur le même thread que le thread graphique. Cela signifie que pendant ce temps l’interface utilisateur est bloquée (impossible de cliquer sur les boutons), et qu’aucun repaint de la page (rafraîchissement de l’affichage) ne peut être effectué.

Par exemple, si l’on essaie de faire tourner une boucle infinie, on constate qu’au bout de quelques secondes le navigateur nous propose d’arrêter le script qui selon lui « ne répond pas ». Tous les navigateurs modernes affichent ce comportement, qui vise à empêcher que des scripts malicieux ou mal conçus ne viennent perturber l’expérience utilisateur.

// Boucle infinie
while(true) {}

Capture firefox blocage

Mais nous allons voir maintenant que certaines fonctions peuvent faire varier l’ordre d’exécution du code JavaScript, et nous aider à résoudre les problèmes dus à des scripts trop longs à s’exécuter.

L’asynchronisme en JavaScript

Certaines tâches en JavaScript peuvent s’exécuter de manière asynchrone, c’est-à-dire de manière décalée par rapport au code principal. Cela peut être soit subi soit provoqué par le développeur lui-même.

Un exemple d’appel asynchrone subi est un appel Ajax. Lorsque l’on contacte le serveur pour récupérer des données, il est impossible de savoir combien de temps celui-ci mettra pour nous répondre, c’est pourquoi on indique une fonction de « callback » qui sera chargée de traiter le résultat retourné. Le navigateur va donc exécuter l’appel Ajax, attendre la réponse du serveur, puis exécuter le callback.

$.ajax("/UNE-URL-QUELCONQUE").done(function () {
  // Callback
});

// Ce code s'exécutera AVANT le callback
var toto = "toto";

Pendant le temps d’attente qui suit l’appel au serveur, deux faits remarquables vont se dérouler. Tout d’abord, le moteur JavaScript va traiter tout code en attente d’exécution, et notamment le code qui pourrait avoir été déclaré à la suite de l’appel Ajax. Ensuite, une fois que tout le code en attente aura été exécuté et si le serveur n’a toujours pas répondu, le moteur JavaScript rendra la main au thread graphique, permettant ainsi à l’utilisateur d’interagir normalement avec la page. Ce n’est que lorsque le serveur aura répondu que le thread graphique sera de nouveau interrompu afin de laisser le moteur JavaScript exécuter notre callback de traitement de la réponse.

Mais il est aussi possible de provoquer volontairement des appels asynchrones. Pour cela on utilise les méthodes JavaScript setTimeout() et setInterval(). Ces méthodes permettent respectivement de retarder l’exécution d’une fonction selon un temps d’attente défini, et de répéter l’exécution d’une fonction selon un intervalle de temps défini.

var timeoutId = setTimeout(function () {
  // Cette fonction s'exécutera dans 1 seconde (1000 millisecondes)
}, 1000);

Pendant le temps qu’attendra le navigateur avant d’exécuter le callback, l’interface utilisateur sera libérée. Ce sont ces fonctions que l’on utilise pour gérer l’affichage d’une animation (sur les vieux navigateurs) et surtout pour permettre au thread graphique de prendre une grande bouffée d’air avant de lancer une routine susceptible de mettre très longtemps à s’exécuter, anticipant ainsi l’affichage de l’avertissement « le script ne répond pas » que nous avons vu plus haut. Ces méthodes renvoient un identifiant unique (un nombre entier en fait) qui permet à tout moment d’annuler l’exécution retardée des callbacks avec respectivement les méthodes clearTimeout() et clearInterval().

// Finalement j'ai changé d'avis
// et je ne souhaite pas que le callback soit exécuté
clearTimeout(timeoutId);

Notez qu’Internet Explorer depuis la version 10 propose également la fonction setImmediate(), qui est l’équivalent d’un setTimeout() avec un délai d’attente de zéro. Son utilisation revient à dire au moteur JavaScript : termine de traiter tout ce qui est en attente, laisse le thread graphique faire un repaint, et ensuite seulement occupe-toi de ce bloc de code. Cette méthode, bien qu’elle n’ait pas été homologuée par le W3C, peut être très utile dans le cadre du développement d’applications Windows Store avec WinJS.

Au chapitre des fonctions introduisant de l’asynchronisme dans JavaScript, on peut aussi citer requestAnimationFrame(), une nouveauté HTML5 qui permet de demander au navigateur ne nous réserver une « fenêtre » avant le prochain repaint. C’est la méthode moderne pour qui veut gérer plus finement l’affichage de ses animations.

Les WebWorkers

Les WebWorkers sont une nouveauté HTML5 permettant d’exécuter du code JavaScript dans une tâche de fond, c’est-à-dire de faire du multi-thread. L’intérêt est de pouvoir effectuer côté client de lourds calculs dans un thread séparé, permettant ainsi de ne pas bloquer le thread graphique.

Pour cela, on doit déporter le code qui sera traité dans un fichier .js séparé. Le thread principal et le thread de tâche de fond que représente ce fichier pourront alors discuter par le biais d’une API de message.

// On créé un WebWorker en indiquant le fichier .js
var backgroundTask = new Worker("background-task.js");

// On s'abonne aux messages que va renvoyer le WebWorker
backgroundTask.addEventListener("message", function (event) {
  // Traitement des données renvoyées par le WebWorker
  var returnedData = event.data;
});

// On poste un message au WebWorker pour le lancer
backgroundTask.postMessage("");

Contenu du fichier « background-task.js » (le WebWorker) :

// Le fait de recevoir un message du code principal
// lance le traitement du WebWorker
onmessage = function (event) {
  var mainThreadData = event.data;

  // On simule une opération longue à s'exécuter
  setTimeout(
        function () {
            postMessage("Coucou du WebWorker!");
        },
        5000
    );
};

Le thread principal et le WebWorker peuvent s’échanger du JSON mais les données seront dupliquées. Comprendre : les modifier d’un côté ne les modifiera pas de l’autre, il faut les échanger grâce à l’API de message. Notez aussi que les WebWorkers reposent sur des threads gérés par le système d’exploitation lui-même.

Les WebWorkers ont toutefois une lourde limitation : ils s’exécutent dans une sorte de « bac à sable » conçu pour limiter les problèmes de sécurité, et à ce titre ils n’ont pas accès aux variables globales de l’objet window, notamment jQuery et document. Autrement dit les WebWorkers n’ont pas accès au DOM.

Ce dernier point peut s’avérer problématique, car JavaScript est souvent utilisé pour manipuler le DOM afin de modifier le rendu de la page web. Il est toutefois possible de résoudre cette difficulté en rusant. Par exemple, imaginons que nous ayons dans notre page un tableau contenant quelques centaines de lignes. Nous voulons trier celles-ci en fonction d’une donnée qu’elles contiennent afin de modifier ensuite leur ordre d’affichage. Le calcul permettant de faire le tri étant assez lourd, nous allons le déléguer à un WebWorker à qui nous enverrons un tableau contenant des paires « id de la ligne / donnée de tri ».

// On invoque un WebWorker et on lui envoie les données à trier
var tableSorter = new Worker("background-task.js");
tableSorter.postMessage([
  { "id": "line-1", "data": "Pierre" },
  { "id": "line-2", "data": "Paul" },
  { "id": "line-3", "data": "Jacques" }
]);

La responsabilité du WebWorker sera alors d’effectuer le plus gros du travail en triant le tableau, avant de renvoyer au thread principal un nouveau tableau contenant les ids dans l’ordre attendu. Il ne restera donc plus qu’à manipuler le DOM pour remettre les lignes dans le bon ordre.

// Le WebWorker se charge de l'opération la plus lourde : le tri
onmessage = function (event) {
  var tableData = event.data;
  tableData.sort(function (a, b) {
    if (a.data > b.data)
      return 1;

    if (a.data < b.data)
      return -1;

    return 0;
  });

  return tableData.map(function (line) {
    return line.id;
  });
};

Conclusion

Si vous voulez aller plus loin je vous invite à lire cette réponse sur StackOverflow, qui donne des détails intéressants sur l’aspect single-thread de JavaScript, notamment sur le fait qu’il est possible de « tricher » pour faire s’exécuter du code lorsque par exemple une fenêtre modale « alert » est affichée.

La délégation d’évènement avec jQuery

Une fonctionnalité méconnue et pourtant très utile de jQuery est la délégation d’évènement. Elle permet de brancher un gestionnaire d’évènement sur un élément parent de l’élément que l’on veut réellement écouter.

Pas assez clair? Pour mieux comprendre faisons d’abord un petit rappel.

La notion de « bulle »

Lorsque l’on clique sur un élément du DOM, l’évènement « click » est déclenché sur le nœud en question, puis est propagé sur tous ses nœuds parents jusqu’à remonter sur l’élément racine du document, c’est-à-dire « body ».

Dans l’exemple suivant, si vous cliquez sur le bouton, l’évènement « click » sera d’abord déclenché sur le <button>, puis sur la <div>, puis <article>, <section> et enfin <body>.

<body>
  <section>
    <article>
      <div>
        <button></button>
      </div>
    </article>
  </section>
</body>

Cette remontée du DOM aura lieu que vous traitiez ou non l’évènement à quelque niveau que ce soit – bien qu’il soit possible de bloquer la bulle, mais c’est un autre sujet. Il est donc possible d’intercepter l’évènement à plusieurs reprises en branchant des gestionnaires d’évènement à différents niveaux.

$(document).ready(function () {
  $("article").on("click", function (e) {
	// Gestionnaire d'évènement sur <article>
  });
  
  $("button").on("click", function (e) {
	// Gestionnaire d'évènement sur <button>
  });
});

Dans ce dernier exemple, on branche deux gestionnaires d’évènement, un sur <button> et un sur <article>. Si l’on clique sur le bouton, le gestionnaire d’évènement branché sur <button> sera déclenché en premier, puis suite à la remontée de la bulle le long du DOM, ce sera le tour de celui qui est branché sur <article>. On voit que l’ordre dans lequel ils ont été abonnés importe peu.

Comment mettre en place la délégation

La méthode on() de jQuery permet d’indiquer un paramètre supplémentaire : un sélecteur désignant les nœuds enfants que l’on souhaite écouter. Dans ce cas, le gestionnaire branché sera déclenché lorsque l’évènement se sera propagé jusqu’à l’élément, mais uniquement si la cible initiale – par exemple l’élément sur lequel on a vraiment cliqué – respecte le sélecteur indiqué en paramètre.

$(document).ready(function () {
  $("article").on("click", "button" /* Sélecteur supplémentaire */, function (e) {
	// Gestionnaire d'évènement sur <article>
	// mais qui ne se déclenchera que si on a cliqué sur <button>
  });
});

C’est donc la présence de ce paramètre supplémentaire qui induit la délégation d’évènement dans jQuery.

Vous avez compris le principe. Voyons maintenant trois cas d’utilisation concrets, issus de mon expérience, qui vous démontreront tout l’intérêt que peut revêtir cette fonctionnalité.

Beaucoup d’éléments à écouter

Imaginez que vous affichiez un tableau HTML sur votre page web, que celui-ci contienne un million de cellules, et que vous souhaitiez brancher un gestionnaire d’évènement pour écouter les clicks sur chacune d’entre elles.

<table id="big-table">
  <tr>
    <!-- Ici plein de cellules -->
    <td></td>
    <td></td>
  </tr>
</table>

Si vous le faites en vous branchant individuellement sur chacune des cellules, vous allez enregistrer un million de gestionnaires d’évènement en mémoire. Inutile de vous dire que ce n’est pas une très bonne idée.

En utilisant la délégation vous pouvez brancher un seul gestionnaire d’évènement au niveau du tableau lui-même. Ce gestionnaire sera alors en mesure de traiter les clicks sur chacune des cellules.

$(document).ready(function () {
  $("#big-table").on("click", "td", function (e) {
	// Gestionnaire d'évènement unique pour l'ensemble des <td>
  });
});

A ce stade, vous devriez commencer à vous poser la question suivante : comment savoir quelle cellule a été clickée?

Pour ce cas de figure, jQuery a tout prévu, et dans l’argument passé en paramètre au gestionnaire d’évènement – appelé « e » dans notre exemple – vous trouverez trois propriétés qui vous permettront d’obtenir des informations.

  • e.target désignera l’élément qui a déclenché initialement l’évènement, c’est-à-dire la cellule.
  • e.currentTarget désignera l’élément sur lequel l’évènement est en train de buller, c’est-à-dire le tableau.
  • e.delegateTarget désignera l’élément sur lequel est branchée la délégation, c’est-à-dire ici encore le tableau.

Notez aussi que le mot-clef this comme e.currentTarget désignera toujours l’élément sur lequel l’évènement est en train de buller, c’est-à-dire celui correspodant au sélecteur que l’on a indiqué en paramètre de la fonction on().

Les fragments de code HTML

Imaginez que vous affichez une liste d’items.

<ul id="list">
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
  <li class="list-item"><button type="button" class="delete">Supprimer</button></li>
</ul>

Chacun de ces items peut être supprimé ou ré-ordonné dans la liste par glissé/déposé. Pour ce faire, on branche sur chacun des items des gestionnaires d’évènement chargés de traiter ces opérations.

$(document).ready(function () {
  $("#list .list-item").on("dragstart", function (e) {
	// Gestionnaire d'évènement de glissé/déposé
  });
  
  $("#list .list-item .delete").on("click", function (e) {
	// Gestionnaire d'évènement de suppression des items
  });
});

Une première remarque – inspirée de l’exemple précédent – est qu’il est possible de brancher les gestionnaires d’évènement par délégation sur la liste elle-même. Seulement voilà : cette liste est susceptible à tout moment d’être mise à jour par écrasement, suite par exemple à l’appel d’une requête Ajax.

function refreshList() {
  $.ajax("/UNE-URL-QUELCONQUE").done(function (html) {
  	$("#list").replaceWith(html);
	// Il faut rebrancher tous les gestionnaires d'évènements 😦
  });
}

Le problème, c’est qu’une fois cette opération d’écrasement effectuée, il faut rebrancher tous nos gestionnaires d’évènements car les éléments du DOM auxquels ils étaient rattachés ont été supprimés du document. Notez au passage qu’il est inutile de s’inquiéter du désabonnement de ces gestionnaires d’évènements, jQuery les nettoyant automatiquement lors de l’appel à la méthode replaceWith().

Pour pallier à l’inconvénient d’avoir à tout rebrancher à chaque rafraichissement de la liste, nous allons tout d’abord encadrer celle-ci avec un nouveau parent.

<div id="list-wrapper">
  <ul id="list">
    <!-- Ici les items -->
  </ul>
</div>

Nous allons ensuite brancher nos gestionnaires d’évènements par délégation sur ce nouvel élément.

$(document).ready(function () {
  $("#list-wrapper").on("dragstart", ".list-item", function (e) {
	// Gestionnaire d'évènement de glissé/déposé
  });
  
  $("#list-wrapper").on("click", ".list-item .delete", function (e) {
	// Gestionnaire d'évènement de suppression des items
  });
});

Le résultat de ces changements est que lorsque la liste sera écrasée, l’élément qui l’encadre lui ne le sera pas, et les gestionnaires d’évènements qui sont branchés seront par conséquent bien conservés. Par ailleurs, bien que le contenu de la liste soit mis à jour, ses items respectent toujours le sélecteur indiqué en paramètre de la délégation d’évènement. Comme ce sélecteur n’est appliqué que lorsqu’un évènement est capturé au niveau du délégué, les gestionnaires seront bien déclenchés.

Il est très courant de nos jours de mettre à jour des pans entiers d’une page web avec des appels Ajax, et ce procédé vous permettra de vous simplifier grandement la vie quant à la gestion des évènements sur ces fragments.

Gestion de la propagation d’évènements

Imaginez maintenant que lorsque l’utilisateur clique n’importe où sur la page, il faille escamoter certains morceaux de celle-ci, comme typiquement une popup.

<body>
  <div class="popup">
    <button type="button">Cliquez-moi</button>
  </div>
</body>

Pour cela le plus simple est de brancher un gestionnaire d’évènement au niveau le plus haut de la page, c’est à dire sur <body>.

$(document).ready(function () {
  $("body").on("click", function (e) {
	$(".popup").hide();
  });
});

Cette mécanique fonctionnera parfaitement, excepté qu’elle dissimulera également la popup lorsque l’on clique dans le contenu de celle-ci, par exemple sur le bouton qu’elle contient. Or ce n’est pas ce que nous souhaitons.

Encore une fois nous allons pouvoir utiliser la délégation pour corriger ce problème. Pour cela, nous allons enregistrer un nouveau gestionnaire d’évènement click sur le <body> de la page. Mais attention, nous allons l’enregistrer avant celui que nous avons déjà indiqué. Ce gestionnaire d’évènement agira par délégation sur notre popup.

$(document).ready(function () {
  $("body").on("click", ".popup", function (e) {
    e.stopImmediatePropagation();
  });

  $("body").on("click", function (e) {
	$(".popup").hide();
  });
});

Puisque nous avons branché deux gestionnaires d’évènements sur <body>, lors d’un click sur la page jQuery les traitera tous les deux dans l’ordre où nous les avons indiqué. Mais une différence importante est que le premier ne sera déclenché que lorsque le click aura été propagé depuis la popup ou son contenu. Comme on l’a déjà vu le second gestionnaire d’évènement sera lui déclenché quelque soit l’endroit que l’on cliquera sur la page.

Or dans le premier cas, on empêche la bulle de se propager aux autres gestionnaires d’évènement en utilisant la méthode stopImmediatePropagation(). Ainsi, on inhibe l’exécution de tous les autres gestionnaires d’évènements qui pourraient avoir été branchés sur le même élément – ici <body>.

Le résultat est que si l’on clique sur le bouton, le premier gestionnaire d’évènement sera en mesure de capturer ce click au moment où celui-ci atteindra la popup, et l’empêchera d’être capturé par l’autre gestionnaire d’évènement.

Au passage, si l’on place un point d’arrêt dans le premier gestionnaire d’évènement et que l’on clique sur le bouton, on constate que l’argument qui est passé en paramètre contient les informations suivantes :

  • e.target désigne le <button>.
  • e.currentTarget et this désignent <div class= »popup »>.
  • e.delegateTarget désigne <body>.

Notions fondamentales de JSON

Les formats de données

Lorsque l’on développe en Javascript, le format de données roi est le JSON (JavaScript Object Notation). Ce format supporte deux types d’entité : les tableaux (ou array) représentés par la notation littérale « [] », et les objets, aussi appelés dictionnaires ou hash représentés par la notation littérale « {} ».

Les tableaux ont une propriété length qui indique le nombre d’éléments qu’ils contiennent. Il est possible d’accéder à ces éléments par le biais d’un indexeur, et on utilise généralement une boucle for pour les parcourir.

var array = [ "Foobar", 42, true ];
for (var i = 0; i < array.length; i++) {
    var item = array[i];
}

Les hash quand à eux, contiennent des propriétés nommées auxquelles il est possible d’accéder directement, soit par une notation pointée, soit par le biais d’un indexeur nommé.

var object = {
    "Lastname":  "Guillot",
    "Firstname": "François"
};
var lastname = object.Lastname;      // Notation pointée
var firstname = object["Firstname"]; // Indexeur nommé

L’accès par indexeur nommé offre l’avantage de pouvoir être utilisé avec une variable contenant le nom de la propriété.

// Même chose que précédemment, mais le nom de la propriété "Firstname" est contenu dans une variable
var propertyName = "Firstname";
var firstname = object[propertyName];

Pour parcourir les propriétés d’un hash, on utilise une boucle for in. Chaque tour de boucle permet d’accéder au nom d’une propriété du hash, permettant ensuite d’accéder à la valeur de celle-ci par le biais de l’indexeur nommé.

var city = {
    "Name": "Marseille",
    "ZipCode": "13000"
};
for (var key in city) {
    // Au premier tour de boucle, key contiendra "Name", et value contiendra "Marseille"
    var value = city[key];
}

Il n’est pas possible de parcourir un tableau avec la boucle for in, car bien qu’à chaque tour de boucle la clef contiendrait une des valeurs contenue par le tableau, elle contiendrait également la valeur « length », car toutes les propriétés d’un objet Javascript sont inspectées.

La boucle for in inspecte également les propriétés d’un objet héritées par prototypage. Si vous ne souhaitez inspecter que les propriétés que porte l’objet lui-même, vous devez tout d’abord contrôler leur origine avec la méthode hasOwnProperty().

for (var key in city) {
    if (city.hasOwnProperty(key)) {
        // La clef contient bien le nom d'une propriété que l'objet city n'a pas reçu par héritage
        var value = city[key];
    }
}

Il est bien entendu possible de mixer les tableaux et les hash, pour concevoir des graphes de données complexes.

// Tableau contenant un hash, un booléen, et un autre tableau
var complexGraph = [
    { "Language": "C#", "Version": "4.5", "Year": 2012, "Creators": [ "Anders Hejlsbjerg" ] },
    true,
    [ 'Test', 12, { "Id": "4BB84287-B919-45DD-98BA-FFBC7D6F7BF2" } ]
];

Écrire du code JSON valide

JSON est un format de données natif du langage Javascript, ce qui signifie que dans ce contexte, il est possible de l’utiliser au-delà de ses possibilités standards. Par exemple, en Javascript on s’autorise généralement à écrire les noms des propriétés des hash sans les encadrer par des double quotes (« ), et on peut placer dans ces mêmes hash des données non littérales, comme des fonctions.

var hashJavascript = {
    Property: function (param) { return param; }
};

Mais la notation JSON a aujourd’hui largement dépassé le cadre du seul langage Javascript, au point d’être utilisée couramment dans de nombreux autres langages. Ceux-ci disposent généralement d’un parseur, qui est très pointilleux quand au respect de la syntaxe. En effet, le JSON a été normalisé, et les moteurs de parsing lèvent une exception si la chaîne de caractères qui leur est soumise ne respecte pas cette norme.

Cette norme est toutefois assez simple à respecter. Les valeurs contenues par les tableaux ou par les propriétés des hash, ne peuvent être que des chaînes de caractères, des nombres entiers ou décimaux, des booléens, la valeur spéciale null, ou bien entendu des sous-tableaux ou des sous-objets. Sont prohibés les fonctions et les dates (ce qui pose souvent problème pour faire circuler des informations de type DateTime).

Autre point important : les noms de propriétés dans les hash doivent être encadrés par des double quotes (« ), pas des simples quotes (‘), et ils doivent encore moins être écrits sans formatage. Cette règle s’applique également aux chaînes de caractères : double quotes (« ) obligatoires. Notez qu’à titre personnel, j’ai tendance à trouver la notation des propriétés avec des double quotes nettement plus lisible.

// Cet objet JSON est mal formé
var wrongObject = {
    prop: 'je m\'appelle "toto"',
    today: new Date(2012, 6, 21, 12, 44, 55, 0)
};

// Cet objet JSON respecte la norme
var rightObject = {
    "prop": "je m'appelle \"toto\"",
    // La date est une chaîne de caractères au format ISO-8601, qui est en train de devenir la nouvelle norme
    "today": "2012-06-21T12:44:55"
};

Moralité : si vous devez faire circuler des données au format JSON entre votre serveur et le client, prenez soin de bien respecter le norme, car un parseur comme la méthode jQuery.parseJSON() rejettera votre chaîne de caractères si celle-ci contient des erreurs de formatage.

Optimiser la récupération des données

Il arrive couramment que l’on doive retrouver un objet JSON parmi un tableau de ceux-ci, à partir de la valeur d’une de ses propriétés; typiquement un Id.

var animals = [
    { "Id": "D8777CD6-5E94-4464-8B3D-474DF4EC99FB", "Name": "Warthog" },
    { "Id": "BCDFEEC7-63F5-44C1-850D-246FB40B470A", "Name": "Hedgehog" },
    { "Id": "A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1", "Name": "Fawn" },
    { "Id": "2EBAC3FC-C03E-4263-95D2-1B26E0260C0F", "Name": "Gibbon" }
];

Admettons que nous souhaitons récupérer parmi cette liste d’animaux celui dont l’Id est A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1 (c’est le faon). Une solution consiste à utiliser la méthode utilitaire jQuery.grep().

var idFawn = "A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1";

// Remarquez que jQuery.grep() renvoie un tableau d'éléments respectant le prédicat passé en paramètre
// Comme nous savons qu'il n'y a qu'un seul élément respectant le prédicat, nous prenons directement le premier élément du tableau résultant
var fawn = jQuery.grep(animals, function (item) {
    return item.Id === idFawn;
})[0];

Une autre solution consiste à le faire en Javascript pur. On s’épargne ainsi de boucler sur toutes les valeurs du tableau, puisqu’on peut arrêter la recherche dès lors que le résultat a été trouvé.

var idFawn = "A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1",
    fawn = null;
for (var i = 0; i < animals.length; i++) {
    var animal = animals[i];
    if (animal.Id === idFawn) {
        fawn = animal;
        break;
    }
}

Le problème de ces deux méthodes, c’est qu’elles ne sont en aucun cas optimisées pour les moteurs Javascript. En effet, la solution idéale consiste à utiliser un indexeur nommé sur un hash. Mais pour cela, il faut qu’au départ nos données soient dans un format quelque peu différent.

var animals = {
    "D8777CD6-5E94-4464-8B3D-474DF4EC99FB": { "Name": "Warthog" },
    "BCDFEEC7-63F5-44C1-850D-246FB40B470A": { "Name": "Hedgehog" },
    "A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1": { "Name": "Fawn" },
    "2EBAC3FC-C03E-4263-95D2-1B26E0260C0F": { "Name": "Gibbon" }
},
    idFawn = "A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1",
    fawn = animals[idFawn];

Cette méthode est optimale car elle permet d’aller récupérer le faon directement dans la liste des animaux par son id, sans avoir à effectuer la moindre boucle. Dans des cas de manipulations de très grandes quantités de données, les performances peuvent s’en trouver nettement améliorées.

C’est pourquoi il est important que les données soient présentées dans un format adéquat. Ce format peut être élaboré côté serveur, avec d’injecter les données dans la page ou de les envoyer par le biais d’une requête Ajax. Pour effectuer ce type d’opération, j’ai généralement recours à la très bonne librairie JSON.NET, qui est maintenant fournie en standard dans les projets ASP.NET Web API (qui l’utilise lui-même pour toutes les opérations de manipulation de JSON).

// Exemple de création d'un objet JSON en C# avec JSON.NET
// N'oubliez pas d'ajouter "using Newtonsoft.Json.Linq;"
Animal[] animals = new Animal[]
{
    new Animal { Id = Guid.Parse("D8777CD6-5E94-4464-8B3D-474DF4EC99FB"), Name = "Warthog" },
    new Animal { Id = Guid.Parse("BCDFEEC7-63F5-44C1-850D-246FB40B470A"), Name = "Hedgehog" },
    new Animal { Id = Guid.Parse("A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1"), Name = "Fawn" },
    new Animal { Id = Guid.Parse("2EBAC3FC-C03E-4263-95D2-1B26E0260C0F"), Name = "Gibbon" }
};

JObject objectJson = new JObject();

foreach (Animal animal in animals)
    objectJson.Add(animal.Id.ToString(), JObject.FromObject(animal));

// Résultat sous forme de chaîne de caractères, non-indenté
string json = objectJson.ToString(Formatting.None);

On peut aussi transformer le format des données côté client, opération coûteuse mais qui peut être ensuite contrebalancée par le gain de performances obtenu par l’utilisation des indexeurs nommés.

// Exemple de transformation du tableau d'animaux vers un hash d'animaux
var animals = [
    { "Id": "D8777CD6-5E94-4464-8B3D-474DF4EC99FB", "Name": "Warthog" },
    { "Id": "BCDFEEC7-63F5-44C1-850D-246FB40B470A", "Name": "Hedgehog" },
    { "Id": "A71ED56F-DB42-4105-97E8-5C0BD7C3D3F1", "Name": "Fawn" },
    { "Id": "2EBAC3FC-C03E-4263-95D2-1B26E0260C0F", "Name": "Gibbon" }
], newAnimals = {};
for (var i = 0; i < animals.length; i++) {
    var animal = animals[i];
    newAnimals[animal.Id] = animal;
}

Comment éteindre Windows 8 / How to shutdown Windows 8

Windows 8 sera disponible pour le public le 26 octobre prochain. Mais les quelques privilégiés qui ont eu l’opportunité de se pencher dessus ont souvent rencontré la même difficulté : avec la disparition du menu « Démarrer », il est difficile de trouver comment éteindre son ordinateur.
Windows 8 will be released on October 26th. But the happy fews who had the opportunity to try it have often encountered the same difficulty: with the vanishing of the « Start » menu, it’s hard to find out how to turn off the computer.

Laissez-moi vous montrer comment retrouver la commande.
Let me show you how to get to the command.

Tout d’abord, il vous faut placer le curseur de la souris dans un des coins supérieur droit ou inférieur droit afin de faire apparaître la « Charm bar » (les rectangles rouges sur l’image). Vous pouvez aussi appuyez sur les touches « Windows + C » de votre clavier. Si vous êtes sur une tablette, vous devez effectuer un geste du doigt depuis le côté droit de l’écran vers l’intérieur.
First and foremost, you have to place the mouse cursor in the upper right of lower right corner so the « Charm bar » show up (the red rectangles on the picture). You can also press the touches « Windows + C » on your keyboard. If you’re on a tablet, you must execute a gesture by pulling your finger from the right border of the screen toward the center.

Ensuite, il vous faut vous rendre dans la section « Settings » (« Paramètres ») représentée par un engrenage, en bas du menu. Vous pouvez aussi accéder directement à ce menu en pressant les touches « Windows + I » du clavier.
Then, you have to go to the « Settings » section represented by a gear, at the bottom of the menu. You can also access this menu directly with the touches « Windows + I » of your keyboard.

Un nouveau menu « Settings » apparaît alors. Cliquez sur le bouton « Power » (« Marche/Arrêt »).
A new menu shows up. Click on the « Power » button.

Finalement, cliquez sur « Shutdown » (« Arrêter »).
Finally, click on « Shutdown ».

Animer vos pages web avec CSS3

Il n’est un secret pour personne que la nouvelle norme HTML5, et la norme CSS3 qui l’accompagne, ont pour objectif de rendre à terme obsolète l’utilisation de plugins tiers comme Flash ou Silverlight. A ce titre, une nouvelle API permettant d’animer les éléments d’une page web est actuellement en cours de normalisation par le W3C, l’organisme en charge de mettre au point les nouveaux standards de demain.

Cette nouvelle API, bien qu’actuellement à l’état de brouillon et disséminée dans plusieurs modules de la norme CSS3, a déjà été largement implémentée dans les dernières versions des navigateurs que nous connaissons tous (à l’exception d’Internet Explorer 10 qui se fait attendre) et est donc d’ores et déjà exploitable.

Nous allons étudier chacune des nouveautés qui nous permet d’animer nos sites. Notez néanmoins que bien que les différents acteurs du monde du web se soient déjà mis d’accord sur une syntaxe commune, l’utilisation de préfixes CSS est encore pour le moment d’usage. Le but de ceux-ci est de permettre aux développeurs d’être en mesure de différencier les différents navigateurs, afin de pouvoir effectuer le cas échéant de menus réglages.

Par soucis de brièveté, dans les exemples qui suivront ces différents préfixes seront omis pour ne conserver que la syntaxe qui devrait devenir définitive à terme.

Les transformations

Tout d’abord, de nouvelles propriétés CSS3 vont nous permettre de transformer nos éléments HTML de manière inédite. Pour cela, on utilise la propriété CSS transform associée à une fonction de transformation. Ces fonctions de transformation vont nous permettre par exemple de modifier les dimensions de l’élément (translate / translate3d), de le faire pivoter sur lui-même (rotate / rotate3d) sur un ou plusieurs de ses axes, de l’étirer (skew) ou d’appliquer une transformation matricielle (matrix / matrix3d). Comme vous le voyez, la plupart de ces transformation existent en version 2D ou 3D. Par ailleurs, il est généralement possible de les appliquer sur un seul axe à la fois, avec par exemple rotateX, rotateY et rotateZ.

.mon-element {
    /* L'élément pivotera de 30 degrés dans le sens horaire */
    transform: rotate(30deg);
}

Notez – et c’est important – que toutes ces transformations se font à la fois sur l’élément et son contenu, que le flux d’affichage de la page n’est pas modifié et que cette opération se fait à un niveau graphique. Par exemple lors d’un étirement, le texte inclus dans l’élément sera lui aussi transformé.

La propriété CSS transform s’accompagne de plusieurs autres propriétés permettant de préciser certains éléments d’affichage. Par exemple, la propriété transform-origin permet d’indiquer à partir de quel point de l’élément la transformation doit s’appliquer. Si l’on reprend notre précédent exemple de la rotation, on peut ainsi préciser que celle-ci doit s’appliquer non pas sur le centre de l’élément – comme c’est le cas par défaut – mais par exemple à dix pixels de haut et dix pixels de large de son coin supérieur gauche.

.mon-element {
    transform: rotate(30deg);
    /* La transformation s'appliquera avec un point d'origine différent */
    transform-origin: 10px 10px;
}

Lorsque la transformation s’applique en trois dimensions, il est possible avec la propriété backface-visibility de préciser si l’on souhaite ou non que le dos de l’élément soit visible. La propriété perspective permet quand à elle de modifier la perspective selon laquelle un objet est perçu dans l’espace.

La transformation en elle-même se fait sans effet d’animation. Il est néanmoins possible de rendre cette transformation dynamique en utilisant les pseudo-éléments CSS comme :hover ou :focus.

a.mon-lien:hover {
    /* Multiplie par deux la largeur et la hauteur de l'élément
       lorsque le curseur de la souris le survole */
    transform: scale(2,2);
}

Les transitions

Il est courant dans une page web de vouloir modifier dynamiquement l’apparence d’un élément, que ce soit ses dimensions, la taille du texte qu’il contient, ou ses couleurs. Toutefois, ces opérations se faisaient jusqu’à maintenant en Javascript, et elles étaient généralement assez abruptes (sauf à utiliser des moteurs d’animation comme celui de jQuery). Le changement de couleur de fond d’un élément se faisait par exemple instantanément.

Grâce à la nouvelle propriété CSS3 transition, il est maintenant possible de préciser que l’on souhaite que certaines caractéristiques d’un élément changent progressivement lorsque celles-ci sont altérées. Concrètement, lorsque par exemple on modifie la largeur d’un élément de 100 pixels à 200 pixels, il est possible d’indiquer au moteur de rendu du navigateur que la transition entre ces deux états doit se faire en passant par tous les états intermédiaires (les valeurs entre 100 et 200), et non pas instantanément. L’utilisation de Javascript devient alors caduque, car tout se fait en CSS.

La déclaration de ces effets de transition s’effectue en indiquant à quelle propriété elle s’applique, et combien de temps doit durer la transition. Il est possible de cumuler plusieurs propriétés dans la même déclaration, comme on le voit dans l’exemple suivant :

.mon-element {
    transition: width 2s, height 2s, transform 2s;
}

Il est possible d’appliquer ces effets sur n’importe quelle propriété CSS. Lorsque la valeur de l’une de celles-ci sera altérée, de quelque manière que ce soit (Javascript, pseudo-element CSS, …), si un effet de transition a été appliqué à l’élément, alors la transition se fera automatiquement selon les paramètres spécifiés.

On peut également préciser directement dans la propriété transition ou par le biais de la propriété transition-timing-function un effet « d’assouplissement » (en anglais : easing), permettant d’altérer la manière dont la transition va s’appliquer dans le temps. Par exemple, on peut indiquer que l’on souhaite que la transition commence très rapidement, puis ralentisse sur la fin. Pour cela il existe déjà plusieurs mots-clefs standardisés (linear, ease, ease-in, ease-out, ease-in-out), mais on peut également utiliser la fonction cubic-bezier pour avoir un contrôle plus fin sur ce timing. Vous pouvez d’ailleurs vous amuser à tester différents effets sur ce site.

.mon-element {
    transition: width 3s cubic-bezier(.99, .01, -.01, .01);
}

Dernière possibilité offerte par la propriété transition-delay : différer le lancement de la transition. Comme la durée de la transition elle-même, la valeur de cette propriété peut être indiquée en secondes (s) ou en millisecondes (ms).

Dans l’exemple suivant nous appliquons un effet de transition en utilisant séparément chacune des propriétés CSS3 distinctes, plutôt qu’en les rassemblant par le biais de la propriété transition :

.mon-element {
    transition-property: font-size;
    transition-duration: 5s;
    transition-timing-function: ease-in-out;
    transition-delay: 1000ms; /* Équivalent à 1 seconde */
}

Cette effet de transition s’appliquera donc sur la propriété font-size (la taille des caractères autrement dit), il durera cinq secondes mais ne commencera qu’une seconde après que la propriété ait été altérée. Par ailleurs l’effet s’effectuera selon le timing ease-in-out (légèrement plus rapide au début et à la fin).

Voici un exemple de code Javascript modifiant la valeur du style CSS font-size d’un élément. Ce code permettrait de provoquer l’exécution de l’effet de transition :

document.getElementsByClassName('mon-element')[0].style.fontSize = '48px';

Les animations

Les animations avec CSS3 sont cousines des transitions, à l’exception qu’elles peuvent être répétées en boucle, et qu’elles offrent un contrôle plus fin sur la manière dont va évoluer l’apparence des éléments du DOM.

A la base d’une animation, il y a la notion de keyframe. Une keyframe n’est pas une propriété CSS mais une règle. Elle permet d’indiquer la suite d’états par lesquels l’élément du DOM va transiter au cours de l’animation.

@keyframes mon-animation {
    0% {
        background-color: red;
    }

    25% {
        background-color: green;
    }

    75% {
        background-color: blue;
    }

    100% {
        background-color: yellow;
    }
}

Dans cet exemple, nous indiquons que l’élément auquel sera appliquée l’animation devra avoir un fond de couleur rouge au début de celle-ci, puis vert au premier quart, puis bleu au troisième quart, puis jaune à la fin. Les mots-clefs from et to peuvent remplacer respectivement 0% et 100%, mais n’importe quelle valeur entre 0 et 100 est aussi acceptée.

Ensuite pour appliquer cette animation à un élément, on utilise la propriété animation proprement dite :

.mon-element {
    animation: mon-animation 5s;
}

Le minimum est d’indiquer la durée souhaitée de l’animation. Mais il est également possible, comme pour les transitions, d’indiquer un effet d’assouplissement, et un délai d’attente avant le lancement de l’animation. Par ailleurs, les animations disposent également des propriétés animation-iteration-count et animation-direction. La première permet d’indiquer combien de fois l’animation doit s’effectuer (on peut utiliser le mot-clef infinite pour que celle-ci tourne en boucle), et la seconde, si l’animation doit s’effectuer toujours dans le même ordre (mot-clef normal), ou si celui-ci doit s’inverser entre deux itérations (mot-clef reverse), ce qui s’avère très pratique lorsque l’on veut par exemple faire tourner un élément dans un sens puis dans l’autre.

.mon-element {
    animation: mon-animation 5s;
    animation-timing-function: linear;
    animation-delay: 2s;
    animation-iteration-count: infinite;
    animation-direction: alternate;
}

Les animations disposent enfin d’une dernière propriété : animation-play-state. Celle-ci permet de contrôler l’exécution de l’animation, avec la possibilité de mettre celle-ci en pause pour la continuer plus tard. Cela permet donc d’imaginer des scénarios où l’utilisateur peut piloter l’exécution de l’animation grâce au Javascript ou aux pseudo-éléments CSS.

.mon-element {
    animation: mon-animation 5s;
    animation-play-state: running;
}

.mon-element:hover {
    animation-play-state: paused;
}

Pour aller plus loin

Si vous souhaitez consulter la documentation complète des transformations, transitions et animations en CSS3, je vous recommande chaudement l’excellent site W3Schools. Vous pourrez y consulter des démonstrations, mais aussi créer les vôtres grâce à un système de bac-à-sable interactif très bien conçu qui vous permettra de vous entraîner à maîtriser toutes ces nouvelles propriétés.

Avec tout cela il devient beaucoup plus simple d’animer nos pages web. Toutefois, la création d’animations complexes reste fastidieuse à réaliser sans outils dédiés. On peut noter l’arrivée prochaine du nouveau logiciel Adobe Edge, qui est d’ores et déjà disponible en version béta, et dont l’objectif est précisément de permettre la création de contenu web animé en utilisant les nouveaux standards HTML5, CSS3 et le langage Javascript.

Les petites astuces du langage Javascript

Javascript est un langage qui avait été initialement conçu pour permettre de rendre les pages web un peu plus dynamiques, mais à l’époque de sa conception personne n’aurait imaginé qu’il pourrait prendre un jour une place aussi prépondérante dans la conception des applications web.

Alors que la nouvelle norme ECMAScript 5 commence à être doucement implémentée par les différents navigateurs du marché, certains développeurs ont su faire preuve de beaucoup d’astuce pour permettre à ce langage de donner le meilleur de lui-même.

Déterminer si une année donnée est bissextile

Aucune méthode n’est prévue nativement en Javascript pour permettre de déterminer si une année donnée est bissextile. Mais en s’appuyant sur le comportement par défaut des moteurs Javascript inclus dans les différents navigateurs, il est possible d’obtenir cette information.

function isLeapYear(year) {
    return new Date(year, 1, 29).getMonth() === 1;
}

L’astuce consiste tout simplement à créer une nouvelle date, correspondant au 29 février de l’année que l’on souhaite tester. Notez qu’en Javascript, le numéro de mois est en base 0; le mois de février correspond donc au chiffre 1.

Ce qu’il se passe, c’est que si l’année passée au constructeur de l’objet Date n’est pas bissextile, la date retournée ne sera pas le 29 février… mais le 1er mars. Il ne reste donc qu’à tester si le mois de cette date est bien toujours février, ou si celui-ci s’est miraculeusement transformé en mars.

Obtenir la plus petite ou la plus grande valeur contenue dans un tableau

Prenons le tableau suivant :

var numbers = [ 4, 8, 15, 16, 23, 42 ];

Par défaut, le langage Javascript ne contient aucune méthode particulière permettant de déterminer la plus petite valeur contenue par ce tableau. Par contre, il existe dans l’objet Math une méthode min() permettant de déterminer qu’elle est la plus petite valeur parmi toutes celles passées en paramètre. Il serait donc tentant d’essayer de brancher les deux ensembles, et c’est possible, grâce à la méthode spéciale apply().

Array.min = function(array) {
    return Math.min.apply(Math, array);
};

La méthode apply() permet d’exécuter une méthode en lui passant seulement deux paramètres. Le premier correspond au contexte d’exécution (le mot clef this dans le corps de la méthode), mais ici nous ne souhaitons pas le modifier et nous contentons donc de passer l’objet Math lui-même. Le second paramètre est celui qui nous intéresse. Il permet de passer les paramètres de la méthode non pas les uns après les autres mais regroupés dans un tableau. Or c’est justement d’un tableau de nombres dont nous disposons et que nous souhaitons tester.

Grâce à ce mécanisme, il est alors facile d’ajouter une nouvelle méthode min() à l’objet Array, et de brancher celle-ci à la méthode Math.min(). L’opération devient alors un jeu d’enfant :

var smallestNumber = Array.min(numbers); // 4

Vous pourriez arguer qu’il n’est pas beaucoup plus difficile d’écrire soi-même un algorithme pour boucler sur ces nombres et trouver lequel est le plus petit. Mais en utilisant une méthode incluse nativement dans le moteur Javascript, nous bénéficions d’une amélioration des performances, ce qui sur de très grands tableaux peut s’avérer décisif.

Je vous laisse deviner vous-même comment permettre le calcul de la plus grande valeur contenue dans un tableau.

Créer son propre opérateur de coalescence sur null

Javascript est un langage extrêmement souple, et un nouvel exemple de cette souplesse tient dans le fait que l’opérateur de comparaison OR (noté « || ») est capable d’avoir une influence sur l’assignation d’une variable. Voyons plutôt un exemple :

var nullVariable = null;
var anotherVariable = nullVariable || 12;

La variable nullVariable contient la valeur null. Nous tentons d’assigner cette valeur à une autre variable. Mais notez l’utilisation de l’opérateur OR. Grâce à lui, si la variable source a une valeur booléenne correspondant à false – ce qui est le cas pour le mot-clef null – c’est la valeur de l’opérateur de droite qui sera assignée. Dans notre exemple, la variable anotherVariable se verra donc assigner la valeur 12.

Ce mécanisme, très pratique au demeurant, correspond peu ou prou à l’opérateur ?? en C#. Attention néanmoins, car le test des valeurs booléennes en Javascript obéit parfois à des règles quelque peu abstraites. Par exemple le test du chiffre 0 renvoie false, alors que tout autre nombre – même négatif – renverra true.