Subversion Repositories eFlore/Applications.cel

Rev

Rev 3893 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

import {inputFile} from './display.js';
import {findFieldset, showField, hideNRemove, replacer, valeurOk} from './utils.js';
import {newFieldsPreview} from './preview.js';
import {onChangeCheckKeyUnique, missingValuesClass} from './validation.js';

// Tableau d'envoi des données
const datasToSubmit = [],
  datePattern       = '(^(((0[1-9]|1[0-9]|2[0-8])[\/](0[1-9]|1[012]))|((29|30|31)[\/](0[13578]|1[02]))|((29|30)[\/](0[4,6,9]|11)))[\/](19|[2-9][0-9])\d\d$)|(^29[\/]02[\/](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)$)',
  isModification    = Array.isArray(CHAMPS_SUPP_JSON) && 0 < CHAMPS_SUPP_JSON.length;

/**
 * ChampsSupp
 */
export function ChampsSupp() {
  this.fieldIndex = -1;
}

ChampsSupp.prototype.init = function() {
  // Ajout de nouveaux champs
  $('#add-fields').on('click', this.onClickAddNewFields.bind(this));
  // Activation/Desactivation des boutons valider et prévisualiser
  this.onClickButtonsTagMissingValues();
  // Activer la checkbox de valeur par default uniquement si une valeur est entrée
  this.onInputListValueLabelEnableDefaultCheckbox();
  // Modifications
  this.onExtentedFieldsForModification();
};

/***********************************************************
 *  Fonctions pour la création des champs supplémentaires  *
 ***********************************************************/

// Logique globale pour l'ajout de nouveaux champs
ChampsSupp.prototype.onClickAddNewFields = function() {
  this.fieldIndex++;
  this.dataIdAttr = `data-id="${this.fieldIndex}"`;
  // Affichage du formulaire pour un champ
  this.displayNewField();
  // Affichage du nom du champ
  this.onChangeDisplayFieldLabel();
  // Empêcher de créer plus d'une fois la même clé
  onChangeCheckKeyUnique();
  // Affichage des images/nom des documents importés dans les champs ajoutés
  inputFile();
  // Recueil des informations correspondantes au nouveau champ
  this.onChangeFieldTypeCollectDetails();
  // Suppression d'un champ
  this.onClickRemoveField();
};

