Projet

Général

Profil

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

Thomas Jund, 11 mai 2021 17:09

Télécharger (16,5 ko)

Voir les différences:

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

 .../wcs/manager/card-infos-cell-form.html     |  86 ++++-
 combo/manager/static/css/combo.manager.css    |  79 +++++
 combo/manager/static/js/combo.manager.js      | 309 ++++++++++++++++++
 3 files changed, 473 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":[{"varname":"adresse_lieu","cell_size":"size--1-1","display":["title"],"cell_size_label":"1/1"},{"varname":"adresse_lieu","cell_size":"","display":["key","value"],"cell_size_label":"auto"},{"varname":"zip_code_lieu","cell_size":"","display":["value"],"cell_size_label":"auto"},{"varname":"activite","cell_size":"","display":["key","value"],"cell_size_label":"auto"}]}
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
    <span class="wcs-cards-cell--grid-layout-label">auto</span>
24
    <a role="button" class="wcs-cards-cell--grid-layout-btn">
25
      Modifier
26
    </a>
27
  </div>
28
  <div class="wcs-cards-cell--grid-cells">
29
  </div>
30
  <div class="wcs-cards-cell--grid-buttons">
31
    <button type="button" class="wcs-cards-cell--add-grid-cell-btn">Ajouter</button>
32
  </div>
