ZeGuigui
Le Weblog de ZeGuigui - Technique

Archives "Technique"

14 novembre 2008

Gérer sa médiathèque avec Movable Type v. 4

Spirou et Fantasio, l'intégrale tome 1 : Les débuts d'un dessinateur

Vous avez probablement constaté sur ce site un changement d'envergure : l'ajout d'une médiathèque. Celle-ci est gérée de façon quasi automatique grâce à Movable Type et quelques plugins astucieux. 

Quelques prérequis

Déjà il vous faut movable type... j'utilise la version 4.1 et donc tout ce que je vais écrire là se rapporte à cette version. Cependant cette idée de gérer ma médiathèque avec movable type est née à partir d'une expérience similaire datant de 2002. Idée qu'il a fallut adapter pour suivre les évolutions de Movable Type notamment. On va supposer ici que Movable Type est installé correctement et que vous savez vous en servir. Le but n'est pas ici de faire un mode d'emploi exhaustif de ce logiciel (!).

Ensuite il vous faut une clé d'API Amazon. Là il faut causer un peu anglais pour pouvoir l'obtenir sur le site dédié.

Il vous faudra aussi le greffon Media Manager pour Movable Type 4. Il est pour l'instant disponible uniquement en version beta. Il inclue MTAmazon dont on aura besoin pour afficher les pages du site. Il est disponible sur le site de majordojo.

 

Une idée simple

L'idée simple de départ consiste à dire que la médiathèque est gérée comme un sideblog. Autrement dit vous avez votre blog principal et vous utilisez les fonctionnalités de movable type pour générer des pages dans un coin.

Au sein de ce sideblog, chaque article de la médiathèque est représenté par une note. Là vous avez deux options : soit vous utilisez la fonctionnalité de gestion des assets de movable type avec Media manager : création de l'asset, création de la note, etc. soit vous optez pour quelque chose d'un peu plus sioux. J'ai bien entendu choisi cette seconde option bien que la première fonctionne parfaitement (pour preuve l'illustration de cet article).

Pour bien gérer une médiathèque il faut des catégories. J'ai choisi de créer une catégorie par type de média (CD, DVD, livre, jeux vidéo, etc.) puis pour chaque catégorie de décliner en sous-catégories. Cela permet de ne pas tout mélanger. On peut même envisager de créer une catégorie Wish Liste et lorsqu'on a acheté (ou qu'on vous a offert ?!) un élément de cette liste il ne reste plus qu'à en changer la catégorie !

Ensuite chaque média est représenté par une note. J'utilise le titre de la note comme nom du média (c'est original non ?!). Le corps de la note me permet d'ajouter un commentaire ou une description si je me sens une âme de commentateur. Ensuite je stocke l'ASIN dans le champs Mots clés. A noter que la version 4.2 de Movable Type (sortie depuis que j'ai commencé à écrire ce billet !) permet de gérer des champs personnalisés (fonctionnalité jusqu'alors payante de la version pro) et on pourrait donc mettre l'ASIN dans un champ à part... mais bon c'est juste un détail !

Qu'est-ce donc que cet ASIN ? C'est l'identifiant d'un objet chez Amazon. C'est LA clé d'entrée de l'API Amazon qui va permettre d'afficher une image du produit, d'en récupérer des informations comme le nom de l'auteur voir une description plus complète. Grâce à cet ASIN et en bidouillant les templates de Movable Type on va pouvoir afficher une belle médiathèque !

Et comme je suis amateur de bandes dessinées il me faut gérer des collections (par exemple la série des Tintin) et quel champ mieux adapté à cela que celui des tags (les fonctions de recherche par tag étant intégrée dans MT).

Mise en route

Première chose à faire : créer le sideblog dans Movable Type. En quelques clics hop c'est fait. Ensuite on installe Media Manager et on va le configurer aussi bien dans les propriétés du système que dans les propriétés du sideblog (notamment pour la locale qui permet de choisir le magasin Amazon dans lequel on fait les recherches pour la création des assets).

Enfin il ne reste plus qu'à créer sa première note avec son livre préféré... pour cela se rendre sur Amazon, rechercher le livre en question. Dans la description on trouve l'ASIN. S'il n'y est pas il suffit de prendre l'ISBN.

On clique sur "créer > note", on rentre le titre, on choisi la catégorie, on met l'ASIN dans les mots clés et éventuellement la collection en tag (attention : pas de virgule qui est le séparateur de tags !).

Une fois cela fait on peut aller voir le site publié... bon il manque l'illustration et la présentation n'est pas franchement très "médiathèque". Mais on va remédier à cela grâce à MTAmazon !

Paramétrage de Movable Type

On va déjà commencer par gérer l'accès aux médias. Pour l'instant si vous avez fait tout comme je vous l'ai dit vous devriez avoir un truc qui ressemble à ça :

mediamanager1.jpg

L'accès au livre se fait par une adresse qui inclut la date de la note... Si ce choix est optimal pour un blog, pour une médiathèque il est plus intéressant d'avoir un accès par catégorie et sous catégorie. On va donc aller changer celà dans Movable Type. Pour cela il faut aller dans Design / gabarits et choisir les "gabarits d'archives".

Cliquer sur "Note" et modifier la table de correspondance des archives pour choisir un chemin de type "categorie/sous-categorie/nomdebase-note.html" (ou les variantes avec le caractère souligné, comme vous préférez). Enregistrez.

On va aussi en profiter pour supprimer des archives inutiles (et accélérer ainsi la publication) : cliquez sur "Liste des notes" et dans la table de correspondance ne conservez que la ligne "par catégories". Republiez votre site et admirez les changements d'adresses (!).

Oui bon c'est gentil tout ça mais on a pas encore les jaquettes... patience, ça arrive !!!

Bon alors l'idée c'est d'utiliser MTAmazon qui est fourni avec Media Manager. Pour cela on va aller modifier quelques gabarits standards. Le premier à modifier c'est "Résumé de la note" (c'est un gabarit de type module).

Grâce à MT 4 on peut maintenant utiliser des variables. Il est donc facile de mémoriser le mot clé (qui contient l'ASIN du produit) dans une variable et d'utiliser celle-ci en paramètre à la fonction MTAmazonItemLookup. En gros ça donne ça :


	<$MTEntryKeywords setvar="asin"$>
	<MTAmazonItemLookup ItemId="$asin">
		<div id="entry-<$MTEntryID$>" class="entry-asset asset hentry">
			<a rel="bookmark" href="<$MTEntryPermalink$>"><img src="<$MTAmazonCustomImageURL size="small" shadow="right"$>" alt="<$MTAmazonTitle encode_html="1"$>" title="<$MTAmazonTitle encode_html="1"$>" /></a><br />
			<a rel="bookmark" href="<$MTEntryPermalink$>"><small><$MTEntryTitle$></small></a>
		</div>
	</MTAmazonItemLookup>
</mt:ifnonempty>

Au passage on remarquera que j'ai supprimé pas mal de choses :) Avec plusieurs livres le résultat devrait être semblable à celui-ci (après sauvegarde et republication).

mediamanager2.jpg

On a bien nos jaquettes par contre la mise en page laisse à désirer : chaque titre prends une ligne à lui tout seul ! On va donc aller modifier la feuille de style pour améliorer tout cela. Retour aux gabarits index et direction la feuille de style (styles.css).

Par défaut c'est du minimaliste : on inclut les feuilles de style du thème courant... on va ajouter nos propres déclarations pour forcer les choses :

/* Default Layout:  */
@import url(<$MTStaticWebPath$>themes-base/blog.css);
@import url(<$MTStaticWebPath$>themes/minimalist-red/screen.css);

#alpha .asset {
width : 200px;
height : 220px;
line-height : 1.0em;
float : left;
vertical-align : bottom;
text-align : center;
padding : 0;
margin : 0.25em;
clear : none;
}

.content-nav {
clear : both;
}

En gros on lui explique que l'on désire avoir des éléments carrés de 200 pixels de largeur qui "floatent" les uns à côté des autres.

Déjà ça commence à ressembler à quelque chose. Il ne nous reste plus qu'à modifier ce que l'on voit lorsqu'on clique sur un livre (ou autre média)... mais ça je vous le laisse en exercice (façon simple de mettre en ligne ce billet qui trainait en mode "brouillon" depuis le mois de juin dernier !

A noter que j'ai fait une petite modification dans la librairie MTAmazon. En effet par défaut l'URL de l'image est pour la version américaine (.01. dans l'URL, de tête) alors que la majorité de mes livres, CD, etc. sont français. J'ai donc modifié le code pour prendre en compte cette différence (je détaillerai dès que j'aurai un peu de temps... si vous êtes sages !).

Publié par zeguigui à 08:00 dans Technique | Commentaires (3) | TrackBack

20 janvier 2008

ViaMichelin 3.x et Palm T|X...

Depuis quelques temps déjà, je suis l'heureux propriétaire d'un palm T|X. Sur mon ancien palm j'avais installé ViaMichelin 3 et là j'ai voulu installer ce dernier sur mon palm "dernière génération". Murphy aidant c'était le début de mes problèmes.

L'installation sur le PC du logiciel s'est bien déroulée. Je vous passe le temps interminable nécessité pour la synchro de la carte en bluetooth lors de la hotsync (la prochaine fois je prends le mode avancé et je copie la carte sur la SD via mon lecteur de cartes, ça ira plus vite !). Je lance et là... erreur ! En gros la mémoire du palm a besoin d'être optimisée et ça se fait par un soft reset. Pas de soucis, ViaMichelin va se relancer tout seul. Sauf qu'à la fin du soft reset pouf j'ai à nouveau ce message d'erreur et ça boucle.

