Forums : Xul, Xbl, JS...

Aller à la discussion :  Plus récente Plus ancienne

# Le composant dictionary pour faire des singletons

Envoyé par : ilhooq

Date : 16/12/2006 20:00

Bonsoir,

Tout d'abord, puisque c'est mon premier sujet, je tiens à remercier Laurent Jouanneau et tous les contributeurs à xulfr.org pour leurs articles et leurs traductions.

Voilà, je planche actuellement sur la construction d'une appli cliente en xul pour un cms. Un des points sur lequel je me suis heurté est la possibilité d'instancier des variables globales accessible à toute les fenêtres de l'application. Du coup, après avoir compulsé de la doc, j'ai retenu une solution avec un composant XPCOM : @mozilla.org/dictionary;1 à utiliser comme service. D'ailleurs à ce propos, il semble que tous les composants peuvent être appelé soit avec getService() ou createInstance() comme le montre cet article

Voici un exemple d'utilisation :

Pour Creer un singleton

  • param string key
  • param mixed value
  • return void
function Register( key , value)
{
  var component_object = {
           get wrappedJSObject() { return this; }
           };
  component_object[key] = value;
  
  var dico = Components.classes["@mozilla.org/dictionary;1"]
                   .getService(Components.interfaces.nsIDictionary);
  dico.setValue ( key , component_object );
  return;
}

Pour recuperer un singleton

  • param string key
  • return mixed value
function Registry (key)
{
   var dico = Components.classes["@mozilla.org/dictionary;1"]
                   .getService(Components.interfaces.nsIDictionary);
   var component_object = dico.getValue(key).wrappedJSObject;
   return component_object[key];
}

Dans la fenêtre xul principale:

Register('mainWindow', window );

Récupérer la valeur dans une iframe:

var winMain = Registry ('mainWindow');
var test = winMain.document.getElementById("main-notification");
alert(test.value);

Du coup, j'aimerais avoir votre avis pour savoir si cette manière de faire est propre... Apparement une autre méthode aurait été de construire son propre composant pour y stocker ses singletons...

cordialement.

liste de références:

# Re: Le composant dictionary pour faire des singletons

Envoyé par : Paul Rouget

Date : 17/12/2006 01:30

Pour les singletons, travaillant souvent avec mes propres composants XPCom, je n'hésite pas à créer mon propre composant et l'exploiter sous forme de service, je n'avais jamais pensé ça, et j'avoue que cette approche est particulièrement intéressante et assez propre (comparée à tous les trucs gruik qui tournent).

Je pense que ça vaudrait le coup d'en faire une page sur le wiki. Ilhooq, si tu es motivé ;)

# Re: Le composant dictionary pour faire des singletons

Envoyé par : ilhooq

Date : 17/12/2006 02:26

Je voulais justement en discuter avant d'éditer une page dans le wiki car je ne suis pas tout à fait sur de moi étant donné que le XPFE m'est encore trop récent pour en apréhender toutes les subtilités.

En fait, je ne suis pas sur que sûr que le composant dictionnary soit destiné à être instantié directement en javascript, car pour accéder à l'objet stocké, je suis obligé de faire appel à la propriété wrappedJSObject. Or cet article dit qu'il vaut mieux créer son propre composant plutôt que de passer par la propriété wrappedJSObject. Mais il n'explique pas pourquoi...

# Re: Le composant dictionary pour faire des singletons

Envoyé par : laurentj

Date : 18/12/2006 11:26

Si ton composant fournit des méthodes et propriétés qui ne sont pas dans une interface commune, tu dois alors créer ta propre interface (fichier idl), et déclarer que ton composant utilise cette interface.

Le fait d'utiliser wrappedJSObject évite d'avoir à créer l'interface, mais c'est hyper crade, limité et tu casses la "philosophie" xpcom : d'autres composants ne pourront jamais appeler les méthodes et propriétés puisqu'elles sont en fait "cachée", elles ne sont pas visibles au travers d'une interface.

Et puis si un jour tu décides de passer du JS à un autre langage pour ton composant, cela veut dire revoir toutes tes sources JS des pages XUL.

En bref, wrappedJSObject, c'est la porte de derrière, et ce n'est pas bien de l'utiliser. Mieux vaut utiliser la porte officielle : les interfaces.

# Re: Le composant dictionary pour faire des singletons

Envoyé par : ilhooq

Date : 18/12/2006 21:17

Merci pour ces précisions. Comment faire alors pour récupérer des objets stockés par le composant dictionnary sans faire appel à wrappedJSObject?

En simplifiant le code cela donne:

function Register( key , value)
{  
  var dico = Components.classes["@mozilla.org/dictionary;1"]
                   .getService(Components.interfaces.nsIDictionary);
  dico.setValue ( key , value );
  return;
}

