Projet

Général

Profil

0001-card-infos-cell-form-add-UI-to-customize-content-lay.patch

Voir les différences:

Subject: [PATCH] card infos cell form: add UI to customize content layout
 (#52073)

 .../wcs/manager/card-infos-cell-form.html     |  83 ++++-
 combo/manager/static/css/combo.manager.css    |  69 ++++
 combo/manager/static/js/combo.manager.js      | 308 ++++++++++++++++++
 3 files changed, 459 insertions(+), 1 deletion(-)
combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form.html
4 4
{{ block.super }}
5 5
{% if card_schema %}
6 6
{{ card_schema|json_script:card_schema_id }}
7

  
8
{# Si une personnalisation existe déjà, simplement retourner le Json dans la cellule #}
9
{% comment "existing grid schema" %}
10
<script type="application/json" id="{{cell.id}}-grid-schema">
11
{"grid_class":"fx-grid--t2","grid_layout_label":"2 colonnes","cells_order":["3","0","4","1","2"],"cells":[{"varname":"activite","cell_size":"","display":["key","value"],"cell_size_label":"auto","id":0},{"varname":"adresse_lieu","cell_size":"size--t2-3","display":["key"],"cell_size_label":"2/3","id":1},{"varname":"zip_code_lieu","cell_size":"size--t1-3","display":["key"],"cell_size_label":"1/3","id":2},{"varname":"nom","cell_size":"size--1-1","display":["key","value"],"cell_size_label":"1/1","id":3},{"varname":"activite","cell_size":"","display":["key"],"cell_size_label":"auto","id":4}]}
12
</script>
13
{% endcomment %}
14

  
15
{# Checkbox qui doit activé l'UI de personnalisation // TODO #}
16
<p>
17
<label> <input type="checkbox" name="active-custom" class="wcs-cards-cell--active-custom"> Personnaliser l'affichage</label>
18
</p>
19

  
20
{# Grille de personalisation #}
21
<div class="wcs-cards-cell--grid">
22
  <div class="wcs-cards-cell--grid-options">
23
    <a role="button" class="wcs-cards-cell--grid-layout-btn icon-edit">
24
      <span class="sr-only">Disposition de la grille</span>
25
    </a>
26
    <span class="wcs-cards-cell--grid-layout-label">auto</span>
27
  </div>
28
  <div class="wcs-cards-cell--grid-cells">
29
    <button type="button" class="wcs-cards-cell--add-grid-cell-btn">Ajouter</button>
30
  </div>
31
</div>
32

  
33
{# templates utilisées par le JS #}
34
<script type="text/template" class="wcs-cards-cell--grid-form-tpl">
35
  <form>
36
    <p>
37
      Disposition
38
      <select name="grid-layout">
39
        <option value="fx-grid--auto">auto</option>
40
        <option value="fx-grid">1 colonne</option>
41
        <option value="fx-grid--t2">2 colonnes</option>
42
        <option value="fx-grid--t3">3 colonnes</option>
43
      </select>
44
    </p>
45
  </form>
46
</script>
47
<script type="text/template" class="wcs-cards-cell--grid-cell-form-tpl">
48
  <form>
49
    <p>
50
      <label>
51
        Champ
52
        <select name="card_field_varname"></select>
53
      </label>
54
    </p>
55
    <p>
56
      <label>
57
        Afficher
58
        <select name="card_field_elements">
59
          <option value="key,value">Label & valeur</option>
60
          <option value="key">Label uniquement</option>
61
          <option value="value">Valeur uniquement</option>
62
        </select>
63
      </label>
64
    </p>
65
    <p>
66
      <label>
67
        Taille
68
        <select name="cell_size">
69
          <option value="">auto</option>
70
          <option value="size--1-1">1/1</option>
71
          <option value="size--t1-2">1/2</option>
72
          <option value="size--t1-3">1/3</option>
73
          <option value="size--t2-3">2/3</option>
74
        </select>
75
      </label>
76
    </p>
77
  </form>
78
</script>
79
<script  type="text/template" class="wcs-cards-cell--grid-cell-tpl">
80
  <div class="wcs-cards-cell--grid-cell">
81
    <div class="wcs-cards-cell--grid-cell-content"></div>
82
    <div class="wcs-cards-cell--grid-cell-buttons">
83
      <a role="button" class="wcs-cards-cell--grid-cell-edit icon-edit"><span class="sr-only">Editer la cellule</span></a>
84
      <a role="button" class="wcs-cards-cell--grid-cell-delete icon-remove-sign"><span class="sr-only">Effacer la cellule</span></a>
85
    </div>
86
  </div>
87
</script>
7 88
{% endif %}
8
{% endblock %}
89
{% endblock %}
combo/manager/static/css/combo.manager.css
602 602
	margin: 0 0 0 1em;
603 603
	padding: 0;
604 604
}
605

  
606

  
607
.wcs-cards-cell--grid {
608
	border : 1px solid #aaa;
609
  	/*resize: horizontal;*/
610
  	overflow: hidden;
611
}
612
.wcs-cards-cell--grid-options {
613
	background-color: #eee;
614
	padding: 3px;
615
}
616
.wcs-cards-cell--grid-options > * {
617
	vertical-align: middle;
618
}
619
.wcs-cards-cell--grid-cells[class*="fx-grid--"] {
620
	padding: 3px;
621
}
622
.wcs-cards-cell--grid-cell {
623
	box-sizing: border-box;
624
	border: 1px solid #aaa;
625
	padding: 3px;
626
	background-color: #fff;
627
	cursor: move;
628
}
629
.wcs-cards-cell--grid-cell,
630
.wcs-cards-cell--add-grid-cell-btn {
631
	margin-top: 3px;
632
	margin-bottom: 3px;
633
}
634
.wcs-cards-cell--grid-cell.ui-sortable-helper {
635
	opacity: 0.7;
636
}
637
.wcs-cards-cell--grid-cell-placeholder {
638
	background-color: #eee;
639
}
640
.wcs-cards-cell--grid-cell-content > * {
641
	display: block;
642
}
643
.wcs-cards-cell--grid-cell-content > .key {
644
	font-weight: bold;
645
}
646
.wcs-cards-cell--grid-cell-content > .key::before {
647
	content: "Label ";
648
	font-style: italic;
649
}
650
.wcs-cards-cell--grid-cell-content > .value::before {
651
	content: "Valeur ";
652
	font-style: italic;
653
}
654
.wcs-cards-cell--grid-layout-label,
655
.wcs-cards-cell--grid-cell-content > .cell-size-label {
656
	color: #666;
657
}
658
.wcs-cards-cell--grid-layout-label::before,
659
.wcs-cards-cell--grid-cell-content > .cell-size-label::before {
660
	content: "[ ";
661
}
662
.wcs-cards-cell--grid-layout-label::after,
663
.wcs-cards-cell--grid-cell-content > .cell-size-label::after {
664
	content: " ]";
665
}
666
.wcs-cards-cell--grid-cell-buttons {
667
	cursor: default;
668
}
669
.wcs-cards-cell--grid a[class^="icon-"],
670
.wcs-cards-cell--grid a[class*=" icon-"] {
671
	font-size: 150%;
672
}
673

  
combo/manager/static/js/combo.manager.js
397 397
    window.location = $(this).parent('div').find('option:selected').data('add-url');
398 398
    return false;
399 399
  });
400

  
401
});
402

  
403

  
404

  
405
////////////////////////////////////////
406

  
407

  
408
const Card_cell_custom = function(cell) {
409
  this.cell = cell;
410
  const cardSchema_el = cell.querySelector('[id*="card-schema-eservices"]');
411
  this.cardSchema = cardSchema_el ? JSON.parse(cardSchema_el.innerText) : undefined;
412

  
413
  if (!this.cardSchema) return;
414

  
415
  this.active_custom_ckbox = cell.querySelector('.wcs-cards-cell--active-custom');
416

  
417
  this.edit_grid_btn = cell.querySelector('.wcs-cards-cell--grid-layout-btn');
418
  this.grid_layout_label = cell.querySelector('.wcs-cards-cell--grid-layout-label');
419

  
420
  const grid_form_tpl_string = cell.querySelector('.wcs-cards-cell--grid-form-tpl').innerText;
421
  this.grid_form = this.parse_string_tpl(grid_form_tpl_string);
422

  
423
  this.add_grid_cell_btn = cell.querySelector('.wcs-cards-cell--add-grid-cell-btn');
424

  
425
  const grid_cell_form_tpl_string = cell.querySelector('.wcs-cards-cell--grid-cell-form-tpl').innerText;
426
  this.grid_cell_form = this.parse_string_tpl(grid_cell_form_tpl_string);
427

  
428
  const grid_cell_tpl_string = cell.querySelector('.wcs-cards-cell--grid-cell-tpl').innerText;
429
  this.grid_cell_tpl = this.parse_string_tpl(grid_cell_tpl_string);
430

  
431
  this.grid_wrapper = cell.querySelector('.wcs-cards-cell--grid-cells');
432

  
433
  const gridShema_default = {
434
    "grid_class": "fx-grid--auto",
435
    "grid_layout_label": "auto",
436
    "cells_order": [],
437
    "cells": []
438
  }
439
  const gridShema_existing_el = cell.querySelector('[id*="grid-schema"]');
440
  this.gridShema_existing = gridShema_existing_el ? JSON.parse(gridShema_existing_el.innerText) : undefined;
441
  this.gridShema =  this.gridShema_existing || gridShema_default;
442
  this.init();
443
}
444

  
445

  
446
Card_cell_custom.prototype = {
447

  
448
  parse_string_tpl: function(string_tpl) {
449
    const wrapper = document.createElement('div');
450
    wrapper.innerHTML = string_tpl;
451
    return wrapper.firstElementChild;
452
  },
453

  
454
  field_with_varname: function(varname) {
455
    const field = this.cardSchema.fields.filter(function(i) {
456
      return i.varname === varname;
457
    })
458
    return field[0];
459
  },
460

  
461
  //
462
  //  Grid methods
463
  //
464

  
465
  grid__form_dialog: function(callback){
466
    const _self = this;
467
    $(this.grid_form).dialog({
468
      modal: true,
469
      'title': "Disposition de la grille",
470
      width: 'auto',
471
      buttons: [
472
        {
473
          text: "Annuler",
474
          class:"cancel-button",
475
          click: function() {
476
              $(this).dialog("close");
477
          }
478
        },{
479
          text: "Modifier",
480
          class: "submit-button",
481
          click: function() {
482
            const form_datas = {};
483
            const select_layout = _self.grid_form[0];
484
            form_datas.grid_class = select_layout.value;
485
            form_datas.label = select_layout[select_layout.selectedIndex].text;
486
            callback(form_datas);
487
            $(this).dialog("close");
488
          }
489
        }
490
      ]
491
    });
492
  },
493

  
494
  grid__set_shema: function(form_datas){
495
    this.gridShema.grid_class = form_datas.grid_class;
496
    this.gridShema.grid_layout_label = form_datas.label;
497

  
498
    this.grid__set_layout();
499
    $(this.cell).trigger("custom_cell:change");
500
  },
501

  
502
  grid__set_layout: function() {
503
    this.grid_layout_label.textContent = this.gridShema.grid_layout_label;
504
    if (this.grid_wrapper.dataset.grid_layout) {
505
      this.grid_wrapper.classList.remove(this.grid_wrapper.dataset.grid_layout); }
506
    this.grid_wrapper.classList.add(this.gridShema.grid_class);
507
    this.grid_wrapper.dataset.grid_layout = this.gridShema.grid_class;
508
  },
509

  
510
  //
511
  //  Grid cell methods
512
  //
513

  
514
  grid_cell__init_form: function() {
515
    this.grid_cell_form.varname = this.grid_cell_form[0];
516
    this.grid_cell_form.display = this.grid_cell_form[1];
517
    this.grid_cell_form.size = this.grid_cell_form[2];
518

  
519
    const varname_select = this.grid_cell_form.varname;
520
    this.cardSchema.fields.forEach(function(el, id) {
521
      if (el.varname) {
522
        $('<option />')
523
          .attr('value', el.varname)
524
          .text(el.label)
525
          .appendTo(varname_select);
526
      }
527
    })
528
  },
529

  
530
  grid_cell__form_dialog: function(button_label, callback){
531
    const _self = this;
532
    $(this.grid_cell_form).dialog({
533
      modal: true,
534
      'title': button_label,
535
      width: 'auto',
536
      buttons: [
537
        {
538
          text: "Annuler",
539
          class:"cancel-button",
540
          click: function() {
541
              $(this).dialog("close");
542
          }
543
        },{
544
          text: button_label,
545
          class: "submit-button",
546
          click: function() {
547
            const form_datas = {};
548
            $(_self.grid_cell_form).serializeArray().forEach(function(el){
549
              form_datas[el.name] = el.value;
550
            });
551
            form_datas.cell_size_label = _self.grid_cell_form.size[_self.grid_cell_form.size.selectedIndex].textContent;
552
            callback(form_datas);
553
            $(this).dialog("close");
554
          }
555
        }
556
      ]
557
    });
558
  },
559

  
560
  grid_cell__new: function() {
561
    const el = this.grid_cell_tpl.cloneNode(true);
562
    el.deletBtn = el.querySelector('.wcs-cards-cell--grid-cell-delete');
563
    el.editBtn = el.querySelector('.wcs-cards-cell--grid-cell-edit');
564
    el.contentEl = el.querySelector('.wcs-cards-cell--grid-cell-content');
565
    return el;
566
  },
567

  
568
  grid_cell__set: function(grid_cell, shema_cell) {
569
    const _self = this;
570

  
571
    // Set size css class
572
    if (!grid_cell.classList.contains(shema_cell.cell_size)) {
573
      if (grid_cell.dataset.cell_size) grid_cell.classList.remove(grid_cell.dataset.cell_size);
574
      if (shema_cell.cell_size) grid_cell.classList.add(shema_cell.cell_size);
575
    }
576

  
577
    // Store Shema in el data
578
    for (const key in shema_cell) {
579
      grid_cell.dataset[key] = shema_cell[key];
580
    }
581

  
582
    // set cell text
583
    let cell_text = "";
584
    shema_cell.display.forEach(function(el){
585
      cell_text += '<span class="' + el + '">' + _self.field_with_varname(shema_cell.varname).label + '</span>';
586
    })
587
    cell_text += '<span class="cell-size-label">' + shema_cell.cell_size_label + '</span>';
588
    grid_cell.contentEl.innerHTML = cell_text;
589
  },
590

  
591
  grid_cell__add: function(shema_cell) {
592
    const _self = this;
593
    const new_grid_cell = this.grid_cell__new();
594
    this.grid_cell__set(new_grid_cell, shema_cell);
595

  
596
    new_grid_cell.deletBtn.addEventListener('click', function() {_self.grid_cell__delete(new_grid_cell)});
597
    new_grid_cell.editBtn.addEventListener('click', function() {_self.grid_cell__edit(new_grid_cell)});
598

  
599
    this.add_grid_cell_btn.insertAdjacentElement('beforebegin', new_grid_cell);
600
  },
601

  
602
  grid_cell__delete: function(grid_cell) {
603
    const id = grid_cell.dataset.id;
604

  
605
    delete this.gridShema.cells[id];
606
    this.gridShema.cells_order = this.gridShema.cells_order.filter(function(i){
607
      return i != id
608
    })
609
    $(grid_cell).remove();
610
    $(this.cell).trigger("custom_cell:change");
611
  },
612

  
613
  grid_cell__edit: function(grid_cell) {
614
    const _self = this;
615
    this.grid_cell_form.varname.value = grid_cell.dataset.varname;
616
    this.grid_cell_form.size.value = grid_cell.dataset.cell_size;
617
    this.grid_cell_form.display.value = grid_cell.dataset.display;
618

  
619
    const grid_cell_shema = this.gridShema.cells[grid_cell.dataset.id];
620

  
621
    this.grid_cell__form_dialog("Modifier", function(form_datas){
622
      const grid_cell_shema_mod = _self.grid_cell__set_shema(form_datas, grid_cell_shema);
623
      _self.grid_cell__set(grid_cell, grid_cell_shema_mod);
624
      $(_self.cell).trigger("custom_cell:change");
625
    });
626
  },
627

  
628
  grid_cell__set_shema: function(form_datas, shema_cell) {
629
    shema_cell.varname = form_datas.card_field_varname;
630
    shema_cell.cell_size = form_datas.cell_size;
631
    shema_cell.display = form_datas.card_field_elements.split(',');
632
    shema_cell.cell_size_label = form_datas.cell_size_label;
633
    return shema_cell
634
  },
635

  
636
  grid_cell__add_shema: function(form_datas) {
637
    let shema_cell = {};
638
    shema_cell = this.grid_cell__set_shema(form_datas, shema_cell);
639
    shema_cell.id = this.gridShema.cells.length;
640

  
641
    this.gridShema.cells.push(shema_cell);
642
    this.gridShema.cells_order.push(shema_cell.id);
643

  
644
    this.grid_cell__add(shema_cell);
645
    $(this.cell).trigger("custom_cell:change");
646
    compute_max_height($(this.cell));
647
  },
648

  
649
  grid_cell__init: function() {
650
    if (!this.gridShema_existing) return;
651

  
652
    const _self = this;
653
    this.gridShema.cells_order.forEach(function(el){
654
      _self.grid_cell__add(_self.gridShema.cells[el]);
655
    });
656

  
657
    $(this.cell).on("cell:open", function(){
658
      compute_max_height($(this));
659
    })
660
  },
661

  
662
  //
663
  // Init method
664
  //
665

  
666
  init: function() {
667
    if (!this.cardSchema) return;
668

  
669
    const _self = this;
670

  
671
    this.grid__set_layout();
672
    this.grid_cell__init();
673
    this.grid_cell__init_form();
674

  
675
    // Edit grid layout btn click
676
    $(this.edit_grid_btn).on('click', function(){
677
      _self.grid__form_dialog(_self.grid__set_shema.bind(_self));
678
    })
679
    // Add grid cell Btn click
680
    $(this.add_grid_cell_btn).on('click', function(){
681
      _self.grid_cell__form_dialog("Ajouter", _self.grid_cell__add_shema.bind(_self));
682
    });
683
    // Grid cells sortable
684
    $(_self.grid_wrapper).sortable({
685
      items: "> .wcs-cards-cell--grid-cell",
686
      placeholder: "wcs-cards-cell--grid-cell-placeholder",
687
      update: function(event, ui){
688
        _self.gridShema.cells_order = $(this).sortable("toArray", {attribute: "data-id"});
689
        $(_self.cell).trigger("custom_cell:change");
690
      },
691
      start: function(event, ui){
692
        ui.placeholder.addClass(ui.item[0].dataset.cell_size).css('height', ui.item[0].offsetHeight);
693
      }
694
    });
695
    // when shema change
696
    $(this.cell).on("custom_cell:change", function(){
697
      console.log(_self.gridShema);
698
      console.log(JSON.stringify(_self.gridShema));
699
    })
700
  }
701
}
702

  
703
// custom card UI for each card cell
704
$(function() {
705
  $('.wcs-card-infos-cell').each(function(i, el) {
706
    const custom_card = new Card_cell_custom(el);
707
  })
400 708
});
401
-