Tag: JavaScript
Reglib : précurseur d’une nouvelle vague de bibliothèques JavaScript ?
par Loïc le Lundi 24/11/2008 à 01:03, dans JavaScript
Actuellement, lorsque vous souhaitez placer un événement sur certains noeuds particuliers de votre page, par exemple tous les liens ayant une classe particulière, comment cela se passe-t-il ?
- d’abord, vous attendez que le DOM soit complétement chargé afin d’être certain de ne pas louper certains noeuds supposés recevoir l’événement
- ensuite, vous faites une recherche sur l’intégralité du DOM, soit via votre librairie javascript favorite, soit comme un grand avec vos petites patounes, afin de récupérer la liste des noeuds qui correspondent à votre recherche
- une fois que vous avez votre collection de noeuds, vous faites une boucle dessus pour tous leur appliquer le même événement, par exemple sur le clic
La majorité des développements en JavaScript fonctionnent actuellement de cette manière et les librairies javascript sont conçues sur ce principe.
Reglib va à l’encontre de ce principe et adopte une approche qu’on pourrait considérer comme plus efficace et plus intelligente.
Le principe est plutôt simple :
- le gestionnaire d’événement est appliqué sur le body et non pas sur les noeuds du DOM qui sont visés (par exemple nos liens qui ont la bonne classe)
- lorsque l’utilisateur clic quelque part (et plus globalement lorsqu’il déclenche un événement), l’événement remonte vers le body grâce au mécanisme de propagation des événements,
- lorsque le body reçoit l’événement, il vérifie s’il n’a pas une règle associé à la cible initiale de l’événement, si c’est le cas, il exécute la fonction associée.
Ce fonctionnement a plusieurs avantages non-négligeables :
- pas besoin d’attendre le chargement complet du DOM vu qu’on place le gestionnaire d’événement directement sur le noeud body, qui est l’un des premiers créé au chargement de la page
- pas de traitement lourd sur l’initialisation de la page étant donné qu’on ne boucle pas sur des collections de noeuds auxquels on doit appliquer un gestionnaire d’événement, on se contente de l’appliquer sur le body,
- inutile de réappliquer le gestionnaire d’événement lorsqu’on crée du contenu de façon dynamique, les événements déclenchés par le contenu créé dynamique remonteront eux aussi vers le body donc seront traités correctement,
Bon, on peut toutefois noter quelques défauts à ce mécanisme :
- Tous les événements passent dans la moulinette associée au body pour savoir si leur cible initiale correspond à l’une des règles placées sur le body et vu la quantité astronomique d’événements (en particulier ceux générés par les déplacements et les survols de la souris), ça en fait un paquet.
- On ne peut pas retirer facilement l’événement appliqué à un noeud particulier. Par exemple si vous avez un gestionnaire d’événement basé sur tous les noeuds qui respectent la règle “a.maClasse”, autrement dit tous les liens ayant pour classe “maClasse”, et que vous souhaitez désactiver l’événement sur un lien particulier ayant cette classe là (faire en sorte que le clic sur le lien ne marche qu’une seule fois par exemple), avec la méthode classique il suffit de retirer le gestionnaire d’événement basé sur le onclick du noeud en question mais avec Reglib, il faut soit faire en sorte que le noeud ne respecte plus la règle placée sur le body (on lui retire sa classe “maClasse” mais elle est peut-être nécessaire pour le design ou pour d’autres événements) soit ajouter une information au noeud pour que le gestionnaire d’événement ne s’exécute pas.
Quoiqu’il en soit ce mécanisme de gestion des événements est très prometteur et on peut supposer que les grandes librairies JavaScript vont rapidement proposer des fonctions pour utiliser ce système.
Une petite demo comparant la gestion d’un widget entre jQuery et Reglib.
Un simulateur de batterie en JavaScript
par Loïc le Vendredi 21/11/2008 à 22:24, dans JavaScript
Il y a des prouesses qu’il est nécessaire de saluer…
Dans le cadre de la conférence “Web Directions South 2008″ ayant eut lieu à Sydney fin Septembre, Cameron Adams a réalisé un simulateur de batterie pour étayer sa présentation et le résultat est assez sympathique.
Le résultat est visible ici : JS-909.
Côté technique, la prouesse vient du fait qu’il n’utilise aucune librairie ni aucun code flash : les sons sont situés à la fin du body dans des objets embed et leur exécution est effectuée via l’interface JavaScript de Quicktime (il est donc nécessaire d’avoir Quicktime d’installé pour que cela fonctionne).
L’intérêt reste limité car à partir d’un certain nombre de sons le moteur JavaScript commence à peiner mais le résultat reste néanmoins surprenant…
L’héritage en JavaScript
par Loïc le Mercredi 12/11/2008 à 12:32, dans HTML5, JavaScript, POO
Dans son livre Object-Oriented JavaScript, Stoyan Stefanov propose pas moins de 12 méthodes pour mettre en place de l’héritage en JavaScript.
Nous allons reprendre ces méthodes une à une afin d’en lister les avantages et les inconvénients… Nous allons réutiliser l’exemple de Stoyan pour montrer la syntaxe de chaque méthode : son exemple consiste à mettre en place un héritage entre trois classes FormeGeometrique, FormeGeometrique2D et Triangle.
Cet article est divisé en de nombreuses pages, chaque page traitant une méthode d’héritage différente.
- Chaînage de prototype
- Héritage des propriétés partagées uniquement
- Utilisation d’un constructeur temporaire
- Héritage par copie de propriétés
- Copie en Surface
- Copie en profondeur
- Héritage par prototypage
- Mélange d’héritage par prototype et de copie de propriétés
- Héritage multiple
- Héritage par Parasitage
- Emprunt de constructeur
- Emprunt de constructeur et copie de son prototype
- Conclusion
Eviter à coup sûr les problèmes de cache sur les CSS et les JS
par Loïc le Mercredi 05/11/2008 à 00:22, dans CSS, JavaScript, PHP
Une excellente méthode proposée par Le Potlatch pour éviter les problèmes de cache chez les utilisateurs lorsque les JS ou les CSS sont modifiés : plutôt que de versionner les fichiers et de devoir mettre à jour la version à chaque fois qu’on modifie le fichier (et modifier les appels aux fichiers), le Potlatch propose plutôt de mettre un paramêtre GET dans l’url du fichier, par exemple monfichier.css?param=valeur.
Et à votre avis, quelle est la valeur la plus adaptée ? La date de dernière modification bien sûr ! On peut la récupérer en php via la méthode filemtime().
Autrement dit, lorsqu’on inclus un CSS ou un JS dans une page, on ne met plus monFichier.css comme nom de fichier mais monFichier.css<?php echo filemtime("monFichier.css"); ?>
Testeur d’expressions régulières en JavaScript
par Loïc le Mercredi 05/11/2008 à 00:12, dans JavaScript
Une petite appli web bien pratique permettant de tester ses expressions régulières : ça se passe ici.
Le micro-templating JavaScript de John Resig à la loupe
par Loïc le Mercredi 05/11/2008 à 00:06, dans JavaScript, Tutoriel
Le templating JavaScript est une technique récente dont l’objectif est l’application du principe de templates dans une page web en les gérant via le JavaScript.
Cette technique trouve tout particulièrement un grand intérêt dans le cadre de communication asynchrones (XML ou JSON) avec la création de toute une partie du DOM à la réception de la réponse.
Le principe est relativement simple : on prépare une structure HTML contenant des mots-clef aux endroits où devront se trouver les données récupérées de façon asynchrones. A la réponse des données en question, le système de templating JavaScript se charge de récupérer le contenu de ce HTML sous forme d’une chaîne de texte et de remplacer les mots-clef par les données adéquates, puis de réinjecter ce nouveau contenu à l’endroit voulu dans le DOM de la page.
Les solutions de templating JavaScript sont encore rares et il est encore plus difficile d’en trouver des efficaces donnant une grande latitude lors de la création d’un template. En juillet dernier, John Resig a publié un script de templating sur son blog offrant la possibilité d’utiliser n’importe quelle fonctionnalité JavaScript dans le template. Etant donné que son code est assez obscur, je me propose de le décortiquer avec vous pour en comprendre le fonctionnement.
Pour décortiquer ce script, nous allons utiliser un exemple. Supposons que nous récupérions en JSON asynchrone (ce sera réalisé avec jQuery) un bloc de données caractérisant un groupe de personnes. Ce groupe est caractérisé par un nom et chaque personne est caractérisée par un ID, une image, un nom et un prénom.
Notre template aura la forme suivante :
<script type="text/html" id="groupTemplate">
<h3><%= name %></h3>
<ul id="users-list">
<% for (i = 0; i < users.length; i++) { %>
<li id="<%= users[i].ID %>">
<img src="<%= users[i].photo %>"/>
<span class="firstname"><%= users[i].firstname %></span>
<span class="name"><%= users[i].name %></span>
</li>
<% } %>
</ul>
</script>
Le template est encapsulé dans un script de type “text/html”. C’est un type MIME inexistant et nous aurions pu mettre n’importe quel type, par exemple “template/html”. L’essentiel est de mettre un type que le navigateur ne comprendra pas et donc ne cherchera pas à traiter.
Notre code JavaScript sera le suivant :
$(document).ready(function() {
$.getJSON("http://webdev-fr.com/examples/templating-js/json.php", null, function(data) {
var mygroup = document.getElementById("my-group");
mygroup.innerHTML = tmpl("groupTemplate", data);
});
});
Le fonctionnement est le suivant : au chargement de la page, on fait un appel asynchrone pour récupérer du code JSON. Ce code est passé au à la méthode javascript de templating à laquelle on passe également l’ID de notre template. Le résultat du templating est inséré dans un DIV ayant pour ID “my-group”.
La structure renvoyée par l’appel JSON est la suivante :
{
name:"Mon super groupe",
users:[
{ID:"u0",firstname:"firstname1",name:"name1",photo:"http://webdev-fr.com/examples/templating-js/img/photo.gif"},
{ID:"u1",firstname:"firstname2",name:"name2",photo:"http://webdev-fr.com/examples/templating-js/img/photo.gif"},
{ID:"u2",firstname:"firstname3",name:"name3",photo:"http://webdev-fr.com/examples/templating-js/img/photo.gif"}
]
}
Bien, ça semble marcher correctement, décortiquons un peu ce qui se passe derrière la fonction tmpl() de John Resig, qui se trouve dans le fichier templating.js…
Le code de John Resig est le suivant :
// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
var cache = {};
this.tmpl = function tmpl(str, data){
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +
// Introduce the data as local variables using with(){}
"with(obj){p.push('" +
// Convert the template into pure JavaScript
str
.replace(/[\r\t\n]/g, " ")
.split("<%").join("\t")
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");
// Provide some basic currying to the user
return data ? fn( data ) : fn;
};
})();
Vu qu’il n’est pas forcément évident de comprendre le fonctionnement de ce code, je me suis permis de le récrire dans un second fichier, templating2.js :
(function(){
var cache = {};
this.tmpl = function tmpl(str, data) {
if (!/\W/.test(str)) {
if (cache[str]) {
var fn = cache[str];
} else {
var fn = tmpl(document.getElementById(str).innerHTML);
}
} else {
var functionCode = "";
functionCode += "var p = [],";
functionCode += "print = function() {";
functionCode += " p.push.apply(p, arguments);";
functionCode += "};";
functionCode += "with(obj) {";
functionCode += " p.push('";
var jsCode = str;
jsCode = jsCode.replace(/[\r\t\n]/g, " ");
jsCode = jsCode.split("<%");
jsCode = jsCode.join("\t");
jsCode = jsCode.replace(/((^|%>)[^\t]*)'/g, "$1\r");
jsCode = jsCode.replace(/\t=(.*?)%>/g, "',$1,'");
jsCode = jsCode.split("\t");
jsCode = jsCode.join("');");
jsCode = jsCode.split("%>");
jsCode = jsCode.join("p.push('");
jsCode = jsCode.split("\r");
jsCode = jsCode.join("\\'");
functionCode += jsCode + "');";
functionCode += "}";
functionCode += "return p.join('');";
var fn = new Function("obj", functionCode);
}
if (data) {
return fn(data);
} else {
return fn;
}
};
})();
Je n’ai pas changé grand chose en fait, j’ai surtout supprimé l’utilisation d’opérateurs ternaires pour les remplacer par des if classiques et j’ai modifié la grosse suite de regexp afin de rendre le pas à pas plus facile à expliquer.
Ce nouveau script fonctionne parfaitement, on peut le tester sur notre précédent exemple en ramplaçant le script original par le nouveau.
Comme vous avez pu le constater plus haut, la méthode tmpl() prend deux paramètres :
- le premier paramètre peut être l’ID d’un template ou bien directement une chaîne de caractères correspondant au template au question. Passer un ID a plus d’intérêt car cela permet de mettre en cache la fonction de transformation correspondant à ce template. Néanmoins, si le template n’est utilisé qu’une seule fois ou bien s’il est dynamique, il peut être intéressant de le passer directement à la fonction.
- le second paramètre est optionnel. C’est l’objet qui correspond aux données qui vont être templatées. Si cet objet est passé en paramètre alors tmpl() retourne un code HTML (qu’on injecte dans notre conteneur résultat via sa propriété innerHTML). Si ce paramètre est absent, la méthode tmpl() retourne la fonction de transformation correspondant à notre template, cette fonction peut ensuite être utilisée en lui passant un objet. Ca peut avoir de l’intérêt si on compte passer plusieurs objets de données à la suite dans un même template : on récupère la fonction de transformation et on l’applique sur les objets en question dans une boucle.
La regexp /\W/.test(str) a pour rôle de tester si le premier paramètre passé à la fonction est un ID ou bien un template sous forme de ligne de texte. Pour rappel, \W correspond à n’importe quel caractère non-alphanumérique ou underscode. Autrement dit, tout sauf “a-z”,”A-Z” et “_”.
En conséquent, le test peut se lire de la façon suivante :
if (!/\W/.test(str)) {
// str ne possède pas de caractère non-alphanumérique, c'est donc un ID
} else {
// str possède un caractère non-alphanumérique, c'est donc un template sous forme de
// chaîne de caractères
}
Si le premier paramètre est un ID (on est alors dans le premier cas du test), alors la méthode est rappelée de façon récursive en lui passant, cette fois-ci, le contenu de la balise dont l’ID correspond au paramètre, autrement dit le contenu de notre template. Le résultat de ce second appel est placé en cache, ce qui permet par la suite de ne pas effectuer le second appel récursif mais de retourner directement le contenu mis en cache.
Le second appel récursif va retourner une fonction de transformation, c’est la raison pour laquelle l’objet de données n’est pas passé en paramètre sur ce second appel.
A la fin de la fonction tmpl(), un test est effectué pour savoir si le deuxième argument a été fourni ou non. Si c’est le cas, on applique la fonction de transformation sur ce second argument, sinon on retourne simplement la fonction de transformation.
if (data) {
return fn(data);
} else {
return fn;
}
En résumé, nous avons 4 cas d’appel pour notre fonction tmpl() :
- le premier argument est un ID, le second argument est fourni
- => on effectue un appel récursif en lui passant le innerHTML correspondant à l’ID, on obtient ainsi une fonction de transformation qu’on applique au second paramètre afin d’obtenir un code HTML qu’on injecte dans notre conteneur résultat.
- le premier argument est un template sous forme de chaîne de caractères, le second argument est fourni
- => pas d’appel récursif effectué, on obtient directement une fonction de transformation à partir de notre template en paramètre et on applique cette fonction au second arguement pour récupérer le code HTML qu’on injecte dans le conteneur résultat.
- le premier argument est un ID, pas de second argument
- => on effectue un appel récursif en lui passant le innerHTML correspondant à notre ID, on obtient une fonction de transformation qu’on retourne
- le premier argument est un template sous forme de chaîne de caractères, pas de second argument
- => on n’effectue pas d’appel récursif, on génère une fonction de transformation à partir de notre template et on retourne cette fonction (c’est ce cas qui se produit dans le cas d’un appel récursif).
Bien, maintenant qu’on sait comment fonctionne l’algorithme, il est temps de nous pencher sur la fonction de transformation et de sa batterie de regexp…
Le plus simple est de nous baser sur notre cas concret en utilisant notre template. L’objectif de la fonction de transformation est de retourner une fonction de la forme suivante :
function fn(data) {
var str = '';
str += '<h3>' + data.name + '</h3>';
str += '<ul id="users-list'>;
for (i = 0; i < data.users.length; i++) {
str += '<li id="' + data.users[i].ID + '">';
str += '<img src="' + data.users[i].photo + '"/>';
str += '<span class="firstname">' + data.users[i].firstname + '</span>';
str += '<span class="name">' + data.users[i].name + '</span>';
str += '</li>';
}
str += '</ul>';
}
Pour arriver à ce résultat, le système de templating utilise quelques subtilités :
- la création d’une fonction via le constructeur Fonction() pour avoir un code dynamique (qui dépend du template). Ce constructeur prend N paramètres : les premiers paramètres correspondent aux paramètres de la fonction, le dernier paramètre correspond au code de la fonction. Par exemple :
var displayAlert = new Function("msg", "alert(msg); return false;"); displayAllert();Le code précédent est équivalent à :
var displayAlert = function(msg) { alert(msg); return false; } displayAlert(); - l’utilisation du mot clef with. Par exemple le code suivant :
with(data) { field1 = "val1"; field2 = "val2"; }est équivalent au code suivant :
data.field1 = "val1"; data.field2 = "val2";
Ce mécanisme a l’avantage de nous éviter de devoir utiliser le même nom d’objet dans notre fonction de transformation et dans notre template.
- l’utilisation intelligente des regexp afin de découper le template en fonction des balises spécifiques au template (<% … %>). Nous les décortiquerons plus loin.
Plus exactement, la fonction de transformation visée aura le code suivant :
function fn(obj) {
var p = [],
print = function() {
p.push.apply(p, arguments);
};
with(obj) {
p.push('<h3>',
name,
'</h3><ul id="users-list">');
for (i = 0; i < users.length; i++) {
p.push('<li id="',
users[i].ID,
'"><img src="',
users[i].photo,
'"/><span class="firstname">',
users[i].firstname,
'</span><span class="name">'
users[i].name,
'</span></li>');
}
p.push('</ul>');
return p.join('');
}
}
Etudions les regexp appliquées une à une, c’est la partie vraiment indigeste du code…
Avant la première regexp, notre variable jsCode a la valeur de str, autrement dit :
<h3><%= name %></h3>
<ul id="users-list">
<% for (i = 0; i < users.length; i++) { %>
<li id="<%= users[i].ID %>">
<img src="<%= users[i].photo %>"/>
<span class="firstname"><%= users[i].firstname %></span>
<span class="name"><%= users[i].name %></span>
</li>
<% } %>
</ul>
La première manipulation est la suivante : jsCode = jsCode.replace(/[\r\t\n]/g, ” “);, autrement dit elle remplace tous les retours chariot (\r), les tabulations (\t) et les retours à la ligne (\n) par des espaces.
Notre variable jsCode aura donc la valeur suivante (je supprime les espaces superflus) :
<h3><%=name%></h3><ul id="users-list"><%for(i=0;i<users.length;i++){%><li id="
<%=users[i].ID%>"><img src="<%=users[i].photo%>"/><span class="firstname">
<%=users[i].firstname%></span><span class="name"><%=users[i].name%></span></li><%}
%></ul>
La seconde regexp fait une découpe sur le séparateur “<%” (le séparateur n’est pas conservé) afin de récupérer le tableau suivant :
jsCode = [
'<h3>',
'=name%></h3><ul id="users-list">',
'for(i=0;i<users.length;i++){%><li id="',
'=users[i].ID%>"><img src="',
'=users[i].photo%>"/><span class="firstname">',
'=users[i].firstname%></span><span class="name">',
'=users[i].name%></span></li>',
'}%></ul>'
]
La commande suivante est l’inverse du split : un join pour réassembler le tableau en une chaîne de caractère en insérant des tabulation entre ses éléments.
jsCode = '<h3> =name%></h3><ul id="users-list"> for(i=0;i<users.length;i++){%><li id="
=users[i].ID%>"><img src=" =users[i].photo%>"/><span class="firstname">
=users[i].firstname%></span><span class="name"> =users[i].name%></span></li>
}%></ul>'
La regexp qui suit est un poil plus compliquée : jsCode = jsCode.replace(/((^|%>)[^\t]*)’/g, “$1\r”);. Disons simplement qu’elle va rajouter des \r là où cela s’avère nécessaire.
La regexp qui suit (jsCode = jsCode.replace(/\t=(.*?)%>/g, "',$1,'"); va remplacer les =champs%> par simplement "', champs, '".
Ensuite on effectue de nouveau un split de notre chaîne, cette fois-ci sur les \t :
jsCode = [
"<h3>', name ,'</h3><ul id="users-list">",
"for(i=0;i<users.length;i++){%><li id="',users[i].ID,'"><img src="',users[i].photo,'"/>
<span class="firstname">',users[i].firstname,'</span><span class="name">',users[i].name,'</span></li>",
"}%></ul>"
]
Le join("');") suivant va permettre de fermer les p.push() pour la fonction.
"<h3>', name ,'</h3><ul id="users-list">"');" for (i = 0; i < users.length; i++) { %><li id="', users[i].ID ,'">
<img src="', users[i].photo ,'"/><span class="firstname">', users[i].firstname ,'</span>
<span class="name">', users[i].name ,'</span></li>"');\" } %></ul>"
Un nouveau split sur "%>" :
jsCode = [
"<h3>', name ,'</h3><ul id="users-list">"');" for (i = 0; i < users.length; i++) { ",
"<li id="',users[i].ID,'"><img src="',users[i].photo,'"/><span class="firstname">',users[i].firstname,'</span>
<span class="name">',users[i].name,'</span></li>"');"}",
"</ul>"
]
On enchaîne avec un nouveau join(), cette fois-ci pour insérer les p.push() :
"<h3>',name,'</h3><ul id="users-list">"');" for (i = 0; i < users.length; i++) { "p.push('"
<li id="',users[i].ID,'"><img src="',users[i].photo,'"/><span class="firstname">',users[i].firstname,
'</span><span class="name">',users[i].name,'</span></li>"');"}"p.push('"</ul>"
Oui, se perd facilement dans tous ces split() et ces join() successifs. On tient néanmoins le bon bout, on enchaîne avec un nouveau split(), sur \r cette fois, mais celle-ci n’a aucun effet dans notre cas.
Enfin, on termine par un join() avec "\\'" :
"<h3>',name,'</h3><ul id="users-list">"');"for(i=0;i<users.length;i++){"p.push('"<li id="',users[i].ID,'">
<img src="',users[i].photo,'"/><span class="firstname">',users[i].firstname,'</span><span class="name">', users[i].name ,'</span>
</li>"');"}"p.push('"</ul>"
Pour finir, on insère tout ça dans le début et la fin de notre fonction de transformation, pour obtenir en définitive le code suivant pour la fonction :
"var p = [],print = function() { p.push.apply(p, arguments);};with(obj) { p.push('<h3>', name ,'</h3><ul id="users-list">');
for (i = 0; i < users.length; i++) { p.push('<li id="',users[i].ID,'"><img src="',users[i].photo,'"/>
<span class="firstname">',users[i].firstname,'</span><span class="name">',users[i].name,'</span></li>');}p.push('</ul>');}
return p.join('');"
On obtient bien notre fonction de transformation…
Tutoriel sur la manipulation des dates en JavaScript
par Loïc le Mardi 28/10/2008 à 22:09, dans JavaScript, Tutoriel
Personnellement, j’oublie en permanence la syntaxe pour manipuler des dates et ce quelque soit le langage utilisé.
Si vous êtes dans le même cas que moi, voici un petit tutoriel sur la manipulation des dates en JavaScript.
Firelight : une librairie JavaScript capable de remplacer Silverlight
par Loïc le Dimanche 26/10/2008 à 20:25, dans JavaScript, SVG, Silverlight
Le gros problème de Silverlight, c’est qu’il nécessite un plugin sur le navigateur du client pour fonctionner.
Pour éviter ce désagrément, l’auteur de pleased precariously propose une librairie JavaScript appelée Firelight (toujours en cours de développement) dont le rôle est de prendre du XAML et du WPF en entrée et de générer à aprtir de ça du SVG / JavaScript / DOM équivalent.
Une petite démo ? ça se passe ici (fonctionne pour l’instant sous Firefox 3.x, Safari 3.1.2 et sous Ipod).
La démo se base sur ce fichier XAML.
L’avenir des frameworks JS ?
par Loïc le Samedi 25/10/2008 à 17:02, dans CSS, JavaScript
Dans mon précédent billet dédié aux moteurs de sélecteurs CSS en JavaScript, je signale que certaines personnes estiment qu’on en voit la fin : les moteurs ont des performances optimales, il est inutile de chercher à les améliorer de ce côté.
C’est un peu ce que s’est dit Eric Meyer dans un billet publié mercredi dernier où il donne de bonnes idées pour les moteurs à venir.
D’un côté, nous avons les CSS 3 dont les fonctionnalités visent à remplacer des particularités que nous réalisons à l’heure actuelle avec des méthodes de Sioux mélangeant allégrement HTML, CSS, JavaScript et images (coin arrondis, effets d’ombre, animation, dégradés, etc). Le point noir, c’est que les navigateurs évoluent lentement et IE6 nous tire vers le bas, bridant nos possibilités et l’utilisation de tout ce potentiel qui commence à être géré par les nouvelles versions des navigateurs, ce qui nous oblige à continuer avec nos méthodes de Sioux qui sont rôdées, certes, mais qui obligent à déporter une partie de la couche design (les CSS) dans les autres, par exemple en ajoutant les div et les span qui vont bien pour réaliser un joli rendu (div et span qui sont parfois injectés dans le DOM par du JavaScript).
De l’autre côté, on a des moteurs de sélecteurs en JavaScript dont le rôle est de permettre l’utilisation des sélecteurs CSS 3 dans du code JavaScript afin de faciliter l’accès aux données dans la page.
Et si ces moteurs JavaScript faisaient un peu plus que ça ? Ils pourraient par exemple se charger de parcourir la feuille de style, repérer les règles CSS contenant des sélecteurs non-gérés par le navigateur et appliquer les propriétés des règles en question sur les bons éléments. Le développeur pourrait ainsi se mettre à utiliser les sélecteurs CSS 3 dans ses feuilles de style, le moteur JS se chargerait d’appliquer les règles non-gérées par le navigateur.
Il est même possible d’aller encore plus loin : pourquoi ces moteurs javascript ne pourraient-ils pas également gérer des propriétés CSS 3 ? Eric mentionne par exemple la possibilité d’appliquer plusieurs images de fond à un objet en CSS 3 :
#monID {
background:url(top.png) no-repeat top left,
url(bottom.png) no-repeat bottom left,
url(middle.png) no-repeat 50% 50%;
}
Le moteur javascript se chargerait de détecter ce genre de règle et de modifier la structure de l’élément (en lui rajoutant des div et des span) pour lui appliquer les fonds multiple.
La même chose pourrait se faire avec d’inombrables propriétés actuellement inutilisables à moins de cibler des navigateurs de dernière génération. La couche présentation se composerait alors d’une sous-couche de style (les feuilles de style) et d’un moteur javascript pour gérer les problèmes de mauvaise gestion de ces feuilles de style par les navigateurs.
Le Javascript non plus pour aider le développeur à faire son interface mais pour aider le navigateur à afficher ce que lui demande le développeur.
Sizzle, Peppy : la nouvelle vague de moteurs de selectors
par Loïc le Samedi 25/10/2008 à 16:10, dans CSS, JavaScript
Fin août dernier, John Resig a annoncé la création de son tout nouveau moteur de sélecteurs CSS en JavaScript, Sizzle, supposé être intégré dans l’une des prochaines versions de jQuery.
Il y a quelques jours, un autre moteur de sélecteurs a fait son apparition, il s’agit de Peppy, réalisé par James Donaghue.
Côté perf, les deux moteurs sont ce qui se fait de mieux, vous pouvez le constater en lançant le SlickSpeed sur le blog de James Donaghue. Ils sont loin devant les frameworks classiques et ont l’avantage de la légéreté : Sizzle fait 4 ko, Peppy fait 10 ko. Bref idéal pour être intégré n’importe et pour, pourquoi pas, surcharger le moteur de sélecteur de votre framework favori.
A noter toutefois que Peppy a encore quelques soucis avec une mauvaise gestion du cache sous IE : le moteur marche parfaitement à condition que le DOM ne soit jamais modifié, dans le cas contraite peuvent survenir des résultats erronés (c’est d’ailleurs cette mauvaise gestion du cache qui lui permet d’afficher des résultats bien meilleurs que ceux de Sizzle sous IE). Ce problème devrait être réglé au cours du weekend car James Donaghue a annoncé une nouvelle release dans les jours à venir.
En tout cas, ces deux moteurs annoncent le début de la fin de la guerre des perf sur les moteurs de sélecteurs : de nombreuses personnes s’accordent à dire qu’il n’est plus nécessaire d’optimiser la vitesse et qu’il faut se tourner vers d’autres directions.