2/25/2009

Réaliser une copie profonde d’objet (deep copy) en Javascript

Un des problèmes récurrent avec Javascript est qu’il est difficile de savoir si une variable passée par référence ou par valeur.

En VB (VB6, VB.NET) il est possible de déclarer dans l’entête de la fonction by val ou by ref pour préciser le mode de passage mais ce n’est pas le cas en Javascript.

//Création de l'objet monObjet
var monObjet = new Object();

// monDeuxiemeObjet réfère à l'objet monObjet
var monDeuxiemeObjet = monObjet;

// On modifie une propriété du premier objet
monObjet.unePropriete = true;

// Les changements sont aussi appliqué sur le second objet
// (Le deuxième objet réfère au premier objet)
alert( monObjet.unePropriete === monDeuxiemeObjet.unePropriete );//affiche true

 

Dans cette exemple, la copie de monObjet dans monDeuxiemeObjet à été effectuée par référence, ce qui signifie que monDeuxiemeObjet pointe vers l’adresse de monObjet (même si la réalité est un peu plus complexe que cela…monDeuxiemeObjet pointe sur la référence de l’objet final monObjet mais c’est une autre histoire).

 

Seulement dans certains cas, il arrive que nous ayons besoin de réaliser une vrai copie. Par exemple sauvegarder monObjet dans une variable temporaire et effectuer des traitements uniquement sur cette variable sans que cela n’affecte monObjet. Dans certains cas là méthode que je vous propose n’est pas indispensable notamment dans le cas où l’objet à copier n’est pas complexe.

 

Heureusement jQuery intègre la méthode extend. Basiquement elle permet de gérer l’héritage d’un objet vers un à plusieurs autres objets. Mais elle permet aussi la copie profonde (deep copy) d’un objet vers un autre et donc une copie par valeur (et non plus par référence) via son paramètre optionnel “deep”.

 

jQuery.extend( [deep], target, object1, [objectN] )

 

//Création de l'objet monObjet
var monObjet = new Object();

var monDeuxiemeObjet = {};
$.extend(true,monObjet,monDeuxiemeObjet);//deep copy

// On modifie une propriété du premier objet
monObjet.unePropriete = true;

// Les changements ne sont pas appliqué sur le second objet
// monDeuxiemeObjet.unePropriete est indéfini
alert( monObjet.unePropriete === monDeuxiemeObjet.unePropriete );//affiche false

Ici, monDeuxiemeObjet ne réfère plus à monObjet. Ces deux objets possèdent chacun leurs propres adresses mémoires, il est ainsi possible de travailler sur l’un sans modifier l’autre.

2/21/2009

Modifier openWYSIWYG afin qu’il supporte Google Chrome

L’outil pour ajouter sa signature HTML à Gmail utilise l’éditeur openWYSIWYG que j’apprécie particulièrement pour son côté cross-browser, open-source et son interface très léger. Seulement, même la dernière version ne supporte pas Google Chrome.

Après un bref regard sur le code, je me suis aperçu que la vérification de la compatibilité s’effectuait au niveau de la méthode isBrowserCompatible :
isBrowserCompatible: function() {
// Validate browser and compatiblity
if ((navigator.userAgent.indexOf('Safari') != -1 ) || !document.getElementById || !document.designMode){
//no designMode (Safari lies)
return false;
}
return true;
},