Pour arrêter la boucle des softs resets le plus simple c'est de faire un warm reset (bouton à l'arrière + flèche vers le haut maintenue) puis un nouveau soft reset (bouton à l'arrière seul). Mais ça ne résout pas le problème de lancement de ViaMichelin.

Alors comment faire ?

Ce qui différencie le palm T|X du T3 (mon précédent PDA) c'est :

  • un processeur moins puissant (!)
  • la présence du Wifi
  • une mémoire non volatile

C'est la mémoire non volatile qui ici est importante. Sur le T|X et les palms de même technologie la RAM a été remplacée par de la mémoire non volatile comme celle qu'on trouve par exemple dans une clé USB. Avantage : si on oublie de recharger son palm on ne perds plus les données.

Maintenant quel est le problème avec ViaMichelin ? Quand le logiciel se lance il vérifie s'il a assez de mémoire. Si le T|X il vérifie une partie "spéciale" de la mémoire allouée à cela. Quand il n'y a pas assez de mémoire soft reset. Sur les anciens palms ça permet de vider la mémoire mal désallouée quand un logiciel sur termine.

Mais sur le T|X ce qui se passe lors d'un soft reset c'est bien un vidage mémoire puis tous les logiciels installés en mémoire sont notifiés qu'il vient d'y avoir un soft reset. Ca leur permet de faire du ménage ou ce genre de choses. Problème : le fait que les logiciels soient notifiés remplie la mémoire et quand ViaMichelin se relance on recommence à zéro !

La solution, car elle existe, consiste à installer un logiciel qui permette de récupérer la mémoire libre. On pourra utiliser pour cela Memory Info (voir par ici). C'est en anglais mais en gros il faut utiliser dans le menu les options flush. Vous verrez que ça libère la mémoire et après, ô miracle, ViaMichelin fonctionne parfaitement !

A la décharge de ViaMichelin notons tout de même que les Palms utilisant cette technologie n'existaient pas au moment où la version 3.x est sortie. La version actuelle du logiciel étant la 6 ou 7 ce comportement bizarre est probablement résolu depuis !

Publié par zeguigui à 19:50 dans Technique | Commentaires (2) | TrackBack

3 octobre 2007

Dotclear 1.2.7 et les binettes... !

Pour tous ceux qui sont passés à dotclear 1.2.7 et qui ne retrouvent plus leur gestionnaire de binettes (qui plus est le site de l'auteur a semble-t'il fermé) j'ai fait une rapide conversion du plugin pour cette nouvelle version de dotclear. Attention la modification automatique du fichier poster.php change avec le passage en 1.2.7 et donc ça ne fonctionne qu'avec cette version !

Et comme ça ne suffisait pas (et surtout que je l'utilise pas mal...) j'ai aussi adapté pour la version 1.2.7 de dotclear le plugin filemanager. Là encore ce sont les modifications de sécurité de cette nouvelle version qui plantait le plugin (lors de la modification de fichiers... le reste fonctionnait encore !)

Et comme je suis gentil (et que la license GPL du plugin l'impose ;-)) je vous livre le tout ci-dessous :

Mise à jour : nouvelle version 0.4 qui corrige les instructions de modification manuelle de poster.php et qui permet d'utiliser le greffon même quand on a renommer son dossier ecrire (si vous ne comprenez pas ce que ça veut dire, c'est pas grave... c'est juste que c'est mieux comme ça !).

Mise à jour : la version 0.5 corrige la modification d'un smiley qui n'était pas compatible avec dotclear 1.2.7 (precondition failed).

Mise à jour : la version 0.6 affiche un avertissement si l'affichage des smilies est désactivé dans la configuration de dotclear.

Publié par zeguigui à 21:14 dans Technique | Commentaires (20) | TrackBack

3 septembre 2007

Géolocalisation de ses photos

Géolocalisation Le nouveau buzz à la mode c'est la géolocalisation des photos. Alors forcément il fallait que moi aussi je m'essaye à ce petit jeu.

Tout a commencé avec la démocratisation des GPS autonomes. Il devient facile de se procurer un petit GPS bluetooth (par exemple) pour le brancher sur son PDA. Souvent couplé à un logiciel de cartographie / navigation cela permet de retrouver son chemin facilement (et quand on connait mon sens de l'orientation on se doute que j'ai fait rapidement l'acquisition de ce petit gadget technologique)...

Par la suite les usages ont évolués. De l'itinéraire on est passé aux POI (POint d'Intérêt) qui permettent, entre autre, d'éviter les radars automatiques ou du moins de signaler leur présence. Avec la réduction des coûts liée à un développement du marché les "puces GPS" se retrouvent partout. Il y a maintenant des smartphones (PDA qui font également téléphone) qui intègrent une telle puce.

Et puis un jour Monsieur Sony il a eu une bonne idée et il a sorti une sorte de clé USB qui intègre un récepteur GPS et qui enregistre sa position. Avec un petit logiciel ça permet de dire où la photo a été prise. L'astuce consiste dans l'exploitation des méta données EXIF présentent dans chaque photo (dont la date/heure de prise de vue).

Il faut aussi noter que les EXIF prévoient la possibilité d'avoir des coordonnées GPS. En effet certains appareils photos haut de gamme permettent (voire intègrent !) de brancher un GPS via un simple câble de liaison (c'est le cas de mon D200 par exemple). Malheureusement un tel câble ne fonctionne qu'avec certains GPS et surtout pas en bluetooth.

Oui mais voilà moi mon GPS il est bluetooth, branché avec mon palm et je me suis dit qu'il devrait être possible de faire quelque chose qui ne soit pas trop une usine à gaz. Et en cherchant bien on finit par trouver ! Trouver des logiciels commerciaux mais aussi un logiciel libre : gps2photo qui utilise ExifTool.

La première chose à noter c'est que la bestiole est écrite en perl. Perl c'est bien sur linux mais sous windows c'est déjà moins à la portée du premier venu. En plus il faut au moins un perl 5.8.8 alors à vos mises à jour ! Je ne vais cependant pas détailler l'usage de perl ici, ce n'est pas le but...

Première constat : il faut un fichier trace dans le format standard GPX... sur le palm on peut obtenir un tel fichier avec cotoGPS ou encore Cetus GPS. Pour cette fois j'ai utilisé cotoGPS (dispo en français qui plus est). Il faut connecter le GPS au Palm puis aller sur la page "Piste". On crée une nouvelle piste en cliquant sur "Pistes" et on oublie pas de cliquer sur "utilise". Après il suffit de faire "Début" pour commencer l'enregistrement.

A partir de là il faut aller se balader et prendre des photos. Pour faire dans l'original je suis aller faire un tour dans le jardin du Luxembourg (Paris VI). Une fois les photos prises on récupère la piste (dans le répertoire backup après une synchro de son palm), on prend jcotoDT (utilitaire desktop de cotoGPS) et on converti en GPX (et en KMZ pour le voir sous google earth).

Ma ballade

On remarque au passage que mon GPS n'était pas très précis à l'allumage car il me voit dans la cour d'honneur du Sénat alors que j'étais devant l'entrée...

Fin de la ballade, on décharge les photos sur son ordinateur. J'ai mis dans un dossier jpeg et un dossier raw mes images (je photographie dans les deux formats simultanément). Dans la racine j'ai mis le fichier gpx. J'ouvre ma ligne de commande et je tape :

perl gpsPhoto.pl
--dir=jpg
--gpsfile=track.gpx
--timeoffset=-7200
--copydate
--credit="Guillaume Lapierre"
--city="Paris"
--sublocation="Jardin du Luxembourg"
--country="France"
--copyright="(c) 2007 Guillaume Lapierre"

En fait tout est sur une seule ligne de commande. Le point important c'est le paramètre timeoffset. C'est là que la photo qui illustre cet article est importante. Elle permet de voir le décalage entre le GPS et l'heure stockée dans les exifs. Mon appareil étant bien réglé l'heure affichée à l'écran et l'heure dans les exif correspondent (même heure/minute/seconde). Mais attention : cotoGPS affiche en UTC+2 (options / configuration) afin de correctement synchroniser l'heure du palm et l'heure du GPS. Par contre le fichier stocke bien les dates et heures en UTC. Il y a donc un décalage de 2h soit 7200 secondes.

A partir de là tout fonctionne tout seul (du moins si tout est bien installé !) et on obtient des photos avec des EXIF et des IPTC qui contiennent les coordonnées GPS. Magique :)

Avec l'option --kmz=toto.mkz on peut même créer un fichier google earth qui contient ses photos (pas fait).

Prochaine opération : ajouter le module Google Earth pour Gallery 2 et le thème associé afin de vous faire profiter de tout ça sur une carte !  

Publié par zeguigui à 13:38 dans Technique | Commentaires (1) | TrackBack

14 juin 2006

Un plugin Movable Type pour identifier un auteur de commentaire

Vous aurez peut-être remarqué que les commentaires que je poste sur mon blog apparaissent dans une autre couleur. Si vous vous demandez comment j'ai fait ça sous movable-type et bien c'est grâce à un plugin maison.

Le but de ce plugin est de permettre d'identifier un auteur de commentaire à partir de son adresse email. A quoi ça sert ? Par exemple à ajouter une classe dans le code HTML afin de changer la couleur et ainsi reconnaître un auteur du blog.

Ce plugin est en fait ma première réalisation technique pour Movable Type. Jusqu'à présent j'avais surtout bidouillé les modèles mais je n'avais pas trouvé de solution miracle pour changer la couleur de mes commentaires, sauf à passer par un intermédiaire PHP (ce qui est réaliste pour mon site puisqu'il utilise PHP).

Ce plugin ajoute une nouvelle balise conditionnelle <MTIfCommenterEmailIs> qui accepte deux paramètres : email et trusted. email est un paramètre obligatoire qui correspond à l'adresse email à reconnaître. Si trusted="1" alors non seulement l'adresse email doit correspondre mais en plus le commentaire doit avoir été posté dans un mode authentifié (typekey par exemple). On peut bien entendu utilisé la balise <MTElse> dans sa page pour ajouter du code en cas de commentaire non reconnu.

package MT::Plugin::ZeGuigui;

use strict;
use warnings;

use vars qw( $VERSION );
$VERSION = 1.0;

eval { use MT::Plugin };
unless ($@) {
    my $static_path = MT::ConfigMgr->instance->StaticWebPath;
    my $about = {
             key         => __PACKAGE__,
             name        => 'mt-zeguigui',
             description => 'Small plugins by ZeGuigui',
             author_name => 'ZeGuigui',
             author_link => 'http://www.zeguigui.com/',
             plugin_link => 'http://www.zeguigui.com/technique.php',
             version     => $VERSION
    };
    MT->add_plugin(MT::Plugin->new($about));
}

MT::Template::Context->add_conditional_tag("IfCommenterEmailIs" => \&checkCommenterEmail);

sub checkCommenterEmail {
	my ($ctx, $args) = @_;
	
	# Check context
	my $comment = $ctx->stash('comment')
		or return $ctx->error("Tag called without a comment in context");

	# Check arguments
	if (! $args->{email}) {
		return $ctx->error("An 'email' argument must be provided");
	}

	my $email   = $args->{email};
	my $trusted = $args->{trusted};

	return (($email eq $comment->email) && ($trusted ? $comment->commenter_id : 1));
}