// Création/affichage du formulaire d'un nouveau champ
ChampsSupp.prototype.displayNewField = function() {
  const fieldsetHtml    = `<fieldset ${this.dataIdAttr} class="new-field"></fieldset>`,
    fieldsetHtmlContent =
      `<h3>Nouveau champ :<br><strong class="field-title" ${this.dataIdAttr}></strong></h3>
      <!-- Nom du champ -->
      <div class="row">
        <div class="col-sm-12 mt-3 mb-3">
          <label for="field-name" title="Donnez un titre à votre champ">Nom du champ *</label>
          <input type="text" name="field-name" ${this.dataIdAttr} class="field-name form-control" placeholder="Titre de votre champ" title="Le titre du champ" required>
        </div>
        <!-- Clé du champ -->
        <div class="col-sm-12 mt-3 mb-3">
          <label for="field-key" title="Nom du champ dans la base de données">
            Clé du champ *
          </label>
          <input type="text" name="field-key" ${this.dataIdAttr} class="field-key form-control" placeholder="Clé du champ" pattern="^(?:[a-z]+(?:(?:[A-Z]+[a-z]+)+)?|[a-z]+(?:(?:-[a-z]+)+)?)$" title="Clé Unique en Camelcase ou minuscule séparés par tirets, pas d’accents pas de caractères spéciaux." required>
        </div>
        <p class="message m-2">
          <i class="fa fa-exclamation-triangle" aria-hidden="true" style="color:#ff5d55"></i>
          Une clé doit être unique<br>
          En "camelCase" (ecriture chameau)<br>
          Ou en minuscule avec tirets ("-") si nécessaire<br>
          Pas d’espaces, aucuns caractères spéciaux (accents, cédilles, etc.).
        </p>
        <!-- Type de champ -->
        <div class="col-sm-12 mt-3 mb-3 add-field-select" ${this.dataIdAttr}>
          <label for="field-element" title="Quel type de champ">Type de champ *</label>
          <select name="field-element" ${this.dataIdAttr} class="field-element form-control custom-select">
            <option value="text">Champ texte</option>
            <option value="email">Champ email</option>
            <option value="textarea">Champ rédaction</option>
            <option value="select">Menu déroulant</option>
            <option value="checkbox">Cases à cocher</option>
            <option value="list-checkbox">Liste de cases à cocher</option>
            <option value="radio">Boutons radio</option>
            <option value="date">Calendrier</option>
            <option value="range">Curseur (entre 2 bornes)</option>
            <option value="number">Nombre</option>
          </select>
        </div>
        <!-- Checkbox "champ requis" -->
        <div class="col-sm-12 radio mt-3 mb-3">
          <label class="radio-label" for="field-is_mandatory" title="Ce champ est obligatoire">
            <input type="checkbox" name="field-is_mandatory" ${this.dataIdAttr} class="field-is_mandatory form-control">
            Champ requis ?
          </label>
        </div>
        <!-- Unité des valeurs -->
        <div class="col-sm-12 mt-3 mb-3">
          <label for="field-unit" title="Unité de mesure de vos valeurs">Unités (cm, kg, ha, etc.)</label>
          <input type="text" name="field-unit" ${this.dataIdAttr} class="field-unit form-control" placeholder="symbole de vos unités">
        </div>
        <!-- Tooltip -->
        <div class="col-sm-12 mt-3 mb-3">
          <label for="field-description" title="Ajoutez une info-bulle">Info-bulle</label>
          <input type="text" name="field-description" ${this.dataIdAttr} class="field-description form-control" placeholder="Quelques mots">
        </div>
        <!-- Import d'une image d'aide à afficher en popup -->
        <div class="input-file-row row">
          <div class="input-file-container col-sm-10">
            <input type="file" class="input-file field-help" name="field-help${this.fieldIndex}" ${this.dataIdAttr} id="help-doc-${this.fieldIndex}" accept="image/*">
            <label for="field-help${this.fieldIndex}" class="label-file"><i class="fas fa-download"></i> Popup aide image (.jpg)</label>
          </div>
          <div class="btn btn-danger btn-sm remove-file" name="remove-file" ${this.dataIdAttr} title="Supprimer le fichier"><i class="fas fa-times" aria-hidden="true"></i></div>
          <div class="file-return help-doc-${this.fieldIndex} hidden"></div>
        </div>
        <!-- Boutons supprimer -->
        <div class="col-sm-12 mt-3 mb-3">
          <label for="remove-field">Supprimer</label>
          <div class="remove-field button" name="remove-field" ${this.dataIdAttr} title="Supprimer un champ"><i class="fa fa-skull" aria-hidden="true"></i></div>
        </div>
        <input type="hidden" name="field-is_visible" class="field-is_visible" ${this.dataIdAttr} value="1">
      </div>`;

  $('#new-fields').append(fieldsetHtml);

  const $fieldset = findFieldset(this.fieldIndex);

  // Insertion du contenu html du formulaire du nouveaux champs inséré dans le dom
  $fieldset.append(fieldsetHtmlContent);
  // Animation de l'affichage
  if (!isModification) {
    showField($fieldset);
    $('html, body').stop().animate({
      scrollTop: $fieldset.offset().top
    }, 300);
  }
  this.$fieldset = $fieldset;
};

// Affichage du nom du champ dès qu'il est renseigné
ChampsSupp.prototype.onChangeDisplayFieldLabel = function() {
  const $fieldset = this.$fieldset;

  $('.field-name', $fieldset).on('change', function () {
    $('.field-title', $fieldset).text($(this).val());
  });
};

// Supprimer un nouveau champ
ChampsSupp.prototype.onClickRemoveField = function() {
  $('.remove-field').click(function () {
    const $fieldset = $(this).closest('fieldset'),
      fieldIndex = $fieldset.data('id');

    $fieldset.hide(200, function () {
      if (!CHAMPS_SUPP_JSON[fieldIndex]) {
        $fieldset.remove();
      } else {
        if (0 === $('#info-suppression-champs-supp').length) {
          $('#infos-validation-boutons').after(
            `<p id="info-suppression-champs-supp" class="message invalid">
              <i class="fa fa-exclamation-triangle" aria-hidden="true" style="color:#ff5d55"></i>
              vous avez supprimé un ou plusieurs champs supplémentaires ici<br>
              Lorsque vous aurez fini de saisir/modifier/supprimer vos champs suppléménetaires, pensez à cliquer sur le bouton <i class="fa fa-bolt" aria-hidden="true" style="color:#B3C954"></i> "Valider", même si vous les avez tous supprimés, sans quoi ces changements ne seront pas pris en compte.
            </p>`
          );
        }
        $('.field-is_visible', $fieldset).val(0);
      }
    });
  });
};