N’ayant pas Safari et ne pouvant donc pas vérifier si oui ou non “Safari lies” j’ai préféré simplement ajouter le support de Chrome tout en laissant le blocage de Safari. Il suffit donc de modifier le test et d'y ajouter l'expression booléen suivante :
if ((navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1 ) || !document.getElementById || !document.designMode){

C’est fini ? Eh bien non, après un test cela ne fonctionnait toujours pas, Chrome retournait une erreur Uncaught TypeError: Object # has no method 'insertAdjacentHTML'. Une recherche plus tard, je découvre ce block de code :
/**
* Emulates insertAdjacentHTML(), insertAdjacentText() and
* insertAdjacentElement() three functions so they work with Netscape 6/Mozilla
* by Thor Larholm me@jscript.dk
*/
if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement){ HTMLElement.prototype.insertAdjacentElement = function (where,parsedNode){
    HTMLElement.prototype.insertAdjacentElement = function (where,parsedNode) {.. };
    HTMLElement.prototype.insertAdjacentHTML = function (where,htmlStr) {…};
    HTMLElement.prototype.insertAdjacentText = function (where,txtStr) {… };
}


Or sous Chrome l’objet HTMLElement ET sa méthode insertAdjacentElement existe mais pas la méthode insertAdjacentHTML. Cette condition n’était donc pas validée. Il suffisait de modifier la condition comme ceci pour que openWYSIWYG supporte Chrome :
if((typeof HTMLElement!="undefined" && (!HTMLElement.prototype.insertAdjacentElement || !HTMLElement.prototype.insertAdjacentHTML))){
Remarque: il est préférable ici de ne pas agir en fonction du navigateur (donc un test sur le user-agent) mais plutôt sur la présence ou non de la fonctionnalité sur le navigateur. En utilisant cette méthode on code ainsi de façon plus générique et les scripts deviennent compatibles (ou inversement) avec les mises à jour des navigateurs.

Ps : En bon webnaute j’ai proposé cette modification sur le forum dédié afin qu’elle soit intégrée à la prochaine release.
2/15/2009

Algorithme tri de couleur (+ demonstration javascript)

 

Il y a 3 semaines, j’expliquais sur ce blog comment créer un algorithme qui était capable de définir automatiquement la couleur d’un texte par rapport à son arrière plan. Aujourd’hui, je vous propose de trier un set (ou une palette) de couleur.

 

Pour vous faciliter nous faciliter la tâche voici quelques restrictions :

  1. Notre set (ou palette) sera composé de 5 couleurs
  2. Les couleurs devront être triées de la plus claire à la plus foncée (l’inverse est tout aussi possible)

 

En fidèle lecteur de ce blog vous vous souvenez sans doute de cet article où j’expliquais comment réaliser une fonction de tri simple. Grâce à ces deux précédents articles nous sommes capable de réaliser de réaliser une fonction de tri de couleur.

 

La théorie

Pour savoir si une couleur est plus clair ou plus foncée qu’une autre, il suffit de se référer à la luminance de leurs codes HSL. Au lieu de trier des nombres du plus petit au plus grand il faut donc trier les couleurs par leurs composantes HSL de la plus grande (100% : blanc) à la plus petite (0% : noir).

 

L’algorithme

Ce qui nous donne cet algorithme :

tabCouleur = ["0B8C8F", "FCF8BC", "CACF43","2B2825","D6156C"]

//Convertir de HEX en HSL
convertirTableauCouleurHEXversHSL(tabCouleur);

//Le tableau est maintenant de la forme :
//tabCouleur = [[,,], [,,], [,,], [,,], [,,]]

//Luminance de la première couleur : tabCouleur[0][2]

Faire
    Si(tabCouleur[0][2] < tabCouleur[1][2])
        tabCouleur.intervertir(0,1);
    SinonSi(tabCouleur[1][2] < tabCouleur[2][2])
        tabCouleur.intervertir(2,3);
    SinonSi(tabCouleur[2][2] < tabCouleur[3][2])
        tabCouleur.intervertir(2,3);
    SinonSi(tabCouleur[3][2] < tabCouleur[4][2])
        tabCouleur.intervertir(3,4);
TantQue(!(    tabCouleur[0][2] >= tabCouleur[1][2]
        &&     tabCouleur[1][2] >= tabCouleur[2][2]
        &&     tabCouleur[2][2] >= tabCouleur[3][2]
        &&     tabCouleur[3][2] >= tabCouleur[4][2]))

//Convertir de HSL -> HEX
convertirTableauCouleurHSLversHEX(tabCouleur);

L’équivalent Javascript n’est pas très différent. Les fonctions convertirTableauCouleurHEXversHSL et convertirTableauCouleurHSLversHEX vont en fait transformer le code HEXA en RGB puis en HSL et inversement.

 

Pour ce qui est de la méthode intervertir. Elle ne fait rien d’autre qu’une inversion (swap) entre 2 éléments (spécifiés par leurs index) d’un même tableau. Le code Javascript est donc :

var tmp=tabCouleur[x];
tabCouleur[x]=tabCouleur[y];
tabCouleur[y]=tmp;

 

Démonstration en javascript

J’ai réalisé une démonstration en javascript de cet algorithme sur le sous domaine projets. Le script importe dynamiquement (via l’API de ColourLovers) des palettes de couleurs il vous suffit alors de cliquer sur une palette pour la trier.

 

A chaque chargement de l’API, une seconde palette est générée et contient toutes les couleurs des autres palettes le temps de tri est légèrement plus long mais le résultat est là.

 

Pour accéder à la démo de tri des couleurs en javascript c’est par ici.

 

Remarque : Certaines palettes ont déjà leurs couleurs de triées de la plus foncées à la plus clair.

2/10/2009

Mise à jour : Bookmarklet pour avoir une signature HTML sous Gmail

 

Petite note de service pour vous informer de la mise à jour de mon générateur de bookmarklet permettant d’insérer une signature HTML sous Gmail. J’avais réalisé la première version dans mes débuts avec jQuery et je ne connaissais pas la méthode .prepend() : maintenant la signature s’ajoute tout en haut de votre email, il vous suffit donc de l’ajouter puis d’écrire ensuite votre message.

 

D’ailleurs Ghacks proposait aujourd’hui un article, qui (…outre le fait d’y intégrer un lien vers mon générateur ^^) propose 90 outils et astuces pour devenir un Pro de Gmail.

 

Si vous avez des suggestions concernant le bookmarklet, j’en tiendrais compte pour la prochaine version.

2/06/2009

Note de service : flux RSS du site

Certains d’entre vous l’on peut-être remarqué. L’ancienne adresse du flux RSS redirige vers http://feeds2.feedburner.com/geekfg. Cette adresse est donc la nouvelle adresse du flux, pensez à mettre à jour vos Netvibes, Google Reader et autres agrégateurs RSS.

« »
 
 
Made with on a hot august night from an airplane the 19th of March 2017.