1;

Comme on peut le voir rien de bien extraordinaire dans le code source... sauf peut-être l'utilisation de commenter_id de l'objet $comment qui n'est pas documenté sur le site de SixApart. Probablement un oubli mais en lisant le source de Movable Type on trouve rapidement l'existence de ce paramètre qui simplifie grandement la reconnaissance d'un commentaire authentifié !

Et maintenant pour nos amis anglophones une description nettement plus succinte et rapide de ce plugin.

This plugin adds a new MovableType conditionnal tag named MTIfCommenterEmailIs. It accepts two arguments: email (mandatory) and trusted. The aim is to recognise a commenter by its email address. If trusted is set to 1 then the comment must also be from an authentified source (typekey for example). You can use MTElse to add some code when the comment is not from the expected source.

En pratique voici comment vous pouvez utiliser ce tag (small example) :

<MTComments>
    <MTIfCommenterEmailIs email="authoremail@someisp.com" trusted="1">
         <div class="comment blogauthor" id="comment-<$MTCommentID$>">
       <MTElse>
         <div class="comment" id="comment-<$MTCommentID$>">
       </MTElse>
    </MTIfCommenterEmailIs>
[...]
</MTComments>

Si vous avez des questions, commentaires, améliorations à suggérer, n'hésitez pas à utiliser les commentaires !

Publié par zeguigui à 21:25 dans Technique | Commentaires (10) | TrackBack

23 mai 2006

Flux RSS, la totale sur ZeGuigui !

RSS

Il était une fois un blogueur qui était bien tranquille avec son site perso. Il utilisait blogger.com pour mettre à jour ses pages pour éviter de les modifier à la main. Et puis, le temps faisant, d'autres personnes dans son entourage ont commencé à écrire dans des blogs. Sa maman, ses amis, sa frangine... à tel point que tout le monde écrit sur son blog et met des commentaires dans ceux des autres (voire parfois utilise des rétroliens).

Donc ce blogueur il commence à mettre tous les blogs dans ses signets. Et il surf régulièrement d'un site à l'autre pour voir s'il y a des nouveautés... pas très pratique. Heureusement Zorro est arrivé... heu... non... les flux RSS. Un flux RSS c'est quoi donc ? C'est un petit fichier qui présent sur un site web (pas forcément un blog) annonce la liste des derniers billets parus sur le site et ce dans un format bien déterminé. Avec un logiciel adapté qui charge ce petit fichier régulièrement vous êtes immédiatement informé quand un nouveau message arrive sur l'un de vos sites préférés. On appelle ce type de logiciel un "agrégateur de flux RSS".

En pratique on distingue différents types de flux RSS. On parle de RSS 0.96, RSS 1.0, RSS 2.0 et Atom. Le but de ces fichiers est strictement le même. Ce qui change c'est la façon dont c'est écrit dedans et les fonctionnalités proposées par chaque format. Atom est le plus récent de ces formats.

Alors hop le blogueur commence à faire une collection de flux dans son logiciel préféré, Thunderbird par exemple. Le blogueur est content et ça lui permet de mettre un petit commentaire sur le blog de chacun lorsque c'est nécessaire.

Et puis arrive une soirée où le blogueur croise un autre blogueur qui lui dit "t'as vu, sur le blog de Fabrice, Coralie a répondu à mon commentaire..." Heu... oui, certes... peut-être. Et c'est là que le blogueur se retrouve à nouveau à visiter les blogs individuellement et, pire, à devoir re-lire les commentaires des notes sur lesquelles il est intervenu. Bref il faut pouvoir suivre les commentaires.

Oui mais quels commentaires ? Autant sur le blog de ses amis le blogueur veut pouvoir suivre tous les commentaires (des fois que) autant sur un blog technique trouvé en surfant il peut-être intéressant de suivre les commentaires d'un seul billet. De même sur certains blogs il peut-être intéressant de suivre tous les billets autant sur d'autres il peut-être utile de ne suivre qu'une catégorie.