/**** Recueil des informations et détails qui dépendent du type de champ choisi ****/

// Logique de recueil d'informations en fonction du type de champ choisi
ChampsSupp.prototype.onChangeFieldTypeCollectDetails = function() {
  const lthis = this,
    placeholderFieldHtml =
      `<div class="col-sm-12  mt-3">
        <label for="aide-saisie" title="Deux ou 3 mots ou chiffres pour comprendre ce que doit contenir ce champ (ex: min 20, 10 par 10, etc.)">Texte d’aide à la saisie</label>
        <input type="text" name="aide-saisie" ${this.dataIdAttr} class="aide-saisie form-control" placeholder="Ce que doit contenir ce champ">
      </div>`,
    $element = $('.field-element', this.$fieldset);

  // On insère les champs par défaut de recueil d'informations
  this.displayFieldDetailsCollect(placeholderFieldHtml);
  // Sinon :
  $element.on('change', function() {
    const selectedItem = this.value;
    // On intialise l'index pour les listes la variable qui contiendra un id pour chaque option
    let valueIndex = 0,
      fieldDetails = placeholderFieldHtml;

    // Si on hésite on qu'on se trompe dans la liste :
    // les champs de détails de l'option précédente doivent être supprimés
    hideNRemove($('.field-details', lthis.$fieldset));
    // Html de recueil de données en fonction de l'élément choisi
    switch(selectedItem) {
      case 'range':
      case 'number':
        fieldDetails =
          `<p class="message">
            <i class="fa fa-exclamation-triangle" aria-hidden="true" style="color:#ff5d55"></i> 
            Ne pas oublier de prévisualiser !!<br>
            Vérifier le bon fonctionnement et changer, si nécessaire, les valeurs de défaut, incrémentation (step), min et max.<br>
            Si le navigateur considère que certaines valeurs sont incohérentes il pourrait les modifier automatiquement
          </p>
          <!-- Placeholder -->
          ${placeholderFieldHtml}
          <!-- Valeur par défaut -->
          <div class="col-sm-12  mt-3">
            <label for="default" title="Valeur par défaut">Valeur par défaut</label>
            <input type="number" name="default" ${lthis.dataIdAttr} class="default form-control" step="0.01" lang="en">
          </div>
          <!-- Incrémentation ( attribut step="" ) -->
          <div class="col-sm-12  mt-3">
            <label for="step" title="De 10 en 10, de 0.5 en 0.5, etc.">Incrémentation (step)</label>
            <input type="number" name="step" ${lthis.dataIdAttr} class="step form-control" step="0.01" value="1" lang="en">
          </div>
          <!-- Min -->
          <div class="col-sm-12  mt-3">
            <label for="min" title="valeur min">Valeur minimale</label>
            <input type="number" name="min" ${lthis.dataIdAttr} class="min form-control" step="0.01" value="0" lang="en">
          </div>
          <!-- Max -->
          <div class="col-sm-12  mt-3">
            <label for="max" title="valeur max">Valeur maximale</label>
            <input type="number" name="max" ${lthis.dataIdAttr} class="max form-control" step="0.01" value="1" lang="en">
          </div>`;
        break;

      case 'date':
        fieldDetails =
          `<!-- Date min -->
          <div class="col-sm-12 mt-3">
            <label for="min" title="date min">Date minimale</label>
            <input type="date" name="min" ${lthis.dataIdAttr} class="min form-control" pattern="${datePattern}" title="jj/mm/aaaa">
          </div>
          <!-- Date max -->
          <div class="col-sm-12 mt-3">
            <label for="max" title="date max">Date maximale</label>
            <input type="date" name="max" ${lthis.dataIdAttr} class="max form-control" pattern="${datePattern}" title="jj/mm/aaaa">
          </div>`;
        break;

      case 'select':
      case 'checkbox':
      case 'list-checkbox':
      case 'radio':
        const mayHavePlaceholder = ['select', 'list-checkbox'].includes(selectedItem);
        let additionnalMessage = '',
          required             = 'required',
          asterisk             = ' *';

        if (mayHavePlaceholder) {
          additionnalMessage =
            `<br><i class="fas fa-info-circle" style="color:#009fb8"></i> 
            Si aucune valeur n’est indiquée pour la première option,
            <br>celle-ci servira de placeholder (indication affichée dans le champ),
            <br>et n’apparaitra pas dans les options à choisir/cocher.
            <br><i class="fa fa-exclamation-triangle" aria-hidden="true" style="color:#ff5d55"></i> 
            Dans ce cas il est impossible de choisir une "valeur par defaut"`;
          required = '';
          asterisk = '';
        }

        fieldDetails =
          `<p class="message element-message">
            <i class="fa fa-exclamation-triangle" aria-hidden="true" style="color:#ff5d55"></i> 
            Entrez au moins une valeur de ${$element.children('option:selected').text()}
            <br>Si aucun label à afficher n’est indiqué, la valeur entrée sera utilisée (première lettre en majuscule).
            ${additionnalMessage}
          </p>
          <!-- Première option -->
          <div class="new-value center-block row" data-list-value-id="${valueIndex}">
            <!-- Recueil d'une valeur de la liste -->
            <div class="col-sm-12 mt-3">
              <label for="list-value">Valeur${asterisk}</label>
              <input type="text" name="list-value" ${lthis.dataIdAttr} class="list-value form-control" data-list-value-id="${valueIndex}" placeholder="Une des valeurs de la liste" ${required}>
            </div>
            <!-- Recueil du label à afficher -->
            <div class="col-sm-12 mt-3">
              <label for="displayed-label">Label</label>
              <input type="text" name="displayed-label" ${lthis.dataIdAttr} class="displayed-label form-control" data-list-value-id="${valueIndex}" placeholder="Label à afficher">
            </div>
            <!-- Checkbox valeur par défaut -->
            <div class="col-sm-12 radio mt-3">
              <label for="is-defaut-value" title="Ceci est la valeur par défaut" class="radio-label">
                <input type="checkbox" name="is-defaut-value" ${lthis.dataIdAttr} class="is-defaut-value" checked="checked" data-list-value-id="${valueIndex}" disabled >
                Valeur par défaut
              </label>
            </div>
          </div>
          <!-- Bouton ajout d'une valeur à la liste -->
          <div class="col-sm-12 mt-3 add-value-container" ${lthis.dataIdAttr}>
            <label for="add-value" class="add-value" ${lthis.dataIdAttr} title="Ajouter une valeur à la liste">Ajouter une valeur</label>
            <div class="button add-value-button" name="add-value" ${lthis.dataIdAttr} title="Ajouter une valeur à la liste"><i class="fa fa-puzzle-piece" aria-hidden="true"></i></div>
          </div>
          <!-- checkbox ajouter une valeur "Autre:" -->
          <div class="col-sm-12 radio mt-3">
            <label for="option-other-value" title="Ajouter une option \"Autre:\" à la fin" class="radio-label">
              <input type="checkbox" name="option-other-value" ${lthis.dataIdAttr} class="option-other-value" title="Ajouter une option \"Autre\" à la fin">
              Valeur "Autre"
            </label>
          </div>`;
        break;

      // case 'email':
      // case 'text':
      // case 'textarea':
      default:
        break;
    }
    lthis.displayFieldDetailsCollect(fieldDetails);
    // Ajout des valeurs possibles
    // lorsque le champ est une liste ou case à cocher
    lthis.onClickAddNewValueToList(valueIndex);
  });
};