function Registry (key)
{
   
   var dico = Components.classes["@mozilla.org/dictionary;1"]
                   .getService(Components.interfaces.nsIDictionary);
   return dico.getValue(key);
}

var test = {
  toto : "super!"
}


Register ( "test" , test );

var testobj = Registry("test");

alert(testobj); //donne [xpconnect wrapped nsIsupport];

A partir de là je ne vois pas comment récupérer mon objet...

# Re: Le composant dictionary pour faire des singletons

Envoyé par : laurentj

Date : 19/12/2006 11:21

en faisant un testobj.QueryInterface(Components.interfaces.nsITonInterface)

# Re: Le composant dictionary pour faire des singletons

Envoyé par : ilhooq

Date : 19/12/2006 17:35

D'accord, ta réponse semble évidente mais testobj n'ayant pas d'interface déclarée, je ne vois pas comment appeler cette dernière. Cela dit, XPCconnect semble envelopper l'objet et en lui donner une par défaut: nsISupports. Cependant, testobj.QueryInterface(Components.interfaces.nsISupports) ne donne rien. J'ai même testé les 1024 interfaces dans une boucle, seulement deux sont acceptées: nsISupports et IDispatch. Par contre si l'on enregistre un objet qui a une interface déclarée, comme window ou document, l'objet est immédiatement récupérable par nsIDictionnary sans faire appel à QueryInterface. Il semble donc que, si l'on veut récupérer son propre objet, il faut qu'il soit déclaré comme composant XPCOM, ou alors lui donner l'accesseur wrappedJSObject. La première solution semble toutefois assez contraignante lorsque l'on veut, par exemple, enregistrer un simple objet de configuration global à l'application... D'un autre côté, j'aimerai savoir s'il n'y pas une autre solution qui permettrait de récupérer ( de nsIDictionnary ) un objet non déclaré comme composant et sans l'accesseur wrappedJSObject.

var test = {
 toto : "super!"
}

Register ( "test" , test );

var testobj = Registry("test"); //comment récupérer test à son état original? testobj est-il exploitable?

# Re: Le composant dictionary pour faire des singletons

Envoyé par : Paul Rouget

Date : 19/12/2006 18:43

Oui, dans ce cas, à toi d'implémenter la méthode QueryInterface et de faire tes propres IDL, et c'est vrai que ç'est d'un coup beaucoup plus lourd à gérer. Un service générique basé sur nsIVariant, ce serait pas mal, mais je pense que tu ne pourras que stocker des éléments pouvant être traduits en nsISupports (donc c'est mort pour les objets date par exemple).

# Re: Le composant dictionary pour faire des singletons

Envoyé par : ilhooq

Date : 19/12/2006 20:14

Cela dit avec nsIdictionary, les objets sont bien traduits en nSISupports. Prenons par exemple l'objet date et window:

var dico = Components.classes["@mozilla.org/dictionary;1"]
               .getService(Components.interfaces.nsIDictionary);

var today = new Date ; //objet qui n'implémente pas nsIsupports
var fenetre = window ; //objet qui implémente nsIsupports

dico.setValue ( "ladate" , today ); //accepte d'enregistrer l'objet ( xpconnect doit l'emballer pour qu'il soit de type nsIsupports )
dico.setValue ( "fenetre" , fenetre ); //ici pas de probleme puisque fenetre est de type nsIsupports

alert (dico.getValue("fenetre")); //donne [object Window]
alert (dico.getValue("ladate")); //donne [xpconnect wrapped nsIsupports]

Si xpconnect a emballé l'objet date (dans le respect de l'interface nsIDictionary), il doit bien exister un moyen de faire l'opération inverse pour le récupérer... C'est ce moyen que je cherche à découvrir. Cela dit, l'exemple montre que l'on peut tout de même enregistrer une fenêtre en singleton ! ceci peut s'appliquer aussi pour un élément XUL. Ce qui veut dire qu'une iframe pourrait controller par exemple des éléments de la fenêtre parente.

# Re: Le composant dictionary pour faire des singletons

Envoyé par : laurentj

Date : 20/12/2006 09:57

D'accord, ta réponse semble évidente mais testobj n'ayant pas d'interface déclarée, je ne vois pas comment appeler cette dernière

C'est pour cela que tu dois déclarer une interface et tout et tout. Bref, faire un composant propre.

Il n'est plus possible de poster des messages dans ce forum.


Copyright © 2003-2013 association xulfr, 2013-2016 Laurent Jouanneau - Informations légales.

Mozilla® est une marque déposée de la fondation Mozilla.
Mozilla.org™, Firefox™, Thunderbird™, Mozilla Suite™ et XUL™ sont des marques de la fondation Mozilla.