Catégorie « JavaScript »

De l'intérêt d'utiliser des standards

Lorsqu'il y a peu, Opera a annoncé sa migration sous Webkit, certains se sont réjouis à l'idée de voir réduire le nombre de moteurs de rendus et donc la diversité des navigateurs à supporter lorsqu'on développe un site.

D'autres ont rétorqué qu'une réduction de la diversité, si elle pouvait potentiellement faire gagner du temps à court terme, ne pouvait qu’être néfaste à long terme pour le web en général. En effet, le développement des standards et leur respect dans les différents navigateurs ne se fait que parce que plusieurs moteurs ont une part de marché significative. Pour preuve : à l'époque où Internet Explorer faisait 95% de part de marché, non seulement l'innovation se faisait uniquement en mode propriétaire à la seule initiative de Microsoft mais pire encore, elle a fini par s'assécher totalement après la sortie d'IE6. Seule l'arrivée de Firefox a fini par relancer la machine.

Actuellement, si Webkit est encore loin d'atteindre la part de marché passée d'IE sur les ordinateurs de bureaux, il est largement majoritaire sur les mobiles et tablettes, ce qui conduit de plus en plus de développeurs à ne développer leurs sites et applications web que dans l'optique de webkit, ignorant totalement les autres.

Faire ce choix de la facilité est à mon sens une grave erreur car si webkit est largement majoritaire actuellement, qu'en sera-t-il dans un ou deux ans ? Nul doute que l'écart se sera resserré si Firefox OS prend des parts de marché significative. Je doute assez peu que ce soit le cas, la seule inconnue restant la taille de cette part.

L'importance de respecter les standards est essentielle pour fonctionner sur un large panel de navigateur. Et fonctionner sur un large panel de navigateurs en respectant les standards (plutôt qu'en abusant de hacks en tous genre ou en développant des version parallèles) est non seulement plus maintenable mais aussi plus pérenne.

En effet, quand on se base sur les spécificités d'un navigateur, on est à la merci de son évolution. Car si les standards implémentés dans les différents navigateurs sont destinés à durer (un site qui fonctionnait bien sur les standards d'il y a dix ans fonctionne toujours actuellement), les éléments spécifiques, eux, peuvent disparaitre ou changer du jour au lendemain.

Nous en avons fait la douloureuse expérience avec RBS Change ces derniers mois. En effet, le backoffice est basé sur XUL, une technologie propriétaire de Mozilla, donc limitée au seul moteur Gecko (donc Firefox essentiellement). Depuis qu'elle a renoncé il y a quelques années à en faire un standard, Mozilla tend à réduire progressivement la portée de XUL. Initialement utilisables pour des applications web standard comme alternative plus riche à (X)HTML, XUL n'est actuellement plus utilisé que pour l'interface de Firefox. Pour continuer à l'utiliser dans le backoffice de Change, il nous faut passer par une extension.