// Insertion dans le dom des champs de recueil d'informations
ChampsSupp.prototype.displayFieldDetailsCollect = function(fieldDetails) {
  const $detailsCollect = $('.add-field-select', this.$fieldset);

  $detailsCollect.after(`<div class="field-details col-sm-11 mt-3 row" ${this.dataIdAttr}>${fieldDetails}</div>`);
  showField($detailsCollect);
};

/**** Ajout des valeurs (options) des "champs de listes" (select, checkbox, radio, etc.) ****/

// Ajout des options des listes (deroulantes, cases à cocher etc.)
ChampsSupp.prototype.onClickAddNewValueToList = function(valueIndex) {
  const lthis = this,
    $addValueContainer = $('.add-value-container', this.$fieldset);

  $('.add-value-button', this.$fieldset).click(function() {
    valueIndex++;
    $addValueContainer.before(
      `<div class="new-value center-block row" data-list-value-id="${valueIndex}">
        <!-- Recueil d'une valeur de la liste -->
        <div class="col-sm-12 mt-3">
          <label for="list-value">Valeur *</label>
          <input type="text" name="list-value" ${lthis.dataIdAttr} class="list-value form-control" data-list-value-id="${valueIndex}" placeholder="Une des valeurs de la liste" required>
        </div>
        <!-- Recueil du label à afficher -->
        <div class="col-sm-12 mt-3">
          <label for="displayed-label">Label</label>
          <input type="text" name="displayed-label" ${lthis.dataIdAttr} class="displayed-label form-control" data-list-value-id="${valueIndex}" placeholder="Label à afficher">
        </div>
        <!-- Checkbox valeur par défaut+bouton supprimer -->
        <div class="col-sm-12 mt-3 row">
          <!-- Bouton supprimer une option -->
          <div class="col-sm-5">
            <div class="remove-value button" name="remove-value" ${lthis.dataIdAttr} data-list-value-id="${valueIndex}" title="Supprimer une valeur"><i class="fa fa-trash" aria-hidden="true"></i></div>
          </div>
          <!-- Valeur par défaut -->
          <div class="col-sm-7 radio">
            <label for="is-defaut-value" title="Ceci est la valeur par défaut" class="radio-label">
              <input type="checkbox" name="is-defaut-value" ${lthis.dataIdAttr} class="is-defaut-value" title="entrez une valeur pour activer cette case" data-list-value-id="${valueIndex}" disabled >
              Valeur défaut
            </label>
          </div>
        </div>
      </div>`
    );
    showField($addValueContainer);
    // Une seule valeur par défaut pour select et radio
    lthis.onClickDefaultValueRemoveOthers();
    // Supprimer une valeur
    lthis.onClickRemoveListValue();
  });
};

