Archives de l'année 2012

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 automatique 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 extensions pour Firefox #5

Cet article est marqué comme contenant des informations dépassées depuis le 21/10/2018.
Status-4-Evar n'a bien entendu pas survécu à Firefox Quantum et à l'abandon du système historique d'extensions.

Status-4-Evar

Depuis Firefox 4, la barre d'état ou statusbar a disparu de Firefox, remplacée par une "barre de modules" et une infobulle au survol des liens donnant leur URL.

À mon sens cette infobulle remplaçant une barre statique est une mauvaise chose. Personnellement je ne suis pas fan des éléments qui apparaissent et disparaissent de mon interface, surtout quand ils apparaissent très souvent et ne prennent pas particulièrement de place. D'autant que comme j'ai des modules ajoutant leurs boutons dans la barre des modules, il n'y a même pas de gain de place. Puis pour couronner le tout, par moment quand le lien est en bas de page, on se retrouve avec une infobulle qui clignotent en continu et devient illisible.

Contrairement à l'habitude de Mozilla il ne semble pas y avoir de manière simple de remettre cette barre par configuration. Par contre, cette extension le permet.

Ghostery

Cette excellente extension propose de bloquer un grand nombre de scripts tiers qui pullulent sur les sites web pour recueillir une foule d'informations sur nous, ralentir les chargements et rendus de pages et accessoirement de temps à autres proposer des fonctionnalités un peu utiles (ou pas).

