Conception d'une interface complète, en utilisant mappings, inclusions ajax, templates et displays.
{#func:this.setEditable(false)#} {#func:this.addSelector(113)#} {#func:this.setFiltreCaption("Rechercher une entreprise")#} {#set:this.ajaxIncludes=true#} {#set:this.isShowCaption=true#} {#set:this.listContentUrl="entreprises.do"#} {#mask:<td>{rs}</td><td>{adresse}</td><td>{ville}</td><td>{evaluations}</td><td>{F2}</td>#} {#mask:<td>{rs}</td><td>{adresse}</td><td>{ville}</td><td>{evaluations}</td><td>{F2}</td>#} {_ajx} {_listContent} {_filtre} {_page} <div class="boxButtons">{_pageCounter}{_navBarre}</div> {/_listContent} <div id="detail" style="display:none"></div>
Comportement attendu : La zone DOM d'id detail va afficher les informations sur l'entreprise sélectionnée au clavier (flèches de direction) ou à la souris (double clic).
{#set:this.ajaxIncludes=true#} {_fieldset} <div id="divEntrepriseShow"> {rs}{adresse}{mail}{tel}{ville} <div class="boxButtons"><a class="btn" id="btUpdateEntreprise">Modifier l'entreprise</a></div> </div> <div id="divEntrepriseUpdate" style="display: none"> </div> {/_fieldset} </div>
<mappings> ... <mapping requestURL="entrepDetail.do" responseURL="WEB-INF/forms/entreprise.show"/> ... </mappings>
<ajax-includes> ... <request requestURL="entreprises{#(.*?)#}.do"> <js triggerSelector="body" triggerEvent="load"> <include targetURL="entrepDetail.do" targetId="detail" condition="!$('divEntrepriseUpdate')"/> </js> </request> ... </ajax-includes>
<ajax-includes> ... <request requestURL="entreprises{#(.*?)#}.do"> <js triggerSelector="body" triggerEvent="load"> <include targetURL="entrepDetail.do" targetId="detail" condition="!$('divEntrepriseUpdate')"/> </js> <js triggerSelector="#list-KEntreprise" triggerEvent="itemchange" > <refreshFormValues keyValues="{js:e.detail.value}" kobjectShortClassName="KEntreprise" virtualURL="changeEntrep.do"> <showHide targetSelector="#detail" visible="1"/> <showHide targetSelector="#divEntrepriseShow" visible="1"/> </refreshFormValues> </js> </request> ... </ajax-includes>
<mappings> ... <virtualMapping requestURL="changeEntrep.do" mappingFor="refreshFormValues"/> ... </mappings>
Utiliser le mode debug, si le résultat n'est pas conforme à celui attendu :
Il est alors possible de visualiser les inclusions ajax chargées, et leurs dépendances.
L'adresse http://127.0.0.1:8080/kotd6/siteMap.main permet également de visualiser la logique des inclusions ajax :
Nous allons maintenant compléter l'affichage de la vue en agissant sur la classe display (net.display.EntrepriseDisplay) associée à la classe KEntreprise :
public class EntrepriseDisplay extends KObjectDisplay { ... @Override public String getRefreshValue(KObject ko, String memberName, KObjectController koc, HttpServletRequest request) { String result=super.getRefreshValue(ko, memberName, koc, request); if("ville".equals(memberName)){ KEntreprise entreprise=(KEntreprise) ko; if(entreprise.getVille()!=null) result=entreprise.getVille()+""; } if(KString.isNull(result)) result="[non renseigné]"; return result; } @Override public String[] getRefreshFields() { return new String[]{"ville"}; } }
{#formName:frmEntrep#} {#set:this.ajaxIncludes=true#} {_form} {rs}{adresse}{idVille}{mail} {/_form} <div class="boxButtons"> <input type="button" id="btUpdateEntrep" value="Mettre à jour" class="btn"> <input type="button" id="btCancelEntrep" value="Annuler" class="btn"> </div>
<controllers> ... <class name="KEntreprise" caption="Entreprise" display="net.display.EntrepriseDisplay" transformer="net.validation.MyTransformers"> <member max="60" name="rs" required="1" type="string" caption="Raison sociale" transform="xssClean|onlyFirstWordUpper|trim"/> <member max="200" name="adresse" required="0" type="string" caption="Adresse"/> <member max="11" name="idVille" required="1" type="int" caption="Ville" control="radioajaxlist"/> <member max="200" name="mail" required="0" type="mail" caption="Mail"/> <member max="20" name="tel" required="1" type="tel2" caption="Tél." transform="tel"/> </class> ... </controllers>
@SuppressWarnings("serial") public class MyTransformers extends KTransformer { public static String tel(String value){ value=value.replaceAll("(\\d{2}).?(\\d{2}).?(\\d{2}).?(\\d{2}).?(\\d{2})", "$1\\.$2\\.$3\\.$4\\.$5"); return value; } }
<mappings> ... <mapping requestURL="entreprise.do" responseURL="/WEB-INF/forms/entreprise.view"/> <virtualMapping requestURL="submitFormKEntreprise.do" mappingFor="submitForm"/> <mapping requestURL="entreprisesRefresh.do" responseURL="/WEB-INF/list/entreprise.list" queryString="_refresh=true"/> ... </mappings>
<ajax-includes> ... <request requestURL="entrepDetail.do"> <js triggerSelector="#btUpdateEntreprise" triggerEvent="click"> <showHide targetSelector="#divEntrepriseShow" visible="0"/> <showHide targetSelector="#divEntrepriseUpdate" visible="1"/> <includeForm targetId="divEntrepriseUpdate" targetParams="id={js:$('list-KEntreprise').selector.getValue()}" formKobjectShortClassName="KEntreprise" timeout="5000" targetURL="entreprise.do" formTargetId="divEntrepriseUpdate" formName="frmEntrep" formButtonId="btUpdateEntrep" formButtonKeyCode="13"> <include targetURL="entreprisesRefresh.do" targetId="_ajxContent"/> <message targetId="info">'Entreprise modifiée'</message> </includeForm> </js> </request> ... </ajax-includes>
* Dans la vue entrepDetail.do, un clic sur le bouton btUpdateEntreprise :
<ajax-includes> ... <request requestURL="entreprise.do"> <js triggerSelector="#btCancelEntrep" keyCode="27"> <message targetId="divEntrepriseUpdate">''</message> <showHide targetSelector="#divEntrepriseShow" visible="1"/> <message targetId="info">'Modifications annulées'</message> </js> </request> ... </ajax-includes>
Pour terminer, il s'agit d'empêcher le déplacement de la sélection dans la liste, lorsqu'une entreprise est en cours de modification dans le formulaire :
<ajax-includes> ... <request requestURL="entreprise.do"> <js triggerSelector="input" triggerEvent="change"> <function script="document.insertMode=true;"/> </js> <js triggerSelector="#btCancelEntrep" keyCode="27"> <message targetId="divEntrepriseUpdate">''</message> <showHide targetSelector="#divEntrepriseShow" visible="1"/> <function script="document.insertMode=false;"/> <message targetId="info">'Modifications annulées'</message> </js> </request> ... </ajax-includes>
<ajax-includes> ... <request requestURL="entrepDetail.do"> <js triggerSelector="#btUpdateEntreprise"> <showHide targetSelector="#divEntrepriseShow" visible="0"/> <showHide targetSelector="#divEntrepriseUpdate" visible="1"/> <includeForm targetId="divEntrepriseUpdate" targetParams="id={js:$('list-KEntreprise').selector.getValue()}" formKobjectShortClassName="KEntreprise" timeout="5000" targetURL="entreprise.do" transition="opacityShow" formTargetId="divEntrepriseUpdate" formName="frmEntrep" formButtonId="btUpdateEntrep" formButtonKeyCode="13"> <include targetURL="entreprisesRefresh.do" targetId="_ajxContent"/> <message targetId="info">'Entreprise modifiée'</message> <function script="document.insertMode=false;"/> </includeForm> </js> </request> ... </ajax-includes>
<ajax-includes> ... <request requestURL="entreprises{#(.*?)#}.do"> ... <js triggerSelector="#list-KEntreprise" triggerEvent="itemchange" > <function script="if(document.insertMode) e.preventDefault();"/> <refreshFormValues keyValues="{js:e.detail.value}" kobjectShortClassName="KEntreprise" virtualURL="changeEntrep.do" condition="!document.insertMode"> <showHide targetSelector="#detail" visible="1"/> <showHide targetSelector="#divEntrepriseShow" visible="1"/> <message targetId="divEntrepriseUpdate">''</message> <function script="document.insertMode=false;"/> </refreshFormValues> <message targetId="info" condition="document.insertMode==true"><![CDATA['<span class=\'errMessage\'>Impossible de changer d\'entreprise avant validation ou annulation</span>']]></message> </js> ... </request> ... </ajax-includes>
Dans une liste avec sélection (comme celle des entreprises), la touche F2 du clavier permet de déclencher le clic sur un élément de la ligne sélectionnée, dont la classe css est default. Nous allons ajouter cet élément, et l'associer à l'édition de l'entreprise sélectionnée :
{#func:this.setEditable(false)#} {#func:this.addSelector(113)#} {#func:this.setFiltreCaption("Rechercher une entreprise")#} {#set:this.ajaxIncludes=true#} {#set:this.isShowCaption=true#} {#set:this.listContentUrl="entreprises.do"#} {#mask:<td>{rs}</td><td>{adresse}</td><td>{ville}</td><td>{evaluations}</td><td>{F2}</td>#} {#mask:<td>{rs}</td><td>{adresse}</td><td>{ville}</td><td>{evaluations}</td><td>{F2}</td>#} {_ajx} {_listContent} {_filtre} {_page} <div class="boxButtons">{_pageCounter}{_navBarre}</div> {/_listContent} <div id="detail" style="display:none"></div>
public class EntrepriseDisplay extends KObjectDisplay { ... @Override public String getCaption(KObject ko, String memberName) { String result=super.getCaption(ko, memberName); if(memberName.equals("F2")){ result=""; } return result; } @Override public String showInList(KObject ko, String memberName) { String result= super.showInList(ko, memberName); if(memberName.equals("F2")){ result="<span class='default'></span>"; } return result; } ... }
<ajax-includes> ... <request requestURL="entreprises{#(.*?)#}.do"> ... <js triggerSelector="#list-KEntreprise .default"> <fireEvent triggerId="btUpdateEntreprise"/> </js> ... </request ... </ajax-includes>
Il s'agit maintenant de permettre la suppression d'une entreprise, sur frappe de la touche SUPPR du clavier (code 46), en ayant au préalable un message de confirmation.
<ajax-includes> ... <request requestURL="entreprises{#(.*?)#}.do"> ... <js triggerSelector="document" triggerEvent="keyup" keyCode="46"> <messageDialog title="Suppression d'entreprise" transition="rotation10"> <button caption="Oui"> <deleteOne virtualURL="deleteEntrep.do" kobjectShortClassName="KEntreprise" targetId="_ajx"> <include targetURL="entreprisesRefresh.do" targetId="_ajxContent"/> </deleteOne> <function script="return true;"/> </button> <button caption="Annuler"> <function script="return true;"/> </button> <message><![CDATA['Supprimer l\'entreprise <b>'+Forms.Utils.getFirstChild($('list-KEntreprise').selector.getSelectedElement(),'td').innerHTML+'</b> ?' ]]></message> </messageDialog> </js> ... </request> ... </ajax-includes>
Ajouter les 2 mappings utilisés dans mox.xml :
<mappings> ... <mapping requestURL="entreprisesRefresh.do" responseURL="/WEB-INF/list/entreprise.list" queryString="_refresh=true"/> <virtualMapping mappingFor="deleteOne" requestURL="deleteEntrep.do"/> ... <mappings>
Sur la liste des entreprises :
Concevoir l'interface suivante :