// Activer la checkbox de valeur par default uniquement si une valeur est entrée
ChampsSupp.prototype.onInputListValueLabelEnableDefaultCheckbox = function() {
  $('#new-fields').on('input blur', '.list-value', function () {
    const $fieldset = findFieldset($(this).data('id')),
      $firstDefautValue = $('.is-defaut-value', $fieldset).first();

      if ('' === $('.list-value', $fieldset).first().val()) {
        $('.is-defaut-value', $fieldset).attr('disabled', true).removeAttr('checked');
        $firstDefautValue.attr('checked', true).prop('checked',true);

      } else {
        $('.is-defaut-value', $fieldset).each(function () {
          const $thisListValue = $(`.list-value[data-list-value-id=${$(this).data('list-value-id')}]`, $fieldset);

          if ('' !== $thisListValue.val()) {
            $(this).removeAttr('disabled');
          } else {
            $(this).attr('disabled', true).removeAttr('checked');
          }
        });
      }
  });
};

// Pour les éléments "select" et "radio" il ne peut y avoir qu'une valeur par défaut cochée
ChampsSupp.prototype.onClickDefaultValueRemoveOthers = function() {
  const lthis = this,
    selectedFieldElement = $('.field-element', this.$fieldset).val();

  if (selectedFieldElement === 'select' || selectedFieldElement === 'radio') {
    $('.is-defaut-value', this.$fieldset).click(function () {
     if ($(this).is(':checked')) {
        // Décocher tous les autres
        $('.is-defaut-value:checked', lthis.$fieldset).not($(this)).removeAttr('checked');
      }
    });
  }
};

// Bouton supprimer une valeur
ChampsSupp.prototype.onClickRemoveListValue = function() {
  $('.remove-value.button', this.$fieldset).off('click').on('click', function () {
    hideNRemove($('.new-value[data-list-value-id='+$(this).data('list-value-id')+']'));
  });
};

/**** Envoi des nouveaux champs ****/