Et là en matière de blogs les logiciels sont inégaux. Je vais parler ici uniquement des 3 logiciels que je connais à peu près.

  • MovableType (le logiciel que j'utilise) ne propose, par défaut, qu'un flux pour les billets du site. Impossible de suivre les commentaires ou une catégorie. Cependant MovableType permet d'ajouter des modèles personnalisés et de combler ces petits manques
  • DotClear, un produit français fort sympatique, propose un flux pour les billets et un flux pour les commentaires. C'est un bon début. Un système de plugins permet probablement d'étendre ces possibilités mais je n'ai pas vérifié :-)
  • Serendipity propose quant à lui un flux global des billets, un flux par catégorie et un flux global pour les commentaires. Il permet également, lorsqu'on pose un commentaire sur un billet, de s'abonner par email pour être prévenu des mises à jour des commentaires.

Comme on peut le voir c'est assez varié comme approche. Le flux RSS pour les commentaires d'une note je ne me souviens plus sur quelle plateforme je l'ai vu mais je sais que certains le mettent en place. Et ce billet a achevé de me convaincre :-)

Prenant mon courage à deux mains et armé de mon ami Google je décide d'ajouter des flux RSS dans tous les sens sur mon site. Pour cela je surf un peu et je tombe rapidement sur un article expliquant comment ajouter un flux RSS pour les commentaires sur Movable Type. Et pour les catégories j'ai trouvé un autre tutorial.

Je reprend donc l'habillage proposé pour les commentaires et je le modifie à ma sauce. Je recherche ensuite comment faire de même pour Atom mais je ne trouve pas grand chose. Au passage j'applique le tutoriel d'Anders Jacobsen et roule. Mes premiers essais sont assez concluants. Pour les  flux de RSS pour les notes j'adapte tout bêtement le tutoriel d'Anders : je reprend l'habillage global des commentaires pour créer une archive par note. Et roule.

Etape ultime j'ai modifié mes index et mes fichiers d'archives pour ajouter les différents flux RSS/Atom dans les pages sur lesquelles c'est pertinent.

Pour résumer vous trouverez donc sur mon site :

  • Un flux pour l'ensemble des billets. Ce flux est proposé aux formats RSS 1.0, RSS 2.0 et Atom. On trouve le lien directement sur la page d'accueil du site.
  • Un flux pour l'ensemble des commentaires du site (RSS 2.0 et Atom), directement sur la page d'accueil du site.
  • Un flux pour chaque catégorie. Pour accéder au lien il suffit de cliquer sur la catégorie en question sur la page d'accueil. Le lien se trouve en bas de la page d'archive de la catégorie.
  • Le lien vers le flux des commentaires d'une note n'est accessible que depuis la note en question. Sur la même page les flux des catégories du billet sont déclarées dans l'entête pour que votre navigateur puisse éventuellement les détecter.

Et, cerise sur le gâteau, pour ceux qui navigent avec un butineur qui reconnait les flux déclarés dans l'entête de la page (Opéra, Firefox, le futur IE 7) une petite icône devrait apparaître qui présente les flux disponibles.

Voici les modèles que j'ai utilisé pour mon site :

Flux RSS des commentaires (type index, fichier commentaires.xml) :

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>
<rss version="2.0">
  <channel>
    <title><$MTBlogName remove_html="1" encode_xml="1"$> - Commentaires</title>
    <link><$MTBlogURL$></link>
    <description>Derniers commentaires sur <$MTBlogName remove_html="1" encode_xml="1"$></description>
    <language>fr-fr</language>
    <lastBuildDate><MTComments lastn="1"><$MTCommentDate language="en" format="%a, %d %b %Y %H:%M:%S"$> <$MTBlogTimezone no_colon="1"$></MTComments></lastBuildDate>
    <generator>http://www.movabletype.org/?v=<$MTVersion$></generator>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
<MTComments lastn="20" sort_order="descend">
    <item>
      <title><MTCommentEntry><$MTEntryTitle remove_html="1" encode_xml="1"$></MTCommentEntry> - <$MTCommentAuthor encode_xml="1"$></title>
      <link><MTCommentEntry><$MTEntryPermalink$></MTCommentEntry>#comment-<$MTCommentID$></link>
      <description><$MTCommentBody encode_html="1"$> <p>- <$MTCommentAuthorLink show_email="0" encode_html="1"$></p></description>
      <guid isPermaLink="false">comment<$MTCommentID pad="1"$>@<$MTBlogURL$></guid>
      <pubDate><$MTCommentDate language="en" format="%a, %d %b %Y %H:%M:%S"$> <$MTBlogTimezone no_colon="1"$></pubDate>
    </item>
</MTComments>
  </channel>
</rss>

Flux Atom des commentaires (type index, fichier commentaires.atom.xml) :

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title><$MTBlogName remove_html="1" encode_xml="1"$> - Commentaires</title>
    <id>tag:<$MTBlogHost exclude_port="1" encode_xml="1"$>,<$MTDate format="%Y"$>:<$MTBlogRelativeURL encode_xml="1"$>/comments/<$MTBlogID$></id>
    <updated><MTComments lastn="1"><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></MTComments></updated>
    <link rel="alternate" type="text/html" href="<$MTBlogURL encode_xml="1"$>" />
    <link rel="self" type="application/atom+xml" href="<$MTBlogURL$>commentaires.atom.xml" />
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type <$MTVersion$></generator>

<MTComments lastn="20" sort_order="descend">
<entry>
    <title><MTCommentEntry><$MTEntryTitle remove_html="1" encode_xml="1"$></MTCommentEntry></title>
    <link rel="alternate" type="text/html" href="<MTCommentEntry><$MTEntryPermalink$></MTCommentEntry>#comment-<$MTCommentID$>" />
    <id><MTCommentEntry><$MTEntryAtomID$>.<$MTCommentID$></MTCommentEntry></id>
    <published><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></published>
    <updated><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></updated>
    <summary type="html"><$MTCommentBody remove_html="1" encode_xml="1" $></summary>
    <author>
        <name><$MTCommentAuthor encode_xml="1" $></name>
    </author>
</entry>
</MTComments>

</feed>

Flux RSS 2.0 des catégories (type archive catégorie, fichier %c/index.rss.xml) :

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>
<rss version="2.0">
<channel>
<title><$MTBlogName remove_html="1" encode_xml="1"$> - <$MTArchiveTitle remove_html="1" encode_xml="1" $></title>
<link><$MTArchiveLink$></link>
<description><$MTArchiveTitle remove_html="1" encode_xml="1"$></description>
<copyright>Copyright <$MTDate format="%Y"$></copyright>
<lastBuildDate><MTEntries lastn="1"><$MTEntryDate format_name="rfc822"$></MTEntries></lastBuildDate>
<generator>http://www.movabletype.org/?v=<$MTVersion$></generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs> 

<MTEntries lastn="15">
<item>
<title><$MTEntryTitle remove_html="1" encode_xml="1"$></title>
<description><$MTEntryBody encode_xml="1"$></description>
<link><$MTEntryPermalink encode_xml="1"$></link>
<guid><$MTEntryPermalink encode_xml="1"$></guid>
<category><$MTEntryCategory remove_html="1" encode_xml="1"$></category>
<pubDate><$MTEntryDate format_name="rfc822"$></pubDate>
</item>
</MTEntries>

</channel>
</rss>

Flux Atom des catégories (type archive catégorie, fichier %c/index.atom.xml) :

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title><$MTBlogName remove_html="1" encode_xml="1"$></title>
    <link rel="alternate" type="text/html" href="<$MTArchiveLink encode_xml="1"$>" />
    <link rel="self" type="application/atom+xml" href="<$MTArchiveLink encode_xml="1"$>atom.xml.php" />
   <id>tag:<$MTBlogHost exclude_port="1" encode_xml="1"$>,<$MTDate format="%Y"$>:<$MTBlogRelativeURL encode_xml="1"$><$MTBlogID$>/C/<$MTCategoryID$></id>
    <link rel="service.post" type="application/atom+xml" href="<$MTCGIPath$><$MTAtomScript$>/weblog/blog_id=<$MTBlogID$>" title="<$MTBlogName encode_html="1"$>" />
    <updated><MTEntries lastn="1"><$MTEntryModifiedDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></MTEntries></updated>
    <MTIfNonEmpty tag="MTArchiveTitle"><subtitle><$MTArchiveTitle remove_html="1" encode_xml="1"$></subtitle></MTIfNonEmpty>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type <$MTVersion$></generator>
<MTEntries lastn="15">
<entry>
    <title><$MTEntryTitle remove_html="1" encode_xml="1"$></title>
    <link rel="alternate" type="text/html" href="<$MTEntryPermalink encode_xml="1"$>" />
    <link rel="service.edit" type="application/atom+xml" href="<$MTCGIPath$><$MTAtomScript$>/weblog/blog_id=<$MTBlogID$>/entry_id=<$MTEntryID$>" title="<$MTEntryTitle encode_html="1"$>" />
    <id><$MTEntryAtomID$></id>
    
    <published><$MTEntryDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></published>
    <updated><$MTEntryModifiedDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></updated>
    
    <summary type="html"><$MTEntryExcerpt remove_html="1" encode_xml="1"$></summary>
    <author>
        <name><$MTEntryAuthorDisplayName encode_xml="1"$></name>
        <MTIfNonEmpty tag="MTEntryAuthorURL"><uri><$MTEntryAuthorURL encode_xml="1"$></uri></MTIfNonEmpty>
    </author>
    <MTEntryCategories>
        <category term="<$MTCategoryLabel encode_xml="1"$>" />
    </MTEntryCategories>
    <content type="html" xml:lang="<$MTBlogLanguage ietf="1"$>" xml:base="<$MTBlogURL encode_xml="1"$>">
        <$MTEntryBody encode_xml="1"$>
        <$MTEntryMore encode_xml="1"$>
    </content>
</entry>
</MTEntries>
</feed>

Flux RSS 2.0 des commentaires d'une note (type archive de note, fichier %y/%m/commentaires_%F.rss.xml) :

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>
<rss version="2.0">
  <channel>
    <title><$MTArchiveTitle remove_html="1" encode_xml="1"$> - Commentaires</title>
    <link><$MTArchiveLink encode_xml="1"$></link>
    <description>Derniers commentaires de la note <$MTArchiveTitle remove_html="1" encode_xml="1"$></description>
    <language>fr-fr</language>
    <lastBuildDate><MTComments lastn="1"><$MTCommentDate language="en" format="%a, %d %b %Y %H:%M:%S"$> <$MTBlogTimezone no_colon="1"$></MTComments></lastBuildDate>
    <generator>http://www.movabletype.org/?v=<$MTVersion$></generator>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
<MTComments sort_order="descend">
    <item>
      <title><MTCommentEntry><$MTEntryTitle remove_html="1" encode_xml="1"$></MTCommentEntry> - <$MTCommentAuthor encode_xml="1"$></title>
      <link><MTCommentEntry><$MTEntryPermalink$></MTCommentEntry>#comment-<$MTCommentID$></link>
      <description><$MTCommentBody encode_html="1"$> <p>- <$MTCommentAuthorLink show_email="0" encode_html="1"$></p></description>
      <guid isPermaLink="false">comment<$MTCommentID pad="1"$>@<$MTBlogURL$></guid>
      <pubDate><$MTCommentDate language="en" format="%a, %d %b %Y %H:%M:%S"$> <$MTBlogTimezone no_colon="1"$></pubDate>
    </item>
</MTComments>
  </channel>
</rss>

Flux Atom des commentaires d'une note (type archive de note, fichier %y/%m/commentaires_%F.atom.xml) :

<?xml version="1.0" encoding="<$MTPublishCharset$>"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title><$MTArchiveTitle remove_html="1" encode_xml="1"$> - Commentaires</title>
    <id><$MTEntryAtomID$>/comments</id>
    <updated><MTComments lastn="1"><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></MTComments></updated>
    <link rel="alternate" type="text/html" href="<$MTArchiveLink encode_xml="1"$>" />
    <link rel="self" type="application/atom+xml" href="<$MTBlogArchiveURL encode_xml="1"$><$MTFileTemplate format="%y/%m/commentaires_%F.atom.xml" encode_xml="1"$>" />
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type <$MTVersion$></generator>

<MTComments lastn="20" sort_order="descend">
<entry>
    <title><MTCommentEntry><$MTEntryTitle remove_html="1" encode_xml="1"$></MTCommentEntry></title>
    <link rel="alternate" type="text/html" href="<MTCommentEntry><$MTEntryPermalink$></MTCommentEntry>#comment-<$MTCommentID$>" />
    <id><MTCommentEntry><$MTEntryAtomID$>.<$MTCommentID$></MTCommentEntry></id>
    <published><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></published>
    <updated><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%SZ"$></updated>
    <summary type="html"><$MTCommentBody remove_html="1" encode_xml="1" $></summary>
    <author>
        <name><$MTCommentAuthor encode_xml="1" $></name>
    </author>
</entry>
</MTComments>

</feed>

Déclaration des flux dans les archives individuelles

[...]
<link rel="stylesheet" href="<$MTBlogURL$>styles-site.css" type="text/css" />
<link rel="alternate" type="application/rss+xml" title="Billets (RSS 1.0)" href="<$MTBlogURL$>index.rdf.php" />
<link rel="alternate" type="application/rss+xml" title="Billets (RSS 2.0)" href="<$MTBlogURL$>index.xml.php" />
<link rel="alternate" type="application/atom+xml" title="Billets (Atom)" href="<$MTBlogURL$>atom.xml.php" />
<MTEntryCategories>
<link rel="alternate" type="application/rss+xml" title="<$MTCategoryLabel encode_xml="1"$> (RSS 2.0)" href="<$MTCategoryArchiveLink$>index.rss.php" />
<link rel="alternate" type="application/rss+xml" title="<$MTCategoryLabel encode_xml="1"$> (Atom)" href="<$MTCategoryArchiveLink$>index.atom.php" />
</MTEntryCategories>
<MTIfCommentsActive>
<link rel="alternate" type="application/rss+xml" title="Commentaires (RSS 2.0)" href="<$MTBlogURL$>commentaires.xml" />
<link rel="alternate" type="application/atom+xml" title="Commentaires (Atom)" href="<$MTBlogURL$>commentaires.atom.xml" />
<link rel="alternate" type="application/atom+xml" title="Commentaires de la note au format Atom" href="<$MTBlogArchiveURL encode_xml="1"$><$MTFileTemplate format="%y/%m/commentaires_%F.atom.xml" encode_xml="1"$>" />
<link rel="alternate" type="application/rss+xml" title="Commentaires de la note au foramt RSS 2.0" href="<$MTBlogArchiveURL encode_xml="1"$><$MTFileTemplate format="%y/%m/commentaires_%F.rss.xml" encode_xml="1"$>" />
</MTIfCommentsActive>
[...]

Je vous laisse les autres fichiers d'archive ou d'index en exercice... mais le principe est globalement le même.

Publié par zeguigui à 13:04 dans Technique | Vie du site | Commentaires (4) | TrackBack

19 mai 2006

Calcul de la distance entre deux points "GPS"

La Terre vue depuis Apollo 17 (merci la NASA !)Pour celles et ceux qui voudraient connaître une méthode rapide pour calculer la distance à vol d'oiseau entre deux points dont on connait les coordonnées GPS voici comment faire. Attention, allergiques aux math s'abstenir :-)

On suppose ici, pour simplifier, que la terre est une sphère. Je sais, ce n'est pas exact et le relief peut également intervenir (c'est pour ça que j'ai écrit à vol d'oiseau !). On suppose aussi que l'on dispose des coordonnées GPS (lattitude et longitude) en degrés et non pas en degrés, minutes, secondes.

La première étape consiste à convertir nos degrés en radians. Ca c'est facile, il suffit de tout multiplier par 2?/360.

Ensuite la distance c'est, si le point source a comme coordonnées (sourceLat, sourceLong) et le point destination (destLat, destLong) :

d = R * (Pi/2 - ArcSin( sin(destLat) * sin(sourceLat) + cos(destLong - sourceLong) * cos(destLat) * cos(sourceLat)))

L'unité de d dépendra de l'unité prise pour le rayon. Si celui-ci est exprimé en km alors la distance sera elle aussi en kilomètres.

Pour R je prend généralement 6378km.

Publié par zeguigui à 11:55 dans Technique | Commentaires (20) | TrackBack

22 avril 2006

Mes extensions firefox préférées

