From 6ccd4283667a070f838140b87a9bd7003e06707f Mon Sep 17 00:00:00 2001
From: Thomas JUND <tjund@entrouvert.com>
Date: Wed, 5 May 2021 14:52:49 +0200
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(-)

diff --git a/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form.html b/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form.html
index 780a52ab..1998a34a 100644
--- a/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form.html
+++ b/combo/apps/wcs/templates/combo/wcs/manager/card-infos-cell-form.html
@@ -4,5 +4,89 @@
 {{ block.super }}
 {% if card_schema %}
 {{ card_schema|json_script:card_schema_id }}
+
+{# Si une personnalisation existe déjà, simplement retourner le Json dans la cellule #}
+{% comment "existing grid schema" %}
+<script type="application/json" id="{{cell.id}}-grid-schema">
+{"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"}]}
+</script>
+{% endcomment %}
+
+{# Checkbox qui doit activé l'UI de personnalisation // TODO #}
+<p>
+<label> <input type="checkbox" name="active-custom" class="wcs-cards-cell--active-custom"> Personnaliser l'affichage</label>
+</p>
+
+{# Grille de personalisation #}
+<div class="wcs-cards-cell--grid">
+  <div class="wcs-cards-cell--grid-options">
+    <span class="wcs-cards-cell--grid-layout-label">auto</span>
+    <a role="button" class="wcs-cards-cell--grid-layout-btn">
+      Modifier
+    </a>
+  </div>
+  <div class="wcs-cards-cell--grid-cells">
+  </div>
+  <div class="wcs-cards-cell--grid-buttons">
+    <button type="button" class="wcs-cards-cell--add-grid-cell-btn">Ajouter</button>
+  </div>
+</div>
+
+{# templates utilisés par le JS #}
+<script type="text/template" class="wcs-cards-cell--grid-form-tpl">
+  <form>
+    <p>
+      Disposition
+      <select name="grid-layout">
+        <option value="fx-grid--auto">auto</option>
+        <option value="fx-grid">1 colonne</option>
+        <option value="fx-grid--t2">2 colonnes</option>
+        <option value="fx-grid--t3">3 colonnes</option>
+      </select>
+    </p>
+  </form>
+</script>
+<script type="text/template" class="wcs-cards-cell--grid-cell-form-tpl">
+  <form>
+    <p>
+      <label>
+        Champ
+        <select name="card_field_varname"></select>
+      </label>
+    </p>
+    <p>
+      <label>
+        Afficher
+        <select name="card_field_elements">
+          <option value="key,value">Label & valeur</option>
+          <option value="key">Label uniquement</option>
+          <option value="value">Valeur uniquement</option>
+          <option value="title">Titre</option>
+        </select>
+      </label>
+    </p>
+    <p>
+      <label>
+        Taille
+        <select name="cell_size">
+          <option value="">auto</option>
+          <option value="size--1-1">1/1</option>
+          <option value="size--t1-2">1/2</option>
+          <option value="size--t1-3">1/3</option>
+          <option value="size--t2-3">2/3</option>
+        </select>
+      </label>
+    </p>
+  </form>
+</script>
+<script  type="text/template" class="wcs-cards-cell--grid-cell-tpl">
+  <div class="wcs-cards-cell--grid-cell">
+    <div class="wcs-cards-cell--grid-cell-content"></div>
+    <div class="wcs-cards-cell--grid-cell-buttons">
+      <a role="button" class="wcs-cards-cell--grid-cell-edit">Modifier</a>
+      <a role="button" class="wcs-cards-cell--grid-cell-delete">Supprimer</a>
+    </div>
+  </div>
+</script>
 {% endif %}
-{% endblock %}
+{% endblock %}
\ No newline at end of file
diff --git a/combo/manager/static/css/combo.manager.css b/combo/manager/static/css/combo.manager.css
index e60be20c..422a021d 100644
--- a/combo/manager/static/css/combo.manager.css
+++ b/combo/manager/static/css/combo.manager.css
@@ -602,3 +602,82 @@ form .choices {
 	margin: 0 0 0 1em;
 	padding: 0;
 }
+
+
+.wcs-cards-cell--grid {
+	border : 1px solid #aaa;
+  	/*resize: horizontal;*/
+  	overflow: hidden;
+}
+.wcs-cards-cell--grid-options {
+	background-color: #eee;
+	padding: 3px;
+}
+.wcs-cards-cell--grid-cells[class*="fx-grid--"],
+.wcs-cards-cell--grid-buttons {
+	padding: 3px;
+}
+.wcs-cards-cell--grid-cell {
+	box-sizing: border-box;
+	border: 1px solid #aaa;
+	padding: 3px;
+	margin-top: 3px;
+	margin-bottom: 3px;
+	background-color: #fff;
+	cursor: move;
+	display: flex;
+	flex-direction: column;
+}
+.wcs-cards-cell--grid-cell.ui-sortable-helper {
+	opacity: 0.7;
+}
+.wcs-cards-cell--grid-cell-placeholder {
+	background-color: #eee;
+}
+.wcs-cards-cell--grid-cell-content {
+	flex-grow: 1;
+}
+.wcs-cards-cell--grid-cell-content > * {
+	display: block;
+}
+.wcs-cards-cell--grid-cell-content > .key {
+	font-weight: bold;
+}
+.wcs-cards-cell--grid-cell-content > .title {
+	font-size: 1.2em;
+	font-weight: bold;
+}
+.wcs-cards-cell--grid-cell-content > .key::before {
+	content: "Label ";
+	font-style: italic;
+}
+.wcs-cards-cell--grid-cell-content > .value::before {
+	content: "Valeur ";
+	font-style: italic;
+}
+.wcs-cards-cell--grid-cell-content > .title::before {
+	content: "Titre valeur ";
+	font-style: italic;
+}
+.wcs-cards-cell--grid-layout-label,
+.wcs-cards-cell--grid-cell-content > .cell-size-label {
+	color: #666;
+}
+.wcs-cards-cell--grid-layout-label::before,
+.wcs-cards-cell--grid-cell-content > .cell-size-label::before {
+	content: "[ ";
+}
+.wcs-cards-cell--grid-layout-label::after,
+.wcs-cards-cell--grid-cell-content > .cell-size-label::after {
+	content: " ]";
+}
+.wcs-cards-cell--grid-cell-buttons {
+	cursor: default;
+	display: flex;
+	justify-content: space-between;
+}
+.wcs-cards-cell--grid a[class^="icon-"],
+.wcs-cards-cell--grid a[class*=" icon-"] {
+	font-size: 150%;
+}
+
diff --git a/combo/manager/static/js/combo.manager.js b/combo/manager/static/js/combo.manager.js
index cb6e3aed..1389cd16 100644
--- a/combo/manager/static/js/combo.manager.js
+++ b/combo/manager/static/js/combo.manager.js
@@ -397,4 +397,313 @@ $(function() {
     window.location = $(this).parent('div').find('option:selected').data('add-url');
     return false;
   });
+
+});
+
+
+
+////////////////////////////////////////
+
+
+const Card_cell_custom = function(cell) {
+  this.cell = cell;
+  const cardSchema_el = cell.querySelector('[id*="card-schema-eservices"]');
+  this.cardSchema = cardSchema_el ? JSON.parse(cardSchema_el.innerText) : undefined;
+
+  if (!this.cardSchema) return;
+
+  this.active_custom_ckbox = cell.querySelector('.wcs-cards-cell--active-custom');
+
+  this.edit_grid_btn = cell.querySelector('.wcs-cards-cell--grid-layout-btn');
+  this.grid_layout_label = cell.querySelector('.wcs-cards-cell--grid-layout-label');
+
+  const grid_form_tpl_string = cell.querySelector('.wcs-cards-cell--grid-form-tpl').innerText;
+  this.grid_form = this.parse_string_tpl(grid_form_tpl_string);
+
+  this.add_grid_cell_btn = cell.querySelector('.wcs-cards-cell--add-grid-cell-btn');
+
+  const grid_cell_form_tpl_string = cell.querySelector('.wcs-cards-cell--grid-cell-form-tpl').innerText;
+  this.grid_cell_form = this.parse_string_tpl(grid_cell_form_tpl_string);
+
+  const grid_cell_tpl_string = cell.querySelector('.wcs-cards-cell--grid-cell-tpl').innerText;
+  this.grid_cell_tpl = this.parse_string_tpl(grid_cell_tpl_string);
+
+  this.grid_wrapper = cell.querySelector('.wcs-cards-cell--grid-cells');
+
+  const gridShema_default = {
+    "grid_class": "fx-grid--auto",
+    "grid_layout_label": "auto",
+    "cells": []
+  }
+  const gridShema_existing_el = cell.querySelector('[id*="grid-schema"]');
+  this.gridShema_existing = gridShema_existing_el ? JSON.parse(gridShema_existing_el.innerText) : undefined;
+  this.gridShema =  this.gridShema_existing || gridShema_default;
+  this.init();
+}
+
+
+Card_cell_custom.prototype = {
+
+  parse_string_tpl: function(string_tpl) {
+    const wrapper = document.createElement('div');
+    wrapper.innerHTML = string_tpl;
+    return wrapper.firstElementChild;
+  },
+
+  field_with_varname: function(varname) {
+    const field = this.cardSchema.fields.filter(function(i) {
+      return i.varname === varname;
+    })
+    return field[0];
+  },
+
+  //
+  //  Grid methods
+  //
+
+  grid__form_dialog: function(callback){
+    const _self = this;
+    $(this.grid_form).dialog({
+      modal: true,
+      'title': "Disposition de la grille",
+      width: 'auto',
+      buttons: [
+        {
+          text: "Annuler",
+          class:"cancel-button",
+          click: function() {
+              $(this).dialog("close");
+          }
+        },{
+          text: "Modifier",
+          class: "submit-button",
+          click: function() {
+            const form_datas = {};
+            const select_layout = _self.grid_form[0];
+            form_datas.grid_class = select_layout.value;
+            form_datas.label = select_layout[select_layout.selectedIndex].text;
+            callback(form_datas);
+            $(this).dialog("close");
+          }
+        }
+      ]
+    });
+  },
+
+  grid__set_shema: function(form_datas){
+    this.gridShema.grid_class = form_datas.grid_class;
+    this.gridShema.grid_layout_label = form_datas.label;
+
+    this.grid__set_layout();
+    $(this.cell).trigger("custom_cell:change");
+  },
+
+  grid__set_layout: function() {
+    this.grid_layout_label.textContent = this.gridShema.grid_layout_label;
+    if (this.grid_wrapper.dataset.grid_layout) {
+      this.grid_wrapper.classList.remove(this.grid_wrapper.dataset.grid_layout); }
+    this.grid_wrapper.classList.add(this.gridShema.grid_class);
+    this.grid_wrapper.dataset.grid_layout = this.gridShema.grid_class;
+  },
+
+  //
+  //  Grid cell methods
+  //
+
+  grid_cell__init_form: function() {
+    this.grid_cell_form.varname = this.grid_cell_form[0];
+    this.grid_cell_form.display = this.grid_cell_form[1];
+    this.grid_cell_form.size = this.grid_cell_form[2];
+
+    const varname_select = this.grid_cell_form.varname;
+    this.cardSchema.fields.forEach(function(el, id) {
+      if (el.varname) {
+        $('<option />')
+          .attr('value', el.varname)
+          .text(el.label)
+          .appendTo(varname_select);
+      }
+    })
+  },
+
+  grid_cell__form_dialog: function(button_label, callback){
+    const _self = this;
+    $(this.grid_cell_form).dialog({
+      modal: true,
+      'title': button_label,
+      width: 'auto',
+      buttons: [
+        {
+          text: "Annuler",
+          class:"cancel-button",
+          click: function() {
+              $(this).dialog("close");
+          }
+        },{
+          text: button_label,
+          class: "submit-button",
+          click: function() {
+            const form_datas = {};
+            $(_self.grid_cell_form).serializeArray().forEach(function(el){
+              form_datas[el.name] = el.value;
+            });
+            form_datas.cell_size_label = _self.grid_cell_form.size[_self.grid_cell_form.size.selectedIndex].textContent;
+            callback(form_datas);
+            $(this).dialog("close");
+          }
+        }
+      ]
+    });
+  },
+
+  grid_cell__new: function() {
+    const el = this.grid_cell_tpl.cloneNode(true);
+    el.deletBtn = el.querySelector('.wcs-cards-cell--grid-cell-delete');
+    el.editBtn = el.querySelector('.wcs-cards-cell--grid-cell-edit');
+    el.contentEl = el.querySelector('.wcs-cards-cell--grid-cell-content');
+    return el;
+  },
+
+  grid_cell__set: function(grid_cell, shema_cell) {
+    const _self = this;
+
+    // Set size css class
+    if (!grid_cell.classList.contains(shema_cell.cell_size)) {
+      if (grid_cell.dataset.cell_size) grid_cell.classList.remove(grid_cell.dataset.cell_size);
+      if (shema_cell.cell_size) grid_cell.classList.add(shema_cell.cell_size);
+    }
+
+    // Store Shema in el data
+    for (const key in shema_cell) {
+      grid_cell.dataset[key] = shema_cell[key];
+    }
+
+    // set cell text
+    let cell_text = "";
+    shema_cell.display.forEach(function(el){
+      cell_text += '<span class="' + el + '">' + _self.field_with_varname(shema_cell.varname).label + '</span>';
+    })
+    cell_text += '<span class="cell-size-label">' + shema_cell.cell_size_label + '</span>';
+    grid_cell.contentEl.innerHTML = cell_text;
+  },
+
+  grid_cell__add: function(shema_cell) {
+    const _self = this;
+    const new_grid_cell = this.grid_cell__new();
+    this.grid_cell__set(new_grid_cell, shema_cell);
+
+    new_grid_cell.deletBtn.addEventListener('click', function() {_self.grid_cell__delete(new_grid_cell)});
+    new_grid_cell.editBtn.addEventListener('click', function() {_self.grid_cell__edit(new_grid_cell)});
+
+    this.grid_wrapper.append(new_grid_cell);
+  },
+
+  grid_cell__delete: function(grid_cell) {
+    const cell_id = $(grid_cell).index();
+
+    this.gridShema.cells = this.gridShema.cells.filter(function(el, i){
+      return i !== cell_id;
+    });
+
+    $(grid_cell).remove();
+    $(this.cell).trigger("custom_cell:change");
+  },
+
+  grid_cell__edit: function(grid_cell) {
+    const _self = this;
+    this.grid_cell_form.varname.value = grid_cell.dataset.varname;
+    this.grid_cell_form.size.value = grid_cell.dataset.cell_size;
+    this.grid_cell_form.display.value = grid_cell.dataset.display;
+    const cell_id = $(grid_cell).index();
+    const grid_cell_shema = this.gridShema.cells[cell_id];
+
+    this.grid_cell__form_dialog("Modifier", function(form_datas){
+      const grid_cell_shema_mod = _self.grid_cell__set_shema(form_datas, grid_cell_shema);
+      _self.grid_cell__set(grid_cell, grid_cell_shema_mod);
+      $(_self.cell).trigger("custom_cell:change");
+    });
+  },
+
+  grid_cell__set_shema: function(form_datas, shema_cell) {
+    shema_cell.varname = form_datas.card_field_varname;
+    shema_cell.cell_size = form_datas.cell_size;
+    shema_cell.display = form_datas.card_field_elements.split(',');
+    shema_cell.cell_size_label = form_datas.cell_size_label;
+    return shema_cell
+  },
+
+  grid_cell__add_shema: function(form_datas) {
+    let shema_cell = {};
+    shema_cell = this.grid_cell__set_shema(form_datas, shema_cell);
+
+    this.gridShema.cells.push(shema_cell);
+
+    this.grid_cell__add(shema_cell);
+    $(this.cell).trigger("custom_cell:change");
+    compute_max_height($(this.cell));
+  },
+
+  grid_cell__init: function() {
+    if (!this.gridShema_existing) return;
+
+    const _self = this;
+    this.gridShema.cells.forEach(function(el){
+      _self.grid_cell__add(el);
+    });
+
+    $(this.cell).on("cell:open", function(){
+      compute_max_height($(this));
+    })
+  },
+
+  //
+  // Init method
+  //
+
+  init: function() {
+    if (!this.cardSchema) return;
+
+    const _self = this;
+
+    this.grid__set_layout();
+    this.grid_cell__init();
+    this.grid_cell__init_form();
+
+    // Edit grid layout btn click
+    $(this.edit_grid_btn).on('click', function(){
+      _self.grid__form_dialog(_self.grid__set_shema.bind(_self));
+    })
+    // Add grid cell Btn click
+    $(this.add_grid_cell_btn).on('click', function(){
+      _self.grid_cell__form_dialog("Ajouter", _self.grid_cell__add_shema.bind(_self));
+    });
+    // Grid cells sortable
+    $(_self.grid_wrapper).sortable({
+      items: "> .wcs-cards-cell--grid-cell",
+      placeholder: "wcs-cards-cell--grid-cell-placeholder",
+      update: function(event, ui) {
+        ui.item.data('update_index', ui.item.index());
+        const moved_cell_shema = _self.gridShema.cells[ui.item.data('start_index')];
+        _self.gridShema.cells.splice(ui.item.data('start_index'), 1);
+        _self.gridShema.cells.splice(ui.item.data('update_index'), 0, moved_cell_shema);
+        $(_self.cell).trigger("custom_cell:change");
+      },
+      start: function(event, ui) {
+        ui.item.data("start_index", ui.item.index());
+        ui.placeholder.addClass(ui.item[0].dataset.cell_size).css('height', ui.item[0].offsetHeight);
+      }
+    });
+    // when shema change
+    $(this.cell).on("custom_cell:change", function(){
+      console.log(_self.gridShema);
+      console.log(JSON.stringify(_self.gridShema));
+    })
+  }
+}
+
+// custom card UI for each card cell
+$(function() {
+  $('.wcs-card-infos-cell').each(function(i, el) {
+    const custom_card = new Card_cell_custom(el);
+  })
 });
-- 
2.20.1