// Enregistrement des valeurs à transmettre
ChampsSupp.prototype.onClickStoreNewFields = function() {
  const count = $('fieldset').last().data('id');
  // Lorsqu'on valide
  let resultArrayIndex = 0,
    newHelpFileExists  = false;

  // Savoir si au moins un fichier "aide" est enregistré
  $('.field-help').each(function () {
    if ('' !== $(this).val()){
      newHelpFileExists = true;
    }
  })
  // dans ce cas intégrer dans le formulaire à soumettre un bloc
  // qui contiendra une copie de chacun de ces input[type="file"]
  if (newHelpFileExists){
    $('#submit-button').before('<div id="help-doc-submit" style="position:fixed;visibility:hidden;"></div>');
  }

  let $thisFieldset = $('fieldset').first(),
    valueForIsVisible,
    $inputFile,
    uploadedHelpFiles;

  // On déroule les blocs de champs supplémentaires
  for(let index = $thisFieldset.data('id'); index <= count; index++) {
    $thisFieldset = findFieldset(index);
    valueForIsVisible = $('.field-is_visible', $thisFieldset).val();
    // Certains indices peuvent correspondre à un champ supprimé
    if (0 < $($thisFieldset).length) {
      if (0 === parseInt(valueForIsVisible)) {
        datasToSubmit[resultArrayIndex] = CHAMPS_SUPP_JSON[resultArrayIndex];
      } else {
        // initialisation du tableau de résultats
        datasToSubmit[resultArrayIndex]             = {fieldValues:{}};
        $.each(['key','name','element','unit','description'], (i, fieldName) => datasToSubmit[resultArrayIndex][fieldName] = $('.field-'+fieldName, $thisFieldset).val() || null);
        // Ajout de la valeur 'requis' ou non au tableau de resultats
        datasToSubmit[resultArrayIndex].mandatory   = $('.field-is_mandatory', $thisFieldset).is(':checked');
        // Collecte les des données dépendantes de l'élément choisi
        // sous forme d'un tableau de resultats
        this.onSelectCollectDataValuesToSubmit(datasToSubmit[resultArrayIndex], $thisFieldset);

        if ($.isEmptyObject(datasToSubmit[resultArrayIndex].fieldValues)){
          delete datasToSubmit[resultArrayIndex].fieldValues;
        }
        // Copie d'un champ de fichier d'aide dans le bloc d'envoi
        $inputFile = $('.field-help', $thisFieldset);
        uploadedHelpFiles = $inputFile.get(0).files;
        if (0 < uploadedHelpFiles.length) {
          // Présence d'un document d'aide
          datasToSubmit[resultArrayIndex].help = uploadedHelpFiles[0].type;
          $inputFile.clone()
            .attr('name', 'help-'+datasToSubmit[resultArrayIndex].key)// l'attribut name prend la valeur de la clé
            .appendTo('#help-doc-submit');
        // si un fichier d'aide était déjà présent et que l'utilisateur ne le supprime pas on réinjecte le type mime
        // ce qui indique la présence d'un fichier d'aide lors de l'affichage du widget de saisie
        } else if (!!CHAMPS_SUPP_JSON[resultArrayIndex] && !!CHAMPS_SUPP_JSON[resultArrayIndex]['help'] && !$('.file-return', $thisFieldset).hasClass('hidden')) {
          datasToSubmit[resultArrayIndex].help = CHAMPS_SUPP_JSON[resultArrayIndex]['help'];

        } else {
          datasToSubmit[resultArrayIndex].help = null;
        }
        datasToSubmit[resultArrayIndex].is_visible = valueForIsVisible;
        resultArrayIndex++;
      }
    }
  }

  const resultsArrayJson = JSON.stringify(datasToSubmit, replacer);

  console.log(resultsArrayJson);

  // Désactivation de tous les champs et boutons (nouveaux champs)
  $('#new-fields, #new-fields .button, #add-fields, #preview-field').addClass('disabled');
  $('#validate-new-fields').addClass('validated');
  $('.validate-new-fields').text('Champs validés');
  // Mise à disposition des données pour le bouron submit
  $('#submit-button').before(
    //la value est passée avec des apostrophes pour que les guillemets de la string json passent bien en string de l'attribut
    `<input type="hidden" name="champs-supp" id="champs-supp" value="${resultsArrayJson}">`
  );
  // suppression du message d'alerte validations des champs supprimés en mode modification
  $('#info-suppression-champs-supp').remove();
};