Le but de ce billet est de lister les extensions Firefox que j'utilise le plus. Comme vous allez vite voir je ne suis pas pour surcharger l'animal et je vais donc à l'essentiel.
  • AdBlock. Celle-là je crois que tout le monde devrait l'avoir. C'est un filtre qui permet de réécrire les pages à la volées pour faire disparaître un maximum de pub. Ca ne gère pas forcément les intersticiels mais c'est assez efficace pour certaines pubs envahissantes ! Remplace efficacement le proxomitron.
  • Html Validator. Ca c'est mon côté développeur web qui resort ! Ca ajoute une chtite icône en bas de la page qui dit si la page est valide ou non ou s'il y a des avertissements. En pratique ça utilise HtmlTidy qui n'est pas parfait et signale parfois des erreurs là où le validateur du W3C n'en voit pas (l'inverse est parfois vrai mais nettement plus rare). Une extension pratique donc mais qui ne dispense pas de vérifier.
  • Live HTTP Header. Là encore c'est pour du développement (90%) et la curiosité (10%). Ca permet de voir tout ce qui s'est passé entre le navigateur et le serveur web. Ca remplace la fenêtre de log du proxomitron.
  • Tabbrowser Preferences permet d'améliorer la gestion des onglets de firefox (qui est déjà exemplaire !).
  • Fasterfox... Ca je l'ai installé mais je ne sais pas si ça accélère vraiment. Quoi qu'il en soit ça me dit en combien de temps une page a été chargée ce qui peut-être rigolo :-)
  • TabFx est une autre extension pour les onglets. Ca permet de rajouter un bouton de fermeture sur chaque onglet (plutôt que d'utiliser celui qui est tout à droite, qu'on peut conserver ou cacher).
  • Bookmarks Synchronizer (édition SiteBar). Celui là je ne peux plus m'en passer ! Ca permet d'avoir un fichier de signets quelque part sur internet et de le partager sur tous ses ordinateurs. Par exemple le navigateur à la maison, le navigateur au travail, etc. En plus ça génère des fichiers compatibles XBEL ce qui permet d'afficher le fichier sur mon site (oui, c'est la page liens !)
  • FxIF permet de visualiser les métadonnées EXIF d'une image en affichant les propriétés de cette dernière.
  • Web Developer ajoute une barre dédiée au développement web. Elle permet de torturer une page directement depuis le navigateur ou d'aller directement sur les sites de validation.
  • Performancing (que je suis en train d'utiliser à l'instant même) est un éditeur de blogs (en anglais). Ca permet d'ajouter des notes sur son blog sans pour autant devoir se connecter à l'interface de celui-ci. On verra à l'usage si je le conserve ou non mais quand on a plusieurs blogs ça évite de se souvenir des URL de chacun et de son login / pass. Bref à voir !
Si vous avez d'autres extensions que vous aimez bien, pensez à les indiquer dans les commentaires !

Publié par zeguigui à 01:01 dans Divers | Technique | Commentaires (3) | TrackBack

13 février 2006

Mise à jour pour Sébastien ;-)

Sébastien trouvant que le flux RSS manque d'actualité je crée une note rien que pour lui

Ce WE j'ai commencé à jouer avec le Google SiteMap. Cette technique permet d'aider les moteurs de recherche à indexer le contenu du site en listant les URL disponibles et en leur donnant une priorité (priorité pour le webmaster... pas forcément pour le moteur de recherche !).

Pour expérimenter cela j'ai créé un template pour Movable Type à partir de celui fourni par Anders Jacobsen (pour les entrées directes qui prennent en compte les commentaires) et celui de Cameron. Et ça fonctionne plutôt bien !

Malheureusement le blog n'est pas la seule source d'information de ce site et j'ai donc été obligé de modifier mon générateur de base DVD pour qu'il crée également un index sitemap. Coup de chance j'ai pu réutiliser la modification que j'avais faite pour gérer la liste des nouveautés (fonction demandée par Sébastien justement).

Restait également à créer un petit script pour générer un index SiteMap pour Gallery 2. Là je suis reparti de zéro et j'ai tapé directement dans la base de données... Le script que j'ai créé n'est vraiment pas optimisé mais ça suffira en attendant la prochaine version de Gallery 2 qui elle incluera directement un module export SiteMap (que j'ai bien tenté d'ajouté à mon installation à partir du CVS mais il faudrait que je monte en version le reste de l'install ce que je ne compte pas faire vu que ça fonctionne !).

Le script pour MovableType et le script Gallery2 sont disponibles dans la suite !

Habillage pour Movable Type

<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.google.com/schemas/sitemap/0.84">

<url>
<loc><$MTBlogURL encode_xml="1"$></loc>
<priority>1.0</priority>
<MTEntries lastn="1">
<lastmod><$MTEntryModifiedDate utc="1" format="%Y-%m-%dT%H:%M:%S+00:00"$></lastmod>
</MTEntries>
<changefreq>daily</changefreq>
</url>

<MTEntries lastn="10">
<url>
<loc><$MTEntryPermalink encode_xml="1"$></loc>
<lastmod><MTIfNonZero tag="MTEntryCommentCount"><MTComments lastn="1"><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%S+00:00"$></MTComments><MTElse><$MTEntryModifiedDate utc="1" format="%Y-%m-%dT%H:%M:%S+00:00"$></MTElse></MTIfNonZero>
</lastmod>
<priority>0.9</priority>
<changefreq>daily</changefreq>
</url>
</MTEntries>

<MTEntries lastn="10" offset="10">
<url>
<loc><$MTEntryPermalink encode_xml="1"$></loc>
<lastmod><MTIfNonZero tag="MTEntryCommentCount"><MTComments lastn="1"><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%S+00:00"$></MTComments><MTElse><$MTEntryModifiedDate utc="1" format="%Y-%m-%dT%H:%M:%S+00:00"$></MTElse></MTIfNonZero>
</lastmod>
<priority>0.8</priority>
<changefreq>daily</changefreq>
</url>
</MTEntries>

<MTEntries lastn="1000" offset="20">
<url>
<loc><$MTEntryPermalink encode_xml="1"$></loc>
<lastmod><MTIfNonZero tag="MTEntryCommentCount"><MTComments lastn="1"><$MTCommentDate utc="1" format="%Y-%m-%dT%H:%M:%S+00:00"$></MTComments><MTElse><$MTEntryModifiedDate utc="1" format="%Y-%m-%dT%H:%M:%S+00:00"$></MTElse></MTIfNonZero>
</lastmod>
<priority>0.5</priority>
<changefreq>monthly</changefreq>
</url>
</MTEntries>

<MTArchiveList archive_type="Category">
<url>
<loc><$MTArchiveLink encode_xml="1"$></loc>
<changefreq>weekly</changefreq>
<priority>0.6</priority>
</url>
</MTArchiveList>

<MTArchiveList archive_type="Monthly">
<url>
<loc><$MTArchiveLink encode_xml="1"$></loc>
<changefreq>monthly</changefreq>
<priority>0.4</priority>
</url>
</MTArchiveList>

</urlset>

Petit script pour Gallery2

<?
header("Content-Type: text/xml; charset=utf-8");
echo ('<?xml version="1.0" encoding="UTF-8"?>');
?>
<urlset xmlns="http://www.google.com/schemas/sitemap/0.84">
<?
// Sitemap for Gallery2 (waiting for CVS next release!)
// Scratch from database... brute force !

//
// HERE YOUR NEED TO SETUP AN ACCESS TO YOUR DATABASE
// YOUR WEBSITE AND OTHER STUFF...
//
// Note: this site relies on URL rewriting!
// You'll need to modify this script if table prefix is not 'g2_'
//
// Todo:
// - check if comments exist and use last comment date
// - use G2 module to handle URLs and configuration
//
define ('BdDServer', 'localhost');
define ('BdDLogin', 'gallery2');
define ('BdDPass', 'password');
define ('BdDDatabase', 'gallery2');
define ('rootURL', 'http://www.zeguigui.com/photos/v/');
define ('albFreq', 'daily');
define ('albPrio', '0.8');
define ('phoFreq', 'weekly');
define ('phoPrio', '0.5');

mysql_connect(BdDServer, BdDLogin, BdDPass) or die("Unable to connect: " . mysql_error());
mysql_select_db(BdDDatabase);

function getURL($id, $album) {
// Looks like i am a recursive function... oops!

$sql = 'select c.g_id, c.g_parentId, f.g_pathComponent '
. 'from g2_ChildEntity c, g2_FileSystemEntity f '
. 'where c.g_id = f.g_id and '
. "c.g_id = $id";

$s = mysql_query ($sql) or die ('Error in getURL: ' . mysql_error());
$r = mysql_fetch_array ($s);
mysql_free_result ($s);

if ($r['g_parentId'] == 0) {
return rootURL;
} else {
if ($album) {
return getURL($r['g_parentId'], true) . $r['g_pathComponent'] . '/';
} else {
return getURL($r['g_parentId'], true) . $r['g_pathComponent'] . '.html';
}
}
}

// Add albums to Google Index
$sql = 'SELECT i.g_id, i.g_title, i.g_originationTimestamp '
. 'FROM g2_Item i, g2_AlbumItem a '
. 'WHERE a.g_id = i.g_id';

$statement = mysql_query ($sql) or die ("Error: " . mysql_error());
while ($row = mysql_fetch_array($statement)) {
$url = getURL ($row['g_id'], true);
?>
<url>
<loc><?= $url ?></loc>
<lastmod><?= gmdate('Y-m-d', $row['g_originationTimestamp']) . 'T' .
gmdate('H:i', $row['g_originationTimestamp']) . 'Z'
?></lastmod>
<changefreq><?= albFreq ?></changefreq>
<priority><?= albPrio ?></priority>
</url>
<?
}
mysql_free_result ($statement);

// Photos
$sql = 'SELECT i.g_id, i.g_title, i.g_originationTimestamp '
. 'FROM g2_Item i, g2_PhotoItem p '
. 'WHERE p.g_id = i.g_id';

$statement = mysql_query ($sql) or die ("Erreur : " . mysql_error());
while ($row = mysql_fetch_array($statement)) {
$url = getURL ($row['g_id'], false);
?>
<url>
<loc><?= $url ?></loc>
<lastmod><?= gmdate('Y-m-d', $row['g_originationTimestamp']) . 'T' .
gmdate('H:i', $row['g_originationTimestamp']) . 'Z'
?></lastmod>
<changefreq><?= phoFreq ?></changefreq>
<priority><?= phoPrio ?></priority>
</url>
<?
}
mysql_free_result ($statement);

mysql_close();
?>
</urlset>

