Table des matières

Entreprises

-- Objectifs

Conception d'une interface complète, en utilisant mappings, inclusions ajax, templates et displays.

-- Liste des entreprises

{#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>

-- Affichage des informations détaillées

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).

-- Création de la vue en lecture seule

{#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>

-- Ajout de la dynamique

	<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>

Tester la page des entreprises, et l'affichage des informations de détail sur changement de la sélection (en bleu)

Débogage éventuel

Mode debug

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.

Site map

L'adresse http://127.0.0.1:8080/kotd6/siteMap.main permet également de visualiser la logique des inclusions ajax :

-- Corrections sur l'affichage de la vue

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"};
	}
}

Tester les modifications

-- Formulaire de modification d'entreprise

-- Création du formulaire

{#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>

-- Modification des contrôles

<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;
    }
}

-- Ajout de la dynamique

-- Mappings

	<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>

-- Inclusions ajax

Formulaire et validation

	<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 :

Annulation

	<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>

Tester le comportement implémenté, sans oublier de redémarrer l'application (à partir de classes.main)

-- Ajustements

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 :

Ajout d'une variable dans le document

	<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>

Tester le comportement implémenté, sans oublier de redémarrer l'application (à partir de classes.main)

-- Action par défaut

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>

Tester le comportement implémenté, et notamment le bon fonctionnement de la touche F2 du clavier, sans oublier au préalable le redémarrage de l'application (à partir de classes.main)

-- Boîte de message et suppression

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>

-- Affichage des évaluations

Sur la liste des entreprises :

  1. Modifier la classe KEntreprise pour qu'elle charge automatiquement ses évaluations
  2. Modifier le Display net.display.EntrepriseDisplay pour afficher les évaluations dans la liste (méthode showInList à modifier)
    1. la colonne Évaluations doit faire apparaître la liste des évaluations (leur date uniquement)
    2. Un clic sur 1 évaluation doit faire apparaître dans une boîte de dialogue l'évaluation cliquée. Il faudra à cet effet :

Concevoir l'interface suivante :