// Renseigne le tableau de resultat
// pour les données dépendant de l'élément choisi
ChampsSupp.prototype.onSelectCollectDataValuesToSubmit = function(datasToSubmitObject, $thisFieldset) {
  switch(datasToSubmitObject.element) {
    case 'select':
    case 'checkbox':
    case 'list-checkbox':
    case 'radio':
      datasToSubmitObject.fieldValues.listValue = [];
      // Ajout des valeurs de liste
      this.onChangeStoreListValueLabel(datasToSubmitObject, $thisFieldset);
      // S'il y a une valeur 'autre' on l'indique à la fin de la liste
      if ($('.option-other-value', $thisFieldset).is(':checked') && -1 === datasToSubmitObject.fieldValues.listValue.indexOf('other')) {
        datasToSubmitObject.fieldValues.listValue.push('other');
      }
      break;

    case 'number':
    case 'range':
      // Placeholder
      datasToSubmitObject.fieldValues.placeholder = $('.aide-saisie', $thisFieldset).val() || null;
      // Valeur par défaut
      datasToSubmitObject.fieldValues.default = $('.default', $thisFieldset).val() || null;
      // Incrémentation ( attribut step="" )
       datasToSubmitObject.fieldValues.step = $('.step', $thisFieldset).val() || null;

    case 'date':
      // Min
      datasToSubmitObject.fieldValues.min = $('.min', $thisFieldset).val() || null;
      // Max
      datasToSubmitObject.fieldValues.max = $('.max', $thisFieldset).val() || null;
      break;

    case 'email':
    case 'text':
    case 'textarea':
    default:
      // Placeholder
      datasToSubmitObject.fieldValues.placeholder = $('.aide-saisie', $thisFieldset).val() || null;
      break;
  }
  return datasToSubmitObject;
};

// Ajout d'une valeur d'un élément liste (select, checkbox etc.)
// dans le tableau de resultats
ChampsSupp.prototype.onChangeStoreListValueLabel = function(datasToSubmitObject, $thisFieldset) {
  const $listValues = $('.list-value', $thisFieldset),
    hasPlaceholder = !valeurOk($listValues.first().val());

  $('.list-value', $thisFieldset).each(function (i) {
    const valueId          = $(this).data('list-value-id'),
      $displayedLabel      = $(`.displayed-label[data-list-value-id=${valueId}]`, $thisFieldset),
      hasDisplayedLabel    = valeurOk($displayedLabel.val());
    let displayedLabel = hasDisplayedLabel ? $displayedLabel.val() : '';

    if ($(this).val()){
      // Is-default-value non cochée
      if (!$(`.is-defaut-value[data-list-value-id="${valueId}"]`, $thisFieldset).is(':checked')) {
        datasToSubmitObject.fieldValues.listValue.push([$(this).val(), displayedLabel]);
      // Is-default-value cochée pour select/radio
      } else if (['select', 'radio'].include($('.field-element', $thisFieldset).val())) {
        // Une seule valeur par defaut, devient la première valeur du tableau+'#'
        datasToSubmitObject.fieldValues.listValue.unshift([$(this).val()+'#', displayedLabel]);
      // Is-default-value cochée pour checkbox/list-checkbox
      } else {
        // On ajoute simplement la valeur au tableau+'#'
        datasToSubmitObject.fieldValues.listValue.push([$(this).val()+'#', displayedLabel]);
      }
    } else if (0 === i) {// deviendra un placeholder
      displayedLabel = hasDisplayedLabel ? $displayedLabel.val() : '...Choisir...';
      datasToSubmitObject.fieldValues.listValue.push([null, displayedLabel]);
    }
  });
};

/*********************************************************
 *  Modification des champs supp sur un Widget existant  *
 *********************************************************/

ChampsSupp.prototype.onExtentedFieldsForModification = function() {
  if (!$('#type').val() && isModification) {
    $.each(CHAMPS_SUPP_JSON, this.fillFieldsForModification);
  }
};