Note : je n'ai pas testé le script Gallery2 tel que... Je viens de le modifier pour le rendre un peu plus paramétrable et pour qu'il soit exploitable en dehors de mon installation personnelle. N'hésitez pas à me laisser un commentaire s'il y a un problème avec.

Mise à jour : vu le grand nombre de spams reçus en commentaire sur cette note, j'ai décidé de fermer les commentaires !

Publié par zeguigui à 13:10 dans Technique | Vie du site

21 juin 2005

Comment formater une partition de plus de 32Go en FAT32 !?

J'ai récemment fait l'acquisition d'un disque dur externe qui propose la fonction "OTG". Cette fonction permet de copier le contenu d'un périphérique USB (comme un appareil photo ou une clé USB) directement sans passer par un PC. Pour un fan de photo comme moi c'est assez pratique lorsqu'on part en vacances...

Le seul soucis c'est que cette fonction OTG ne fonctionne QUE si le disque dur est formatté en FAT32. Cela semble assez logique puisque le NTFS est bien plus compliqué à gérer...

Me voici donc à vouloir formater le disque dur de 40Go en FAT32... Or windows XP ne permet pas de formater les partitions de plus de 32Go en FAT32 pour des raisons de taille de cluster qui sont trop importantes à partir de 32Go. J'ai essayé la ligne de commande mais après avoir testé tous les secteurs du disque celle-ci dit que le formatage n'aura pas lieu (dommage !).

