Écrit par Neil Deakin.
Traduit par Laurent Jouanneau (15/11/2004).
Page originale :
http://www.xulplanet.com/tutorials/xultu/commands.html
Une commande est une opération qui peut être invoquée.
L'élément command
est utilisé pour créer des commandes qui pourront être utilisées pour exécuter des opérations.
Vous n'avez pas besoin d'utiliser les commandes si vous avez juste à appeler un script pour manipuler des choses.
Cependant, une commande a l'avantage qu'elle peut être désactivée automatiquement quand c'est nécessaire,
et peut être invoquée de l'extérieur sans avoir besoin de savoir les détails de son implémentation.
Les commandes fournissent un moyen pour séparer de façon abstraite les opérations et le code.
Elles deviennent très utiles pour les grosses applications.
Par exemple, pour implémenter les commandes de menus du presse-papiers, couper, copier et coller, vous pouvez utiliser les commandes. Si vous ne les utilisiez pas, vous devriez trouver quel champ a le focus, ensuite s'assurer que l'opération est valable pour cet élément. De plus, les commandes de menus devraient être activées ou désactivées selon si l'élément cible a du texte sélectionné ou pas, et pour les opérations de collage, si il y a quelque chose de valable dans le presse-papiers, à coller. Comme vous pouvez le voir, cela devient compliqué. En utilisant les commandes, votre travail est simplifié.
Vous pouvez utiliser une commande pour n'importe quelle opération. Mozilla les utilise la plupart du temps pour les menus. De plus, les champs de saisie de texte et autres composants graphiques ont un nombre de commandes qu'ils supportent nativement, que vous pouvez donc invoquer. Vous devriez les utiliser quand les opérations dépendent de l'élément sélectionné.
Une commande est identifiée par son attribut id
.
Mozilla utilise une convention : les id de commandes commencent par cmd_.
Vous voudrez probablement utiliser le même identifiant que celui d'une commande déjà utilisée, cependant,
pour vos propres commandes, vous pouvez utiliser n'importe quel id de commande souhaité.
Pour éviter les conflits, il est préférable d'inclure le nom de l'application dans l'id de la commande.
Un moyen simple d'utilisation des commandes est montré ci-après :
<command id="cmd_openhelp" oncommand="alert('Help!');"/>
<button label="Help" command="cmd_openhelp"/>
Dans cet exemple, au lieu de placer l'attribut oncommand
sur l'élément button
,
nous le plaçons sur un élément command
.
Les deux sont alors liés en utilisant l'attribut command
, qui a la valeur de l'id de la commande.
Ainsi quand le bouton est pressé, la commande est invoquée.
Il y a deux avantages en utilisant cette approche. Premièrement, cela déplace toutes les opérations dans des commandes, qui peuvent être toutes regroupées ensemble dans une seule section de fichier XUL. Cela signifie que ce code est au même endroit, et n'est pas éparpillé dans tout le code de l'interface utilisateur. Le deuxième avantage est que différents boutons et autres éléments de l'interface graphique peuvent être rattachés à une même commande. Par exemple, vous pouvez avoir un item de menu, un bouton d'une barre de boutons et un raccourci clavier pour effectuer la même opération. Plutôt que de répéter le code trois fois, vous pouvez rattacher ces trois éléments à la même commande. Normalement, vous rattacherez seulement les éléments qui enverront un événement de commande.
Si vous spécifiez l'attribut disabled
sur une commande,
elle sera désactivée et ne pourra pas être invoquée. En plus de cela, tous les boutons
et les items de menus qui lui sont rattachés seront désactivés automatiquement.
Si vous réactivez la commande, les boutons deviendront actifs de nouveau.
<command id="cmd_openhelp" oncommand="alert('Aide');"/>
<button label="Aide" command="cmd_openhelp"/>
<button label="Plus d'aide" command="cmd_openhelp"/>
<button label="Désactiver"
oncommand="document.getElementById('cmd_openhelp').setAttribute('disabled','true');"/>
<button label="Activer"
oncommand="document.getElementById('cmd_openhelp').removeAttribute('disabled');"/>
Dans cet exemple, les deux boutons utilisent la même commande. Quand le bouton "désactiver" est pressé, la
commande est désactivée en mettant son attribut disabled
, et les deux
boutons seront aussi désactivés.
Il est usuel de mettre un groupe de commandes à l'intérieur d'un élément
commandset
,
prés du début du fichier XUL, comme ce qui suit :
<commandset>
<command id="cmd_open" oncommand="alert('Open!');"/>
<command id="cmd_help" oncommand="alert('Help!');"/>
</commandset>
Une commande est invoquée quand l'utilisateur active le bouton ou les autres éléments
rattachés à la commande. Vous pouvez aussi invoquer une commande en appelant
la méthode doCommand
, que ce soit de l'élément
command
ou d'un élément rattaché à la commande comme un bouton.
Vous pouvez aussi utiliser les commandes sans utiliser l'élément
command
,
ou, au moins, sans ajouter un attribut oncommand
sur la commande.
Dans ce cas, la commande n'invoquera pas un script directement, mais recherchera à la place
un élément ou une fonction qui traitera la commande.
Cette fonction peut être séparée du XUL lui-même, et peut être embarquée par un élément graphique en interne.
Afin de trouver ce qui traitera la commande, XUL utilise un objet appelé répartiteur de commande
(NdT : command dispatcher).
Cet objet localise le gestionnaire d'une commande. Le gestionnaire d'une commande est appelé contrôleur.
Ainsi, quand une commande est invoquée, le répartiteur de commande localise un
contrôleur qui traite la commande. Vous pouvez déduire que l'élément
command
est un type de contrôleur pour une commande.
Le répartiteur de commandes localise un contrôleur en regardant l'élément sélectionné pour voir si il
a un contrôleur qui gère la commande. Les éléments XUL ont une propriété controllers
qui
est utilisée pour la vérification. Vous pouvez l'utiliser pour ajouter vos propres contrôleurs.
Vous pourriez l'utiliser pour avoir une boîte de liste qui répond aux opérations de couper, copier et
coller. Un exemple sera fourni plus tard.
Par défaut, seules les boîtes de saisie (textbox
) ont un contrôleur fonctionnel. Ce contrôleur gère aussi bien les opérations de presse-papiers, sélection, défaire et refaire
que les opérations d'édition. Notez qu'un élément peut avoir plusieurs contrôleurs, qui
seront alors tous pris en compte.
Si l'élément courant sélectionné n'a pas le contrôleur attendu, la fenêtre sera alors vérifié.
L'élément window
a aussi une propriété controllers
que vous
pouvez modifier comme bon vous semble. Si le focus est à l'intérieur d'une frame, chaque frame parente
est également vérifiée. Cela signifie que les commandes
fonctionneront même si le focus est à l'intérieur d'une frame.
Cela fonctionne bien pour un navigateur : les commandes d'édition invoquées
à partir du menu principal fonctionneront à l'intérieur de la zone de contenu.
Notez que HTML a aussi un système de commandes et de contrôleur, bien que vous
ne pouvez pas l'utiliser sur des pages Web non privilégiées. Mais vous pouvez
l'utiliser, par exemple, dans une extension du navigateur. Si la fenêtre
ne fournit pas un contrôleur capable de gérer la commande, rien ne se passera.
Vous pouvez récupérer le répartiteur de commande en utilisant la propriété
commandDispatcher
de l'objet document
ou pouvez
le récupérer à partir des contrôleurs listés dans un élément ou la fenêtre.
Le répartiteur de commande contient des méthodes pour récupérer les contrôleurs
pour les commandes et pour récupérer et modifier le focus.
Vous pouvez implémenter vos propres contrôleurs pour répondre aux commandes. Vous pouvez tout aussi bien surcharger la gestion par défaut d'une commande en plaçant le contrôleur correctement. Un contrôleur doit implémenter quatre méthodes, qui sont listées ci-dessus :
supportsCommand (command)
isCommandEnabled (command)
doCommand (command)
onEvent (event)
Imaginons que nous voulions implémenter une boîte de liste (listbox
)
qui gère la commande "effacer" (delete
). Quand un utilisateur sélectionne "effacer"
dans le menu, la boîte de liste efface la ligne sélectionnée.
Dans ce cas, vous avez juste à attacher un contrôleur à l'élément listbox
qui exécutera la méthode doCommand
.
Essayez d'ouvrir l'exemple qui suit dans une fenêtre du navigateur et sélectionnez des items de la liste. Vous noterez que la commande "effacer" du menu "édition" du navigateur est activée, et que la choisir effacera la ligne. L'exemple n'est cependant pas complet. Nous devrions nous assurer que la sélection et le focus soient ajustés comme il faut après l'effacement.
Exemple : voir
<window id="controller-example" title="Exemple de contrôleur" onload="init();"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script>
function init()
{
var list = document.getElementById("theList");
var listController = {
supportsCommand : function(cmd){ return (cmd == "cmd_delete"); },
isCommandEnabled : function(cmd){
if (cmd == "cmd_delete") return (list.selectedItem != null);
return false;
},
doCommand : function(cmd){
list.removeItemAt(list.selectedIndex);
},
onEvent : function(evt){ }
};
list.controllers.appendController(listController);
}
</script>
<listbox id="theList">
<listitem label="Océan"/>
<listitem label="Desert"/>
<listitem label="Jungle"/>
<listitem label="Marécage"/>
</listbox>
</window>
Le contrôleur listController
implémente les quatre fonctions
décrites plus haut. La méthode supportsCommand
renvoi
true pour la commande cmd_delete, qui est le nom de
la commande utilisé lorsque l'item de menu "Effacer" est sélectionnée.
Pour les autres commandes, false est renvoyé puisque le contrôleur
ne gère aucune autre commande. Si vous voulez gérer plusieurs commandes,
indiquez les ici, étant donné que vous utiliserez souvent un seul contrôleur
pour plusieurs commandes apparentées.
La méthode isCommandEnabled
renvoi
true si la commande est activée. Dans le cas présent, nous vérifions
si il y a un item sélectionné dans la liste et renvoyons true
si il y en a un. Si il n'y a pas de sélection, false est renvoyé.
Si vous effacez toutes les lignes dans l'exemple, la commande "effacer" deviendra
inactive. Vous aurez à cliquer sur la liste pour mettre à jour le menu dans cet
exemple simple.
La méthode doCommand
sera appelée lorsque l'item de menu "effacer" sera
sélectionné, et cela provoquera l'effacement de la ligne sélectionnée dans la liste.
Rien ne se passera pour la méthode onEvent
, aussi nous n'ajouterons pas
de code pour celle-ci.
Nous attachons le contrôleur à l'élément listbox
en appelant
la méthode appendController
des objets contrôleurs de la liste.
L'objet controller
a un certain nombre de méthodes qui peuvent être utilisées pour manipuler les contrôleurs.
Par exemple, il y a aussi une méthode insertControllersAt
qui insère un contrôleur
dans un élément avant les autres. Cela peut être utile pour surcharger des commandes. Par exemple,
le code suivant desactivera le collage du presse-papiers dans une zone de saisie.
var tboxController = {
supportsCommand : function(cmd){ return (cmd == "cmd_paste"); },
isCommandEnabled : function(cmd){ return false; },
doCommand : function(cmd){ },
onEvent : function(evt){ }
};
document.getElementById("tbox").controllers.insertControllerAt(0,tboxController);
Dans cet exemple, nous inserons le contrôleur à l'index 0,
c'est à dire avant tous les autres. Le nouveau contrôleur supporte la commande
'cmd_paste' et indique qu'elle est désactivée. Le contrôleur par défaut de textbox
ne sera jamais appelé parce que le répartiteur de commande trouve un contrôleur avant celui-ci, prenant
en charge la commande en premier.
Dans la section suivante, nous allons voir comment mettre à jour les commandes.