Or la version 17 de Firefox a introduit un changement qui entrainait un plantage de Firefox dès l'ouverture du backoffice. Ce bug, critique pour les utilisateurs de Change était loin de l'être pour Mozilla puisque si un patch a été proposé en quelques jours par un contributeur externe, la validation du patch et son intégration dans Firefox a pris plusieurs mois. Et ce n'est que dans la future version 20, soit trois version plus tard qu'il sera enfin corrigé (alors qu'il avait été remonté le jour de la sortie de la 17).

Le choix de reposer sur XUL, s'il semblait bon en 2005 lorsqu'il a été fait (et l'était probablement étant donné ce qu'il permettait à une époque où les frameworks JavaScript étaient balbutiants et où les API standard étaient bien plus limitées) s'avère aujourd'hui avoir des conséquences coûteuses : redévelopper l'intégralité de l'interface ça a un coût assez élevé. Avec une technologie standard on n'aurait pas eu ce problème. Certains pans auraient dû être repensés de toutes façons mais cela aurait pu être bien plus progressif.

Je viens d'évoquer une techno 100% propriétaire comparable à Flash ou Silverlight par exemple dans le sens où, propulsée par un seul éditeur elle peut du jour au lendemain cesser d’être maintenu ou bannie de certaines plateformes. On est donc assez loin de ce qu'on risque de voir arriver avec le ciblage en "Webkit only", du moins dans un premier temps.

Mais les problèmes de ce choix de XUL a d'autres conséquences moins évidentes. En effet, choisir XUL c'est faire du développement dédié à Firefox uniquement. C'est donc se permettre d'utiliser des spécificité de Firefox à tous les niveaux, voire d'en exploiter sans s'en rendre compte ce qui s'avère être des bugs.

Nous en avons fait l'expérience une fois le bug évoqué plus haut puisque même si le navigateur ne plantait plus, le backoffice n'en était pas pour autant redevenu fonctionnel ! En effet à partir de Firefox 17, E4X (déprécié et désactivé dans la version 10) ne cause plus des erreurs seulement lorsqu'il est utilisé mais déjà des erreurs de parsing lorsqu'il est simplement présent dans un fichier. Or si on avait fait en sorte de ne plus passer dedans pour un usage normal, certaines fonctionnalités dépréciées de Change en contenaient encore... nous avions donc le choix entre tuée définitivement ces fonctionnalités ou assurer la compatibilité avec les version actuelles de Firefox. C'est le second choix qui a été fait mais d'une part ça implique qu'il faut mettre à jour Change pour pouvoir tourner sur les dernières versions de Firefox et d'autre part ça a impliquer de tuer des fonctionnalités (certes dépréciées depuis longtemps) dans une version corrective, ce qui n'est pas forcément très réjouissant.

De même, Firefox 20 modifie le comportement de la méthode setAttribute() sur un élément du DOM. Jusqu'à présent en affectant la valeur null, cela affectait au final un chaine vide et maintenant cela affecte la chaine "null". En soi c'est très bien puisque c'est conforme à ce que font tous les autres navigateurs mais ça a des conséquences sur le fonctionnement de l'interface. Si nous avions travaillé en contexte multi-navigateur, nous aurions remarqué cela très tôt. Là encore une fois, ça impose une mise à jour de Change pour rester compatible avec les derniers Firefox.

Et c'est bien cela qui pend aux nez de tous ces développeurs qui font du "Webkit only" : lorsqu'un bug sera corrigé, si leur applications reposent dessus (parfois sans qu'ils s'en doutent), il leur faudra faire des correctifs en urgence pour réparer voir coincera des entreprises sous des vieilles versions comme cela a pu et est encore le cas avec IE6. Et cela arrivera de plus en plus souvent si Webkit continue à progresser en part de marché.

Donc on ne le dira jamais assez : utilisez des standards (et de préférence matures, sans reposer sur des propriétés préfixées) et validez vos développement même mobiles sur plusieurs moteurs différents ! Ne reproduisez pas le désastre d'IE6.

Et en ce qui me concerne, sur ma tablette Android, par principe je ne lance jamais aucun navigateur sous Webkit (sauf tests justement). Jusqu'à présent j'utilisais Firefox et Opera. Maintenant je n'utiliserai plus que Firefox. C'est dommage mais c'est comme ça. Et si un site ne fonctionne que sous Webkit, tant pis pour lui.


Le champ de recherche qui se vide au clic...

Certains développeurs (ou plus souvent encore, leurs clients) on des fois des idées saugrenues. De ces idées qu'une personne normalement constituée n'aurait jamais eu (et quand bien même l'aurait-elle eue qu'elle l'aurait écartée aussi sec). De ces idées qui leur vaudront d'être maudits par une bonne partie de leurs utilisateurs.

Des fois l'idée initiale peut se défendre mais l'implémentation finale la relègue au même rang que les précédentes.

L'une d'elle consiste vider par JavaScript le contenu d'un champ de recherche lorsqu'on clique dessus. Souvent c'est parce qu'on a voulu mettre dedans un descriptif initial qui doit partir lorsqu'on clique sur le champ. Il y a des solutions pour le faire bien, comme par exemple celle-ci.

Il y a aussi des solutions pour le faire mal, comme vider systématiquement le champ même si la valeur actuelle n'est pas le texte initial. Et c'est ce qui est fait sur le site BD Gest' qui comporte l'insanité suivante :

$('#cse-search-text').click(function() {
  $(this).attr('value','');
});
$('#cse-search-text').focusout(function() {
  if($(this).val()=='') {
    $(this).attr('value','Une chronique, une preview, un article ...');
  }
});

Donc moi quand je cherche une BD en copie/collant le titre depuis une boutique et qu'ensuite je dois retoucher ce même titre parce que la ponctuation n'est pas la même et qu'aucun résultat ne remonte, immanquablement je clique là où je veux faire la retouche... et ça me vide le champ :blase:

Bon, râler c'est bien mais au bout d'un moment, c'est plus constructif de trouver une solution.

Voilà donc un petit script pour Greasemonkey (j'imagine qu'elle doit exister sur d'autres navigateurs aussi) qui résout le problème :

// ==UserScript==
// @name        BDGest Pas vider le champ de recherche
// @namespace   http://darathor.com/vrac/UserScripts
// @description Désactive le vidage automarique du champ de recherche, ce qui permet de coller un texte puis de l'éditer.
// @include     http://www.bdgest.com/*
// @version     1
// ==/UserScript==
jQuery('#cse-search-text').click(function() {
	jQuery(this).unbind();
});

Avec ça, le champ se vide au premier clic (ce qui vire la phrase inutile qu'il contient) puis tous les listeners sont supprimés, du coup plus rien ne se passe aux clics suivants. Simple et efficace \o/

Bon, dans l'idéal il faudrait que la valeur saisie reste après la recherche pour qu'on n'ait pas besoin de la recoller dedans avant de la retoucher en cas d'absence de résultats... mais bon, on peut pas remédier de l'extérieur à tous les vices de conception non plus...


Quelques trucs sur l’iPod Touch/iPhone #3

Ne plus ouvrir iPhoto lorsque l'iPhone est branché

Par défaut quand vous branchez un iPhone sur un Mac, il ouvre automatiquement iPhoto (l'iPhone étant reconnu comme un appareil photo). Pour désactiver ça, rendez-vous dans les préférences d'iPhoto et modifiez la valeur de l'option "Le fait de connecter l'appareil photo ouvre :" en sélectionnant "aucune application".

Verrouiller la touche majuscules

Sur un ordinateur, la touche permettant de verrouiller le clavier en mode majuscules est souvent assez inutile (on peut facilement utiliser un second doigt pour activer la majuscule), voire gênante : on l'enclenche plus souvent par erreur que volontairement... mais sur un iPhone, ça permet d'éviter de re-cliquer sur majuscule à chaque frappe quand on tape un mot en majuscule (sigle ou autre).

Pour cela il faut que dans les préférences (Réglages > Général > Clavier), vous activiez l'option plutôt mal nommée "Maj. verrouillées". Mal nommée parce que tout ce qu'elle active c'est le fait de pouvoir double-cliquer sur la touche de majuscule pour la bloquer (elle devient alors bleue)... Donc elle active le mode permettant de bloquer en majuscules et non le mode majuscules lui-même.

Voir la source

Cette petite astuce trouvée ici consiste à ajouter un signet dont la cible est en réalité un code JavaScript qui affichera la source de la page.

La méthode est simple :

  1. copiez ce code JavaScript, que je reprends ici au cas où le site en question cesserait d'émettre :
        javascript:(function(){var d=window.open("about:blank"),a=d.document;a.write("<!DOCTYPE html><html><head><title>Loading Source</title></head><body></body></html>");a.close();var b=a.body.appendChild(a.createElement("form"));b.setAttribute("method","post");b.setAttribute("action","http://ole.michelsen.dk/viewsource/?uri="+location.href);var c=b.appendChild(a.createElement("input"));c.setAttribute("type","hidden");c.setAttribute("name","DOM");c.setAttribute("value",encodeURIComponent(document.documentElement.innerHTML));b.submit()})()
        
  2. ajoutez un signet bidon nommé "Voir la source" (ou toute autre dénomination qui vous plaira)
  3. éditez le signet précédemment créé et collez ce code à la place de l'URL

Il vous suffit maintenant pour voir le code source d'un lancer le signet.


Rollovers compatible iPhone

En intégrant la nouvelle charte par défaut d'RBS Change (à venir avec la prochaine version 3.6), j'ai intégré quelques blocs avec du rollover (notamment le sélecteur de langues ou le bloc de récap du panier).

Ça fonctionne très bien via du CSS avec la pseudo-classe hover, si ce n'est que sur iPhone tous ne passent pas : le menu déroulant marche sans problème, par contre le bloc de sélection des langues ne passe pas. Le point qui bloque c'est que dans le menu il y a des liens sur les items qu'on survole, du coup au premier "clic" l'iPhone active le hover au lieu de suivre le lien (qui n'est suivi qu'au second clic) alors que quand on n'a pas de liens il n'active pas le hover.

J'ai cherché des solution sur le net et je suis tombé sur pas mal de chose pas super convaincantes :

  • une solution basée sur des événements spécifiques au tactile : "touchstart" et "touchend" (comme expliqué par exemple) mais que je n'ai pas réussi à faire marcher...
  • passer par l'événement "clic" pour placer puis enlever comme dans solution précédente une classe "hover" sur les éléments

Dans les deux cas c'est loin d'être parfait... Notamment dans le 2e cas, ça merdouille si on a les style à la fois sur la pseudo-classe hover (pour tout ce qui n'est pas tactile c'est quand même mieux vu qu'on ne dépend pas de JavaScript) et sur la classe ajoutée.

Finalement, du coup j'ai compris que l'iPhone active le hover à partir du moment où on place un listener sur l'événement "clic" ! Du coup j'ai simplement mis un listener au clic sur mon élément où je veux appliquer le hover qui ne fait rien de particulier et mon problème est réglé sans pourrir mes styles avec une classe ajoutée à la volée \o/

Donc concrètement, si par exemple j'ai ce code HTML :

<div class="test">
  Toto
  <p>Visible uniquement au survol</p>
</div>
Associé à ce CSS :
.test p {
  display: none;
}
.test:hover p {
  display: block;
}

Ça fonctionnera très bien sur un ordinateur mais pas sur un iPhone ou un iPad, à moins d'y ajouter ce code JavaScript (utilisant jQuery mais j'imagine que ça doit marcher sans aussi...) :

jQuery(document).ready(function() {
  jQuery('.test').click(function() {});
});

Quelques trucs sur Javascript #1

Packed VS minified

Il existe deux méthodes couramment utilisée pour alléger les javascripts :

  • En les "compactant" : le code est alors ré-écrit en une version nettement plus compacte et surtout nettement moins lisible.
  • En utilisant jSmin : là le script est juste allégé de tous ses commentaires et espaces superflus. Il est moins compact mais reste cependant relativement lisible.

En général la version "compactée" est environ un tiers moins lourde que la version "minifiée" mais en contrepartie, l'exécution est presque deux fois plus lente. Et donc le ressenti côté utilisateur est nettement dégradé dans la version compactée. La version minifiée est donc en général préférable, d'autant que pour le debug c'est nettement plus pratique !

La fonction parseInt

Cette fonction permet, comme son nom l'indique, de convertir une chaine en entier. A priori rien de bien compliqué. Son deuxième paramètre permet de spécifier la base dans laquelle on se place. Rien de compliqué non plus.

Là où ça peut un peu plus surprendre si on lit la doc trop rapidement, c'est qu'en l'absence du deuxième paramètre, si la chaine commence par un zéro, la conversion se fait en octale, soit en base huit et non dix. Cette fonctionnalité semble être dépréciée mais elle est toujours prise en compte.

On a donc les résultats suivants :

  • parseInt("000") -> 0
  • parseInt("001") -> 1
  • parseInt("002") -> 2
  • parseInt("003") -> 3
  • parseInt("004") -> 4
  • parseInt("005") -> 5
  • parseInt("006") -> 6
  • parseInt("007") -> 7
  • parseInt("008") -> 0
  • parseInt("009") -> 0
  • parseInt("010") -> 8
  • parseInt("011") -> 9
  • ...

La console d'erreur de Firefox

Dans un contexte d'extension (ou au moins dans un contexte signé il me semble), il est possible d'écrire des messages dans la console d'erreur de Firefox via JavaScript.

Par contre (du moins dans certaines versions), tenter de loguer un message vide fait planter la console. Elle continue à accumuler les message mais il faut la fermer et la rouvrir pour les voir. Chose très agaçante quand on ne sait pas d'où ça vient...