Les autres solutions trouvées sur le net était de passer par Partition Magic (mais payant et je ne voulais pas l'acheter rien que pour ça), Ranish Partition Manager (gratuit lui !) ou encore de booter sur le CD d'installation de Windows XP qui n'a pas cette limite... oui mais le disque dur est en USB et Ranish Partition Manager comme le CD de démarrage demandent de rebooter le PC et donc on ne voit plus le disque dur externe.

J'étais résigné à booter sur une Knoopix (distribution linux qui n'a pas besoin d'être installée) quand je suis tombé sur l'utilitaire mkdosfs (qui vient de linux justement) mais compilé pour windows. Téléchargement, décompression de l'archive, une ligne de commande plus tard le disque dur était formaté en FAT32 !

Une histoire qui se finit bien... À noter que comme d'habitude je suis tombé sur le seul disque externe qui avait un défaut (arrêt du disque au bout de 15/20s de copie avec un bruit symptomatique de futurs problèmes). Échangé (en fait remboursé puis racheté) chez Carrefour lundi soir sans aucun soucis... quelques fois passer par une enseigne traditionnelle a du bon !

Mise à jour du 5 juillet 2007 : le lien vers vers mkdosfs a changé (merci à Franchil de m'avoir signalé le lien mort)... on remarque aussi que 2 ans après sa première publication cet article est toujours d'actualité, sauf en ce qui concerne les disques USB : certaines cartes mères récentes scannent le bus USB et il est donc possible que le disque soit vu par des outils comme Ranish. Si certains ont réussi laissez un commentaire

Publié par zeguigui à 11:17 dans Technique | Commentaires (0) | TrackBack

12 janvier 2005

Désécuriser des pages sous Apache

Ne vous méprenez pas sur le but de cet article. Le but n'est pas de casser le serveur web Apache mais plutôt de jouer avec ses options de configuration. Le but est de vous montrer comment améliorer la gestion de la sécurité d'accès a ses pages.

Les préliminaires

Le nombre de sites web qui expliquent comment configurer apache par un .htaccess pour interdire l'accès non autorisé à des pages d'un site ne manquent pas. Cependant comme c'est un pré-requis pour aller plus loin je vais faire un rapide résumé.

On peut, dans Apache, modifier l'accès à des pages. Ceci se fait au niveau du fichier de configuration du serveur. On peut cependant autorisé les utilisateurs à reparamétrer à la volée l'accès à certain répertoires en utilisant des fichiers spéciaux (généralement nommé .htaccess mais c'est paramétrable). A noter aussi qu'un FAI peut interdire l'utilisation des .htaccess pour améliorer les performances de son serveur web (qui n'a plus à vérifier l'existance de ces fichiers à chaque nouvel accès à un répertoire).

Pour sécuriser l'accès à un répertoire on utilise généralement un fichier de login / mot de passe stockés dans un répertoire non visible depuis le web (soit en dehors de l'arborescence du serveur - ce qui est le plus sécurisé - soit dans un dossier lui-même protégé par une interdiction totale d'accès en HTTP). On peut également utiliser la notion de groupes qui permet de limiter l'accès à un ou plusieurs groupes.

Ensuite il suffit d'écrire un petit .htaccess qui pourrait resembler à ceci, en partant du plus contraignant :

AuthUserFile /auth/.htpasswd
AuthName "Secure Access"
AuthType Basic require user toto
AuthUserFile /auth/.htpasswd
AuthGroupFile /auth/.htgroups
AuthName "Secure Access"
AuthType Basic require group admin
AuthUserFile /auth/.htpasswd
AuthName "Secure Access"
AuthType Basic require valid-user

Dans le premier exemple seul l'utilisateur toto peut accéder aux pages. Dans le deuxième exemple tout membre du groupe admin peut accéder aux pages. Enfin dans le troisième tout utilisateur déclaré dans le fichier .htpasswd peut accéder aux pages. Bien entendu ceci suppose d'avoir connaissance du mot de passe !

Les fichier .htpasswd et .htgroups peuvent resembler à ceci :

# Fichier .htpasswd
toto:CryptedPassword
tutu:OtherCryptedPass
titi:SecurePass!

# Fichier .htgroups
admin: titi toto
test: tutu titi

L'avantage des groupes c'est que quand vous ajoutez un utilisateur à votre système, si vous avez plusieurs zones logiques, il suffit d'ajouter l'utilisateur aux différents groupes auxquels il a droit et hop tout le site est bon. Sans cela il faut aller éditer tous les fichier .htaccess (ou modifier le fichier de config du serveur) pour ajouter / enlever l'utilisateur avec toujours le risque d'en oublier un quelque part. Bref d'un point de vue maintenance cela permet de tout centraliser... bien entendu si votre fichier central est mal protégé le château de cartes s'écroule !

Hey, c'est récursif cette protection !

Une fois un répertoire sécurisé, tous ses sous-répertoires se voient appliquer les même restrictions. C'est dans 99,999% des cas une bonne chose mais il peut arriver qu'on désire modifier voire supprimer la sécurité d'un répertoire. Pourquoi ? Parce-que ! Bon disons que par exemple vous sécurisez une zone de votre site web en l'appelant extranet. Dedans vous mettez les outils qui sont accessibles à votre collaborateurs et vous spécifiez que cette zone est cryptée SSL. Et puis vous vous dites tient je vais mettre tel outil que j'ai trouvé qui a l'air sympa (IMP pour lire son mail ?)... et comme de juste cet outil propose sa propre authentification. Donc pour éviter le double login vous devez supprimer l'une ou l'autre des protection d'accès. Généralement pour le logiciel c'est pas évident... donc il faut supprimer la protection apache. Oui mais comment ?

Une tentative pour mettre un .htaccess vide ne fonctionne pas. Zut, bien essayé. Mais alors comment lui faire comprendre à l'animal ? En fait il suffit de ruser un peu. Il existe une directive permettant de restreindre les adresses IP qui peuvent se connecter au répertoire. Ainsi on peut sécuriser une zone en n'autorisant que les adresses IP du réseau interne. C'est pas 100% sûr (on peut usurper une adresse IP) mais c'est déjà un bon début. On peut aussi dire j'autorise/interdit n'importe quelle adresse IP.

Voici par exemple un fichier qui interdit tout acces à un répertoire et ce quelle que soit l'adresse utilisée. Un tel fichier est souvent placé pour interdire à un client web de lire le contenu du répertoire qui peut contenir, au hasard, un fichier .htpasswd

Deny from all 

On peut donc se dire que si on utilise la directive Allow from all celle-ci va remplacer la sécurité du répertoire... un rapide essai vous prouvera le contraire. En fait les directives se complètent. On pourrait en effet expliquer au serveur web qu'il faut que l'utilisateur soit valide ET qu'il se connecte depuis une adresse IP valide.

Heureusement il y a une solution. En fouillant un peu dans la documentation Apache on trouve la directive magique Satisfy. Celle-ci permet de modifier le mode de sécurisation par défaut (un ET de toutes les directives) pour, par exemple, dire qu'une seule directive suffit. Exemple :

AuthUserFile /auth/.htpasswd
AuthName "Secure Access"

AuthType Basic
require valid-user

Order allow,deny
Allow from all

Satisfy any

J'ai remis la directive de protection par utilisateur mais en réalité elle ne sera jamais utilisée puisque dans cet exemple j'ai mis un "Allow from all". La directive Order permet de dire qu'on commence par autoriser l'accès puis ensuite on applique les restrictions. Je ne pense pas que dans ce cas préci cela change quelque chose mais je n'ai pas vérifié !

Autre exemple d'utilisation de la directive satisfy. Revenons à notre exemple d'extranet. Disons que depuis internet nous trouvions normal que les utilisateurs saisissent un login et un mot de passe (à noter que cela pourrait tout aussi bien être "présenter un certificat SSL... mais là n'est pas notre propos). Cependant en interne on peut décider d'autoriser toutes les machines à se connecter sans mot de passe.

Première mauvaise idée utiliser le nom de domaine pour le allow. Il ne faut surtout pas dire Allow from .mondomaine.com car il est plus facile d'usurper un nom qu'une adresse IP (du moins je pense, je ne suis pas expert en sécurité !). Il faut donc donner le domaine d'adresse IP autorisées (adresses qui si c'est bien fait ne seront pas routables sur internet).

Pour en savoir plus sur ce domaine je vous invite à lire en détail la documentation du serveur Apache. On trouve toujours plein de choses amusantes. A noter que tout ceci est valable pour une version 1.3 du serveur. Je n'ai pas expérimenté sur une version 2.x donc si ça ne fonctionne pas merci de m'envoyer un petit message !

Publié par zeguigui à 21:53 dans Technique | Commentaires (3) | TrackBack

11 janvier 2005

Tester le format PNG

Cette page vous permet de tester la compatibilité de votre navigateur avec le format graphique PNG (qui présente plein d'avantages). Je suis parti d'une image avec un fond dégradé blanc vers bleu + transparence de 100% pour le haut pour atteindre 0% dans le bas. J'ai ajouté une sphère sans transparence sur le tout avec un dégradé de couleurs difficile à reproduire en GIF ou même en JPEG. Enfin j'ai coupé un morceau de sphère pour qu'il soit 100% transparent et ainsi mieux constater les différences avec le dégradé de transparence. À titre de comparaison j'ai mis le .gif généré. Voici le résultat final.

Couleur transparente, 16 millions de couleurs Test PNG
Alpha chanel, 16 millions de couleurs Test PNG
Couleur transparente, palette Test PNG
Pas de transparence Test PNG
Format gif Test GIF

Publié par zeguigui à 22:00 dans Technique | Commentaires (0) | TrackBack

10 janvier 2005

Mise en page de mes sites web

Introduction

Si comme moi vous aimez le PHP et que vous le mettez à toutes les sauces sur votre site web, vous vous êtes certainement posé un certain nombre de questions. Je vais donc essayer ici de donner quelques éléments de réponses... qui ne sont pas exhaustifs mais seulement ce que j'ai personnellement retenu comme solution.

Avoir son site web sur son PC et sur Free

Je n'ai pas encore l'ADSL et donc je ne suis pas connecté en permanence à Internet. Or il faut bien tester son site perso pour se rendre compte de ce qu'il va donner. J'ai testé plusieurs solutions :

  • Apache + PHP
  • IIS + PHP
  • PWS + PHP

Apache est la solution qui se rapproche le plus de la configuration de Free. Pourquoi Free ? Parce que c'est un hébergeur français (comme moi) qui propose PHP (à l'exception de la fonction mail()), 100 Mo d'espace disque et qui est très rapide.

Cependant comme vous pouvez le constater Apache n'est pas obligatoire. J'ai réussi à faire fonctionner mes sites web avec IIS (serveur Web de Microsoft sous NT/Windows 2000) et sous PWS (version de IIS adapté à windows 98 et ME). Cependant le but de cette page n'est pas d'expliquer comment faire fonctionner PHP avec ces serveurs web. D'autre sites le font très bien !

Ma configuration personnelle est PHP 4.0.5. Ce choix peut parraître surprenant étant donné que Free fonctionne toujours en version 3. Cependant avec un peu de rigueur et en regardant dans la doc à partir de quelle version une fonction est valide on s'en sort très bien. J'ai modifié le fichier php.ini et la configuration de mon serveur pour accepter les extensions .php et .php3. Cette dernière est la seule utilisable sur free (pour le moment bien entendu).

Je n'ai pas installé MySQL (ce qui est une grave erreur ;-)) mais c'est en projet. Donc pour le moment mes scripts fonctionnent avec base sur free et sans base de données chez moi... Ce qui n'est pas trop grave !

Gestion des Includes

Une des force de PHP est de pouvoir faire des include et des require. La différence entre ces deux fonctions est expliquée dans la FAQ du newsgroup français consacré à PHP et je vous conseille fortement de la lire.

Cependant, je gère plusieurs sites web... Donc l'utilisation de chemins absolus dans mes includes même si elle fonctionne parfaitement sur le site de free ne me convient vraiment pas. Donc je m'arrange toujours pour que mes includes soient relatifs.

A un moment j'avais pensé utiliser la variable $PHP_SELF avec une fonction pour extraire la "racine" de mon site. Ca fonctionnait parfaitement sur mon PC mais je me suis aperçu par la suite que $PHP_SELF prenait des valeurs "étranges" chez Free... et avec PHP4 configuré en module sur apache c'est pas mieux ;-)

Ma solution est donc toute simple. En début de chaque page j'identifie une variable $srcInclude que je positionne sur un répertoire dans lequel je stocke mes fichiers à include. Ensuite ça va tout seul.

Mise en page du site

Pour la mise en page de mes sites, je suis parti d'une constatation simple : la structure des fichiers HTML est toujours la même :

  • Début de page HTML (principalement le doctype et la balise <HTML>)
  • Début de la section <HEAD> avec scripts, feuille de style, etc.
  • Fin de la section <HEAD>
  • Début de la section principale (<BODY>)
  • Fin de la section principale
  • Fin de la page HTML

Je crée donc un fichier PHP par section... ou presque ;-) En effet entre la fin du HEAD et le début du BODY on n'ajoute généralement pas de code HTML.

Exemple

Par exemple, cette page web a la structure suivante :

<?php
 $srcInclude = "../include";
 $pageTitle = "Includes sur Free";
 require ("$srcInclude/dpage.inc");
?>
<html>
<head>
<?php
 require ("$srcInclude/head.inc");
?>
</head>
<body>
<?php
 require ("$srcInclude/dbody.inc");
?>
<p>Mes explications...</p>
<?php
 require ("$srcInclude/fbody.inc");
?>
</body>
</html>
<?php
 require ("$srcInclude/fpage.inc");
?>

Vous remarquerez que j'ai choisi, pour ce site, de laisser les balises HEAD et autres dans mon code... Je trouve que ça en simplifie la lecture tout en n'empêchant pas des effet de fond de page grâce aux feuilles de style (pourvu que le navigateur soit assez récent)... qui sont incluses dans le fichier head.inc (à noter aussi qu'il manque le DOCTYPE dans cet exemple !).

Avantages de ce système

L'avantage principal de ce système est de séparer le contenu de la présentation chez un prestataire proposant le PHP. En effet tout le monde n'a pas de prestataire proposant XML, XPATH, XMLT, XSL et autres ! L'autre avantage c'est que la présentation est gérée par PHP... et autorise donc tout un tas de trucs sympas comme :

  • citation du jour (dans une base de données par exemple)
  • anniversaire du jour
  • modification de l'aspect du site en fonction de paramètres comme, par exemple :
    • préférences de l'utilisateur stockées dans un cookie (site msit.org par exemple)
    • la date du jour (si la date est le 25 décembre alors utiliser tels fichiers)
    • la résolution de l'écran (plus complexe... nécessite javascript).

Comme tous les fichiers sont appelés à chaque page il est également possible d'appeler une fonction à chaque fois (utilisation possible : statistiques de visite stockées en base).

Publié par zeguigui à 22:04 dans Technique | Commentaires (0) | TrackBack

7 janvier 2005

Gestion des objets COM/DCOM en PHP4.

Bonjour... Comme beaucoup de monde se demande comment ça fonctionne COM avec PHP4, et que je me suis aussi posé la question, voici un petit exemple de code source et un objet COM pour le faire fonctionner. Comme cet objet n'est pas révolutionnaire (il fourni un nombre aléatoire... difficile non ?) je vous le livre "tel quel" avec son code source (comme ça les paranoïaques pourront vérifier ce qu'il fait). Pour des raisons de facilité, je l'ai programmé avec Delphi 5, mais n'importe quel langage capable de produire des objets COM fera tout aussi bien l'affaire.

L'objet COM

Vous pouvez le télécharger en cliquant ici (180ko). L'installation est la même que pour tout objet COM : il faut le copier dans un répertoire et dans une fenêtre de commande (cmd sous NT, command.com sous 9x) saisir la commande suivante :

  • Installation : regsvr32 testPHP4.dll
  • Désinstallation : regsvr32 /u testPHP4.dll

Exemple de source PHP4

Ce code appelle la commande n fois (paramétrable) et calcule le temps qu'il faut pour le faire.

<?php
if (!isset($nbAppels))
{
$nbAppels = 100;
}
$comName = "testPHP4.test";
$debMTime = microtime();

$tst = new COM($comName) or die("Unable to instanciate $comName");
$stoquage = array();
for ($i=0; $i < $nbAppels; $i++)
{
$stoquage[$i] = $tst->randNumber();
}
sort($stoquage);
$endMTime = microtime();

list($msec, $sec) = explode(" ", $debMTime);
$debut = $sec + $msec;

list($msec, $sec) = explode(" ", $endMTime);
$fin = $sec + $msec;

echo "<P><B>Résultats</B> : ".number_format($fin - $debut,4,',','')." s.<BR>\n";
?>

Publié par zeguigui à 22:12 dans Technique | Commentaires (0) | TrackBack

5 janvier 2005

Les behaviors, mais qu'est-ce donc ?

Table des Matières

Prérequis

Pour pouvoir apprécier pleinement cette page il faut quelques prérequis. Le premier est de regarder la page sous Internet Explorer 5 (ou plus). Même si les autres navigateurs peuvent lire la page les behaviors sont spécifiques à Microsoft et donc l'exemple ne peut-être visualisé que sous cet environnement. Ensuite il faut quelques connaissances. Le HTML, les feuilles de style et le javascript sont un minimum à connaître pour apprécier complètement l'article (du moins dans les détails techniques).

Aperçu

Les behaviors ont été introduits par Microsoft dans la version 5 d'Internet Explorer. Comme d'habitude c'est une proposition pour le W3C, doux euphémisme pour dire que c'est une extension propriétaire. Le but des behaviors est de séparer encore plus le contenu de la présentation. A ce titre c'est donc une extension des feuilles de style... et d'ailleurs ça se positionne comme une feuille de style.

Mais encore... ça fait quoi ?

Il était une fois le javascript... c'est en gros ce que se dit tout développeur de pages web qui désire faire des effets un peu sympa dans sa page. Le seul problème c'est que pour écrire du javascript un peu générique il faut se lever de bonne heure. Et pour le réexploiter bof. On peut bien entendu mettre son code dans un fichier séparé mais la réutilisabilité est limitée.

L'autre problème de Javascript c'est que même si on a fait un joli script permettant de modifier quelque chose en dynamique, il faut tout de même l'appeler. Par exemple imaginons un tableau dont on désire modifier la couleur de fond des lignes quand la souris passe dedans. Ca veut dire que pour chaque ligne il faut écrire un gestionnaire onMouseOver et un gestionnaire onMouseOut. Sous IE ça pourrait donner ça :

<TABLE>
<TR onMouseOver="this.bgColor='#CCCCCC';" onMouseOut="this.bgColor='white';">
<td>Colonne 1</td>
<td>Colonne 2</td>
</TR>
<TR onMouseOver="this.bgColor='#CCCCCC';" onMouseOut="this.bgColor='white';">
<td>Colonne 1 ligne 2</td>
<td>Colonne 2 ligne 2</td>
</TR>
[...]
</TABLE>

Bref on se rend compte que le comportement de la ligne est générique et on aimerait donc le factoriser. Ca tombe bien, c'est à ça que sert un behavior (dont la traduction en français est comportement... tient donc !).

Comment ça fonctionne ?

En gros on fait un fichier .htc dans lequel on va écrire notre behavior de façon générique. Comme le but c'est de gérer l'élément à la volée, le mot clé this est associé à l'élément sur lequel est attaché le behavior. On peut alors jouer avec des this.style voir même des this.className (attention tout de même à conserver un behavior sur la nouvelle classe).

Ce behavior est ensuite attaché à n'importe quel élément de la page HTML comme on attacherait un style. On a donc plusieurs options :

  • le mettre dans une classe de la feuille de style
  • utiliser le mot clé STYLE sur l'élément à modifier

Exemple de définition de style :

<STYLE TYPE="text/css"><!--
.beh { behavior: url('monbehavior.htc'); }
//-->
</STYLE>

On peut bien entendu mettre d'autre choses sur la classe comme color et autres... mais ce n'est pas un article sur les feuilles de style que je suis en train d'écrire ! ;-)) La classe s'utilise très facilement de par la suite. Pour revenir sur le tableau :

<TABLE>

<TR CLASS="beh">
<td>Colonne 1</td>
<td>Colonne 2</td>
</TR>
<TR CLASS="beh">
<td>Colonne 1 ligne 2</td>
<td>Colonne 2 ligne 2</td>
</TR>
[...]
</TABLE>

Et je met quoi dans le .htc ?

Le fichier .htc est en fait un fichier contenant deux parties distinctes : une partie déclarative et une partie script. La partie déclarative explique ce que fait le behavior et comment il s'insère dans la page tandis que la partie script implémente le comportement. C'est comme les packages en PL/SQL, les unités en Pascal ou les fichier .h / .cpp en C (sauf que pour les .htc tout est dans le même fichier).

Partie déclarative

C'est dans cette zone que l'on déclare quels événements on veut intercepter et que l'on déclare de nouveaux attributs. En effet les behaviors permettent d'enrichir les balises standards pour passer des paramètres au behavior, le rendant ainsi plus générique (mais rien n'empêche d'avoir des valeurs par défaut). Il est même possible de déclarer tout cela dynamiquement via un lot de fonctions spécialisées.

Le plus simple c'est de prendre un exemple. Voici donc la partie déclarative d'un fichier .htc assez simple.

<PUBLIC:ATTACH EVENT="onmouseover" ONEVENT="menuOver()" />
<PUBLIC:ATTACH EVENT="onmouseout" ONEVENT="menuOut()" />
<PUBLIC:PROPERTY INTERNALNAME="hiliteColor" NAME="MOBGCOLOR" />

Comme vous pouvez le constater, la syntaxe est celle d'un fichier XML (comme l'indique le />). L'exemple ci-dessus est relativement simple. Les deux premières lignes indiquent que l'on veut gérer les événements onmouseover et onmouseout via les fonctions menuOver() et menuOut() qui sont alors automatiquement appelée lorsque l'événement source est déclenché. La dernière ligne permet de créer un nouvel attribut de balise qui s'appelle MOBGCOLOR. La valeur de cet attribut est stockée dans la variable hiliteColor. Il est possible de pré-initialiser cette variable dans la section script. Dans ce cas si l'attribut est présent c'est sa valeur qui compte, sinon c'est la valeur par défaut.