L'extension dresse une liste catégorisées des scripts et cookies bloqués et permet de choisir ce que l'on veut laisser passer ou non. De plus, pour les boutons de partages sur les réseaux sociaux, elle permet de remplacer les boutons par des icônes permettant au besoin de les réactiver ponctuellement sur la page en cours, ce qui permet de continuer à les utiliser si on le souhaite sans pour autant les subir continuellement (avec le lot de ralentissements qu'ils impliquent).

Awesome Screenshot Plus

Enfin, terminons cette série sur cette extension qui permet de faire des captures de pages ou d'extraits de pages et qui depuis un certain temps a remplacé chez moi l'extension "Abduction" dont j'avais parlé il y a quelques années. Cette extension est simple et efficace et a en plus l'avantage de s'installer sans redémarrage.


Quelques petites BD #2

Je poursuis (à un rythme assez lent, j'en conviens), la création de petites BD dont la première fournée se trouve . Voici donc les trois suivantes (qui ont déjà été publiées au fur et à mesure sur deviantART et Twitter) :

BD #5 - 15/06/2012 BD #6 - 24/06/2012 BD #7 - 16/09/2012
Images sous licence CC-BY

La première est tirée d'une petite phrase hautement cohérente relevée par @jmramseyer.

La seconde parle de web design et de grilles. Pour les non-habitués du domaine, une petite description de ce qu'est-ce qu'une grille dans ce cas-là.

Quant à la troisième, elle n'est pour une fois pas tirée d'une anecdote de bureau mais de tweets parlant des fortes chaleurs de la mi-aout :

L'été, la chaise de bureau est composée de 35% d'eau.

— ak (@a___k) le 21 août 2012 à 17h25

Putain de temps de merde (pour rester poli) - je meurs et peux pas bosser comme ça moi... quand est-ce qu'il neige ?

— Paul da Silva (@Paul_da_Silva) le 21 août 2012 à 19h28

Je m'inquiète pour Firefox...

Je m'étais habitué à voir progressivement, au fur et à mesure de mises à jour de Firefox, de plus en plus de fonctionnalités disparaitre de l'interface pour être reléguées au fin fond des menus, voire carrément supprimées (détection des flux RSS, des moteurs de recherche, barre d'état, menu, protocole...).

Je suis donc fort surpris et même inquiet de constater que depuis plusieurs versions, plus aucun élément d'interface n'ait disparu. Les équipes de Mozilla se seraient-elles tellement habituées à se contenter de suivre Chrome sur ce sujet qu'elles n'arrivent pas à trouver elles-même quel est l'élément superflu suivant ?

Pourtant ce n'est pas si difficile. Prenez les boutons de navigation "précédent", "suivant" : de nos jours les sites web contiennent tout ce qu'il faut pour naviguer (menus, fils d'Ariane, etc). Je pense qu'il est donc inutile de les conserver par défaut.

Le bouton rafraichir me semble bien inutile aussi : quand les informations varient, les sites proposent en général de rafraichir le contenu et au pire il suffit de cliquer dans la barre d'adresse et appuyer sur "entrer" pour recharger la page.

Après quand on y pense, il me semble bien superflu de garder à la fois une zone de titre et une barre d'adresse : pourquoi ne pas les fusionner comme dans la version mobile ? On éviterait du coup de voir d'inutiles adresses incompréhensibles qui, je n'en doute pas, doivent perdre les utilisateurs non-techniciens. D'ailleurs à bien y repenser, la barre d'adresse et de recherche est bien inutile puisqu'il suffit de mettre un champ de recherche à l'ouverture d'un nouvel onglet.

Ensuite, la barre d'onglets : je pense qu'on peut bien s'en passer aussi. L'être humain est généralement monotâche (et le peu de multitâche qu'il est capable de déployer est déjà bien assez occupé à vérifier sur son smartphone que personne n'essaie de le joindre). Au pire on peut toujours ouvrir plusieurs fenêtres s'il le faut. Parce qu'une barre d'onglets, ça prend facile 20 à 30 pixels de haut, on rigole pas avec ces choses là ! D'autant que le titre de la page, c'est assez inutile. Un petite notification en bas de l'écran au chargement de la page est bien suffisant.

Vous me direz que ce n'est pas pratique vu que c'était à l'ouverture d'un nouvel onglet que l'on pouvait lancer une recherche mais je me vois bien obligé de vous détromper. En effet, maintenant que Google est capable en traçant nos habitudes de deviner ce qu'on va faire, plus besoin de choisir, il suffit de se laisser porter.

Du coup on arrive à quelque chose de vraiment révolutionnaire dans sa simplicité. J'aurais tendance à vouloir proposer un nouveau nom : ça s'appellerait "Télévision".

Mais comme dirait Jean-Pierre Gauffre : évidemment, vous n'êtes pas obligés de me croire.


Quelques extensions pour Firefox sur Android #1

Vu que j'ai acheté une tablette Android, j'y ai installé Firefox et forcément j'ai regardé les extensions disponibles. Première impression : y en a très peu.

Cela étant dit, j'ai quand même trouvé de quoi remédier à 3 problèmes majeurs. Puis pour les retrouver facilement, j'ai créé une collection qui les recense.

La publicité : Adblock Plus

La première raison qui fait que je ne suis pas près de quitter Firefox sur mon PC c'est bien Adblock qui permet de purifier un peu les pages de tous les parasites publicitaires qui plombent les performances, consomment de la bande passante, perturbent la navigation et enfin obligent à faire des efforts pour les ignorer et rester concentré sur ce qu'on est venu voir sur le site.

Et donc, joie : une version d'Adblock existe pour Android \o/

Utiliser les versions desktop des sites : Desktop by Default

Les sites mobiles, ça part d'un bon sentiment. C'est fait pour que quand on a un écran format timbre poste, on ait une chance de pouvoir naviguer. Le hic, c'est que déjà sur un smartphone avec un écran pas trop petit, ce n'est pas toujours justifié mais sur une tablette dix pouces, ça devient juste très chiant ! Parce que ces sites mobiles avec moins de fonctionnalités, un design tout petit et tout ben sur un écran plus grand c'est juste moins navigable et lisible que la version desktop. Quand ce n'est pas bugué (genre Google images, j'arrive juste pas à naviguer entre les pages).

Pour y remédier, Firefox propose dans son menu de passer sur la version desktop du site mais ça a deux inconvénients : il faut le faire manuellement à chaque fois et ça redirige en général sur l'accueil... pas pratique quand on vient sur un article donné (genre via Twitter).

Cette extension permet de cocher cette case par défaut et d'un coup c'est vachement mieux.

Seul bémol : je ne sais pas ce qu'ils font exactement quand on coche la case, mais pour certains sites ça ne fonctionne pas. Par exemple le site du monde qui quoiqu'il arrive te redirige sur sa putain de version mobile toute pourrie écrite en taille 2 mais où le texte s'étire sur toute la largeur, ce qui empêche de zoomer sans devoir scroller horizontalement en permanence...

Toujours autoriser le zoom : Always Zoom

Un problème plus marginal mais ça arrive quand même : certains sites désactivent le zoom. C'est con, ça sert à rien et potentiellement ça emmerde l'utilisateur, autant de raisons manifestement suffisantes pour que certains sites le fassent.

Cette extensions de désactiver la désactivation du zoom. Je n'arrive plus à me souvenir où j'avais eu le problème, donc pas pu valider que ça marche effectivement bien mais y a pas de raison...


Mon avis sur l'ASUS Transformer Pad TF300T

Introduction

Pendant longtemps j'ai considéré qu'une tablette tactile ne me servirait à rien. Mes usages ne l'imposaient pas du tout et je ne suis pas du genre à acheter un nouveau gadget technologique si je n'y pré-sens pas un réel intérêt.

Puis ces derniers mois, je me suis rendu compte que mon usage de mon smartphone avait évolué et finalement se faisait en grande partie dans mon lit et plus majoritairement dans les transports. Dans ce contexte le fait qu'il soit petit n'apporte environ rien mais fait perdre considérablement en terme de lisibilité. Du coup la tablette devenait intéressante. De plus c'était l'occasion de reporter le remplacement de mon iPhone qui était motivé essentiellement par la petite taille de son écran.

Partant de là restait à en choisir une.

Premier candidat possible : l'iPad. Ça aurait été cohérent avec l'iPhone mais tant qu'à faire c'était l'occasion de passer à un truc moins cloisonné, censuré, dirigé et verrouillé. Bref, exit Apple. De toutes façons, je ne compte pas rester sur un iPhone pour ces mêmes raisons.

À part ça on a essentiellement de l'Android. Plein de fabricants font plein de tablettes qui se ressemblent toutes et c'est pas évident de choisir. Je suis passé à la Fnac pour tester un petit peu ce qu'il avaient mais je n'étais pas vraiment emballé : sur la plupart même le défilement d'un bureau à l'autre n'était pas vraiment fluide... Rien de très enthousiasmant.

Puis je suis tombé sur le test de l'ASUS Transformer Pad TF300T (oui ils sont doué pour trouver des noms courts et faciles à retenir...) de La Chaine Techno qui m'a plutôt bien convaincu : un clavier, de bonnes performances, tout ça. Je suis donc repassé par la Fnac pour confirmer que celle là offrait bien un défilement fluide au moins sur les fonctions de base puis je suis rentré chez moi la commander sur le net là où le prix était intéressant (faut pas déconner non plus).

La tablette en elle-meme

Bon, clairement c'est déjà pas une tablette bas de gamme (en même temps si c'est pour acheter de la merde, autant rien acheter du tout, ça évite de regretter une semaine après) puisque l'ensemble m'a coûté environ 500€ pour :
- la tablette
- le dock clavier
- une housse et une carte mémoire de 32Go supplémentaire

Donc comme je le disais plus haut, niveau performances, c'est correct : c'est globalement assez fluide à part de temps en temps quelques ralentissements sur Firefox. Le tactile est réactif et plutôt précis, je n'ai pas senti de différence notable par rapport à l'iPhone, donc techniquement ça fonctionne bien. L'autonomie est pour l'instant très bonne (à voir comment se comportera la batterie sur la durée).

Le doc clavier et bon aussi avec un clavier AZERTY pas trop petit et qui remplace le clavier tactile lorsqu'il est branché (ce qui libère significativement de la place sur l'écran). De plus il contient également une batterie, ce qui double l'autonomie de l'appareil, donc c'est plutôt pas mal.

Seul reproche (mais pas spécifique à celle-ci en particulier) : encore un câble spé pour connecter la tablette au PC ou à une prise de courant. Certes USB d'un côté mais avec une nouvelle prise spé de l'autre qui ressemble furieusement à celle de l'iPhone avec quelques millimètres en moins... Quand les fabricants vont-ils enfin se mettre d'accord là dessus ? J'ai bien peur que ça ne puisse pas arriver tant qu'aucune loi ne les y obligera (et accessoirement que les brevets les en dissuaderont)... dommage, parce que c'est bien chiant de ne pas pouvoir répartir tous ces câbles sur nos différents lieux d'utilisation plutôt que de devoir les trimbaler à chaque fois (ou les acheter chacun en x+n exemplaires).

Maintenant le côté logiciel

Déjà premier point : après plusieurs années à utiliser un iPhone, je redécouvre le bonheur de transférer des fichier dessus sans passer par la case imposée iTunes \o/ Eh oui, pouvoir simplement brancher la tablette sur son PC et accéder à son système de fichier directement. La base quoi. Ça semble évident comme ça mais chez Apple ça n'existe pas.

À part ça c'est mon premier appareil sur Android, et globalement ça passe plutôt bien. Quelques trucs auxquels il faut se faire au début mais globalement c'est comparable à l'iPhone avec quelques petits points un peu moins agréables en terme d'ergonomie et d'autres largement meilleurs.

Le plus gros point fort c'est la navigation entre les applications. Sur l'iPhone, même s'ils ont introduit le multitâche il y a quelque temps, c'est quand même assez rare d'arriver à passer d'une appli à l'autre sans perdre son contexte (genre si vous espérez retrouver le tweet que vous étiez en train de taper sur l'appli Twitter en après un saut sur le client mail, vous allez vite déchanter). Là les applis restent vraiment ouvertes (bon à l'inverse elles restent peut-être un peu trop ouvertes mais bon, je préfère ça personnellement ça marche mieux à l'usage) et le bouton de retour qui vaut autant au sein de l'application que d'une application à l'autre est juste très pratique.

Autre point fort : on peut installer des applications sans passer par un quelconque "store". Donc ça veut dire que si je veux faire un appli et la diffuser à un public restreint sans payer la taxe Apple (plusieurs 10aines d'euro par an rien que pour avoir le droit de mettre un truc sur l'AppStore, même pour une diffusion gratuite). Et du coup le corollaire c'est qu'on est pas bridé à des navigateurs basé sur le moteur de rendu Apple (le dernier pour Safari et le précédent pour les autres). Je peux donc installer un Firefox mobile avec adblock ou un Opera mobile et ça c'est BIEN. Ça me permet de contribuer à ralentir la transformation déjà bien entamée de webkit en IE6 pour les mobile (c'est-à-dire un moteur omniprésent et des sites conçus uniquement pour lui excluant d'emblée tout autre acteur) en faisant baisser sa part de marché.

Enfin un autre point très positif : les applis natives imposées par le constructeur, ben on peut les désactiver. Si si c'est vrai, ça parait fou comme ça mais c'est vrai. Bon faut chercher un peu mais ça se fait. J'ai pu virer les Google+, Gmail et autres qui s'entêtaient à vouloir se relancer continuellement en tâche de fond alors que je ne m'en sers pas.

Bon après ça reste du Google, donc c'est pas non plus le paradis. On a l'impression de vendre son âme en démarrant la tablette la première fois. Puis on se tape de la pub ici ou là (mais finalement pas tellement plus que depuis l'arrivée d'iAd chez Apple) et on se fait sans doute espionner à tout va (mais là non plus Apple n'est sans doute pas en reste). L'idéal aurait été un OS libre piloté par une organisation sans but lucratif mais pour l'instant c'est pas encore trop ça... De deux maux il faut choisir le moindre. En l'occurrence je ne fais pas plus confiance à Google qu'à Apple mais au moins j'ai plus d'ouverture sur l'usage de ma tablette, c'est déjà ça.

Y a aussi quelques points ergonomiques discutables et des habitudes qu'on aurait bien aimé garder de l'iPhone mais qui ne sont pas transposables mais globalement après une semaine d'utilisation je m'y suis fait et à par l'effet de "rebond" marquant le bas d'une fenêtre (qui est sans doute breveté Apple, d'où son absence de la plupart des applis), je ne trouve pas vraiment de gros points noirs sur l'ergonomie.

Sur le store et les applications, je trouve par contre assez gênant l'absence de signalétique disant si l'appli est compatible avec de grand écrans ou non. En effet un certain nombre d'applications ne "scalent" pas ou très mal sur un écran de tablette et sont manifestement optimisées uniquement pour les téléphones. Ça fait souvent tester plusieurs applis avant d'en trouver une satisfaisante (raison de plus pour ne jamais en acheter... ce que je ne prévoyais pas de faire de toutes façons).

Enfin un point gênant : Firefox a un bug avec le clavier et passe en clavier anglais pour les champs de formulaires alors qu'il gère bien le clavier français pour la barre d'adresse. J'espère que ce bug sera vite corrigé..

Conclusion

Pour l'instant je suis plutôt satisfait de mon achat et ne le regrette pas. Ça me confirme également dans mon idée qu'actuellement la concurrence a largement rattrapé Apple sur le segment des appareils mobiles et qu'on peut donc largement s'en passer.

L'iPad est sans doute au moins aussi bon technologiquement et je l'ai écarté d'emblée pour sa fermeture. Ces considération idéologiques sur le caractère ouvert du système peuvent paraitre accessoires puisqu'au final on arrive à faire la majorité de ce qu'on veut vraiment faire sur un iPhone ou un iPad. Mais est-il vraiment raisonnable de continuer à valider les systèmes fermés d'une société si d'autres options sont disponibles avec un niveau de qualité proche ?


Application web de gestion d'achats groupés

Voici un autre module Change que je suis en train de développer. Pour le coup il répond à un besoin très spécifique et correspond plus à un extranet qu'à un site web classique. Mais bon, puisque moi j'en avais besoin, peut-être que d'autres en auront l'usage aussi. Ou pas mais on peut difficilement savoir avant d'en parler :)

De quoi s'agit-il ?

Depuis des années, j'achète souvent sur le net, en particulier des biens culturels et ludiques : livres, mangas, DVD CD, jeux de plateaux, jeux à collectionner, jeux vidéos, etc. Grouper les achats permet en général de réduire les frais de port et en bonus allège un peu le coût écologique total des livraisons. Donc on a pris l'habitude avec mes frère, sœur et parents principalement de grouper nos achats de ce type. Ceci implique de gérer des comptes puisqu'à chaque commande, une seule personne paye effectivement et le autres doivent le rembourser. Le même principe vaut pour les cadeaux groupés ou autres courses occasionnellement faites pour le compte des autres.

S'échanger du liquide à chaque fois c'est chiant, donc pendant longtemps on est passés par du mail pour se tenir au courant de l'état du solde de chacun. Mais le mail c'est quand même assez peu adapté : quand on se plante et qu'on part du mauvais mail pour calculer les nouveaux soldes ou quand on se demande si on a bien pensé à prendre en compte tel ou tel achat c'est vite le bazar. Puis faut faire tous les calculs à la main, c'est lourd et ça introduit un risque d'erreur non négligeable.

Du coup comme on est quand même une famille de développeurs on se disait que faire une appli web accessible de n'importe où pour gérer tout ça ce serait cool et ça nous faciliterait la vie (enfin sauf ma mère qui elle se cantonne en général à rappeler qu'en achetant moins ça serait tout de suite plus simple mais avant de prendre sa retraite elle était prof de maths, pas informaticienne, donc on lui pardonne). Comme toujours, avec les supers solutions ça s'est éternisé quelques temps à l'état de projet hypothétique parce que bon, c'est bien beau de se dire qu'il faudrait le faire mais c'est quand même vachement plus simple que de le faire réellement.

Mais bon, un jour on se dit qu'au final si on veut pas arriver au point où on aura passé plus de temps à se dire qu'il faudrait le faire que le temps nécessaire pour le faire réellement il faut se lancer. Et donc il y a quelques mois j'ai pris mon courage à deux mains et finalisé une première version utilisable (loin d'être complète et ergonomiquement optimale mais utilisable).

Comme j'ai l'habitude de travailler avec Change, c'est donc un module Change. Ça aurait pu être fait avec n'importe quelle autre techno mais c'est celle là que je maitrise.

Bon et donc ça fait quoi concrètement ?

Pour l'instant ce module va vraiment à l'essentiel : il gère des "factures" (que j'aurais pu appeler aussi "transactions") correspondant à un achat dans une boutique avec le montant total payé, les réductions et les frais inclus dans ce total et enfin le détail des achats avec la répartition entre les acheteurs.

Formulaire de création d'une facture
Formulaire de création d'une facture

L'outil valide la cohérence globale de ce qui est saisi, en particulier :
- les répartitions doivent correspondre au total des quantités saisies
- le montant payé doit correspondre au total des lignes après application des réductions et frais
On évite ainsi pas mal d'erreurs de saisie.

Validation de la cohérence de la facture
Validation de la cohérence de la facture

Une fois la facture enregistrée, la répartition des coûts entre les différents acheteurs est calculée (les réductions et frais indiqués étant répartis au prorata des achats) et leurs soldes sont automatiquement mis à jour. Les différents intervenants sont alors avertis par e-mail qu'une facture qui les concerne vient d'être saisie.

Détail d'une facture
Détail d'une facture

On peut également consulter la liste des comptes utilisateurs avec leurs soldes et accéder au détail d'un compte qui donne la liste de ses factures.

Liste des comptes
Détail d'une facture
Détail d'un compte
Détail d'un compte

Et enfin on peut également accéder à l'historique complet des factures enregistrées.

Liste des factures
Liste des factures

C'est tout pour le moment, ce qui suffit à répondre nos besoins minimaux et apporte déjà nettement plus de simplicité que le mail et moins d'erreurs grâce aux différents contrôles de cohérence.

Évolutions envisagées

Même si l'ensemble répond au besoins minimaux, c'est encore loin d'être complet et ergonomique.

Gestion des boutiques

En effet, la création d'une nouvelle boutique implique de passer par le backoffice, ce qui est assez contraignant. De même il n'y a pas encore de listing des boutiques sur le site qui permettrait de suivre l'historique des dépenses dans chacune d'entre elles.

Saisie des factures

La saisie des factures est encore assez figée : tous les comptes ont systématiquement leur colonne dédiée, ce qui fonctionne à note échelle actuelle de 5 personnes mais poserait des problèmes avec une plus grosse volumétrie (qui pourrait être vite atteinte si l'on ajoute des acheteurs plus occasionnels).

De même le nombre de lignes est figé d'autorité à 30, ce qui est à la fois beaucoup trop la plupart du temps et pas assez dans certains cas exceptionnels.

Modification et validation des factures

À l'heure actuelle, les factures sont "validées" automatiquement lors de leur saisie. C'est-à-dire qu'elles ne sont pas modifiables et que les soldes des intervenants sont mis à jour immédiatement.

Pour une utilisation plus pratique et rigoureuse il est prévu d'ajouter une validation par l'ensemble des intervenant avant de mettre à jour les soldes, ceci permettant de détecter les éventuelles erreurs. De plus tant qu'elle n'est pas validée par tout le monde, la facture restera modifiable, voire annulable.

Autres évolutions envisagées

D'autres évolutions seraient intéressantes à mettre en œuvre :

  • Gestion de versements directs : dans notre cas, certaines personnes passent plus fréquemment des commandes que d'autres. Il en résulte que les soldes ont tendance à se déséquilibrer, déséquilibres qui se règlent en général par un versement (liquide, chèque, virement...). Il serait donc intéressant de pouvoir matérialiser dans une entrée dédiée un versement direct d'une personne à une autre dans un formulaire simplifié.
  • Pour certains achats (au hasard les cadeaux), il peut être pratique de ne rendre visibles certaines commandes (voire certaines lignes seulement) que par les personnes concernées (notamment pas le destinataire du cadeau).

Je ne dis pas que tout sera fait et encore moins sous quels délais mais dans l'idée c'est pour l'instant l'essentiel qu'on ait détecté comme évolutions à faire pour améliorer l'appli.

Accès au code

Comme la plupart de mes modules, celui-ci a vocation à être publié (d'ailleurs en théorie l'Afero GPL l'impose un peu) une fois qu'il sera suffisamment finalisé. Je compte également l'archiver dans un repository publique mais je n'ai pas encore tranché entre passer par un site existant genre GitHub ou SourceForge comme pour mes précédents modules (qui aurait l'avantage d'une mise en place simplifiée) et m'installer un repository local sur mon serveur avec un accès web au fichiers (qui d'un côté me plait mieux parce que je garde la maitrise de mon repository plutôt que de le stocker sur une plateforme tierce centralisée mais implique de passer du temps à le mettre en place).

Quoiqu'il en soit, si jamais quelqu'un est intéressé (sait-on sait jamais) je peux déjà lui fournir la version actuelle sur simple demande ^^


Quelques trucs sur Firefox #1

Activer la correction orthographique sur les champs textes mono-ligne

Par défaut Firefox n'active la correction orthographique sur les champs texte multi-lignes. Il est possible également de l'activer sur les champs mono-ligne simplement par configuration (pas besoin d'extension pour ça).

La manip' est la suivante :

  1. dans la barre d'URL, taper about:config pour accéder aux variables de configuration de Firefox
  2. lire l'avertissement si vous ne l'avez pas déjà fait et cliquer sur "Je ferai attention, promis !"
  3. dans le champ de recherche, taper layout.spellcheckDefault
  4. double-cliquer sur la ligne dont le nom est layout.spellcheckDefault

Les autres valeurs possibles sont :

  • 0 : aucune correction
  • 1 : champs multi-lignes seulement
  • 2 : champs multi et mono lignes

(source)

Firefox 13 : changer la page de l'ouverture d'un nouvel onglet

Firefox 13 arrive avec par défaut dans les nouveaux onglet un diaporama des sites que vous consultez le plus souvent. Si je peux concevoir que ça puisse servir à certaines personnes, en ce qui me concerne ce n'est pas le cas.

En effet, les sites que je consulte souvent, soit j'ai un signet pour y accéder tout aussi vite, soit ils arrivent en première suggestion en tapant une à trois des premières lettres dans la barre d'URL... Pas besoin d'un gros visuel pour ça.

Autre point : moi qui utilise beaucoup l'historique de navigation sur les onglets, pour revenir à l'accueil des sites que je consulte souvent (que j'ouvre en général dans des onglets dédiés), ça ne m'arrange pas du tout que la première entrée de cet historique soit squattée par une liste de miniatures inutiles plutôt que la page par laquelle je suis arrivé sur le site.

L'avantage de Firefox par rapport à d'autres logiciels c'est qu'assez souvent quand ils ajoutent une fonctionnalité à la con copiant Chrome, c'est qu'on peut la désactiver pour peu de savoir quelle clé de configuration changer. Celle-ci n'échappe heureusement pas à la règle :)

La manip à faire est donc similaire à celle du point précédent :

  1. dans la barre d'URL, taper about:config pour accéder aux variables de configuration de Firefox
  2. lire l'avertissement si vous ne l'avez pas déjà fait et cliquer sur "Je ferai attention, promis !"
  3. dans le champ de recherche, taper newtab
  4. double-cliquer sur la ligne dont le nom est browser.newtab.url et renseignez l'URL que vous voulez accéder via vos nouveaux onglets, ou about:blank si comme moi vous préférez une page vide qui ne polluera pas l'historique

Notons que si d'aventure vous souhaitez accéder à cette page il suffira de taper about:newtab dans la barre d'URL (que vous pouvez également mettre dans un signet si le cœur vous en dit).

(source)

Firefox 13 : désactiver les mises à jour silencieuses

Firefox 13 fait décidément beaucoup de choses qui ne me plaisent pas directement importées de Chrome. En l'occurrence je parle ici de la nouvelle option de mises à jour "silencieuses" automatiques du navigateur.

En soi je peux concevoir qu'on ait envie de l'activer pour ne plus avoir à s'en préoccuper mais personnellement je préfère choisir de valider volontairement une opération qui peut rendre mes extensions inutilisables ou casser le rendu de certains sites. Et surtout je préfère choisir moi-même le moment : en général pas lorsque je suis en train de faire un truc urgent ou quand je suis énervé pour une quelconque raison.

D'autant plus qu'à l'époque où Firefox suivait un cycle de release plus standard, on ne se posait vraiment de questions que pour les mises à jour majeures, les autres n'étant que des correctifs, le risque était faible. Maintenant toute mise à jour peut contenir des modifications majeures (ou pas la plupart du temps mais rien ne les différencie a priori), donc il est exclus pour moi d'activer des mises à jour automatiques sans validation de ma part sur une application aussi cruciale que mon navigateur.

Le hic c'est que cette nouveauté est semble activée par défaut lors du passage à Firefox 13 (en tous cas je ne me souviens pas avoir eu de dialogue qui me pose la question et hier quand j'ai appris son existence, j'ai constaté qu'elle était activée).

Heureusement elle reste désactivable facilement (même pas besoin de passer par about:config cette fois... quoique vu comme elle est loin dans les menus ça aurait peut-être été plus rapide :euh: ) :

  1. aller dans le menu Outils > Options...
  2. sélectionner l'onglet "Avancé" (le dernier en principe) puis le sous-onglet "Mise à jour
  3. choisissez la seconde option "Vérifier l'existence de mises à jour mais me laisser décider de leur installation

(source)


Historique des méthodes de surcharge de code PHP dans RBS Change

Le but de cet article est de revenir sur les différentes méthodes de surcharge du code PHP qu'on a eu (et que pour beaucoup on a encore) dans RBS Change depuis que je travaille dessus (au départ en faisant des sites avec puis par la suite en tant que développeur du produit).

Je n'entrerai pas dans les détails concrets d'utilisation mais ça me semble intéressant de voir un peu l'évolution des concepts, les différentes tentatives qu'il y a eu et les raisons qui ont pu orienter certains choix.

En fin d'article je présente ce qui sera fait dans la version 4.0 dont la sortie n'est prévue que courant 2013. En conséquence, ce que j'évoque pourrait potentiellement encore évoluer d'ici là et ne reflète que ce qui a été mis en œuvre pour l'instant, pas une vérité gravée dans le marbre.

Écrasement des fichiers dans la webapp

J'ai commencé à travailler avec Change sur la version 1.2 en 2006. À cette époque le seul moyen offert pour surcharger du code du produit était d'écraser certains fichiers (PHP ou autres, cela fonctionnait pour tous les fichiers des modules et même du framework : PHP, XML, templates, styles, etc) dans le dossier "webapp". La mécanique était (trop) simple : à chaque chargement de fichier PHP, l'application commençait par le chercher dans le dossier webapp. S'il était présent cette version était chargée, sinon celle du code standard l'était. Le fichier de surcharge était donc contraint de reprendre l'intégralité du code qu'il surchargeait, même au cas où il réécrivait seulement une méthode d'une classe en comptant cinquante.

C'était toujours un peu mieux que de modifier directement le code du produit mais à peine puisque lors d'une mise à jour, il fallait passer sur chaque fichier surchargé pour ré-appliquer les modification.

Dès la version 2, l'année suivante, la possibilité de surcharge de code PHP directement dans le dossier webapp a été supprimée car elle posait beaucoup trop de problèmes. En remplacement, une autre méthode plus cadrée a été mise en place : "l'injection" de service et peu après, de document.

Injection de service et de document

L'injection de service (toujours d'actualité dans la version 3.6) fonctionne sur un principe qui reste très simple mais qui est nettement plus cadré. Dans la configuration projet déclare des injections consistant à dire "le servie A est à remplacer par le service B". Tous les service sont instanciés via une méthode getInstance() (selon le patron de conception singleton) qui inclut une mécanique qui va chercher dans la configuration projet si une injection a été déclarée sur ce service. S'il y en a une, on retourne une instance de la classe remplaçante au lieu de la classe appelée.

Le code travaille donc simplement avec une autre classe que celle qu'il a demandé. Pour que les choses marchent bien, il faut évidemment que la classe remplaçante étende la classe remplacée.

Peu après le même principe a été appliqué aux documents : en déclarant une injection de document on remplace son modèle, sa classe finale et son service là encore en renvoyant des instances de classes étendant celles que le code demande en réalité.

Globalement ça marche assez bien mais avec deux limitations :

  1. Dans le cas où on injecte une classe déjà étendue par ailleurs, les classes étendues ne profiteront pas de l'injection. Par exemple, si une classe C étend A et que j'injecte A par une classe B. Si je demande une instance de A, j'obtiendrai une instance de B mais si je demande une instance de C j'obtiendrai une instance de C étendant A et non B.

    Cette limitation peut rapidement s'avérer gênante quand on développe des modules complexes avec des documents de base étendus par d'autres (par exemple les différents types de produits dans le module Catalogue et boutiques).

  2. Une même classe ne peut être injectée qu'une seule fois. Cela peut devenir problématique si plusieurs modules veulent se greffer sur un module existant et ont besoin de remplacer du code : il faudra alors écrire une classe en spécifique dans le projet qui cumules les différentes modifications ce qui n'est pas très bon en terme de maintenabilité (on se rapproche à nouveau un peu de l'écrasement décrit plus haut même si ça reste plus restreint).

Points d'entrée spécifiques (stratégies, section "mvc" du project.xml, etc.)

Parallèlement à l'injection, d'autres mécaniques plus ciblées ont été mises en place dans certains modules pour permettre de remplacer du code standard par des implémentations spécifiques.

Les modules liés à l'e-commerce se sont ainsi enrichis d'un certain nombre de "stratégies" (du patron de conception strategy). Ces points d'entrée explicites permettent de choisir entre plusieurs implémentations pour un traitement donné. Par exemple on proposait une stratégie sur l'arrondi des prix avec une implémentation standard qui se contentait d'arrondir à deux chiffres après la virgule, là où certains projets avaient d'autres règles.

On trouve encore ce genre de chose en version 3.6, en particulier sur les points le choix n'est pas unique au sein d'un projet donné (par exemple le calcul du montant d'un frais : deux frais peuvent s'appliquer avec des stratégies de calcul différentes).

On en trouve encore quelques autres dont l'implémentation est choisie une fois pour toutes dans la configuration projet mais elles tendent à disparaitre (cette mécanique spécifiquement mise en place à chaque fois étant alors redondante avec les mécaniques génériques d'injection).

D'autres points d'entrée spécifiques ont été mis en place au fur et à mesure, notamment pour les différentes classes entrant en jeu dans le modèle MVC (notamment les différents contrôleurs) qui peuvent être remplacée via une section dédiée dans la configuration projet.

Dans tous les cas ces points d'entrée ont été mis en place spécifiquement dans certaines parties du code. Les mettre en place implique donc de prévoir volontairement que telle ou telle partie doit pouvoir être remplacé au contraire de l'injection qui fonctionne de manière plus globale.

Réécriture de classe et AOP

Dans la version 3.0 de Change, un nouveau mécanisme a été implémenté, tiré de certains concepts de la programmation orientée aspect (AOP).

Cette mécanique propose plusieurs choses reposant sur la réécriture des classes lors d'une phase de compilation.

Premièrement le remplacement d'une classe par une autre. Il s'agit là non pas de simplement retourner une instance d'une autre classe (comme c'était le cas avec l'injection décrite plus haut) mais bien de réécrire la classe pour y intégrer les modifications. Pour ce faire, on renomme la classe d'origine (avec un suffixe quelconque) puis on renomme la remplaçante avec le nom de l'originale. Ainsi le remplacement est totalement transparent pour le code qui l'entoure : il travaille bien physiquement avec une instance de la classe qu'il a demandé, à ceci près que cette classe a été modifiée.

Par exemple on part d'une classe A que l'on veut remplacer par une classe B (qui doit étendre A). On commence par renommer A en A_replaced0. Puis on renomme B en A et on la fait étendre A_replaced0. On obtient alors une nouvelle classe A qui a toutes les méthodes et propriétés de la classe B, y compris celles de la classe A d'origine.

Cette méthode fait sauter la limitation de l'injection décrite plus haut sur les classe étendues puisque du coup une classe C qui étendrait notre classe A d'origine héritera du même coup du code introduit par B. Dans son implémentation proposé dans la version 3.0 (qui reste la même en 3.6), elle ne fait par contre pas sauter l'autre limitation liée aux sources multiples.

Depuis la version 3.0, c'est sur cette mécanique que repose l'injection de documents et plus sur la mécanique décrite auparavant (ainsi une injection du document catalog/product se répercutera sur tous les documents qui l'étendent : catalog/simpleproduct, catalog/productdeclination, etc.).

Au delà de cette simple mécanique de réécriture (qui n'est pas de l'AOP à proprement parler mais juste un préalable), d'autres possibilités ont été mises en place permettant d'ajouter du code avant ou après l'exécution d'une méthode, d'ajouter une méthode à une classe ou d'en remplacer une (il s'agit là effectivement des concept de l'AOP). Là aussi on fait de la réécriture de classes mais avec l'avantage de pouvoir faire venir des modifications de plusieurs sources.

L'inconvénient est que dans les fait c'est un peu compliqué à comprendre et expliquer (le développeur web n'étant pas forcément familier avec ça) et pas forcément très lisible ni intuitif à écrire. Du coup finalement ça a été assez peu utilisé dans la pratique à part pour contourner la limitation sur les sources multiples ou bien pour agir sur des méthodes privées d'une classe (ce que permet dans une certaine mesure l’implémentation actuelle mais relève à mon sens un peu de l'hérésie... même si dans certains cas c'est tentant, réécrire des méthodes privées c'est réécrire du code qui n'est pas censé être accessible par l'extérieur et c'est très mauvais lors des mises à jour).

Injection de blocs

La dernière mécanique en date à avoir été mise en place est l'injection de blocs qui arrive avec la version 3.5.

Lorsqu'on insère un bloc dans une page, on ne référence pas directement un nom de classe mais un "type" (celui qui est indiqué dans le fichier blocks.xml du module) qui en pratique découle du nom de la classe. Mais a grosse différence avec les service c'est que le bloc n'est pas utilisé en tant que tel par du code des modules. Rien n'oblige donc au final à ce que le bloc finalement rendu soit réellement le bloc identifié par le type.

Lorsqu'on utilise un service on va faire appel à ses méthodes pour effectuer des traitements si une méthode manque ou n'a pas la bonne signature la plupart du temps ça finit avec une belle page dont le contenu commence par "Fatal error:". Lorsqu'on utilise un bloc, on va simplement lui demander de se rendre mais son implémentation importe peu en terme de réussite ou d'échec de l’exécution.

L'injection de bloc peut donc être nettement plus libre que l'injection de service ou le remplacement de classe. En effet, elle se contente de changer le mapping entre le "type" du bloc et la classe PHP effectivement utilisée sans obligation que la nouvelle classe étende la classe d'origine (du moment que ça reste un bloc). Si on reste sur un fonctionnement proche, on étendra le bloc d'origine mais si ce n'est pas le cas on peut aussi repartir d'une feuille blanche et le remplacer par une nouveau bloc totalement différent (voire étendant un autre bloc existant qui se rapproche plus de ce qu'on veut faire).

À venir en 4.0 : unification et simplification

Comme on a pu le voir, les méthodes de remplacement de code disponibles sont très nombreuses avec chacune leur limitations. De tout ce que j'ai pu évoquer, trois sortent du lot car elles apportent vraiment un plus en terme de possibilités (hors des limitation liées à l'implémentation). En effet toutes finalement visent à remplacer des classes par des classes qui les étendent une fois pour toutes globalement pour le projet à l'exception de :

  • l'injection de document est un peu à part puisqu'elle implique plusieurs classes (modèle, classe finale du document, service) mais au final reste du remplacement de classe
  • les stratégies dont le choix ne relève pas de la configuration projet mais se fait au cours de l'exécution selon le contexte (exemples : calcul de frais, calcul de réductions, etc)
  • l'injection de blocs qui n'impose pas de reprendre le code du bloc existant mais peut repartir de zéro dans une autre direction si le besoin s'en fait sentir

Toutes les autres (injection de service, remplacement de classe, AOP, stratégies définies dans la configuration projet, remplacement de classes spécifiques) répondent bien au même besoin : introduire du code spécifique dans une classe existante en ciblant au mieux la partie réécrite pour avoir le moins de problème possible lors des mises à jour. En version 4.0 ces différentes mécaniques parallèles seront donc supprimées au profit d'une seule et unique mécanique reprenant le meilleur de chacune.

Elle s'appellera "injection de classe" et pourra d'une manière générale être appliquée à n'importe quelle classe (à part une poignée qui sont chargées trop tôt dans l'exécution pour pouvoir en profiter). Elle reposera sur le concept de réécriture de classe (comme la mécanique de remplacement de classe) et sera déclarée dans la section injection sur le modèle de l'injection de service actuel.

Reste à couvrir un point que permettait l'AOP : injecter une classe avec du code provenant de plusieurs sources. Conceptuellement, rien ne l'empêche. C'est uniquement l'implémentation mise en œuvre dans les versions précédentes qui ne le permettait pas.

En version 4.0, on pourra donc déclarer des "injections chainées" en gros au lieu d'indiquer une seule classe de remplacement, on pourra en indiquer plusieurs séparées par des virgules. La mécanique de remplacement sera appliquée successivement dans l'ordre indiqué.

Par exemple, si une classe A est déclarée injectée par trois classes B, C et D (qui doivent toujours toutes étendre A), on obtiendra la chaine d'extension suivante : A_injected0 (anciennement A), A_injected1 (anciennement B) qui étend A_injected0, A_injected2 (anciennement C) qui étend A_injected1 et enfin A (anciennement D) qui étend A_injected2. De cette manière plusieurs modules peuvent proposer leur injections spécifiques sans exclure les autres.

Ceci évitera au développeur de se retrouver à devoir choisir entre une multitude de mécaniques proches avec chacune ses limitations pour n'utiliser toujours qu'une seule et même mécanique simple à comprendre et à mettre en œuvre.

Conclusion

Voilà, j'ai fini mon petit tour de l'historique des méthodes de surcharge. Je me suis concentré sur ce qui est lié directement aux classes PHP, omettant volontairement tout ce qui a trait aux templates, styles et fichiers de configuration des modules (déjà comme ça ça donne un sacré pavé).

Comme je le disais en introduction, je ne suis volontairement pas entré dans les détails de mises en œuvre, pour cela référez-vous à la documentation de Change ou posez vos questions sur le forum.

Comme je l'ai dit également, la dernière partie concernant la version 4.0 ne reflète que l'état actuel des développement et pourrait éventuellement évoluer encore un peu d'ici la sortie. Mais globalement les grandes lignes devraient rester valables. On notera du coup qu'il n'est pas conseillé d'abuser de l'AOP dans un projet actuel car cela nécessitera beaucoup de boulot de migration vers la version 4.0 au contraire d'un remplacement de classe qui reste le plus proche de ce qu'on aura au final (c'est d'ailleurs pour cela que l'AOP n'a pas été documentée dans le wiki).

Voilà, félicitations à ceux qui liront mon pavé jusqu'au bout... à supposer qu'il y en ait :euh:


Quelques trucs sur UNIX/Linux #3

Supprimer un grand nombre de fichiers

Quand on a un très grand nombre de fichiers dans un dossier, un simple rm xxx* ne fonctionne pas forcément. J'ai eu le cas notamment avec des sessions PHP qui ne s'effaçaient pas correctement et qui du coup s'accumulaient en masse.

Une solution qui fonctionne est de passer par find :

find . -name 'sess_*' | xargs rm

(source)

Supprimer les .svn d'un répertoire

SVN place un dossier .svn dans chaque dossier d'un projet (contrairement à GIT qui se contente d'un unique dossier .git à la racine).

Pour supprimer l'ensemble des fichiers .svn d'une arborescence, on peut passer par cette commande qui utilise encore une fois find :

find -type d -a \( -iregex ".*/.svn" \) -exec rm -rf {} \;

Exclure des dossiers d'un grep

Pour exclure des dossiers d'un grep, on utilise l'option --exclude-dir. Par exemple pour exclure le dossier .git lors d'une recherche dans des fichiers :

rgrep 'toto' modules/ framework/ --exclude-dir=.git

Du coup pour mes recherches dans le code de Change, je me suis fait cet alias dans mon .bashrc :

alias crep='rgrep --exclude-dir=.git'

On peut également passer par l'option --exclude.

(source)

Exclure des dossiers d'un tar

Les archives de mon serveur devenant un peu trop grosses, j'ai dû mettre en place quelques exclusions de dossiers (par exemple ne plus sauvegarder les logs, caches et médias formatés de mes sites sous Change).

Pour cela je suis passé par l'option -X (ou --exclude-from=) de tar qui permet d'indiquer un fichier contenant les motifs à exclure.

Exemple :

tar cvf archive.tar /home/change -X exclude.txt

Avec un fichier exclude.txt contenant :

/home/change/repository
/home/change/instances/*/log
/home/change/instances/*/cache
/home/change/instances/*/build
/home/change/instances/*/media/formatted
/home/change/instances/*/www
/home/change/instances/*/repository

Attention les motifs sont comparés aux chemins tels que vous les avez décrits. Dans mon exemple, j'ai un chemin absolu pour le dossier à archiver, il faut dont des motifs qui matchent ce chemin. Si j'avais donné un chemin relatif, j'aurais dû revoir mes motifs d'exclusion en conséquence.

On peut également utiliser --exclude en indiquant directement un motif à exclure. Mais c'est moins pratique quand on a toute une liste d'exclusions.


Plus on enlève de code, mieux ça marche

Encore récemment, dans le cadre du chiffrage d'une migration d'un projet vers la dernière version d'RBS Change (CMS / e-commerce dont j'ai déjà parlé plusieurs fois ici), l'un des développeurs disait en parlant de certaines fonctionnalités développées sur le projet en spécifique et qui entre temps ont été implémentées dans le produit que maintenant que le code spécifique était écrit, ça ne coûtait pas cher de le garder tel quel plutôt que de prendre le temps de le remplacer par des appels au code du produit.

À part si un besoin spécifique n'est pas compatible avec le code du produit, je suis intimement convaincu que c'est faux. Et ce pour un certain nombre de raisons.

Le point le plus évident pour moi c'est le coût en maintenance. S'il y a bien une chose que j'ai appris en travaillant sur un logiciel qui fait plusieurs centaines de milliers de lignes de code, c'est que plus on a de code, plus c'est couteux à maintenir. D'une part parce que chaque ligne ajoutée peut comporter des bugs ou s'avérer incompatible avec d'autres parties du logiciel et d'autre part parce que plus il y a de code, plus il est difficile de retrouver la source d'un problème. C'est d'autant plus vrai si l'équipe chargée du projet change. Quand le développeur est le même pendant des années, il peut connaitre assez bien son code pour s'y retrouver parmi les implémentations parallèles (et encore... que celui qui ne s'est jamais senti perdu en se replongeant dans du code qu'il avait écrit rien qu'un an plus tôt lève la main) mais un nouvel arrivant sur le projet mettra beaucoup plus de temps à s'y retrouver s'il doit apprendre à connaitre les implémentations parallèles en plus du produit lui-même.

On en arrive du coup à un second point connexe au précédent : l'évolutivité. Naïvement on se dit que vu que la fonctionnalité est codée spécifiquement, on peut faire ce qu'on veut avec et donc on est bien plus libre qu'en utilisant une fonctionnalité native du produit sur laquelle on n'aura pas autant la main. Ce n'est pas faux. Mais cela implique de se couper en partie des évolutions du produit et de devoir tout faire soi-même de son côté. De plus, se pose le même problème qu'évoqué précédemment où tout nouvel arrivant devra oublier ce qu'il sait déjà du produit pour apprendre ce que fait le projet.

Ensuite on a les coûts d'interface utilisateur et d'apprentissage. De deux choses l'une : soit on laisse les deux implémentations parallèles accessibles dans l'interface et là c'est l'utilisateur qui se sentira perdu, ne sachant quoi choisir (ce qui implique du coût de formation et de réparation de ce que l'utilisateur aura mal fait), soit on doit masquer de l'interface les éléments relatifs à l'implémentation standard pour les remplacer par l'implémentation spécifique (ce qui implique un coût initial plus un coût à chaque mise à jour pour revalider les choses et les réadapter si besoin).

Après on peut avoir du mal à jeter le produit de nombreuses heures de développement. C'est normal mais pour un développeur c'est une chose à laquelle il faut s'habituer. Un logiciel qui n'évolue pas, à part s'il est extrêmement ciblé sur un besoin très pointu qui n'évolue pas du tout (chose très rare), c'est un logiciel mort. Un logiciel vivant évolue continuellement au gré des nouveaux besoins, des nouvelles possibilités et des nouvelles idées. Seulement on ne peut pas se contenter d'empiler de nouvelles choses dessus, sous peine de voir l'ensemble s'effondrer sous sa complexité, de devenir inmaintenable et incompréhensible au nouvel arrivant.

Des choses qui semblaient - et potentiellement étaient réellement - pertinentes à un moment donné ne le seront plus un an plus tard parce que le besoin aura évolué ou simplement parce qu'à force d'y greffer des verrues, on aboutit à un ensemble qui ne ressemble plus à rien. Il ne faut donc pas hésiter à remplacer des fois des pans entiers du logiciel pour repartir sur des bases plus saines. Qui elles-mêmes dégénèreront plus ou moins rapidement (selon la qualité de l’implémentation et la vitesse à laquelle les besoins liés évoluent) avant d'être à leur tour remplacées à nouveau.

Ce principe vaut aussi bien au niveau macroscopique (une API entière finit par devenir trop lourde et doit être remplacée) qu'au niveau microscopique (une méthode donnée peut souvent être réécrite en cinq fois moins de code parce qu'elle prévoyait des cas qui n'existent plus ou bien parce qu'à force de refactoring, le code se répète trop). Il faut toutefois prendre garde à ne pas sauter trop vite aux conclusions et tout réécrire continuellement, sans quoi d'une part on n'avance plus et d'autre part, à aller trop vite, on passe à côté de subtilités qui ne sautent pas aux yeux sans examen approfondi (pour ce dernier point, des tests unitaires ou autres peuvent aider à éviter les régressions, encore faut-il avoir le temps ou simplement prendre le temps de les mettre en place).

Comme souvent il s'agit de trouver un juste milieu entre tout réécrire et conserver à tout prix l'existant. Mais quand la réécriture consiste à utiliser quelque chose qui existe par ailleurs et qu'on n'aura donc pas à maintenir soi-même, je pense qu'il n'y a pas à hésiter : si fonctionnellement c'est compatible, ça vaut le coup de jeter le spécifique pour utiliser du natif.

Voilà voilà, félicitations si vous avez tout lu jusqu'ici et n'hésitez pas à réagir dans les commentaires si vous avez quelque chose à ajouter sur le sujet ou des objections à formuler :)


Récupérer sa bibliothèque iTunes

Je ne m'étais jamais penché sur comment fonctionnait iTunes ou ce qu'il faudrait que je sauvegarde... Au départ il ne contenait rien d'important du coup c'était sans importance (en gros exclusivement mes CD encodés qui sont également sur mon iPhone). Puis j'ai fini par m'abonner à quelques podcasts et du coup sans trop m'en rendre compte, il en est venu à contenir des choses qu'il aurait fallu sauvegarder.

Je savais que je risquais de perdre des choses en cas de crash disque ou en cas de gros plantage du système (virus ou autre). Mais je ne soupçonnais pas qu'un vidage de la batterie et une extinction violente (et sans préavis) du mac pourrait suffire à perdre toutes les données de bibliothèque. Pas les fichiers de son, hein, juste métadonnées (notes des morceaux, playlists, etc) et surtout - dans mon cas la donnée la plus importante - les abonnements de podcasts.

Ce avec quoi je n'étais pas non plus très familier c'est un gros fichier fourre-tout qui s'il est endommagé n'est pas réparable. J'ai l'habitude de bases de données MySQL où quand on a un problème, 99,9% du temps une réparation de la table fautive suffit (au pire on perd quelques entrées mais l'essentiel est toujours là). J'ai l'habitude aussi de fichiers XML ou autre qu'on peut éditer au besoin pour corriger les erreurs. Mais là, rien de tout ça. Juste un gros fichier qui peut que vraquer complètement si l'ordinateur s'éteint alors qu'on est juste en train d'écouter de la musique.

En cherchant un peu sur le net, différents mot-clés, je suis tombé principalement sur des solutions du type "efface tout et réimporte ta musique". La belle affaire. La partie que tu perds dans un cas comme ça est justement celle qui m'importe.

Une autre piste proposée par Apple consiste à récupérer ses podcasts dans le fichier "iTunes Music Library.xml". J'ai bien trouvé le dit fichier mais manque de bol, quand iTunes a trouvé que son fichier de bibliothèque n'était pas valide il en a d'office créé un nouveau et... s'est empressé d'écraser le fichier XML susnommé qui contient une déclinaison human readable des infos de podcasts (entre autres mais c'est ça qui m'intéresse). C'est ballot.

En fouillant dans le dossier iTunes je suis tombé par hasard sur un dossier "Previous iTunes Libraries" contenant... des copies de sauvegarde du fichier de bibliothèque. Je ne sais pas quand il les fait effectivement mais je soupçonne que ce soit lors des mises à jour d'iTunes (celles que j'ai sont réparties tous les 2 à 5 mois)... Quoique, pas seulement puisqu'après que je lui aie refilé la dernière sauvegarde et relancé iTunes, il s'est empressé d'en faire une nouvelle. Super. C'est AVANT le plantage que ça servait à quelque chose, hein. Là c'est un peu tard.

Donc j'ai pu repartir avec une version d'il y a trois mois. C'est toujours ça. J'ai plus qu'à réimporter ce qui manque et ré-abonner les podcasts récents.

Alors bon, je vais maintenant automatiser une sauvegarde plus fréquente de ce fichier (et du XML aussi tant qu'à faire) pour pas me faire avoir une nouvelle fois mais je pensais pas que c'était aussi peu robuste...


Quelques petites BD #1

Au collège et lycée, je dessinais beaucoup, puis j'ai progressivement arrêté. Ces dernières années, ça me reprend une ou deux fois par an mais comme la plupart du temps je n'arrive pas à faire ce que je veux, ça ne dure pas.

Depuis quelques semaines, j'ai commencé à faire quelques petites BD allant de quatre cases à une page présentant de petits gags inspirées pour la plupart (parfois assez librement) d'anecdotes de bureau.

Pour une fois, ça semble tenir un peu. Principalement, je pense, parce que le dessin n'est ici qu'un support pour un gag et pas une fin en soi. Le fait que je trouve la plupart assez ratés techniquement n'est donc pas un si gros problème que d'habitude.

Je les publie au fur et à mesure sur Twitter ou encore deviantART mais je vais aussi les récapituler ici.

Voici donc la première fournée :

BD #1 - 09/04/2012 BD #2 - 21/04/2012 BD #3 - 30/04/2012 BD #4 - 12/05/2012
Images sous licence CC-BY

Concernant la dernière, quelques précisions pour mieux comprendre :

  • Boulder Dash est une célèbre série de jeux vidéos démarrée en 1983 (presque aussi vieille que moi :peur2:), probablement le jeu sur lequel j'ai passé le plus d'heures dans ma vie (même si Guild Wars se défend bien aussi), les captures d'écran sont des captures d'écran du jeu
  • RBS Change, j'en ai déjà parlé ici plusieurs fois, c'est le CMS / solutions e-commerce auquel je contribue au boulot
  • Magento est une solution e-commerce concurrente (l'une des plus connues)
  • Les deux logos dans la dernière case sont les logos des deux solutions

Côté réalisation je fais mes brouillons sur papier (parce que ça reste encore le support où j'arrive le mieux à quelque chose), puis je les scanne je mets au propre, mets en page et colorise via Photoshop Elements et tablette graphique Bamboo de Wacom (ça faisait depuis septembre dernier que je l'avais, il était temps de la rentabiliser un peu ^^).

Là ce sont les premières, donc je tâtonne un peu sur la technique mais j'espère m'améliorer un peu au fil du temps et notamment arriver à les faire un peu plus vite (là même celles qui comporte peu d'illustrations différentes me prennent facilement trois heures... du coup ça bride un peu les choses).


Visionner des fichiers ODT sur iPhone

Comme j'en avais marre (d'oublier) de réimprimer ma liste de livres/mangas/DVD/etc. à chaque fois que je la complète, je me disais que ce serait pratique de pouvoir la stocker directement sur mon iPhone. Sauf que forcément sur un système aussi fermé et cloisonné, ce n'est pas immédiat :

  • on ne peut pas juste le copier dessus vu que l'iPhone ne permet pas de transférer des données autrement que via iTunes (et là je saurais même pas où aller pour transférer un tel fichier)
  • le format ODT n'étant pas ©®Apple Inc.™, forcément l'iPhone ne le lit pas

Du coup il faut forcément passer par une appli dédiée avec toute la lourdeur que ça implique, en particulier la phase de recherche pour en trouver une... qui marche.

Premier essai : Drop Box

Sans trop d'illusions, j'ai tout de même vérifié que l'application Drop Box que j'ai installée il y a quelques temps n'en serait pas capable. La réponse est non. En même temps elle ne prétend pas le faire, on lui pardonne donc volontiers :o

J'ai donc fait une rapide recherche sur Google, pas grand chose d'intéressant à part "Cherchez « ODT » sur l'AppStore". C'est donc ce que j'ai fait.

Second essai : OliveODT

L'appli s'installe et démarre (c'est déjà un on début). On uploade un fichier dessus en activant un serveur web embarqué qui permet d'envoyer des fichiers dessus depuis n'importe quelle machine connectée en réseau local. Ok, ça fonctionne.

Enfin on affiche les fichiers... et là ça se corse : le premier que j'essaie d'ouvrir (et contenant de grands tableaux) bloque l'application que je suis obligé de relancer deux fois pour pouvoir tenter le second qui lui accepte de s'afficher mais qui ressemble à rien (taille du texte aléatoire, respect des sauts de ligne une fois sur deux... bref illisible).

Donc exit OliveODT. Je ne tente pas OliveOfficeBasic du même auteur parce que je doute que le rendu soit meilleur.

Candidat suivant.

Troisième essai : ConfettiDisk

Là aussi ça s'installe et se démarre sans problème, par contre on arrive sur un écran de login : il s'agit en fait d'un système en mode cloud, avec 100Mo de stockage gratuit. Pourquoi pas. C'est peu dans l'absolu mais totalement suffisant pour les 150Ko de listes que je veux pouvoir visionner.

Une fois le compte créé, l'upload depuis un ordinateur, ça se passe via une interface dans le navigateur. L'interface est simple, intuitive et fonctionne. Bon début.

Je me logue donc sur mon iPhone, synchronise les fichier (qui sont bien stockés sur le téléphone jusqu'à la prochaine synchro, pas besoin d'être connecté). Et là l'affichage est bon : conforme à ce que j'ai dans OpenOffice, le format A4 n'est pas idéal sur un écran de la taille de l'iPhone donc il faut zoomer mais ça fonctionne et c'est lisible.

Seul petit bémol : apparemment leur système de cloud ne permet pas de partage avec des amis (or ces listes contiennent aussi bien mes possessions que celles de mes frère et sœur, pouvoir partager les choses directement par là plutôt que par mail comme on le fait actuellement aurait pu être pratique).

Dans le doute, j'ai jeté un œil au dernier gratuit de la recherche "ODT" sur l'AppStore mais il semble apparemment se synchroniser via iTunes, ce qui ne m'arrange pas (je ne l'ai installé que sur mon Macbook, pas sur mon PC principal).

Je retiens donc ConfettiDisk comme répondant le mieux à ma problématique parmi les solutions gratuites.


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.


Firefox : à la recherche de la fonctionnalité perdue

Depuis que Firefox est passé à son nouveau cycle de release tellement rapide que t'as pas le temps de mettre à jour avant que la version suivante soit sortie, les nouveautés sont en général plus que minimes (en six semaines, forcément on fait pas grand chose).

Par contre, dans le cadre de la grande opération d’hystérie collective généralisée sur le thème du "moins j'ai de boutons dans mon interface, mieux c'est", on voit régulièrement disparaitre des choses jugées trop peu utilisées pour rester visibles par défaut (en gros tout ce que Chrome n'a pas dans son interface).

Autant je comprends bien la volonté d'élaguer les fonctionnalités les moins utiles d'un logiciel (on fait la même chose sur Change régulièrement), autant le fait que ce soit systématiquement à la suite des changements initiés par Chrome me convient nettement moins. Fut un temps où Firefox se voulait une alternative innovante à Internet Explorer mais maintenant on a plus le sentiment qu'il se transforme en l'ombre de Chrome et ça c'est franchement dommage.

Quoiqu'il en soit, quand on est un utilisateur un peu plus avancé que l'internaute lambda pour qui Internet se résume à Youtube et Facebook, ben ces fonctionnalités il arrive qu'on s'en serve. Pas forcément toutes les cinq minutes, mais ça arrive. Et donc on peut avoir envie de les garder. La plupart du temps c'est possible, soit par configuration, soit via une extension...

Petit tour (non exhaustif) de ce qui a disparu des écrans l'année passée et de la manière d'y remédier :

  • L'icône de flux RSS dans la barre d'adresse : même s'il est effectivement rare d'utiliser Firefox comme agrégateur de flux, elle était tout de même bien pratique pour les détecter. Il suffit alors de regarder toujours au même endroit pour trouver l'adresse d'un flux plutôt que de fouiller la page pour trouver l'icône. C'est d'autant plus pratique quand le site propose plusieurs flux distincts (par exemple sur un blog : les articles et les commentaires), car souvent tous ne sont pas accessibles facilement dans la page.

    Solution : celle-ci se réactive par simple configuration puisqu'au lieu d'apparaitre dans la barre d'adresse, elle est disponible en tant que bouton que l'on peut insérer dans n'importe quelle barre d'outils en faisant clic droit/personnaliser.

  • Détection des moteurs dans la barre de recherche (via Open Search) : c'est une fonctionnalité très secondaire, j'en conviens mais ça m'a déjà servi. Sauf qu'elle a disparu avec Firefox 4...

    Solution : installer l'extension Open Search Notification.

  • Fond blanc lorsqu'on affiche une image seule : depuis Firefox 11, lorsqu'on affiche une image hors du contexte d'une page, celle-ci est centrée (ça ce n'est pas particulièrement gênant) et sur fond très sombre, ce qui n'est pas forcément pratique quand on visualise une image transparente. Et ceci n'est pas modifiable par configuration.

    Solution : passer par l'extension Old default Image Style. Elle a de plus l'avantage de ne pas nécessiter de redémarrage et d'être configurable en ce qui concerne la couleur de fond et le centrage de l'image (ce qui accessoirement peut être utile pour tester une image transparente sur plusieurs fonds).

  • Marquer tous les onglets : ajouter l'ensemble des onglets ouverts aux marque-pages peut servir dans pas mal de cas... comme par exemple quand on n'a pas le temps de chercher pourquoi il n'enregistre plus les onglets à la fermeture. L'option était avant présente dans le menu "Marque-pages" (logique).

    Solution : en fait la fonctionnalité n'a pas disparu, c'est juste qu'elle n'est maintenant présente que lors d'un clic droit sur un onglet et plus dans le menu "Marque-pages".

  • Affichage du protocole dans la barre d'adresse : depuis Firefox 7, le protocole disparait de la barre d'adresse (comme d'hab, on copie Chrome, hein). C'est pourtant agréable je trouve en tant qu'utilisateur expérimenté de savoir précisément ce qu'on fait (ça me rappelle l'idée stupide de Microsoft d'avoir masqué par défaut les extension de fichiers : la première chose que je fais en installant un Windows c'est de les réactiver, parce que notamment quand j'ouvre une pièce jointe, j'aime bien savoir ce que j'ouvre !). Puis accessoirement quand copier/coller un domaine sans son protocole est impossible avec cette barre. Je ne suis décidément pas fan de cette habitude de vouloir sur-simplifier les choses au point que l'utilisateur perd de vue que même si c'est simple, il faut faire attention à ce qu'on fait.

    Solution : dans la barre d'adresse, entrer about:config. Firefox vous met alors en garde mais comme vous savez ce que vous faites, cliquez sur « Je ferai attention, promis ! ». En haut de la liste, dans le champ précédé de la mention "Rechercher :", saisir browser.urlbar.trimURLs. Il ne reste alors plus qu'une entrée dans la liste, double-cliquez dessus pour passer sa valeur de "true" à "false".

Voilà voilà, vu comme les choses évoluent, nul doute que cet article aura une suite un jour !


Je ne saurais trop vous conseiller de... réfléchir avant de parler

Il arrive qu'on emploie des expressions ou des tournures de phrases sans y penser, juste parce que dans notre entourage il y a des gens qui l'utilisent. On les absorbe avec les temps et elles finissent par sortir naturellement, sans que pour autant on les comprenne forcément. Mais parfois c'est bien de réfléchir un peu avant de les utiliser, histoire de ne pas raconter n'importe quoi.

Un exemple que j'ai relevé au moins quatre ou cinq fois ces deux derniers mois, en particulier dans les quelques podcats que je suis, c'est la tournure de phrase "Je ne saurais trop vous conseiller de [...]", qui devient trop souvent "Je ne saurais que trop vous conseiller de [...]". Quelques fois ça fait sourire, notamment dans la bouche d’Éric Dussart (à 3'27) vu le thème de ses chroniques, mais le reste du temps on se dit juste qu'il serait bon de réfléchir un peu avant de parler.

Parce que bon, il ne faut pas beaucoup plus de 2,6 secondes de réflexion pour se rendre compte que rajouter un "que" ici, ça inverse juste le sens : dans un cas on explique qu'on pourra le conseiller tant qu'on veut ce ne sera jamais assez, dans l'autre on explique qu'en fait le simple fait de l'évoquer c'est déjà trop.


Un nom plus court pour la commande change.php

Cet article n'intéressera pas forcément grand monde. En même temps, le but premier de ce blog était bien à l'origine de me servir de bloc-notes pour garder une trace de certaines choses que j'ai eu plus ou moins de mal à trouver et/ou retenir, pas forcément à intéresser un public très large.

Donc là on parle de développement avec RBS Change et plus particulièrement de la commande change.php. Avant la version 3.5 il fallait installer une commande globale sur le serveur pour pouvoir l'exécuter, à partir de la version 3.5 cette commande globale n'est non seulement plus nécessaire mais carrément gênante (parce qu'on passe dans du code qui n'est plus compatible, même si on ne s'en rend pas compte tout de suite).

Mais toujours est-il que taper php framework/bin/change.php c'est vite lourd. Une solution possible est de passer par un alias de commande dans le .bashrc :

alias change.php="php framework/bin/change.php"

Mais par moment ça marche moyen. Surtout si la commande globale de la version 3.0.x est installée, parce que des fois on se retrouve à exécuter quand même la commande globale alors qu'on voulait exécuter celle contenu dans le framework.

Une meilleure solution est de passer par une commande personnalisée. Sur Ubuntu Serveur inclut par défaut (cf le fichier .profile) le dossier ~/bin dans le PATH. Ainsi il suffit de définir un fichier ~/bin/change.php (sans oublier de lui donner les droits d'exécution : chmod +x ./change.php) contenant :

#!/usr/bin/env php
<?php
if (file_exists("framework/bin/includes")) {
  $script = "framework/bin/change.php";
}
else
{
  $script = "/usr/local/bin/change.php";
}
if (file_exists($script))
{
  array_shift($argv);
  $script = $script . ' ' . implode(' ', $argv);
  system($script);
}
else
{
  echo "Could not find $script";
}

Personnellement j'ajoute aussi un lien symbolique pour pouvoir exécuter simplement c au lieu de change.php :

ln -nfs change.php c

Voilà voilà exécuter juste c plutôt que php framework/bin/change.php c'est quand même nettement plus agréable, surtout quand on développe et qu'on tape la commande toutes les 5 minutes :o


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 Windows #1

Clavier azerty reconnu comme un querty

Par moment, Windows commence à se comporter bizarrement : on écrit de q au lieu des a, les mots de passe ne sont plus reconnus, tout ça... Rien d'ésotérique là dedans, la reconnaissance du clavier a juste switché en qwerty...

Comment ça s'est produit ? En général c'est que vous avez sans vous en rendre compte, tapé le raccourci clavier alt (gauche) + shift (gauche). Je ne sais pas pourquoi un tel raccourci est défini dans Windows mais c'est comme ça. Donc pour revenir à la normale, il suffit d'utiliser ce raccourci.

Pour que cela ne se reproduise plus, il est aussi possible de désinstaller le clavier anglais au niveau de Windows.

Sous XP, ça se trouve dans le panneau de configuration : Démarrer > Paramètre > Panneau de configuration > Options régionales et linguistiques > langues > détails cliquer sur anglais et supprimer (au besoin on peut le rajouter quand on veut avec le même menu).

Sous Seven c'est presque pareil mais pas tout à fait : Démarrer > Panneau de configuration > Horloges, langue et région > Modifier les claviers et les autres méthodes d'entrée > Modifier les claviers... > sélectionner l'anglais et supprimer.

Faire une capture d'écran de la fenêtre courante sous Windows XP/Seven

Sur mac on a pas mal de possibilités pour faire une capture d'écran mais ce que je ne savais pas c'est que sur Windows aussi on dispose de plusieurs raccourcis différents.

En effet, si toute seule la bien connue touche Impr écran capture tout l'écran, combinée avec la touche alt elle ne capture que la fenêtre courante. Ça peut éviter de re-découper la capture après, donc c'est bon à savoir ^^

Sinon Seven est également livré avec un outil de capture d'écran où on sélectionne la zone à capturer. Il est accessible depuis le menu démarrer > Tous les programmes > Accessoires > Outil Capture.

Oui j'essaie de purger un peu les brouillons qui trainent... celui là avait quand même presque trois ans ^^


Se débarasser d'un raccourci clavier indésirable sous Windows Seven...

L'autre jour j'ai fini par comprendre pourquoi de temps à autre je me retrouvais avec dans mon presse papier non pas ce que je croyais avoir mais plutôt le texte que je venais de supprimer. En fait ça vient d'un raccourci clavier standard de Windows que je ne connaissais pas (bien qu'apparemment existe depuis toujours) : shift + suppr. Ça m'arrive quand je fais des sélections au clavier pour les supprimer sans relâcher assez vite le shift avant de supprimer (des fois l'une des mains va légèrement plus vite que l'autre).

Bon personnellement ctrl + x me suffit bien pour couper, pas besoin d'un deuxième, j'ai donc cherché comment le désactiver. Déjà en natif on oublie apparemment. Il faut impérativement passer par un logiciel tiers.

Chose rare, le premier sur lequel je suis tombé faisait l'affaire (le plus souvent on commence par installer un truc inutilisable avant de tomber enfin sur le bon) : AutoHotkey. Bon à la base il est destiné à rajouter des raccourcis clavier mais ça marche aussi pour en écraser un existant.

La procédure à suivre est donc :

  1. installer AutoHotkey
  2. le lancer et cliquer sur "oui" quand il propose d'écrire un script
  3. y placer le code suivant qui mappe le raccourci shift + delete sur l'action supprimer : +Delete::Send {Delete}
  4. relancer le logiciel

Et voilà, ça marche, apu le raccourci à la con \o/

Pour aller jusqu'au bout de la chose, reste plus qu'à le lancer automatiquement au démarrage de Windows. Pour cela le plus simple reste de copier le raccourci dans le dossier "Démarrage" du menu "Démarrer".


Quelques trucs sur UNIX/Linux #2

Ré-écriture d'URL avec Apache

Les règles de ré-écriture peuvent se placer soit dans le .htaccess, soit dans httpd.conf (ou dans les fichiers dédiés à chaque vhost). Il y a une subtile différence de syntaxe entre les deux cas : dans le cas du httpd.conf, URL relatives présentes dans les expressions rationnelles doivent être précédées d'un / et pas dans le cas du .htaccess.

Exemples :

.htaccess

RewriteCond %{HTTP_HOST} www.example.com
RewriteRule ^toto.html$ http://example.com/youpi.html$1 [R=301,L]

httpd.conf

RewriteCond %{HTTP_HOST} www.example.com
RewriteRule ^/toto.html$ http://example.com/youpi.tml$1 [R=301,L]

Résultat suivant dans la recherche dans l'historique de commandes

Lorsqu'on recherche dans l'historique via ctrl+r, taper à nouveau ctrl+r permet de passer au résultat suivant.

Déterminer la taille d'un dossier

Pour déterminer la taille d'un dossier on peut utiliser du, notamment avec les options :

  • h (human readable) : pour avoir un résultat lisible (type "1,7G") plutôt qu'un nombre d'octets
  • s : pour ne pas détailler tous les sous-dossiers

Exemples :

> du -hs .
2,7G     .
> du -hs ./*
8,0K     ./changeRepo.sh
2,7G     ./instances