ChampsSupp.prototype.fillFieldsForModification = function(index, extendedFieldValues) {
  $('#add-fields').click();

  const fieldValues = extendedFieldValues.fieldValues,
    $fieldset       = findFieldset(index),
    textFields      = [
      'name',
      'key',
      'unit',
      'description'
    ],
    fieldsetKeys    = textFields.concat([
      'is_visible',
      'is_mandatory',
      'element'
    ]),
    extendedFields  = {};

  $.each(fieldsetKeys, (i, fieldName) => extendedFields[fieldName] = $('.field-'+fieldName, $fieldset));
  extendedFields.is_visible.val(extendedFieldValues.is_visible);
  if (!extendedFieldValues.is_visible) {
    $fieldset.hide();
  }

  const selectedOption = $(`option[value=${extendedFieldValues.element}]`, extendedFields.element);

  $.each(textFields, (i, fieldName) => extendedFields[fieldName].val(extendedFieldValues[fieldName]));

  const isMandatory = 1 === extendedFieldValues.mandatory;

  extendedFields.key.attr('disabled', true);
  extendedFields.name.change();
  extendedFields.is_mandatory.attr('checked', isMandatory).prop('checked', isMandatory);

  selectedOption.attr('selected','selected');
  selectedOption.change();
  if (!!extendedFieldValues.help) {
    const fileExtension = 'png' === extendedFieldValues.help.replace('image/','').toLowerCase() ? '.png' : '.jpg',
      fileName          = extendedFieldValues.key+fileExtension;

    $('.file-return', $fieldset).append(`${fileName}<img src="${URLS_IMAGES+fileName}" width="50%">`).removeClass('hidden');
  }
  switch(extendedFieldValues.element) {
    case 'select':
    case 'checkbox':
    case 'list-checkbox':
    case 'radio':
      const listValues = fieldValues.listValue;
      let $listValueBlock;

      if ('other' === listValues.slice(-1)[0]) {
        $('.option-other-value', $fieldset).attr('checked', true).prop('checked', true);
        listValues.pop();
      }

      $.each(listValues, (i, listValue) => {
        $listValueBlock = $(`.new-value[data-list-value-id=${i}]`, $fieldset);
        if(valeurOk(listValue[0])) {
          if ('#' === listValue[0].slice(-1)) {
            listValue[0] = listValue[0].slice(0,-1);
            $('.is-defaut-value', $listValueBlock).attr('checked', true).prop('checked', true);
          }
          $('.list-value', $listValueBlock).val(listValue[0]);
        }
        if(valeurOk(listValue[1])) {
          $('.displayed-label', $listValueBlock).val(listValue[1]);
        }
        $('.list-value', $listValueBlock).trigger('input');
        if (1 < listValues.length - i) {
          $('.add-value-button', $fieldset).click();
        }
      });
      break;

    case 'number':
    case 'range':
    case 'date':
    case 'email':
    case 'text':
    case 'textarea':
    default:
      const specificationKeys = ['placeholder', 'default', 'step', 'min', 'max'];
      let classAttr;

      $.each(specificationKeys, (i, key) => {
        classAttr = key === 'placeholder' ? 'aide-saisie' : key;
        if (fieldValues[key] !== undefined) {
          $('.'+classAttr, $fieldset).val(fieldValues[key]);
        }
      });
      break;
  }
};

/*********************************
 *  Enregistrer / prévisualiser  *
 *********************************/

// Activation/desactivation des champs valider/previsualiser
ChampsSupp.prototype.onClickButtonsTagMissingValues = function() {
  const lthis = this
  $('#preview-field, #validate-new-fields').on('click', function () {
    const $button = $(this);
    //S'il n'y a pas (plus) de bloc nouveau champ
    if (0 === $('fieldset').length) {
      return;
    }
    // Classe "invalid"
    missingValuesClass();
    if (!$(this).hasClass('invalid')) {
      if ($(this).is('#validate-new-fields')) {
        // Lancement de l'enregistrement des valeurs à transmettre
        lthis.onClickStoreNewFields();
      } else if ($(this).is('#preview-field')) {
        // Lancement de la prévisualisation
        newFieldsPreview();
      }
    }
  });
  // Si un champ manquant est renseigné
  // ou on choisit nouvel élément liste (au moins une option)
  // Cette action doit être prise en compte dans la validation
  $('#new-fields').on('change', '.invalid[type="text"], .field-element', function () {
    // S'il on a pas encore cliqué sur prévisualiser/valider
    // changer l'élément ne doit pas déclancher le signalement en rouge
    if ($(this).is('.field-element') && !$('#preview-field, #validate-new-fields').hasClass('invalid')) {
      return;
    } else {
      // Classe "invalid"
      missingValuesClass();
    }
  });
};