Le script

A chaque événement intercepté on a affecté une fonction que l'on peut écrire en JScript, JavaScript (il y a de subtiles différences), VBScript, etc. Personnellement j'utilise le JScript (implémentation enrichie de Javascript et d'ECMAScript) car les behavior sont déjà du pur spécifique IE... alors pourquoi se priver de fonctionnalités supplémentaires ?!

Comme pour tous les scripts, cette section commence par une balise <SCRIPT> et se termine par </SCRIPT>. Il faut spécifier le langage dans la balise script pour éviter les surprises. Ainsi peut avoir :

<SCRIPT LANGUAGE="JScript">

// On peut avoir besoin de variables globales, alors hop on en met. Elles
// seront de toutes façons locales au behavior (sauf si précisé autrement ;-)).
var toto;

function mouseOver()
{
// Ici plein de choses à faire lorsque la souris passe sur
// un élément actif.
}

function mouseOut()
{
// Rétablir l'état précédent
}
</SCRIPT>

Vous remarquerez qu'il n'est pas nécessaire de protéger le script par les balises habituelle <!-- et --> car le script est inclus dans un fichier séparé. Il n'y a donc pas de risques de mauvaise interprétation par un vieux navigateur qui de toutes façons ne lira pas la feuille de style (protégée par commentaires) ni par les navigateurs plus récents incompatibles avec les behaviors qui, croisant un mot clé inconnu, ignorera la déclaration.

Exemple complet

Au début de cet article j'avais pris comme exemple un tableau dont les lignes réagissent à la présence de la souris en changeant leur couleur de fond. Voici comment l'implémenter avec les behaviors de façon assez générique :

<PUBLIC:ATTACH EVENT="onmouseover" ONEVENT="Hilite()" />
<PUBLIC:ATTACH EVENT="onmouseout" ONEVENT="Restore()" />
<PUBLIC:PROPERTY INTERNALNAME="hiliteColor" NAME="MOBGCOLOR" />

<SCRIPT LANGUAGE="JScript">

var normalColor;
var hiliteColor = "#CCCCCC";

function Hilite()
{
normalColor = style.backgroundColor;
runtimeStyle.backgroundColor = hiliteColor;
}

function Restore()
{
runtimeStyle.backgroundColor = normalColor;
}
</SCRIPT>

Vous remarquerez l'utilisation d'un attribut personnalisé ayant une valeur par défaut via l'initialisation du script. Il est cependant possible de procéder autrement en détournant l'événement ondocumentready (qui est déclenché lorsque le document parent est chargé) pour initialiser dynamiquement la variable et attacher les événements (ce qui évite leur utilisation tant que le document source n'est pas totalement chargé). Je trouve néanmoins ma solution plus lisible car il n'est plus alors utile de lire la fonction init() pour savoir quels événements sont gérés par le behavior. Voici un fichier HTML exemple :

<HTML>

<HEAD>
<TITLE>Exemple de behavior</TITLE>
<STYLE type="text/css"><!--
// On suppose que l'exemple précédent est stocké dans le même répertoire que
// ce fichier et sous le nom test.htc.
exemple { behavior: url('test.htc'); }
//-->
</STYLE>
</HEAD>
<BODY>
<TABLE WIDTH="100%" CELLPADDING="2" CELLSPACING="1">
<TR CLASS="exemple">
<TD>Attribut personnalisé</TD>
<TD>inexistant</TD>
</TR>
<TR CLASS="exemple" MOBGCOLOR="white">
<TD>Attribut personnalisé</TD>
<TD>white</TD>
</TR>
</TABLE>
</BODY>
</HTML>

Cet exemple donne :

Attribut personnalisé inexistant
Attribut personnalisé white

C'est génial... mais...

Et oui, malheureusement, il y a un mais. Et de taille en plus. Le premier concerne l'utilisation de ces behaviors sur internet. Outre le fait que c'est spécifique à internet explorer il y a aussi la façon dont c'est déclaré. Si vous avez bien fait attention, on utilise la commande url soit dans le style, soit dans la classe. Or pour chaque instance élément de la page auquel on affecte le behavior il va y avoir une requête HTTP pour charger le fichier .htc. Vous allez me dire que ce n'est pas un problème avec le cache du navigateur... Certes... si le navigateur gardait le fichier en cache ce ne serait pas un problème (du moins chez moi il n'est pas conservé en cache... mais ça ne change rien car mes paramètres sont de vérifier la présence d'une nouvelle version des fichiers à chaque visite de la page... d'où des requêtes supplémentaires). Autrement dit si vous avez un tableau de 75 lignes il chargera 75 fois le fichier .htc ce qui n'est pas toujours très rapide (surtout par modem !).

Second problème... J'ai parlé des variables que l'on pouvait déclarer dans un script. J'ai même dit que la variable était locale à chaque instance du behavior. Ca signifie que si vous déclarez 5 variables et que vous avez 20 instances du behavior vous vous retrouvez avec une occupation mémoire de 5 x 20 = 100 variables. Sur des machines puissantes ce n'est pas trop un problèmes mais il faut conserver ce fait en mémoire. La solution consiste à créer des variables dans le document appelant via un script d'initialisation puis de faire référence à ces variables dans le script... Pour peu que l'on puisse globaliser les variables bien entendu.

Conclusion

Ma conclusion c'est que j'aime bien les behaviors. Ca comble une lacune du javascript et des feuilles de style et permet de créer des composants un peu complexes réutilisables. Sur le site de Microsoft par exemple ils utilisent les behaviors pour gérer des pseudo treeviews de façon très simple. En cherchant un peu on arrive à des résultats spectaculaires comme par exemple l'utilisation de HTML dans les infobulles de Internet Explorer (celles qui s'affichent quand il y a un attribut TITLE sur un lien par exemple) permettant ainsi de jouer sur les retour à la ligne ou de mettre des images.

Enfin une dernière remarque : je n'ai fait que vous donner un aperçu de la puissance des behaviors. Si je vous dit que depuis IE5.5 on peut créer des composants appelables comme des balises en HTML, que l'on peut se faire des behavior en C++ ou qu'il y en a d'inclus dans IE5 pour gérer la persistance vous aurez probablement envie d'aller plus loin... en lisant la doc complète sur le site de Microsoft (attention, c'est en anglais).

Publié par zeguigui à 22:17 dans Technique | Commentaires (0) | TrackBack

2 avril 2003

Petite astuce en passant...

Petite astuce en passant à tous ceux qui ont plein de monde sur leurs nappes IDE et notemment au moins une nappe avec un disque dur et un lecteur ou graveur de CD. En faisant des tests chez moi j'ai pu remarquer une nette différence entre les deux réglages possibles.

Sur mon disque dur j'ai une tonne de petits fichiers et des programmes qui y accèdent. Si je met le disque dur en slave et le graveur en master alors j'ai des performances très médiocres. Par contre avec la configuration inverse (HD master, CD slave) je retrouve les performances de mon disque.

Alors j'en vois d'ici qui disent que la différence est négligeable... Et bien montre en main mon programme s'exécute en +10 minutes dans un mode contre environ 1 minute dans l'autre... Comme quoi.... mais bon ça peut aussi venir de l'interface IDE du CD qui est moins optimisée que celle du disque dur.

Publié par zeguigui à 22:52 dans Technique | Commentaires (0)

Technique (RSS) - Technique (Atom)
Retour...