Subversion Repositories eFlore/Applications.cel

Rev

Rev 1008 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1008 Rev 1011
Line 2... Line 2...
2
 
2
 
3
import org.tela_botanica.client.image.ImageMediateur;
3
import org.tela_botanica.client.image.ImageMediateur;
Line 4... Line 4...
4
import org.tela_botanica.client.interfaces.Rafraichissable;
4
import org.tela_botanica.client.interfaces.Rafraichissable;
-
 
5
 
-
 
6
import com.google.gwt.user.client.Window;
5
 
7
import com.google.gwt.user.client.ui.HTML;
6
import com.google.gwt.user.client.Window;
8
import com.google.gwt.user.client.ui.Label;
7
import com.gwtext.client.core.EventObject;
9
import com.gwtext.client.core.EventObject;
8
import com.gwtext.client.data.Node;
10
import com.gwtext.client.data.Node;
9
import com.gwtext.client.data.NodeTraversalCallback;
11
import com.gwtext.client.data.NodeTraversalCallback;
10
import com.gwtext.client.data.Tree;
12
import com.gwtext.client.data.Tree;
11
import com.gwtext.client.widgets.Button;
13
import com.gwtext.client.widgets.Button;
12
import com.gwtext.client.widgets.Panel;
14
import com.gwtext.client.widgets.Panel;
-
 
15
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
13
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
16
import com.gwtext.client.widgets.form.TextField;
14
import com.gwtext.client.widgets.form.TextField;
17
import com.gwtext.client.widgets.layout.FitLayout;
15
import com.gwtext.client.widgets.layout.VerticalLayout;
18
import com.gwtext.client.widgets.layout.VerticalLayout;
16
import com.gwtext.client.widgets.tree.TreeEditor;
19
import com.gwtext.client.widgets.tree.TreeEditor;
17
import com.gwtext.client.widgets.tree.TreeNode;
20
import com.gwtext.client.widgets.tree.TreeNode;
Line 23... Line 26...
23
 * clés cochables et réorganisables à volonté
26
 * clés cochables et réorganisables à volonté
24
 * 
27
 * 
25
 * @author aurelien
28
 * @author aurelien
26
 * 
29
 * 
27
 */
30
 */
