Add trash feature on scase, category and thing
Benjamin Renard

Benjamin Renard commited on 2017-09-17 16:55:25
Showing 3 changed files, with 316 additions and 15 deletions.

... ...
@@ -33,8 +33,14 @@ on_valid_add_scase_modal=function (e) {
33 33
     alert("Vous devez saisir le nom de la valise !");
34 34
     return;
35 35
   }
36
-  if (scases.byName(name)) {
36
+  var nameshake=scases.byName(name);
37
+  if (nameshake) {
38
+    if (nameshake.removed) {
39
+      alert("Une valise de ce nom existe dans la corbeille !");
40
+    }
41
+    else {
37 42
       alert("Cette valise existe déjà !");
43
+    }
38 44
     return;
39 45
   }
40 46
   var scase=scases.newSCase(name);
... ...
@@ -70,8 +76,14 @@ on_valid_rename_scase_modal=function (e) {
70 76
     return;
71 77
   }
72 78
   if ($('#cats').data('scase')!=name) {
73
-    if (scases.byName(name)) {
74
-      alert("Cette valise existe déjà !");
79
+    var nameshake=scases.byName(name);
80
+    if (nameshake) {
81
+      if (nameshake.removed) {
82
+        alert("Une valise portant ce nom existe dans la corbeille !");
83
+      }
84
+      else {
85
+        alert("Une valise portant ce nom existe déjà !");
86
+      }
75 87
       return;
76 88
     }
77 89
 
... ...
@@ -110,8 +122,14 @@ on_valid_copy_scase_modal=function (e) {
110 122
     alert("Vous devez saisir le nom de la nouvelle valise !");
111 123
     return;
112 124
   }
113
-  if (scases.byName(name)) {
114
-    alert("Cette valise existe déjà !");
125
+  var nameshake=scases.byName(name);
126
+  if (nameshake) {
127
+    if (nameshake.removed) {
128
+      alert("Une valise portant ce nom existe dans la corbeille !");
129
+    }
130
+    else {
131
+      alert("Une valise portant ce nom existe déjà !");
132
+    }
115 133
     return;
116 134
   }
117 135
   var scase=scases.copySCase($('#cats').data('scase'),name);
... ...
@@ -164,6 +182,28 @@ on_delete_scase_btn_click=function(event) {
164 182
   }
165 183
 }
166 184
 
185
+on_restore_scase_btn_click=function(event) {
186
+  navbar_collapse_hide();
187
+  var scase=event.data.scase;
188
+  if (scase) {
189
+    myconfirm('Voulez-vous vraiment restaurer la valise '+scase.name+' ?',
190
+    function(data) {
191
+      scase.restore();
192
+      scases.save();
193
+      show_scases();
194
+    });
195
+  }
196
+}
197
+
198
+on_scase_trash_btn_click=function(event) {
199
+  event.preventDefault();
200
+  navbar_collapse_hide();
201
+  var scase=scases.byName($('#cats').data('scase'));
202
+  if (scase) {
203
+    show_scase_trash(scase);
204
+  }
205
+}
206
+
167 207
 /***********************
168 208
  * Add cat
169 209
  **********************/
... ...
@@ -181,8 +221,14 @@ on_valid_add_cat_modal=function (e) {
181 221
   }
182 222
   var scase=scases.byName($('#cats').data('scase'));
183 223
   if (scase) {
184
-    if (scase.cats.byName(name)) {
185
-      alert("Cette catégorie existe déjà !");
224
+    var nameshake=scase.cats.byName(name);
225
+    if (nameshake) {
226
+      if (nameshake.removed) {
227
+        alert("Une catégorie portant ce nom existe dans la corbeille !");
228
+      }
229
+      else {
230
+        alert("Une catégorie portant ce nom existe déjà !");
231
+      }
186 232
       return;
187 233
     }
188 234
     var cat=scase.cats.newCat(name);
... ...
@@ -222,7 +268,13 @@ on_valid_rename_cat_modal=function (e) {
222 268
   var scase=scases.byName($('#cats').data('scase'));
223 269
   if (scase) {
224 270
     if (scase.cats.byName(name)) {
271
+      var namesake=scase.cats.byName(name);
272
+      if (namesake.removed) {
273
+        alert("Une catégorie de se nom existe dans la corbeille !");
274
+      }
275
+      else {
225 276
         alert("Cette catégorie existe déjà !");
277
+      }
226 278
       return;
227 279
     }
228 280
     var cat=scase.cats.renameCat($('#rename_cat_modal').data('cat'),name);
... ...
@@ -259,6 +311,20 @@ on_delete_cat_btn_click=function(event) {
259 311
   }
260 312
 }
261 313
 
314
+on_restore_cat_btn_click=function(event) {
315
+  navbar_collapse_hide();
316
+  var scase=scases.byName($('#cats').data('scase'));
317
+  if (scase) {
318
+    var cat=event.data.cat.name;
319
+    myconfirm('Voulez-vous vraiment restaure la catégorie '+cat+' ?',
320
+    function(data) {
321
+      scase.cats.restoreCat(cat);
322
+      scases.save();
323
+      show_scase(scase);
324
+    });
325
+  }
326
+}
327
+
262 328
 /************************
263 329
  * Check/Uncheck thing
264 330
  ***********************/
... ...
@@ -385,8 +451,14 @@ on_valid_rename_thing_modal=function (e) {
385 451
   if (scase) {
386 452
     var cat=scase.cats.byName($('#rename_thing_modal').data('cat'));
387 453
     if (cat) {
388
-      if (cat.byLabel(label)) {
454
+      var namesake=cat.byLabel(label);
455
+      if (namesake) {
456
+        if (namesake.removed) {
457
+          alert("Un élément de ce nom existe dans la corbeille !");
458
+        }
459
+        else {
389 460
           alert("Un élément de ce nom existe déjà !");
461
+        }
390 462
         return;
391 463
       }
392 464
       var thing=cat.renameThing($('#rename_thing_modal').data('thing'),label);
... ...
@@ -427,6 +499,23 @@ on_delete_thing_btn_click=function(event) {
427 499
   }
428 500
 }
429 501
 
502
+on_restore_thing_btn_click=function(event) {
503
+  navbar_collapse_hide();
504
+  var scase=scases.byName($('#cats').data('scase'));
505
+  if (scase) {
506
+    var cat=scase.cats.byName(event.data.cat.name);
507
+    if (cat) {
508
+      var thing=event.data.thing.label;
509
+      myconfirm("Voulez-vous vraiment restaurer l'élément "+thing+" ?",
510
+      function(data) {
511
+        cat.restoreThing(thing);
512
+        scases.save();
513
+        show_scase(scase,cat.name);
514
+      });
515
+    }
516
+  }
517
+}
518
+
430 519
 /********************
431 520
  * Show one scase
432 521
  *******************/
... ...
@@ -464,6 +553,9 @@ show_cat=function(cat,displayed) {
464 553
   }
465 554
   var ul=$('<ul class="list-group" data-cat="'+cat.name+'"></ul>');
466 555
   for (idx in cat.things) {
556
+    if (cat.things[idx].removed) {
557
+      continue;
558
+    }
467 559
     var li=$('<li class="list-group-item" data-label="'+cat.things[idx].label+'">'+cat.things[idx].label+'</li>');
468 560
     if (cat.things[idx].checked) {
469 561
       li.addClass('done');
... ...
@@ -495,6 +587,9 @@ show_cat=function(cat,displayed) {
495 587
 show_scase=function(scase,display_cat) {
496 588
   clear_page('<h3><span class="glyphicon glyphicon-briefcase" aria-hidden="true"></span> '+scase.name+'</h3><div class="panel-group" id="cats" role="tablist" aria-multiselectable="true" data-scase="'+scase.name+'"></div>');
497 589
   scase.cats.each(function(idx,cat) {
590
+    if (cat.removed) {
591
+      return;
592
+    }
498 593
     show_cat(cat,(cat.name==display_cat));
499 594
   });
500 595
   show_menu('scase');
... ...
@@ -506,12 +601,99 @@ on_back_to_scases_btn_click=function(e) {
506 601
   show_scases();
507 602
 }
508 603
 
604
+/********************
605
+ * Show scase trash
606
+ *******************/
607
+show_scase_trash=function(scase,display_cat) {
608
+  clear_page('<h3><span class="glyphicon glyphicon-trash" aria-hidden="true"></span>'+scase.name+' : Corbeille <button class="btn btn-default btn-xs" id="back_btn"><span class="glyphicon glyphicon-arrow-left"></button></h3><div class="panel-group" id="cats" role="tablist" aria-multiselectable="true" data-scase="'+scase.name+'"></div>');
609
+
610
+  $('#content h3 #back_btn').bind('click', {'scase': scase}, function(event) {
611
+    show_scase(event.data.scase);
612
+  });
613
+
614
+  scase.cats.each(function(idx,cat) {
615
+    show_cat_trash(cat,(cat.name==display_cat));
616
+  });
617
+  if ($('#cats .panel').length==0) {
618
+    $('#content').append('<p class="center">La corbeille est vide.</p>');
619
+  }
620
+  show_menu('scase');
621
+}
622
+
623
+show_cat_trash=function(cat,displayed) {
624
+  var panel=$('<div class="panel panel-default"></div>');
625
+  var panel_heading=$('<div class="panel-heading" role="tab"></div>');
626
+  var panel_title=$('<h4 class="panel-title">'+cat.name+' </h4>');
627
+
628
+  var tag=$('<span class="count-tag pull-right"></span>');
629
+
630
+  panel_title.append(tag);
631
+
632
+
633
+  panel_heading.append(panel_title);
634
+  panel.append(panel_heading);
635
+
636
+
637
+  if (cat.removed) {
638
+    var stats=cat.stats();
639
+    tag.append($('<span class="badge">'+stats.things+'</span>'));
640
+
641
+    var restore_btn=$('<button class="btn btn-default btn-xs pull-right"><span class="glyphicon glyphicon-ok"></button>');
642
+    restore_btn.bind('click',{'cat': cat},on_restore_cat_btn_click);
643
+    tag.append(restore_btn);
644
+  }
645
+  else {
646
+    var deleted_things=[];
647
+    for (idx in cat.things) {
648
+      if (cat.things[idx].removed) {
649
+        deleted_things.push(cat.things[idx]);
650
+      }
651
+    }
652
+    if (deleted_things.length==0) {
653
+      return true;
654
+    }
655
+    panel_title.bind('click',on_title_click);
656
+    tag.append($('<span class="badge">'+deleted_things.length+'</span>'));
657
+
658
+    var panel_collapse=$('<div class="panel-collapse collapse" role="tabpanel"></div>');
659
+    if (displayed) {
660
+      panel_collapse.addClass('in');
661
+    }
662
+    var ul=$('<ul class="list-group" data-cat="'+cat.name+'"></ul>');
663
+    for (idx in deleted_things) {
664
+      var li=$('<li class="list-group-item" data-label="'+deleted_things[idx].label+'">'+deleted_things[idx].label+'</li>');
665
+      var li_actions=$('<span class="actions pull-right"></span>');
666
+
667
+      var restore_el_btn=$('<button class="btn btn-default btn-xs pull-right"><span class="glyphicon glyphicon-ok"></button>');
668
+      restore_el_btn.bind('click',{'cat': cat,'thing': deleted_things[idx]},on_restore_thing_btn_click);
669
+      li_actions.append(restore_el_btn);
670
+
671
+      li.append(li_actions);
672
+
673
+      ul.append(li);
674
+    }
675
+    panel_collapse.append(ul);
676
+    panel.append(panel_collapse);
677
+  }
678
+
679
+  $('#cats').append(panel);
680
+}
681
+
682
+on_back_to_scase_btn_click=function(e) {
683
+  e.preventDefault();
684
+  navbar_collapse_hide();
685
+  show_scase(e.data.scase);
686
+}
687
+
509 688
 /********************
510 689
  * Show scases
511 690
  *******************/
512 691
 show_scases=function() {
513 692
   clear_page('<h3>Vos valises</h3><ul class="list-group" id="scases"></ul>');
514 693
   scases.each(function(idx,scase) {
694
+    if (scase.removed) {
695
+      return;
696
+    }
515 697
     var stats=scase.stats();
516 698
     var tag='<span class="count-tag pull-right">';
517 699
     if (stats.things==stats.done) {
... ...
@@ -535,6 +717,37 @@ on_scase_click=function(event) {
535 717
   show_scase(scase);
536 718
 }
537 719
 
720
+/********************
721
+ * Show scases trash
722
+ *******************/
723
+show_scases_trash=function() {
724
+  clear_page('<h3>Corbeille <button class="btn btn-default btn-xs" id="back_btn"><span class="glyphicon glyphicon-arrow-left"></button></h3><ul class="list-group" id="scases"></ul>');
725
+  $('#content h3 #back_btn').bind('click', function(event) {
726
+    show_scases();
727
+  });
728
+
729
+  scases.each(function(idx,scase) {
730
+    if (!scase.removed) {
731
+      return;
732
+    }
733
+    var stats=scase.stats();
734
+    var tags=$('<span class="count-tag pull-right"></span>');
735
+    tags.append('<span class="badge">'+stats.things+'</span>');
736
+
737
+    var restore_btn=$('<button class="btn btn-default btn-xs pull-right"><span class="glyphicon glyphicon-ok"></button>');
738
+    restore_btn.bind('click',{'scase': scase},on_restore_scase_btn_click);
739
+    tags.append(restore_btn);
740
+
741
+    var li=$('<li class="list-group-item" data-name="'+scase.name+'"><span class="scase-name"><span class="glyphicon glyphicon-briefcase" aria-hidden="true"></span> '+scase.name+'</span></li>');
742
+    li.append(tags);
743
+    $('#scases').append(li);
744
+  });
745
+  if ($('#scases li').length==0) {
746
+    $('#content').append('<p class="center">Aucune valise dans la corbeille.</p>');
747
+  }
748
+  show_menu('scases');
749
+}
750
+
538 751
 clear_page=function(new_content) {
539 752
   if (new_content) {
540 753
     $('#content').html(new_content);
... ...
@@ -645,6 +858,8 @@ $( document ).ready( function() {
645 858
   $("#add_scase_modal").on('hidden.bs.modal',on_close_add_scase_modal);
646 859
   $("#add_scase_modal form").bind('submit',on_valid_add_scase_modal);
647 860
 
861
+  $('#scases_trash_btn').bind('click',show_scases_trash);
862
+
648 863
   $('#rename_scase_btn').bind('click',on_rename_scase_btn_click);
649 864
   $('#rename_scase_submit').bind('click',on_valid_rename_scase_modal);
650 865
   $("#rename_scase_modal").on('shown.bs.modal',on_show_rename_scase_modal);
... ...
@@ -659,6 +874,7 @@ $( document ).ready( function() {
659 874
 
660 875
   $('#reset_scase_btn').bind('click',on_reset_scase_btn_click);
661 876
   $('#delete_scase_btn').bind('click',on_delete_scase_btn_click);
877
+  $('#scase_trash_btn').bind('click',on_scase_trash_btn_click);
662 878
 
663 879
   $('#add_cat_btn').bind('click',on_add_cat_btn_click);
664 880
   $('#add_cat_submit').bind('click',on_valid_add_cat_modal);
... ...
@@ -127,7 +127,7 @@ function SCaseList() {
127 127
   this.removeSCase=function(name) {
128 128
     for (el in this) {
129 129
       if (this.isSCase(this[el]) && this[el].name==name) {
130
-        delete this[el];
130
+        this[el].remove();
131 131
         return true;
132 132
       }
133 133
     }
... ...
@@ -135,7 +135,15 @@ function SCaseList() {
135 135
   }
136 136
 
137 137
   this.newSCase=function(name) {
138
-    if (!this.byName(this[name])) {
138
+    if (this.byName(this[name])) {
139
+      var scase=this.byName(name);
140
+      if (scase.removed) {
141
+        scase.restore();
142
+        return true;
143
+      }
144
+
145
+    }
146
+    else {
139 147
       var uuid=uuid||generate_uuid();
140 148
       this[uuid]=new SCase(uuid,name);
141 149
       return this[uuid];
... ...
@@ -181,6 +189,7 @@ function SCase(uuid,name,data) {
181 189
   this.name=name;
182 190
   this.cats=new CatList();
183 191
   this.lastChange=new Date().getTime();
192
+  this.removed=false;
184 193
 
185 194
   this.isSCase=function() {
186 195
     return true;
... ...
@@ -190,6 +199,7 @@ function SCase(uuid,name,data) {
190 199
     this.uuid=data.uuid || generate_uuid();
191 200
     this.lastChange=data.lastChange || new Date().getTime();
192 201
     this.name=decodeURIComponent(data.name);
202
+    this.removed=data.removed||false;
193 203
     if (jQuery.type(data.cats) == 'object') {
194 204
       this.cats=new CatList(data.cats);
195 205
     }
... ...
@@ -201,6 +211,7 @@ function SCase(uuid,name,data) {
201 211
       'uuid': this.uuid,
202 212
       'lastChange': this.lastChange,
203 213
       'name': encodeURIComponent(this.name),
214
+      'removed': this.removed,
204 215
       'cats': this.cats.export()
205 216
     };
206 217
   }
... ...
@@ -246,6 +257,16 @@ function SCase(uuid,name,data) {
246 257
     return true;
247 258
   }
248 259
 
260
+  this.remove=function() {
261
+    this.removed=true;
262
+    this.lastChange=new Date().getTime();
263
+  }
264
+
265
+  this.restore=function() {
266
+    this.removed=false;
267
+    this.lastChange=new Date().getTime();
268
+  }
269
+
249 270
   /*
250 271
    * Contructor
251 272
    */
... ...
@@ -316,7 +337,14 @@ function CatList(data) {
316 337
   }
317 338
 
318 339
   this.newCat=function(name) {
319
-    if (!this.isCat(this[name])) {
340
+    if (this.byName(name)) {
341
+      var cat=this.byName(name);
342
+      if (cat.removed) {
343
+        cat.restore();
344
+        return true;
345
+      }
346
+    }
347
+    else {
320 348
       var uuid=uuid||generate_uuid();
321 349
       this[uuid]=new Cat(uuid,name);
322 350
       return this[uuid];
... ...
@@ -337,13 +365,22 @@ function CatList(data) {
337 365
   this.removeCat=function(name) {
338 366
     for (el in this) {
339 367
       if (this.isCat(this[el]) && this[el].name==name) {
340
-        delete this[el];
368
+        this[el].remove();
341 369
         return true;
342 370
       }
343 371
     }
344 372
     return false;
345 373
   }
346 374
 
375
+  this.restoreCat=function(name) {
376
+    for (el in this) {
377
+      if (this.isCat(this[el]) && this[el].name==name && this[el].removed) {
378
+        this[el].restore();
379
+        return true;
380
+      }
381
+    }
382
+    return false;
383
+  }
347 384
 
348 385
 
349 386
   /*
... ...
@@ -367,6 +404,7 @@ function Cat(uuid,name,color,data) {
367 404
   this.name=name;
368 405
   this.color=color || '#'+(0x1000000+(Math.random())*0xffffff).toString(16).substr(1,6);
369 406
   this.things={};
407
+  this.removed=false;
370 408
 
371 409
   this.isCat=function() {
372 410
     return true;
... ...
@@ -377,6 +415,7 @@ function Cat(uuid,name,color,data) {
377 415
     this.lastChange=data.lastChange||new Date().getTime();
378 416
     this.name=decodeURIComponent(data.name);
379 417
     this.color=data.color;
418
+    this.removed=data.removed||false;
380 419
     if (jQuery.type(data.things) == 'object') {
381 420
       for (tuuid in data.things) {
382 421
         this.things[tuuid]=new Thing(tuuid);
... ...
@@ -396,6 +435,7 @@ function Cat(uuid,name,color,data) {
396 435
       'lastChange': this.lastChange,
397 436
       'name': encodeURIComponent(this.name),
398 437
       'color': this.color,
438
+      'removed': this.removed,
399 439
       'things': things
400 440
     };
401 441
   }
... ...
@@ -429,7 +469,15 @@ function Cat(uuid,name,color,data) {
429 469
   }
430 470
 
431 471
   this.newThing=function(label) {
432
-    if (!this.byLabel(label)) {
472
+    if (this.byLabel(label)) {
473
+      var thing=this.byLabel(label);
474
+      if (thing.removed) {
475
+        thing.restore();
476
+        thing.setChecked(false);
477
+        return true;
478
+      }
479
+    }
480
+    else {
433 481
       var uuid=generate_uuid();
434 482
       this.things[uuid]=new Thing(uuid,label);
435 483
       return true;
... ...
@@ -450,13 +498,34 @@ function Cat(uuid,name,color,data) {
450 498
   this.removeThing=function(label) {
451 499
     for (idx in this.things) {
452 500
       if (this.things[idx].label==label) {
453
-        delete this.things[idx];
501
+        this.things[idx].remove();
454 502
         return true;
455 503
       }
456 504
     }
457 505
     return false;
458 506
   }
459 507
 
508
+  this.restoreThing=function(label) {
509
+    for (idx in this.things) {
510
+      if (this.things[idx].label==label && this.things[idx].removed) {
511
+        this.things[idx].restore();
512
+        return true;
513
+      }
514
+    }
515
+    return false;
516
+  }
517
+
518
+  this.remove=function() {
519
+    this.removed=true;
520
+    this.lastChange=new Date().getTime();
521
+  }
522
+
523
+  this.restore=function() {
524
+    this.removed=false;
525
+    this.lastChange=new Date().getTime();
526
+  }
527
+
528
+
460 529
   /*
461 530
    * Contructor
462 531
    */
... ...
@@ -477,12 +546,14 @@ function Thing(uuid,label,checked) {
477 546
   this.lastChange=new Date().getTime();
478 547
   this.label=label;
479 548
   this.checked=checked;
549
+  this.removed=false;
480 550
 
481 551
   this.import=function(data) {
482 552
     this.uuid=data.uuid||generate_uuid();
483 553
     this.lastChange=data.lastChange||new Date().getTime();
484 554
     this.label=decodeURIComponent(data.label),
485 555
     this.checked=data.checked;
556
+    this.removed=data.removed||false;
486 557
   }
487 558
 
488 559
   this.export=function() {
... ...
@@ -490,7 +561,8 @@ function Thing(uuid,label,checked) {
490 561
       'uuid': this.uuid,
491 562
       'lastChange': this.lastChange,
492 563
       'label': encodeURIComponent(this.label),
493
-      'checked': this.checked
564
+      'checked': this.checked,
565
+      'removed': this.removed,
494 566
     };
495 567
   }
496 568
 
... ...
@@ -498,4 +570,14 @@ function Thing(uuid,label,checked) {
498 570
     this.checked=value;
499 571
     this.lastChange=new Date().getTime();
500 572
   }
573
+
574
+  this.remove=function() {
575
+    this.removed=true;
576
+    this.lastChange=new Date().getTime();
577
+  }
578
+
579
+  this.restore=function() {
580
+    this.removed=false;
581
+    this.lastChange=new Date().getTime();
582
+  }
501 583
 }
... ...
@@ -68,6 +68,7 @@ div.panel-heading, li.list-group-item, a {
68 68
 	<div class="collapse navbar-collapse" id="navbar-top-collapse">
69 69
           <ul class="nav navbar-nav navbar-right">
70 70
             <li class="menu menu-scases"><a href="#add_scase" id="add_scase_btn"><span class="glyphicon glyphicon-plus-sign"></span> Ajouter une valise</a></li>
71
+            <li class="menu menu-scases"><a href="#scases_trash" id="scases_trash_btn"><span class="glyphicon glyphicon-trash"></span> Voir la corbeille</a></li>
71 72
             <li class="menu menu-scase"><a href="#scases" id="back_to_scases"><span class="glyphicon glyphicon-briefcase"></span> Liste des valises</a></li>
72 73
             <li class="menu menu-scase dropdown">
73 74
               <a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class='glyphicon glyphicon-tag'></span> Gérer la valise <b class="caret"></b></a>
... ...
@@ -78,6 +79,8 @@ div.panel-heading, li.list-group-item, a {
78 79
                 <li><a href="#copy_scase" id="copy_scase_btn"><span class="glyphicon glyphicon-duplicate"></span> Copier la valise</a></li>
79 80
                 <li><a href="#reset_scase" id="reset_scase_btn"><span class="glyphicon glyphicon-cog"></span> Réinitialiser la valise</a></li>
80 81
                 <li><a href="#delete_scase" id="delete_scase_btn"><span class="glyphicon glyphicon-trash"></span> Supprimer la valise</a></li>
82
+                <li class="divider"></li>
83
+                <li><a href="#scase_trash" id="scase_trash_btn"><span class="glyphicon glyphicon-trash"></span> Voir la corbeille de la valise</a></li>
81 84
               </ul>
82 85
             </li>
83 86
             <li><a id='clear_local_data'><span class='glyphicon glyphicon-trash'></span> Purger les données locales</a></li>
84 87