33
</div>
34

  
35
{# templates utilisés par le JS #}
36
<script type="text/template" class="wcs-cards-cell--grid-form-tpl">
37
  <form>
38
    <p>
39
      Disposition
40
      <select name="grid-layout">
41
        <option value="fx-grid--auto">auto</option>
42
        <option value="fx-grid">1 colonne</option>
43
        <option value="fx-grid--t2">2 colonnes</option>
44
        <option value="fx-grid--t3">3 colonnes</option>
45
      </select>
46
    </p>
47
  </form>
48
</script>
49
<script type="text/template" class="wcs-cards-cell--grid-cell-form-tpl">
50
  <form>
51
    <p>
52
      <label>
53
        Champ
54
        <select name="card_field_varname"></select>
55
      </label>
56
    </p>
57
    <p>
58
      <label>
59
        Afficher
60
        <select name="card_field_elements">
61
          <option value="key,value">Label & valeur</option>
62
          <option value="key">Label uniquement</option>
63
          <option value="value">Valeur uniquement</option>
64
          <option value="title">Titre</option>
65
        </select>
66
      </label>
67
    </p>
68
    <p>
69
      <label>
70
        Taille
71
        <select name="cell_size">
72
          <option value="">auto</option>
73
          <option value="size--1-1">1/1</option>
74
          <option value="size--t1-2">1/2</option>
75
          <option value="size--t1-3">1/3</option>
76
          <option value="size--t2-3">2/3</option>
77
        </select>
78
      </label>
79
    </p>
80
  </form>
81
</script>
82
<script  type="text/template" class="wcs-cards-cell--grid-cell-tpl">
83
  <div class="wcs-cards-cell--grid-cell">
84
    <div class="wcs-cards-cell--grid-cell-content"></div>
85
    <div class="wcs-cards-cell--grid-cell-buttons">
86
      <a role="button" class="wcs-cards-cell--grid-cell-edit">Modifier</a>
87
      <a role="button" class="wcs-cards-cell--grid-cell-delete">Supprimer</a>
88
    </div>
89
  </div>
90
</script>
7 91
{% endif %}
8
{% endblock %}
92
{% 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-cells[class*="fx-grid--"],
617
.wcs-cards-cell--grid-buttons {
618
	padding: 3px;
619
}
620
.wcs-cards-cell--grid-cell {
621
	box-sizing: border-box;
622
	border: 1px solid #aaa;
623
	padding: 3px;
624
	margin-top: 3px;
625
	margin-bottom: 3px;
626
	background-color: #fff;
627
	cursor: move;
628
	display: flex;
629
	flex-direction: column;
630
}
631
.wcs-cards-cell--grid-cell.ui-sortable-helper {
632
	opacity: 0.7;
633
}
634
.wcs-cards-cell--grid-cell-placeholder {
635
	background-color: #eee;
636
}
637
.wcs-cards-cell--grid-cell-content {
638
	flex-grow: 1;
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 > .title {
647
	font-size: 1.2em;
648
	font-weight: bold;
649
}
650
.wcs-cards-cell--grid-cell-content > .key::before {
651
	content: "Label ";
652
	font-style: italic;
653
}
654
.wcs-cards-cell--grid-cell-content > .value::before {
655
	content: "Valeur ";
656
	font-style: italic;
657
}
658
.wcs-cards-cell--grid-cell-content > .title::before {
659
	content: "Titre valeur ";
660
	font-style: italic;
661
}
662
.wcs-cards-cell--grid-layout-label,
663
.wcs-cards-cell--grid-cell-content > .cell-size-label {
664
	color: #666;
665
}
666
.wcs-cards-cell--grid-layout-label::before,
667
.wcs-cards-cell--grid-cell-content > .cell-size-label::before {
668
	content: "[ ";
669
}
670
.wcs-cards-cell--grid-layout-label::after,
671
.wcs-cards-cell--grid-cell-content > .cell-size-label::after {
672
	content: " ]";
673
}
674
.wcs-cards-cell--grid-cell-buttons {
675
	cursor: default;
676
	display: flex;
677
	justify-content: space-between;
678
}
679
.wcs-cards-cell--grid a[class^="icon-"],
680
.wcs-cards-cell--grid a[class*=" icon-"] {
681
	font-size: 150%;
682
}
683

  
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": []
437
  }
438
  const gridShema_existing_el = cell.querySelector('[id*="grid-schema"]');
439
  this.gridShema_existing = gridShema_existing_el ? JSON.parse(gridShema_existing_el.innerText) : undefined;
440
  this.gridShema =  this.gridShema_existing || gridShema_default;
441
  this.init();
442
}
443

  
444

  
445
Card_cell_custom.prototype = {
446

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

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

  
460
  //
461
  //  Grid methods
462
  //
463

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

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

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

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

  
509
  //
510
  //  Grid cell methods
511
  //
512

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

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

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

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

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

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

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

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

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

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

  
598
    this.grid_wrapper.append(new_grid_cell);
599
  },
600

  
601
  grid_cell__delete: function(grid_cell) {
602
    const cell_id = $(grid_cell).index();
603

  
604
    this.gridShema.cells = this.gridShema.cells.filter(function(el, i){
605
      return i !== cell_id;
606
    });
607

  
608
    $(grid_cell).remove();
609
    $(this.cell).trigger("custom_cell:change");
610
  },
611

  
612
  grid_cell__edit: function(grid_cell) {
613
    const _self = this;
614
    this.grid_cell_form.varname.value = grid_cell.dataset.varname;
615
    this.grid_cell_form.size.value = grid_cell.dataset.cell_size;
616
    this.grid_cell_form.display.value = grid_cell.dataset.display;
617
    const cell_id = $(grid_cell).index();
618
    const grid_cell_shema = this.gridShema.cells[cell_id];
619

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

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

  
635
  grid_cell__add_shema: function(form_datas) {
636
    let shema_cell = {};
637
    shema_cell = this.grid_cell__set_shema(form_datas, shema_cell);
638

  
639
    this.gridShema.cells.push(shema_cell);
640

  
641
    this.grid_cell__add(shema_cell);
642
    $(this.cell).trigger("custom_cell:change");
643
    compute_max_height($(this.cell));
644
  },
645

  
646
  grid_cell__init: function() {
647
    if (!this.gridShema_existing) return;
648

  
649
    const _self = this;
650
    this.gridShema.cells.forEach(function(el){
651
      _self.grid_cell__add(el);
652
    });
653

  
654
    $(this.cell).on("cell:open", function(){
655
      compute_max_height($(this));
656
    })
657
  },
658

  
659
  //
660
  // Init method
661
  //
662

  
663
  init: function() {
664
    if (!this.cardSchema) return;
665

  
666
    const _self = this;
667

  
668
    this.grid__set_layout();
669
    this.grid_cell__init();
670
    this.grid_cell__init_form();
671

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

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