Utilisation de CForms avec Xdepo
Les formulaires permettant de modifier et saisie des documents XML dans Xdepo sont basés sur la technologie CForms du projet Apache Cocoon . Toutefois, afin de faciliter le développement de certains formulaires et pour permettre leur parfaite intégration dans l'environnement Xdepo, quelques consignes d'utilisation sont nécessaires. Ce document présente ces consignes ainsi que les principaux éléments CForms.
Nous encourageons vivement les lecteurs qui souhaitent développer leur propres formulaires de consulter la documentation CForms de Cocoon ainsi que les exemples livrés avec cette plate-forme.
1) Localisation des fichiers
Chaque document modifiable par un formulaire dans Xdepo est associé à un type de données . Pour un type de données, il peut y avoir plusieurs formulaires. Xdepo connaît les types de données et les formulaires mis à disposition dans une installation en explorant les dossiers et fichiers disponibles à un endroit bien précis.
Prenons comme exemple un type de données dc pour la base de données dont le code est test . S'il y a deux formulaires associés à ce type de données, la structure des fichiers serait la suivante :
01 xdepo-local/datatypes 02 test 03 dc 04 forms 05 forms.xml 06 form1 07 binding.xml 08 default.xml 09 display.xml 10 form.xml 11 form2 12 binding1.xml 13 binding2.xml 14 default.xml 15 display1.xml 16 display2.xml 17 form1.xml 18 form2.xml
Sur la ligne 5, le fichier forms.xml fournit des informations sur les formulaires disponibles, permettant de leur donner un nom en différentes langues. Ce nom sera affiché dans la liste déroulante du menu de création d'un document.
Ensuite, les dossiers form1 et form2 contiennent tous deux les fichiers de spécification d'un formulaire. Il y a toujours quatre types de fichiers pour un formulaire : binding , default , display et form . Le rôle de ces fichiers est expliqué plus loin dans cette documentation.
Si un formulaire est présenté sur plusieurs pages, on doit répété les fichiers binding , display et form en ajoutant comme suffixe un chiffre (1, 2, ...) qui indique l'ordre des pages. Le formulaire form2 dans l'exemple ci-dessus contient des fichiers de spécification pour un formulaire de deux pages.
2) Le fichier forms.xml
C'est dans ce fichier que vous indiquerez la liste des formulaires disponibles pour un type de données particulier.
Cette liste respecte le format des listes Cforms/Xdepo, comme l'illustre l'exemple ci-dessous :
<fd :selection -list xmlns :fd="http ://apache.org /cocoon/forms/1.0#definition "> <fd:item value="form1"> <fd:label>Mon premier formulaire</fd:label> </fd:item> <fd:item value="form2"> <fd:label>Mon second formulaire</fd:label> </fd:item> </fd:selection-list>
A noter que pour les étiquettes, insérées dans l'élément <fd:label> , il est préférable d'utiliser des balises i18n afin de pouvoir les afficher en différentes langues.
3) Le fichier default.xml
Ce fichier contient le modèle par défaut pour les documents édités à l'aide de ce formulaire. Un modèle est un document XML qui contient des valeurs déjà saisies ou au moins la structure de base.
Voici quelques considérations à propos de ce fichier et des modèles de documents en général :
- si un élément de default.xml n'est pas traité par le formulaire, il sera recopié tel quel dans le document ;
- s'il est traité, il sera remplacé par la ou les valeurs fournies par le formulaire ;
- le formulaire peut traiter des éléments non présents dans le modèle ;
- la valeur d'un élément de du modèle servira de valeur par défaut lors de la présentation de l'élément dans le formulaire.
Il est impératif d'ajouter l'attribut xdepo:datatype à l'élément racine de tout modèle, incluant le fichier default.xml . Il doit être de la forme datatypes/[code de base de données]/forms/form[numéro du formulaire] .
Il peut aussi inclure l'attribut xdepo: savetype , pour lequel 3 valeurs sont possibles :
- auto : l'identifiant Xdepo du document sera généré automatiquement ;
- set : l'identifiant Xdepo du document est entré manuellement lors de la saisie ;
- append : l'identifiant Xdepo est le fruit de la concaténation d'un identifiant automatique et d'un identifiant saisi manuellement.
On ne doit pas oublier de déclarer l'espace de nom Xdepo dans ce document :
<test xmlns:xdepo="http://xdepo.org /xdepo/1.0" xdepo:datatype="datatypes/test/forms/form1"> <identifier>Identifiant par défaut</identifier> <title >Titre par défaut</title> </test>
4) Le fichier form.xml
Dans ce fichier, on y déclare les différents contrôles (widgets ) dans le formulaire. On peut donc considérer que ce fichier contient la définition de base des éléments du formulaire, qui seront réutilisés par ailleurs. Dans la terminologie Cocoon, il s'agit du form definition file .
Pour des informations complètes sur la structure de ce fichier et des contrôles qu'il peut contenir, voir la documentation de Cocoon à ce sujet , et en particulier la partie sur les widgets .
5) Le fichier display.xml
Ce fichier va servir à la mise en page du formulaire, en s'appuyant sur la définition des contrôles dans le fichier form.xml . Dans la terminologie Cocoon, il s'agit du form template .
Vous pouvez mettre le contenu que vous souhaitez dans ce document, puisqu'il ne définit que la mise en page des formulaires. Toutefois, si vous souhaitez rester dans la logique des formulaires Xdepo et de leur intégration dans l'application, voici quelques consignes utiles.
L'élément racine est document . Vient ensuite un élément header , dans lequel on donne le titre de la page et les liens vers les feuilles de style CSS :
<header> <title> <i18n:text>Test Form</i18n:text> </title> <style href="lib/xdepo/css/viewer.css"/> </header>
Ensuite, vous pouvez insérer dans le corps du document un entête qui permettra d'afficher l'identifiant du document en cours de création (s'il existe) :
<body>
<div class="main">
<div class="infocontext">
<p><i18n:text>Test Form</i18n:text> : ${cocoon.request.doc}</p>
</div>
...
</div>
</body>
Ensuite, vous pouvez insérer le formulaire lui-même, en y mettant sa définition générale. Dans l'environnement Xdepo, il faut lui mettre les informations suivantes :
- action : #{$continuation/id}.continue?uri=${cocoon.request.uri}&doc=${cocoon.request.doc}
- méthode : POST
- en cas de chargement de documents (file upload ), l'attribut enctype="multipart/form-data"
Voici ce que ça peut donner :
<ft:form-template
method="POST"
action="#{$continuation/id}.continue?uri=${cocoon.request.uri}&doc=${cocoon.request.doc}"
enctype="multipart/form-data">
Vous pouvez ensuite insérer le formatage des erreurs de validation, histoire de les avoir en début de page, comme ceci :
<fi:validation-errors> <header> <i18n:text key="validation.errors.header"/> </header> <footer> <i18n:text key="validation.errors.footer"/> </footer> </fi:validation-errors>
Le résultat à l'écran sera de la forme suivante :
|
Pour le formatage du formulaire, utiliser un tableau défini ainsi :
<table align="center" class="general"> <tbody> l'entête les éléments du formulaire la navigation </tbody> </table>
L'entête du formulaire aura la structure HTML suivante :
<tr> <td colspan="2" align="center" class="formHeader">Description</td> </tr>
A l'écran, vous retrouverez un formatage tel que :
|
Pour naviguer entre les différentes pages d'un formulaire multi-pages, vous pouvez utiliser trois types de boutons définis ainsi :
- précédant : <input type="submit" name="prev" value="Prev" i18n:attr="value"/>
- suivant : <input type="submit" name="next" value="Next" i18n:attr="value"/>
- sauvegarder : <input type="submit" name="save" value="Save" i18n:attr="value"/>
La structure HTML sera de la sorte :
<tr> <td colspan="1" align="left"> <input type="submit" name="prev" value="Prev" i18n:attr="value"/> </td> <td colspan="1" align="right"> <input type="submit" name="save" value="Save" i18n:attr="value"/> </td> </tr>
A l'écran, vous retrouverez un formatage tel que :
|
Plusieurs contrôles non répétables dans un formulaire seront traités selon ce modèle :
<tr class="groupe"> <td class="label"> label de l'élément </td> <td class="value"> valeur de l'élément </td> </tr>
Le résultat à l'écran sera semblable à :
|
L'élément <ft:widget-label> contient l'étiquette associée au formulaire. Toutefois, il ne peut pas être récupéré dans les XSLT de formatage car il est disponible uniquement sous forme de noeud texte. Il faut trouver un moyen de contourner ce problème :
- soit en l' imbriquant dans un élément d'espace de nom Xdepo ;
- soit en modifiant le code Cforms inclus dans Xdepo.
On voudrait pouvoir le traiter pour lui associer la bulle d'aide et l'astérisque des contrôles obligatoires.
L'élément <ft:widget> permet d'afficher le contrôle lui-même. On peut lui rajouter un sous élément <fi:styling> pour surcharger sa mise en forme par défaut. Actuellement, l'astérisque de champ obligatoire, l'aide et l'alerte de validation lui sont associés.
L'élément < fd:field> sans liste définit un contrôle de type zone de texte simple. Avec un sous-élément fi:styling on peut styler, classer, donner un taille à ce contrôle.
<ft:widget id="id1"> <fi:styling size="40" style="background-color:purple; color:white;"/> </ft:widget> <ft:widget id="id2"> <fi:styling class="forms-field-required"/> </ft:widget>
Voici des exemples de formatage :
|
L'élément fi:styling type=" hidden " permet de définir un champ caché.
L'élément fi:styling type=" textarea " permet d'afficher une zone de texte à plusieurs lignes. Par exemple :
<ft:widget id="id3"> <fi:styling type="textarea" style="background-color:yellow ;"/> </ft:widget>
Le format d'affichage sera tel que :
|
L'élément fi:styling type="htmlarea" permet d'afficher une zone de texte riche. Par exemple :
<ft:widget id="id4"> <fi:styling type="htmlarea" /> </ft:widget>
A l'écran vous obtiendrez un contrôle complexe tel que :
|
Pour afficher une liste, il existe différentes options. Voici l'affichage par défaut :
|
Pour une sortie avec des boutons radio, utiliser le formatage fi:styling list-type="radio" ainsi :
<ft:widget id="category6"> <fi:styling list-type="radio"/> </ft:widget>
Vous obtiendrez à l'écran quelque chose du genre :
|
Vous pouvez disposer les mêmes boutons radios à l'horizontal en mod_fiant légèrement l'instruction de mise en forme avec fi:styling list-type="radio" list-orientation="horizontal" , comme dans cet exemple :
<ft:widget id="category6"> <fi:styling list-type="radio" list-orientation="horizontal"/> </ft:widget>
Le formatage sera tel que :
|
Pour obtenir une liste non déroulante mais plutôt à hauteur fixe, utiliser fi:styling list-type="listbox" listbox-size="" , tel que :
<ft:widget id="category2"> <fi:styling list-type="listbox" listbox-size="10"/> </ft:widget>
Vous obtiendrez à l'écran :
|
Si vous optez pour une liste à plusieurs valeurs, utiliser le code fd: multivaluefield et la sortie par défaut sera de la sorte :
|
Le code fi:styling list-type="listbox" listbox-size="" permet de spécifier la taille de la liste multiple. Attention, dans ce cas précis il n'y aura pas d'ascenseur, donc il ne faut pas donner une taille inférieure au nombre d'items dans la liste.
<ft:widget id="toto"> <fi:styling list-type="listbox" listbox-size="5"/> </ft:widget>
Pour présenter les valeurs de la liste dans des cases à cocher, utiliser fi:styling list-type=" checkbox " , comme dans l'exemple suivant :
<ft:widget id="toto"> <fi:styling list-type="checkbox"/> </ft:widget>
Le formatage sera tel que :
|
Pour obtenir une liste double, c'est-à-dire une liste qui permet de sélectionner des items et une autre qui permet de voir les items déjà sélectionnées, utiliser fi:styling list-type="double-listbox" listbox-size="" , comme dans cet exemple :
<ft:widget id="toto2"> <fi:styling list-type="double-listbox" listbox-size="4"/> </ft:widget>
Le formatage sera tel que :
|
Il est souvent intéressant de regrouper des contrôles pour indiquer à l'utilisateur que ces contrôles ont des caractéristiques communes ou qu'ils concernent le même type d'information. Pour ce faire, vous pouvez utiliser une structure HTML telle que celle-ci :
<tr class="groupe"> <td colspan="2"> <fi:group> <fi:styling type="tabs "/> <fi:state > <ft:widget id="tab -state "/> </fi:state > <fi:items> <fi:group> <fi:label>Par colonnes</fi:label> <fi:styling layout ="columns "/> <fi:items> <ft:widget id="identifier"/> <ft:widget id="title"/> <ft:widget id="access -control "/> </fi:items> </fi:group> <fi:group> <fi:label>Par lignes</fi:label> <fi:styling layout ="rows "/> <fi:items> <ft:widget id="size"/> <ft:widget id="accrual "/> </fi:items> </fi:group> <fi:group> <fi:label>Par colonne</fi:label> <fi:styling layout="column "/> <fi:items> <ft:widget id="standards"/> <ft:widget id="legal-status"/> </fi:items> </fi:group> <fi:group> <fi:label>Par ligne</fi:label> <fi:styling layout="row "/> <fi:items> <ft:widget id="title2"/> <ft:widget id="title3"/> </fi:items> </fi:group> </fi:items> </fi:group> </td> </tr>
Avec le code fi:styling type=" tabs " , on obtiendra un regroupement par onglets tel qu'illustré ici :
|
Avec le code fi:styling type=" choice " , le regroupement se fait avec un choix par liste déroulante :
|
Avec le code fi:styling type="fieldset ", le regroupement se fait dans un fieldset HTML tel que :
|
Avec un code fi:styling layout="columns" vous obtiendrez une colonne pour les étiquettes et une colonne pour les champs :
|
Le code fi:styling layout="rows" permet d'obtenir une ligne pour les étiquettes et une ligne pour les champs :
|
Le code fi:styling layout="column" permet d'obtenir tout sur la même colonne :
|
Le code fi:styling layout="row" permet d'obtenir tout sur la même ligne :
|
Certains champs peuvent être répétables. Pour les afficher correctement, incluant les boutons permettant d'ajouter ou supprimer des occurrences, utiliser le code HTML suivant dans le fichier display.xml :
<tr class="groupe"> <td colspan="2"> <fi:group> <fi:styling type="fieldset"/> <fi:label> le label du repeater le bouton add </fi:label> <fi:items> <ft:repeater-widget id="descriptions"> <fi:group> **********quand il y a des sous-éléments***************** <fi:styling type="fieldset"/> <fi:label> le bouton remove le bouton up le bouton down </fi:label> <fi:items> <table align="center"> <tbody> les sous-éléments </tbody> </table> </fi:items> **********sans sous-éléments***************** <fi:label/> <fi:items> le bouton remove le bouton up le bouton down la valeur de l'élément </fi:items> </fi:group> </ft:repeater-widget> </fi:items> </fi:group> </td> </tr>
L'élément ft:repeater-widget-label id="" widget-id="" permet d'afficher l'étiquette du champ répétable, avec les mêmes remarques que pour le code ft:widget-label ci-dessus.
Le bouton d'ajout d'une occurrence peut être inclus ainsi :
<ft:widget id="add{id}">
<xdepo:button type="img" role="add" code="{id}"/>
</ft:widget>
Le bouton de suppression d'une occurrence peut être inclus ainsi :
<ft:widget id="remove{id}">
<xdepo:button type="img" role="remove" code="{id}"/>
</ft:widget>
Le bouton permettant de déplacer une occurrence avant la précédente (remonter) peut être inclus ainsi :
<ft:widget id="up{id}">
<xdepo:button type="img" role="up" code="{id}"/>
</ft:widget>
Le bouton permettant de déplacer une occurrence après la suivante (descendre) peut être inclus ainsi :
<ft:widget id="down{id}">
<xdepo:button type="img" role="down" code="{id}"/>
</ft:widget>
Ces différents boutons auront la forme suivante :
|
6) Le fichier binding.xml
Ce fichier contient les instructions qui permettent de lier les éléments du formulaire avec la structure XML du document à modifier ou créer. Ainsi, si vous souhaitez que le contrôle de nom id du formulaire devienne l'élément identifier du document XML, c'est dans le fichier binding.xml que vous devrez le spécifier. Dans la terminologie Cocoon, il s'agit du binding framework .
7) Les balises i18n
Il est possible de générer le contenu textuel des pages des formulaires à l'aide d'instructions I18n de Cocoon, ainsi :
<i18n:text i18n:catalogue="forms" key="test.identifier ">Identifiant par défaut</i18n:text>
Cela signifie que si vous disposez d'un catalogue michael-forms et que ce dernier possède une entrée de type telle que <message key="test.identifier">Mon identifiant</message> alors votre balise i18n sera remplacée par le texte fourni par le catalogue, ici Mon identifiant . Dans le cas contraire la valeur sera le contenu textuel de la balise i18n, soit Identifiant par défaut .
Les catalogues sont référencés dans le fichier xdepo- system/sitemap /sitemap1.xmap ainsi :
<catalogue id="michael-forms" name ="michael-forms" location="xdepo-local/translations"/>
L'attribut id correspond à la valeur de l'attribut i18n:catalogue de la balise i18n:text . L'attribut name renseigne le début du nom du fichier XML correspondant au catalogue, il doit être suivi de _{langue ou locale}. xml .
L'attribut location indique la localisation du catalogue. On a donc ici un catalogue correspondant aux fichiers (pour une application franco-anglaise) :
- xdepo- local/translations/michael-forms_fr.xml
- xdepo-local/translations/michael-forms_en.xml
La forme du catalogue est telle que :
<catalogue xml:lang="{la locale ex: fr}">
<message key="test.identifier">identifier</message>
<messages key="...">...</message>
...
</catalogue>
De même, dans une balise il est possible de spécifier un attribut i18n:attr={un_nom_d'attribut_de_la_balise un_autre_nom ...} (chaque valeur est séparée par un espace) pour que ces attributs soient traités selon le mécanisme i18n.
La documentation de Cocoon fournit plus d'information sur les mécanismes i18n.