Cet article a fait l'objet d'une traduction automatique.
Aperçu du client
Utilisation de JsRender avec JavaScript et HTML
Télécharger l'exemple de code
Plusieurs plateformes de développement utilisent des modèles pour réduire le code et simplifier la maintenance et HTML5 et JavaScript ne font pas exception. JsRender est une bibliothèque JavaScript qui permet de définir une structure réutilisable une fois et les réutiliser pour générer le code HTML dynamique. JsRender apporte une nouvelle bibliothèque de modèles de développement HTML5 qui possède une syntaxe de la balise codeless et haute performance, n'a aucune dépendance sur jQuery, ni sur le modèle DOM (Document Object), prend en charge la création de fonctions personnalisées et utilise pure chaîne de rendu. Cette colonne traite des scénarios pour lesquels JsRender est idéal et illustre l'utilisation de ses différentes fonctionnalités. Tous les exemples de code peuvent être téléchargés à archive.msdn.microsoft.com/mag201204ClientInsight, et JsRender peut être téléchargé à bit.ly/ywSoNu.
Selon Boris Moore et le blog de l'équipe jQuery UI, en avril 2011, l'équipe a décidé de mettre les modèles de jQuery tenir en faveur de la création d'une bibliothèque de rendu moins logique et axée sur la chaîne. Cela a conduit Moore (une des forces motrices derrière jQuery templates) pour créer JsRender et JsViews. Ces deux bibliothèques sont effectivement les remplacements pour les modèles de jQuery. Vous pouvez lire plus sur l'histoire de la création de modèles et comment JsRender a évolué au poste de Moore sur le jQuery Templates et la feuille de route de JsRender (bit.ly/AdKeDk) et l'équipe jQuery (bit.ly/fhnk8A). Insight client va explorer JsRender et JsViews dans les prochains mois.
Pourquoi modèles ?
À l'aide de modèles avec JavaScript réduit et simplifie le code. Sans modèles, ajout d'une série d'éléments de liste et autres éléments HTML pour un ensemble de données peut nécessiter manipulant DOM. un navigateur C'est où les modèles à l'aide d'un plug-in comme JsRender peut être très utile pour faire le gros du travail. Par exemple, supposons que vous récupérer un ensemble de films et que vous souhaitez afficher. Vous pourriez écrire JavaScript et manipuler le DOM, mais le code suivant illustre que même cette tâche simple peut devenir difficile à lire, même avec l'aide de jQuery :
// Without a template
var i = 1;
$(my.vm.movies).each(function () {
var movie = this;
$("#movieContainer1").append(
"<div>" + i++ + ": " + movie.
name + " ("
+ movie.releaseYear + ")</div>");
});
Le code est entièrement écrit en JavaScript et jQuery, mais il peut être difficile à distinguer du HTML à partir des données de JavaScript. À l'aide d'un modèle, nous pouvons plus facilement séparer la structure et éliminer la plupart du code JavaScript. Le modèle suivant (01-with-and-without-templates-with-jquery.html dans le téléchargement de code qui l'accompagne) illustre ce concept :
<script id="myMovieTemplate" type="text/x-jsrender ">
<div>{{:#index+1}}: {{:name}} ({{:releaseYear}})</div>
</script>
Notez que le modèle est encapsulé dans une balise de script, son type est défini en conséquence et il a donné un id, donc on l'identifie par la suite. Rendering a template requires three aspects: a template, data and a container. Le modèle définit comment les données seront rendues et le conteneur définit où se rendre. Le code suivant montre comment afficher une liste des films en utilisant le modèle nommé myMovieTemplate à un élément avec l'id du movieContainer :
$("#movieContainer").html($("#myMovieTemplate").render(my.vm.movies));
Cet exemple utilise jQuery afin de simplifier la syntaxe. Il est important de noter que le JsRender n'est pas dépendant de jQuery. Le code pour utiliser JsRender pour rendre les données en utilisant le modèle peut également être écrite comme montré ici (02-jsrender-non-jquery.html dans le téléchargement de code) :
my.vm = {
movies: my.getMovies()
};
jsviews.templates({
movieTemplate: document.getElementById("myMovieTemplate").innerHTML
});
document.getElementById("movieContainerNojQuery").innerHTML
= jsviews.render.movieTemplate(my.vm.movies);
Modèles de rendu
Vous pouvez restituer des modèles à l'aide de JavaScript de plusieurs façons. Tout d'abord, vous devrez définir votre modèle sous forme de chaîne ou dans un <script> balise. Le <script> option balise est agréable lorsque vous souhaitez définir vos modèles dans le code HTML, leur donner un id et réutiliser. Vous pouvez également créer modèles de chaînes, qui vous donne la possibilité de créer à la volée dans le code ou même de les tirer d'un magasin de données.
La méthode render est utilisée pour restituer le contenu HTML de données à l'aide d'un modèle. Un ensemble de données peut être rendu avec un modèle déclaré dans un <script> balise à l'aide de la syntaxe $("# myTmpl").render(data). Par exemple, vous pouvait rendre une liste de films avec un modèle en utilisant le code suivant :
// #1: Render the my.vm data using the scriptTmpl from a script tag
var htmlString = $("#scriptTmpl").render(my.vm);
// Insert the htmlString into the DOM
$("#div1").html(htmlString);
Vous pouvez également compiler un modèle à partir d'une chaîne à l'aide de la fonction $.templates(tmplString) et la valeur à une variable. Vous pouvez alors rendre le modèle compilé, comme illustré ici :
// #2: Compile a template from a string, return a compiled template
var tmpl2 = $.templates(tmplString);
htmlString = tmpl2.render(my.vm);
$("#div2").html(htmlString);
Vous pouvez également compiler un modèle à partir d'une chaîne à l'aide de la syntaxe de .templates (nom, modèle) $, comme illustré ici :
// #3: Compile a template, name and register it
$.templates("myTmpl3", tmplString);
var htmlString = $.render.myTmpl3(my.vm);
$("#div3").html(htmlString);
Dans cet exemple, la fonction .templates $ compile un modèle à l'aide de la chaîne de tmplString et il enregistre comme un modèle nommé. Le modèle puis est accessible par un nom et rendu à l'aide de la .render $. Name() syntaxe.
La fonction de .templates $ est similaire aux méthodes de jQuery comme .css ou .attrib en ce qu'elle fournit une syntaxe alternative pour l'enregistrement et compilation de plusieurs modèles en un seul appel. Au lieu de passer deux paramètres (nom et templateString), vous pouvez passer un seul paramètre, consistant en un objet de la cartographie avec des paires clé/valeur pour chaque modèle qui doit être enregistrée :
// #4: Compile multiple templates, register them and render
var tmplString2 = "<div>*** {{:movies.length}} Total Movies ***</div>";
$.templates({
tmpl4a: tmplString,
tmpl4b: tmplString2
});
htmlString = $.render.tmpl4a(my.vm);
htmlString += $.render.tmpl4b(my.vm);
$("#div4").html(htmlString);
Chaque propriété de l'objet devient un modèle nommé et enregistré pouvant être rendus. La valeur de la propriété est la chaîne qui deviendra le modèle.
Vous avez beaucoup d'options pour créer, enregistrer et restituer les modèles. Définition de modèles dans les balises de script est une approche commune pour la plupart des scénarios. Toutefois, la création de modèles de chaînes offre beaucoup de souplesse. La syntaxe étendue précédente fournit encore plus de flexibilité pour associer d'autres caractéristiques des modèles nommés (tels que le déclarant les fonctions d'assistance spécifique au modèle). Tous ces exemples se trouvent dans 03-rendu-templates.html dans le téléchargement de code.
JsRender fondamentaux
JsRender modèles sont constitués de balisage HTML et des balises JsRender, tels que le {{pour …}} tag ou le {{: …}} tag. Figure 1 shows the syntax for the most basic of JsRender tags: the {{: }} and {{> }} tags. Toutes les balises de modèle JsRender sont recouvertes d'un doubles accolades. The tag name (in this case the “:” or “>” character) can be followed by one or more parameters or expressions. (Dans le cas de la balise {:}, le résultat de l'expression serait alors être rendu.) Une fois un modèle a été défini et il existe des données pour rendre à ce modèle, il peut être rendu.
Syntaxe de JsRender base de la figure 1
Description | Exemple | Production |
Valeur de la propriété firstName de l'élément de données avec aucun codage | {{: prénom}} | Madelyn |
Chemin d'objet simple de propriété imbriquée, avec aucun codage | {{: movie.releaseYear}} | 1987 |
Comparaison simple | {{: movie.releaseYear < 2000}} | true |
Valeur avec aucun codage | {{: film. nom}} | Star Wars IV: Return of the Jedi |
Valeur codée en HTML | {{> film. nom}} | Star Wars: Episode VI: <span style='color:purple;font-style: italic;'>Return of the Jedi</span> |
Valeur codée en HTML | {{html:movie. nom}} | Star Wars: Episode VI: <span style='color:purple;font-style: italic;'>Return of the Jedi</span> |
Le code suivant contient un élément HTML nommé filmconteneur (c'est où le modèle est rendus) :
<div id="movieContainer" class="resultsPanel movieListItemMedium"></div>
<script id="movieTemplate" type="text/x-jsrender">
<div class="caption">{{:name}}</div>
<div class="caption">{{>name}}</div>
<img src="{{:boxArt.smallUrl}}"/>
<div class="text">Year Released: {{:releaseYear}}</div>
<div class="text">Rating: {{:rating}}</div>
</script>
Le code précédent contient également le modèle nommé filmmodèle, qui définit un div pour afficher le nom du film à l'aide d'aucun codage HTML à l'aide de la syntaxe {{: nom}}. Le titre dans les données de l'échantillon peut contenir des éléments HTML, afin de rendre des éléments contenant du HTML, il est important de ne pas utiliser le codage. Toutefois, si vous voulez rendre le HTML codé, vous pouvez utiliser la syntaxe avec le > caractère ou utiliser HTML (comme le montre Figure 1).
La valeur de la propriété name contient des éléments HTML, à des fins de démonstration, le code précédent affiche valeur la propriété nom de l'avec aucun codage ({{: nom}}) et montre ensuite la valeur codée en HTML ({{> nom}}). Vous pouvez exécuter l'exemple complet dans 04-render-values.html dans le téléchargement de code.
L'exemple de données de film passé au modèle possède une propriété pour boxArt, qui à son tour possède une propriété pour le smallUrl de l'image. La src de la balise img est définie par la plongée dans la hiérarchie d'un graphique d'objet à l'aide de la boxArt.smallUrl de la syntaxe de la dot. Chemins d'accès peut également être parcouru à l'aide de crochets, donc au lieu d'écrire boxArt.smallUrl, le même résultat code être obtenus à l'aide de boxArt ['smallUrl'].
Il est important de noter que JsRender syntaxe peut aussi servir à rendre d'autres valeurs telles que les noms de classes ou ID pour les éléments HTML.
JsRender rendu de modèle détecte si le paramètre de données est un tableau ou non. Si c'est un tableau, la valeur de retour est la concaténation des chaînes qui résulteraient de chacun des éléments de tableau individuels passant à la méthode render. Si le modèle sera restitué une fois pour les données de chaque élément et le résultat sera la chaîne concaténée.
Le code suivant illustre comment un objet film unique du tableau est rendu à la movieTemplate (la source complète est disponible dans l'échantillon 04-render-values.html) :
my.vm = { movies: getMovies() };
$("#movieContainer").html($("#movieTemplate").render(my.vm.movies[1]));
Le prochain article montrera comment le modèle peut être écrite pour parcourir un tableau, aussi bien.
Forage des données hiérarchiques
Modèles sont souvent utilisés pour rendre une série d'articles, qui souvent peuvent contenir des données imbriquées et hiérarchiques (graphiques de l'objet). La figure2 balise montre comment JsRender peut parcourir une série de données à l'aide de la {{pour}}. Le paramètre pour le {{pour}} tag peut être un tableau ou une série de tableaux, ce qui va être itérée.
La figure 2 itérative Basics
Description | Exemple | Production |
Boucle sur chaque élément d'un tableau, à l'aide de « pour » | {{pour cast}} <div> {{: rétro}} </div> {{/}} |
Papa Landon Ella Papa |
Accès au contexte de données à l'aide de #data | {{pour téléphone}} <div> {{: #data}} </div> {{/}} | 555-555-1212 555-555-1212 |
L'exemple de données de film définit que chaque film a un tableau de cotation des étoiles appelés RatingStars. La propriété contient la classe CSS pour afficher une étoile de cote pour le film. Le code suivant (à partir de 05-pour-data.html dans l'exemple de code) montre comment itérer sur chaque élément du tableau de RatingStars et de rendre les CSS classe nom utilisant le {{: #data}} syntaxe :
<ul>
{{for ratingStars}}
<li class="rating {{:#data}}"/>
{{/for}}
</ul>
Le jeton de #data est un mot clé de JsRender qui représente l'objet étant itéré. Dans ce cas, le tableau de RatingStars contient un tableau de chaînes, ce #data représente une chaîne. La sortie de cet exemple est montrée dans Figure 3, où les classement étoiles sont affichées à côté de l'image du film.
La figure 3, rendre un objet avec et sans codage
Tableaux de Templates
Lorsqu'un tableau est passé à un modèle, le modèle est rendu une fois pour chaque élément du tableau. Un modèle rend contre un élément de données unique, mais si elle comprend un {{pour}} balise de modèle avec un paramètre de tableau, puis la section du modèle entre les balises ouvrantes et fermantes {{pour}} et {{/}} sera être itérée davantage. Le code suivant passe un objet my.vm qui contient un tableau des films à la fonction render pour afficher un élément de liste pour chaque film (la source complète se trouvent dans l'échantillon 06-Si-else.html) :
$("#movieList").html($("#movieTemplateMedium").render(my.vm));
Le modèle sera rendu que le contenu de la <ul> élément avec le movieList id :
<ul id="movieList"></ul>
Figure 4 montre le film modèleTemplateMedium commence par rendre <li>. Pour chaque film dans le tableau, un <li> sera restitué sous le conteneur <ul>.
Le modèle de Figure 4 reçoit l'objet my.vm dans son contexte et parcourt ensuite la propriété du tableau films en raison de la {{pour le cinéma}} code. Si le modèle a reçu le tableau my.vm.movies au lieu de my.vm, le {{pour}} {{/}} bloc pourrait être supprimé, comme le modèle exécuterait alors pour chaque élément du tableau.
Figure 4 une liste d'éléments de rendu et à l'aide d'instructions conditionnelles
{{for movies}}
<li class="movieListItemMedium">
<div class="caption">{{:name}}</div>
{{if boxArt.smallUrl}}
<img src="{{:boxArt.smallUrl}}"/>
{{else}}
<img src="../images/icon-nocover.png"/>
{{/if}}
<br/>
<div class="text">Year Released: {{:releaseYear}}</div>
<div class="text">rating: {{:rating}}</div>
<ul>
{{for ratingStars}}
<li class="rating {{:#data}}"/>
{{/for}}
</ul>
<br/>
<div class="text">${{:salePrice}}</div>
{{if fullPrice !== salePrice}}
<div class="text highlightText">PRICED TO SELL!</div>
{{/if}}
</li>
{{/for}}
Chemins de traverse
Comme nous l'avons vu précédemment, chemins d'accès peuvent être parcourus à l'aide de la syntaxe de la dot ou les crochets. Toutefois, vous pouvez aussi remonter une hiérarchie d'objets à l'aide de #parent ou identifier un élément de tableau à l'aide de crochets. Par exemple, vous pourrait remplacer le code qui affiche la balise img dans le modèle qui suit :
<img src="{{:#parent.parent.data[2].boxArt.smallUrl}}"/>
Le contexte du modèle est un élément dans le tableau my.vm.movies. Afin de naviguer jusqu'à la mère deux fois, le contexte sera l'objet de my.vm. Vous pouvez alors saisir le film avec index 2 et utilisez sa propriété boxArt.smallUrl de l'image. Le résultat de ceci serait pour afficher le même film (le troisième film) pour chaque film dans le tableau (comme le montre Figure 5). Pas exactement idéal dans cette situation, mais il constitue le point de montrer comment traverser les objets le long de la hiérarchie.
La figure 5 qui traversent les chemins d'accès pour afficher la même Image de film pour chaque film
Instructions conditionnelles
La syntaxe JsRender appuient également les instructions conditionnelles en utilisant les balises {{if}} et {{autre}} (en Figure 6). Le {{si}} tag peut être suivi de zéro, une ou plusieurs balises {{autres}}, puis une fermeture {{/ if}} tag. Le contenu du bloc entre la {{if}} tag et le {{/ if}} (ou jusqu'à la première balise {{autre}} si il en existe un) sera rendue dans la sortie uniquement si la valeur de l'expression dans le {{if}} est « truthy ».
Figure 6 conditionnels, Expressions et opérateurs
Description | Exemple | Production |
Création d'un si bloc évalué sur une comparaison | {{Si fullPrice! == salePrice}} < div class = « texte sens » > PRIX pour vendre! </div> {{/ if}} |
PRIX DE VENTE ! |
Un bloc if/else | {{Si qtyInStock > = 10}} En Stock {{qtyInStock else}} Seulement {{: qtyInStock}} gauche ! {{autre}} Non disponible. {{/ if}} |
Seulement 5 à gauche ! |
La balise {{autre}} peut agir comme un ifelse lorsqu'il inclut l'expression de ses propres. Notez le second exemple dans Figure 6, qui montre une conditionnelle avec deux étiquettes autres. Ce code évalue trois conditions dans la séquence.
Le bloc suivant une balise {{someCondition else}} sera sortie si la condition prend la valeur true (ou, plus précisément, truthy). Cette syntaxe peut servir efficacement comme une instruction switch/case à évaluer n certain nombre de conditions.
Les expressions utilisées dans les balises JsRender peuvent être des expressions complexes à l'aide d'évaluation opérateurs, y compris les chemins d'accès, chaînes, nombres, fonctionnent appels et les opérateurs de comparaison tels que ===,! == et < =. C'est le cas pour les expressions évaluées et rendu par la balise {:} et, ici, pour les expressions conditionnelles dans le {{if}} et {{autres}} tags.
À l'aide des compteurs et des Expressions conditionnelles complexes
Il est parfois nécessaire d'afficher ou d'utiliser une variable de compteur dans un modèle. Un tel scénario est lorsque vous souhaitez afficher un numéro de ligne dans le modèle. Un tel scénario pourrait être que vous souhaitez assigner un id unique pour chaque élément dans un modèle, donc vous pouvez référencer ce plus tard. Par exemple, vous Balayez d'une liste de films et vous encapsulez les tous à l'intérieur d'un <div> balise. Vous pouvez affecter l'id de la balise div pour être movieDiv1, movieDiv2 et ainsi de suite. Ensuite, vous pourriez trouver l'élément par son id lorsque cela est nécessaire, peut-être à lier à un gestionnaire d'événements à l'aide de la fonction de délégué de jQuery. Pour chacun de ces scénarios, vous pouvez utiliser le #index de clé JsRender (qui commence à 0). Comme le montre Figure 7, #index peuvent être affichés dans un modèle assez facilement.
Figure 7 compteurs et conditionnels dans les multiples Expressions
Description | Exemple | Production |
À l'aide d'un index de compter à l'intérieur d'un modèle | {{pour le cinéma}} < div class = « caption » > {{:#index}}: {{:name}} </div> {{/}} |
3: The Princess Bride |
À l'aide d'opérateurs logiques | {{Si stars.length || cast.length}} < div class = « text » > Cast complet : </div> {{/ if}} |
Casting complet : |
Souvent une expression unique n'est peut-être pas suffisante. JsRender prend en charge plusieurs expressions à l'aide d'opérateurs logiques tels que || et & & (« ou » et « et », respectivement). Cela le rend facile de combiner plusieurs expressions lorsque vous souhaitez évaluer un ou l'autre d'entre eux pour être vrai.
Parcourir des tableaux multiples ensemble
Le {{pour}} tag peut également parcourir plusieurs tableaux à la fois. Ceci est utile lorsqu'il y a deux tableaux qui doivent être traversés ensemble. Par exemple, le code suivant montre comment la pour la balise va parcourir les étoiles et les tableaux de distribution ensemble :
{{for stars cast}}
<div class="text">{{:name}}</div>
{{/for}}
S'il y a deux éléments dans le tableau des étoiles et trois dans le tableau de distribution, contenu tous les cinq éléments sera rendu.
Il s'agit d'une bonne situation d'utiliser le mot clé #data, trop, si les éléments dans les tableaux ne sont pas des objets (avec les propriétés) mais les valeurs de chaîne simple. Par exemple, les tableaux pourraient être des tableaux de chaîne MobilePhones et HomePhones, et vous pouvez les Lister dans une seule liste.
Modèles imbriqués
Demandes souvent extraire des graphiques d'objets où les objets ont des propriétés dont les valeurs sont des tableaux d'objets qui peuvent aussi contenir d'autres tableaux d'objets. Ces scénarios peuvent rapidement devenir difficiles à gérer lorsque plusieurs {{pour}} des déclarations de nidification. Considérons qu'un objet customer peut-être avoir des ordres, qui sont les éléments de l'ordre, qui ont un produit qui a des entrepôts. Ces données hiérarchiques pourraient être rendues à l'aide de multiples {{pour}} des balises. Il s'agit d'une situation de grande où le contenu d'une {{pour}} bloc peut être emballé dans un modèle séparé et rendu comme un modèle imbriqué. Cela peut réduire le code et rendre plus facilement lisible et maintenable et fournir pour la réutilisation et la modularité des modèles.
Vous pouvez utiliser un modèle imbriqué avec un {{pour}} tag en supprimant le contenu du bloc (rendant à fermeture automatique) et en spécifiant un modèle externe à l'aide du paramètre de modèle. Par exemple, vous pouvez définir le paramètre de modèle est le nom d'un modèle nommé (enregistré à l'aide de $.templates) ou vous pouvez utiliser un sélecteur jQuery pour un modèle déclaré dans un bloc de script. La syntaxe suivante utilise le myTmpl modèle nommé pour chaque élément dans le tableau nommé MonTableau :
{{for myArray tmpl="myTmpl"/}}
L'extrait de code suivant utilisera le modèle avec l'id du movieTemplateMedium pour chaque élément dans le tableau des films (à partir de l'échantillon 04-STAT-combo-iterators.html) :
<ul>
{{for movies
tmpl="#movieTemplateMedium"/}}
</ul>
Vous pouvez parcourir plusieurs baies et appliquer un modèle, aussi bien. Par exemple, l'extrait de code suivant utilise le castTemplate pour chaque élément dans les étoiles et le Cast des propriétés (qui sont les deux tableaux d'échantillon 07-STAT-combo-iterators.html) :
<ul>
{{for stars cast tmpl="#castTemplate"/}}
</ul>
Notez que, dans chacun des précédents, code snippets le {{pour}} la balise est une balise de fermeture automatique plutôt qu'une balise de bloc contenant le contenu. Au lieu de parcourir son contenu du bloc, il est reporter l'itération pour le modèle imbriqué, indiqué par la propriété STAT et rend ce modèle une fois pour chaque élément dans le tableau.
Le {{si}} balise de modèle peut également être utilisée comme une balise de fermeture automatique qui référence un autre modèle pour son contenu, tout comme le {{pour}} balise. Par exemple, le code suivant rendrait le myAddressTmpl modèle nommé si l'adresse est truthy :
{{if address tmpl="myAddressTmpl"/}}
Les exemples disponibles pour téléchargement montrent toutes les fonctionnalités décrites dans cet article. La figure 8 affiche la liste des films rendus à l'aide de toutes ces caractéristiques de l'échantillon 07-STAT -le fichier de zone de liste déroulante-iterators.html.
La figure 8 mettre tous ensemble
Plus sous les couvertures
Cette rubrique illustre les fonctionnalités de base de JsRender, mais il est beaucoup plus sous les couvertures. Par exemple, bien que les balises conditionnelles peuvent comporter plusieurs {{pour}} des balises avec des conditions (comme une instruction switch/case), il pourrait être plus propres façons de gérer cette situation, comme l'utilisation de balises personnalisées. JsRender prend en charge des balises personnalisées pour une logique complexe, fonctions d'assistance, naviguer dans un graphique d'objets à l'aide de chemins d'accès, des fonctions de conversion de client, permettant de code JavaScript dans les modèles, l'encapsulation de modèles et plus encore. J'explorerai certaines de ces techniques dans le prochain numéro.
John Papa a travaillé au sein des équipes Silverlight et Windows 8 de Microsoft, où il a animé la célèbre émission télévisée Silverlight. Il a présenté à l'échelle mondiale à des conférences et des séances pour la BUILD, MIX, PDC, TechEd, Visual Studio Live ! et événements DevConnections. Papa est également un directeur régional Microsoft, un chroniqueur forVisual Studio Magazine (point de vue du Papa) et un auteur de vidéos de formation de Pluralsight. Suivez-le sur Twitter à l'adresse twitter.com/john_papa.
Merci à l'expert technique suivant d'avoir relu cet article: Boris Moore