28
public class ArbreMotsClesVue extends Panel implements Rafraichissable {
31
public class ImageMotsClesVue extends Panel implements Rafraichissable {
Line 29... Line 32...
29
 
32
 
30
	/**
-
 
31
	 * Le médiateur associé à la vue
-
 
32
	 */
-
 
33
	private ImageMediateur iMediateur = null;
-
 
34
 
-
 
35
	/**
-
 
36
	 * Le treepanel qui affiche l'arbre
-
 
37
	 */
-
 
38
	private TreePanel arbreMotsCles = null;
-
 
39
	/**
-
 
40
	 * L'éditeur qui permet de modifier les mots clés dans l'arbre
-
 
41
	 */
-
 
42
	private TreeEditor te = null;
-
 
43
	/**
-
 
44
	 * Le textfield associé à l'éditeur
-
 
45
	 */
-
 
46
	private TextField tfEdit = null;
-
 
47
	/**
-
 
48
	 * Bouton de validation
-
 
49
	 */
-
 
50
	private Button valider = null;
-
 
51
	/**
33
	/**
52
	 * Une string permettant connaitre les mots clés cochés en cours séparés par
34
	 * Une string permettant connaitre les mots clés cochés en cours séparés par
53
	 * des virgules
35
	 * des virgules
54
	 */
36
	 */
Line 59... Line 41...
59
	 * Tableau contenant les mots clés qui n'ont pas encore été jaouté à l'arbre
41
	 * Tableau contenant les mots clés qui n'ont pas encore été jaouté à l'arbre
60
	 * (sert au lazy rendering quand on reçoit des mots clés avant que le rendu
42
	 * (sert au lazy rendering quand on reçoit des mots clés avant que le rendu
61
	 * du conteneur n'ai été effectué)
43
	 * du conteneur n'ai été effectué)
62
	 */
44
	 */
63
	private String[] motsClesEnAttente = new String[0];
45
	private String[] motsClesEnAttente = new String[0];
64
	/**
-
 
65
	 * Booléen d'évènement qui sert à savoir si on est en train d'ajouter un
-
 
66
	 * noeud
-
 
67
	 */
-
 
68
	private boolean ajoutNoeud = false;
-
 
69
	/**
46
	
70
	 * Booléen d'évènement qui sert à savoir si on est en train de modifier un
-
 
71
	 * noeud
-
 
72
	 */
-
 
73
	private boolean modifNoeud = false;
-
 
74
	/**
-
 
75
	 * Booléen d'instanciation du conteneur
-
 
76
	 */
-
 
77
	private boolean arbreCharge = false;
-
 
78
	/**
-
 
79
	 * Booléen d'évènement qui sert à savoir si les mots clés ont bien été reçu
-
 
80
	 */
-
 
81
	private boolean motsCleInitialises;
47
	private HTML motsClesAffiches = new HTML();
Line 82... Line 48...
82
 
48
 
83
	/**
49
	/**
84
	 * Constructeur sans paramètre (privé car interdit d'utilisation)
50
	 * Constructeur sans paramètre (privé car interdit d'utilisation)
85
	 */
51
	 */
86
	@SuppressWarnings("unused")
52
	@SuppressWarnings("unused")
87
	private ArbreMotsClesVue() {
53
	private ImageMotsClesVue() {
88
		super();
54
		super();
Line 89... Line 55...
89
	}
55
	}
90
 
56
 
91
	/**
57
	/**
92
	 * Constructeur avec paramètre
58
	 * Constructeur avec paramètre
93
	 * 
59
	 * 
94
	 * @param im
60
	 * @param im
95
	 *            le médiateur à associer
61
	 *            le médiateur à associer
96
	 */
62
	 */
97
	public ArbreMotsClesVue(ImageMediateur im) {
63
	public ImageMotsClesVue(ImageMediateur im) {
98
		// on crée le panel
-
 
99
		super("Mots clés");
-
 
100
		this.setLayout(new VerticalLayout());
-
 
101
		iMediateur = im;
-
 
102
 
-
 
103
		// on crée le conteneur de l'arbre
-
 
104
		arbreMotsCles = new TreePanel();
-
 
105
		// on permet le drag and drop dans l'arbre
-
 
106
		arbreMotsCles.setEnableDD(true);
-
 
107
		arbreMotsCles.setId("x-view-tree-keyword");
-
 
108
 
-
 
109
		// on crée une racine pour l'arbre
64
		// on crée le panel
110
		TreeNode root = new TreeNode("Tags");
-
 
111
		root.setId("racine");
-
 
112
		String[] usObject = { "Mots clés", "racine" };
-
 
113
		root.setUserObject(usObject);
-
 
114
		arbreMotsCles.setRootNode(root);
65
		super("Mots clés");
115
		arbreMotsCles.setRootVisible(true);
66
		this.setHeight("100%");
116
		arbreMotsCles.setBorder(false);
-
 
117
		arbreMotsCles.setWidth(500);
-
 
118
 
-
 
119
		// on crée l'éditeur pour l'arbre
-
 
120
		tfEdit = new TextField();
-
 
121
		tfEdit.setAutoWidth(true);
-
 
122
		te = new TreeEditor(arbreMotsCles, tfEdit);
-
 
123
		valider = new Button("Appliquer");
-
 
124
		arbreMotsCles.add(te);
-
 
125
 
-
 
126
		// on met en forme le layout
-
 
127
		this.add(arbreMotsCles);
67
		this.add(motsClesAffiches);
128
		this.add(valider);
68
		motsClesAffiches.setHeight("100%");
-
 
69
		
129
 
70
		this.setBorder(false);
130
		this.setBorder(false);
71
		this.setBodyBorder(false);
131
		this.setCollapsible(true);
-
 
132
		this.setTitleCollapse(true);
-
 
133
		
-
 
134
		// on ajoute les listeners
-
 
135
		ajouterListeners();
-
 
136
 
-
 
137
	}
-
 
138
 
-
 
139
	/**
-
 
140
	 * Acesseur pour le médiateur
-
 
141
	 * 
-
 
142
	 * @return le médiateur associé à la vue
-
 
143
	 */
-
 
144
	private ImageMediateur getIMediateur() {
-
 
Line 145... Line 72...
145
 
72
		this.setCollapsible(true);
Line 146... Line 73...
146
		return iMediateur;
73
		this.setTitleCollapse(true);
147
 
-
 
148
	}
-
 
149
 
-
 
150
	/**
-
 
151
	 * Acesseur pour l'arbre des mots clés
-
 
152
	 * 
-
 
153
	 * @return le panel contenant l'arbre
-
 
154
	 */
-
 
155
	public TreePanel getArbreMotsCles() {
-
 
156
		return arbreMotsCles;
-
 
157
	}
-
 
158
 
-
 
159
	/**
-
 
160
	 * Accesseur pour l'éditeur
-
 
161
	 * 
-
 
162
	 * @return l'éditeur associé à l'arbre
-
 
163
	 */
-
 
164
	public TreeEditor getTe() {
-
 
165
		return te;
-
 
166
	}
-
 
167
 
-
 
168
	/**
-
 
169
	 * Acesseur pour le TextField associé à l'éditeur
-
 
170
	 * 
-
 
171
	 * @return le champ texte associé à l'éditeur
-
 
172
	 */
-
 
173
	public TextField getTfEdit() {
-
 
174
		return tfEdit;
-
 
175
	}
-
 
176
 
-
 
177
	/**
-
 
178
	 * Ajoute les listeners nécessaires pour la gestion des évènements
-
 
179
	 */
-
 
180
	private void ajouterListeners() {
-
 
181
						
-
 
182
		arbreMotsCles.addListener(new TreePanelListenerAdapter() {
-
 
183
			
-
 
184
			public void onExpandNode(TreeNode node) {		
-
 
185
				cocherMotsCles(tableauMotsClesEnCours);
-
 
186
			}
-
 
187
 
-
 
188
			// gestion du clic sur un noeud
-
 
189
			public void onClick(TreeNode node, EventObject e) {
-
 
190
 
-
 
191
				e.stopEvent();
-
 
192
				gererClicNoeud(node);
-
 
193
			}
-
 
194
 
-
 
195
			// gestion du clic droit sur un noeud
-
 
196
			public void onContextMenu(TreeNode node, EventObject e) {
-
 
197
 
-
 
198
				e.stopEvent();
-
 
199
				getIMediateur().montrerContextMenuArbre(node, e, getTe());
-
 
200
 
-
 
201
			}
-
 
202
 
-
 
203
			// gestion du double clic sur un noeud
-
 
204
			public void onDblClick(TreeNode node, EventObject e) {
-
 
205
 
-
 
206
				modifNoeud = true;
-
 
207
				if (!node.getId().equals("racine")) {
-
 
208
					te.startEdit(node);
-
 
209
				}
-
 
210
			}
-
 
211
 
-
 
212
			// gestion de la modification du texte d'un noeud
-
 
213
			public void onTextChange(TreeNode node, String text, String oldText) {
-
 
214
 
-
 
215
				// on récupère les informations associées au noeud
-
 
216
				TreeNode nd = node;
-
 
217
				String[] usObject = new String[2];
-
 
218
				usObject[0] = text;
-
 
219
				usObject[1] = ((String[]) nd.getUserObject())[1];
-
 
220
				nd.setUserObject(usObject);
-
 
221
 
-
 
222
				// si c'est un nouveau noeud
-
 
223
				if (ajoutNoeud) {
-
 
224
					// on considère l'ajout achevé
-
 
225
					ajoutNoeud = false;
-
 
226
					// et on notifie le médiateur de l'ajout et on lui passe
-
 
227
					// l'arbre
-
 
228
					getIMediateur().ajouterMotCleDansArbre(nd,
-
 
229
							getArbreMotsCles().getTree());
-
 
230
				}
-
 
231
				// si c'est noeud déjà existant
-
 
232
				else {
-
 
233
					// on considère la modification achevée
-
 
234
					modifNoeud = false;
-
 
235
					
-
 
236
					if(!text.equals(oldText)) {
-
 
237
						// et on notifie le médiateur de la modification et on lui
-
 
238
						// passe l'arbre
-
 
239
						getIMediateur().modifierMotCleDansArbre(nd,
-
 
240
								getArbreMotsCles().getTree());
-
 
241
					}
-
 
242
				}
-
 
243
 
-
 
244
			}
-
 
245
 
-
 
246
			// gestion du déplacement d'un noeud
-
 
247
			public void onMoveNode(Tree tree, TreeNode node,
-
 
248
					TreeNode oldParent, TreeNode newParent, int index) {
-
 
249
				// on notifie le médiateur et on lui passe l'arbre
-
 
250
				getIMediateur().deplacerMotCleDansArbre(node,
-
 
251
						getArbreMotsCles().getTree());
-
 
252
			}
-
 
253
 
-
 
254
		});
-
 
255
 
-
 
256
		// gestion de la validation
-
 
257
		valider.addListener(new ButtonListenerAdapter() {
-
 
258
 
-
 
259
			// lors du clic
-
 
260
			public void onClick(Button button, EventObject e) {
-
 
261
 
-
 
262
				// on vide les mots clés en cours
-
 
263
				motsClesEnCours = "";
-
 
264
				// pour chaque noeud à partir de la racine
-
 
265
				getArbreMotsCles().getRootNode().cascade(
-
 
266
						new NodeTraversalCallback() {
-
 
267
 
-
 
268
							// on éxécute une fonction
-
 
269
							public boolean execute(Node node) {
-
 
270
 
-
 
271
								// on récupère le mot clé associé au noeud et
-
 
272
								// ses infos
-
 
273
								TreeNode tn = getArbreMotsCles().getNodeById(
-
 
274
										node.getId());
-
 
275
 
-
 
276
								String[] usObject = (String[]) tn
-
 
277
										.getUserObject();
-
 
278
								getIMediateur().mettreAjourMotsClesId(
-
 
279
										usObject[0], usObject[1]);
-
 
280
 
-
 
281
								if (tn.getUI().isChecked()) {
-
 
282
									// et les concatène à la string des mots
-
 
283
									// clés en cours
-
 
284
									motsClesEnCours += usObject[1] + ",";
-
 
285
								}
-
 
286
 
-
 
287
								return true;
-
 
288
							}
-
 
289
 
-
 
290
						});
-
 
291
 
-
 
292
				// enfin on notifie le médiateur et on lui passe l'arbre et la
-
 
293
				// liste des mots clés ainsi obtenue
-
 
294
				getIMediateur().mettreAjourMotsCles(motsClesEnCours,
-
 
295
						arbreMotsCles.getTree());
-
 
296
			}
-
 
297
		});
-
 
298
	}
-
 
299
 
-
 
300
	/**
-
 
301
	 * Envoie une demande au médiateur pour obtenir l'arbre des mots clés
-
 
302
	 */
-
 
303
	public void obtenirArbreMotsCles() {
-
 
304
 
-
 
305
		getIMediateur().obtenirArbreMotsCles(this);
-
 
306
 
-
 
307
	}
-
 
308
 
-
 
309
	/**
-
 
310
	 * Supprime un noeud de l'arbre
-
 
311
	 * 
-
 
312
	 * @param n
-
 
313
	 *            le noeud à supprimer
-
 
314
	 */
-
 
315
	public void supprimerNoeud(TreeNode n) {
-
 
316
		// si ça n'est pas la racine (qu'on ne peut pas supprimer)
-
 
317
		if (!n.getId().equals(getArbreMotsCles().getRootNode().getId())) {
-
 
318
			// on détache le noeud et on le détruit
-
 
319
			n.getParentNode().removeChild(n);
-
 
320
			n.destroy();
-
 
321
			// puis on en notifie le médiateur en lui passant le noeud supprimé
-
 
322
			// et l'arbre
-
 
323
			getIMediateur()
-
 
324
					.supprimerMotCleDansArbre(n, arbreMotsCles.getTree());
-
 
325
		} else {
-
 
326
			// si l'utilisateur tente de supprimer la racine, on l'avertit de
-
 
327
			// son erreur
-
 
328
			Window.alert("Impossible de supprimer la racine de l'arbre");
-
 
329
		}
-
 
330
	}
-
 
331
 
-
 
332
	/**
-
 
333
	 * Ajoute un noeud dans l'arbre au parent donné
-
 
334
	 * 
-
 
335
	 * @param parent
-
 
336
	 *            le futur parent du noeud à ajouter
-
 
337
	 */
-
 
338
	public void ajouterNoeud(TreeNode parent) {
-
 
339
 
-
 
340
		// on met l'ajout du noeud à vrai
-
 
341
		ajoutNoeud = true;
-
 
342
		// on crée un nouveau noeud vide
-
 
343
		TreeNode nd = new TreeNode("");
-
 
344
		nd.setCls("x-view-treenode-keyword");
-
 
345
		nd.setChecked(true);
-
 
346
		// on associe un objet au noeud qui contient des infos
-
 
347
		String[] usObject = new String[2];
-
 
348
		// l'objet contient le nom du noeud
-
 
349
		usObject[0] = "";
-
 
350
		usObject[1] = genererIdMotCle(nd);
-
 
351
		nd.setId(usObject[1]);
-
 
352
		nd.setUserObject(usObject);
-
 
353
		// l'identifiant d'un noeud c'est son hashcode
-
 
354
		// l'objet associé au noeud contient aussi son identifiant
-
 
355
 
-
 
356
		// on le concatène au parent et on étend ses enfants
-
 
357
		parent.appendChild(nd);
-
 
358
		parent.expand();
-
 
359
		// enfin on place le curseur et on fait apparaitre le champ d'édition
-
 
360
		// pour que l'utilisateur nomme son mot clé
-
 
361
		te.startEdit(nd);
-
 
362
 
-
 
363
	}
-
 
364
 
-
 
365
	/**
-
 
366
	 * Coche le noeud s'il est décoché, le décoche sinon
-
 
367
	 * 
-
 
368
	 * @param node
-
 
369
	 */
-
 
370
	public void gererClicNoeud(TreeNode node) {
-
 
371
		if (node.getUI().isChecked()) {
-
 
372
			node.getUI().toggleCheck(false);
-
 
373
		} else {
-
 
374
			node.getUI().toggleCheck(true);
-
 
375
		}
-
 
376
	}
-
 
377
 
-
 
378
	/**
-
 
379
	 * Parcourt l'arbre et coche les noeud qui font partie de la liste des mots
-
 
380
	 * clés à cocher
-
 
381
	 * 
-
 
382
	 * @param motsClesIds
-
 
383
	 *            un tableau contenant les identifiants des mots clés à cocher
-
 
384
	 */
-
 
385
	public void cocherMotsCles(final String[] motsClesIds) {
-
 
386
		if (getArbreMotsCles() != null
-
 
387
				&& getArbreMotsCles().getRootNode() != null) {
-
 
388
			// à partir de la racine
-
 
389
			getArbreMotsCles().getRootNode().cascade(
-
 
390
					new NodeTraversalCallback() {
-
 
391
 
-
 
392
						// pour chaque noeud
-
 
393
						public boolean execute(Node node) {
-
 
394
 
-
 
395
							getArbreMotsCles().getNodeById(node.getId())
-
 
396
							.getUI().toggleCheck(false);
-
 
397
							
-
 
398
							// on parcourt le tableau des mots clés
-
 
399
							for (int i = 0; i < motsClesIds.length; i++) {
-
 
400
								// si le mot clé fait partie des id à cocher on
-
 
401
								// le coche
-
 
402
								String usObject[] = (String[]) node
-
 
403
										.getUserObject();
-
 
404
								String nodeId = usObject[1];
-
 
405
 
-
 
406
								if (nodeId.equals(motsClesIds[i])) {
-
 
407
									getArbreMotsCles().getNodeById(nodeId)
-
 
408
											.getUI().toggleCheck(true);
-
 
409
									return true;
-
 
410
								}
-
 
411
							}
-
 
412
							// et on passe au suivant
-
 
413
							return true;
-
 
414
						}
-
 
415
 
-
 
416
					});
-
 
417
		}
74
 
418
	}
75
	}
419
 
76
 
420
	/**
77
	/**
421
	 * Méthode héritée de l'interface rafraichissable
78
	 * Méthode héritée de l'interface rafraichissable
422
	 * 
79
	 * 
423
	 * @param nouvelleDonnees
80
	 * @param nouvelleDonnees
424
	 *            les nouvelles données pour l'objet
81
	 *            les nouvelles données pour l'objet
425
	 * @param repandreRafraichissement
82
	 * @param repandreRafraichissement
Line 426... Line -...
426
	 *            booleen qui dit si on doit répandre l'évenement
-
 
427
	 */
-
 
428
	public void rafraichir(Object nouvelleDonnees,
-
 
429
			boolean repandreRafraichissement) {
-
 
430
		
-
 
431
		if(nouvelleDonnees instanceof Tree) {
-
 
432
 
-
 
433
			Tree nouvelArbre = (Tree)nouvelleDonnees ;
-
 
434
 
-
 
435
			// on prend sa racine et on l'attache à l'arbre des mots clés
-
 
436
			Node[] rootChild = getArbreMotsCles().getRootNode().getChildNodes();
-
 
437
			for (int i = 0; i < rootChild.length; i++) {
-
 
438
				
-
 
439
				rootChild[i].remove();
-
 
440
			}
-
 
441
			
-
 
442
			copierFilsNoeud(nouvelArbre.getRootNode(),getArbreMotsCles().getRootNode());
-
 
443
 
-
 
444
			// si l'arbre n'était pas encore considéré comme instancié
-
 
445
			if (!arbreCharge) {
-
 
446
				// on signale que oui
83
	 *            booleen qui dit si on doit répandre l'évenement
447
				arbreCharge = true;
84
	 */
448
			}
85
	public void rafraichir(Object nouvelleDonnees,
Line 449... Line 86...
449
		}
86
			boolean repandreRafraichissement) {
450
 
87
		
451
		// Si on reçoit un tableau de String (cas ou l'on séléectionne une
88
		// Si on reçoit un tableau de String (cas ou l'on séléectionne une
452
		// nouvelle image)
89
		// nouvelle image)
453
		if (nouvelleDonnees instanceof String[]) {
90
		if (nouvelleDonnees instanceof String[]) {
454
 
91
 
455
				// le tableau de String contient les id des mots clés associés à
92
				// le tableau de String contient les id des mots clés associés à
Line 456... Line -...
456
				// l'image
-
 
457
				// on coche les mots clés contenu dans le tableau
-
 
458
				tableauMotsClesEnCours = (String[]) nouvelleDonnees;
-
 
459
				cocherMotsCles(tableauMotsClesEnCours);
-
 
460
		}
-
 
461
	}
-
 
462
 
-
 
463
	private String genererIdMotCle(TreeNode nd) {
-
 
464
		return "" + (nd.hashCode() + (Math.random() * 10000));
-
 
465
	}
-
 
466
	
-
 
467
	/**
-
 
468
	 * Fonction récursive qui prend deux noeuds d'arbre en paramètre et crée un
-
 
469
	 * copie du sous arbre du premier noeud, qu'elle concatène au deuxième
93
				// l'image
470
	 * 
94
				// on affiche les mots clés contenu dans le tableau
471
	 * @param ndPereOriginal
-
 
472
	 *            le père des noeuds de l'arbre original
-
 
473
	 * @param ndPereCopie
95
				tableauMotsClesEnCours = (String[]) nouvelleDonnees;
474
	 *            le père qui va recevoir les copies
-
 
475
	 */
-
 
476
	private void copierFilsNoeud(Node ndPereOriginal, TreeNode ndPereCopie) {
-
 
477
		if (ndPereCopie != null && ndPereOriginal != null) {
-
 
478
			Node[] ndNodeFils = ndPereOriginal.getChildNodes();
-
 
479
			
-
 
480
			for (int i = 0; i < ndNodeFils.length; i++) {
-
 
481
 
-
 
482
				String[] usObj = (String[]) ndNodeFils[i].getUserObject();
96
				afficherMotsCles(tableauMotsClesEnCours);
483
				TreeNode child = new TreeNode(usObj[0]);
97
		}
484
				child.setId(usObj[1]);
-
 
485
				child.setChecked(false);
-
 
486
				child.setUserObject(usObj);
98
	}
487
				ndPereCopie.appendChild(child);
99
 
-
 
100
	private void afficherMotsCles(String[] tableauMotsClesEnCours) {
-
 
101
		motsClesEnCours = "<ul class=\"liste_mots_cles\">"; 
-
 
102
		for (int i = 0; i < tableauMotsClesEnCours.length; i++) {
488
 
103
			if(!tableauMotsClesEnCours[i].trim().isEmpty()) {
489
				if (!ndNodeFils[i].isLeaf()) {
104
				motsClesEnCours += "<li>"+tableauMotsClesEnCours[i]+"</li>";