view src/add-one-spectrum-index.js @ 1:7e3085fc60c1 draft default tip

master branch Updating
author lain
date Wed, 30 Aug 2023 14:21:18 +0000
parents
children
line wrap: on
line source


var token = "{{ PF_TOKEN_PLACEHOLDER }}" ;
if ({{ TAB_INDEX_PLACEHOLDER }} == 1) {
}

context_{{ TAB_INDEX_PLACEHOLDER }} = {
  prefix: "#accordion-{{ TAB_INDEX_PLACEHOLDER }} ",
  name: "Context[{{ TAB_INDEX_PLACEHOLDER }}]",
  produce_json: {{ PRODUCE_JSON_PLACEHOLDER }},
  DEFAULT_MS_PEAK_VALUES: {{ MS_PEAK_VALUES_PLACEHOLDER }},
  DEFAULT_DATA: {{ DEFAULT_DATA }},
  peakforest_url: "{{ PF_URL_PLACEHOLDER }}",
  tab_index: "{{ TAB_INDEX_PLACEHOLDER }}",
  modeEditSpectrum: false,
  isSeparationFlowRateInit: false,
  isMSpeaksInit: false,
  isLC: false,
  isGC: false,
  isIC: false,
  hot_LC_SFG: null ,
  hot_MS_Peaks: null,
  hot_RCC_ADDED: null,
  jsonSpectrumType: null,
  isJsonSpectrumTypeComplete: false,
  jsonSample: null,
  isJsonSampleComplete: false,
  isJsonRCCaddedComplete: false,
  jsonChromato: null,
  isJsonChromatoComplete: false,
  jsonAnalyzer: null,
  isJsonAnalyzerComplete: false,
  jsonPeaksList: [],
  isJsonPeaksListComplete: false,
  jsonOtherMetadata: null,
  isJsonOtherMetadataComplete: false,
  jsonMolIonization: null,
  jsonMolIonBeam: null,
  cptPeakListTab: 0,
  jsonAnalyzerAcquisition: [],
  idMetadataMap: {},
  listOfViewableSpectra: [],
  singlePick: true,
  multiPickLine: -1,
  subjects: [],
  fitlerSearchLoadlCpd: 5,
  inchikey: null,
  initialized: false,
  selected_ion_index: null,
  lock: {
    precursor_ion: false
  },

  sent_json: null,

  init: function() {

    var self = this ;

    $(document).ready(() => self.on_ready());
    $(document).ready(function() {
      console.log("adding click on open_tab_{{ TAB_INDEX_PLACEHOLDER }}.") ;
      var activate_tab = function() {
        if (self.initialized) {
          return ;
        }
        self.auto_set_spec_type() ;
      }
      if (self.is_ref()) {
        $("#open_tab_{{ TAB_INDEX_PLACEHOLDER }}").click(activate_tab) ;
      }
      if ({{ TAB_INDEX_PLACEHOLDER }} == 1) {
        activate_tab() ;
      }
    }) ;

    return (self) ;

  },

  on_ready: function() {
    var self = this ;

    $(self.prefix+".pickChemicalCompound").click(self.pickChemicalCompound);
    $(self.prefix+".add1spectrum").change(
      function(){self.add1spectrum_change_handler(this)}
    )
    self.attach_search() ;
    self.add_date_check() ;
    self.populate_selects() ;
    self.add_change_handlers() ;
    self.show_hide_ms_ms2_fields() ;
  },

  populate_selects: function() {
    var self = this ;
    var choose_in_list ;

    choose_in_list = `
      <option value="" selected="selected" disabled="disabled">
        choose in list&hellip;
      </option>
    ` ;
    $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(choose_in_list) ;
    $("#add1spectrum-chromatoLC-colConstructor-{{ TAB_INDEX_PLACEHOLDER }}").append(choose_in_list) ;
    $("#add1spectrum-chromatoLC-separationSolvA-{{ TAB_INDEX_PLACEHOLDER }}").append(choose_in_list) ;
    $("#add1spectrum-chromatoLC-separationSolvB-{{ TAB_INDEX_PLACEHOLDER }}").append(choose_in_list) ;
    $("#add1spectrum-sample-lcmsSolvent-{{ TAB_INDEX_PLACEHOLDER }}").append(choose_in_list) ;
    $.getJSON("{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/list-lc-methods.json", self.populate_lc_methods) ;
    $.getJSON("{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/list-lc-columns.json", self.populate_lc_columns) ;
    $.getJSON("{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/list-lc-solvents.json", self.populate_lc_solvents) ;
    $.getJSON("{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/list-ms-ionization-methods.json", self.populate_ms_ionization) ;
    $.getJSON("{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/list-lcms-solvents.json", self.populate_lcms_solvents) ;
    self.resetFromColors();
  },

  attach_search: function() {
    var self = this ;

    $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").bind("keypress", function(e) {
      var code = e.keyCode || e.which;
      if (code == 13) {
        self.searchLocalCompound();
      }
    });
    $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").typeahead({
      source: function(query, process) {
        return self.searchAjax();
      }
    });
  },

  add_date_check: function() {
    var self = this ;

    $("#add1spectrum-other-date-{{ TAB_INDEX_PLACEHOLDER }}").focusout(function() {
      var element = $(this) ;
      self.rm_warning(element);
      self.rm_success(element) ;
      if (element.val() == "") {
        element.parent().addClass("has-warning");
      } else {
        element.parent().addClass("has-success");
      }
    });
  },

  populate_lc_methods: function(data) {
    // load data from json
    $.each(data.methods,function() {
      if (this.name !== undefined) {
        if (this.value !== undefined) {
          $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
            `<option value="${this.value}">${this.name}</option>`
          );
        } else {
          $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
            `<option disabled>${this.name}</option>`
          );
        }
      }
    });
  },

  populate_lc_columns: function(data) {
    // load data from json
    $.each(data.columns, function() {
      $("#add1spectrum-chromatoLC-colConstructor-{{ TAB_INDEX_PLACEHOLDER }}").append(
        `<option value="${this.value}">${this.name}</option>`
      );
    });
    $("#add1spectrum-chromatoLC-colConstructor-{{ TAB_INDEX_PLACEHOLDER }}").append(
      '<option value="other" >Other</option>'
    );
  },

  populate_lc_solvents: function(data) {
    // load data from json
    $.each(data.solvents, function() {
      $("#add1spectrum-chromatoLC-separationSolvA-{{ TAB_INDEX_PLACEHOLDER }}").append(
        `<option value="${this.value}">${this.name}</option>`
      );
      $("#add1spectrum-chromatoLC-separationSolvB-{{ TAB_INDEX_PLACEHOLDER }}").append(
        `<option value="${this.value}">${this.name}</option>`
      );
    });
  },

  populate_ms_ionization: function(data) {
    // load data from json
    $.each(data.methods,function() {
      if (this.name !==undefined) {
        if (this.value !==undefined) {
          $("#add1spectrum-analyzserMS-ionizationMethod-pos-{{ TAB_INDEX_PLACEHOLDER }}").append(
            `<option value="${this.value}">${this.name}</option>`
          );
          $("#add1spectrum-analyzserMS-ionizationMethod-neg-{{ TAB_INDEX_PLACEHOLDER }}").append(
            `<option value="${this.value}">${this.name}</option>`
          );
        } else {
          $("#add1spectrum-analyzserMS-ionizationMethod-pos-{{ TAB_INDEX_PLACEHOLDER }}").append(
            `<option disabled>${this.name}</option>`
          );
          $("#add1spectrum-analyzserMS-ionizationMethod-neg-{{ TAB_INDEX_PLACEHOLDER }}").append(
            `<option disabled>${this.name}</option>`
          );
        }
      }
    });
  },

  populate_lcms_solvents: function(data) {
    // load data from json
    $.each(data.solvents, function () {
      $("#add1spectrum-sample-lcmsSolvent-{{ TAB_INDEX_PLACEHOLDER }}").append(
        `<option value="${this.value}" class="${this.classD}">${this.name}</option>`
      );
    });
  },

  add_change_handlers: function() {
    var self = this ;

    $("#add1spectrum-ionTrapBeam-type-{{ TAB_INDEX_PLACEHOLDER }}").on("change", function() {
      var v = $("#add1spectrum-ionTrapBeam-type-{{ TAB_INDEX_PLACEHOLDER }}").val();
      $(self.prefix + ".add1spectrum-ionTrap").hide();
      if (v == "beam") {
      } else if (v == "trap") {
        $(self.prefix + ".add1spectrum-ionTrap").show();
      }
    }) ;
  },

  show_hide_ms_ms2_fields: function() {
    var self = this ;
    $(self.prefix + " .disabled-if-ms").attr("disabled", self.is_ms())
    $(self.prefix + " .disabled-if-msms").attr("disabled", self.is_ms2())
    $(self.prefix + " .disabled-if-ms2").attr("disabled", self.is_ms2())
    if (self.is_ms()) {
      self.hide(self.prefix + " .hidden-if-ms") ;
    }
    if (self.is_ms2()) {
      self.hide(self.prefix + " .hidden-if-msms") ;
      self.hide(self.prefix + " .hidden-if-ms2") ;
    }
  },

  is_mix: function() {
    return this.DEFAULT_DATA["sample_type"] == "compound-mix" ;
  },

  is_ref: function() {
    return this.DEFAULT_DATA["sample_type"] == "compound-ref" ;
  },

  is_ms: function() {
    return this.DEFAULT_DATA["spectrum_type"] == "LC_MS" ;
  },

  is_ms2: function() {
    return this.DEFAULT_DATA["spectrum_type"] == "LC_MSMS" ;
  },

  is_other_in_mix() {
    return this.is_mix() && {{ TAB_INDEX_PLACEHOLDER }} > 1 ;
  },

  hide: function(id) {
    if (typeof id == Array) {
      return (id.forEach(hide)) ;
    }
    $(id).hide()
  },

  rm_success: function(element) {
    return (this.rm_parent_class(element, "has-success"))
  },
  rm_error: function(element) {
    return (this.rm_parent_class(element, "has-error"))
  },
  rm_warning: function(element) {
    return (this.rm_parent_class(element, "has-warning"))
  },
  set_success: function(element) {
    return (this.set_parent_class(element, "has-success"))
  },
  set_error: function(element) {
    return (this.set_parent_class(element, "has-error"))
  },
  set_warning: function(element) {
    return (this.set_parent_class(element, "has-warning"))
  },
  rm_parent_class: function(element, cls) {
    var parent ;

    if ((parent = element.parent()) == null) {
      return false ;
    }
    return this.rm_class(parent, cls) ;
  },
  set_parent_class: function(element, cls) {
    var parent ;

    if ((parent = element.parent()) == null) {
      return false ;
    }
    return this.set_class(parent, cls) ;
  },
  rm_class: function(element, cls) {
    if (element.hasClass(cls)) {
      element.removeClass(cls) ;
      return true ;
    }
    return false ;
  },
  set_class: function(element, cls) {
    if (element.hasClass(cls)) {
      return false ;
    }
    element.addClass(cls) ;
    return true ;
  },
  is_success: function(element) {
    return (this.parent_has_class(element, "has-success"))
  },
  is_warning: function(element) {
    return (this.parent_has_class(element, "has-warning"))
  },
  is_error: function(element) {
    return (this.parent_has_class(element, "has-error"))
  },
  is_optional: function(element) {
    return (element.hasClass("is-optional"))
  },
  is_mandatory: function(element) {
    return (element.hasClass("is-mandatory"))
  },
  parent_has_class: function(element, cls) {
    var parent ;

    if ((parent = element.parent()) == null) {
      return false ;
    }
    return (parent.hasClass(cls)) ;
  },

  add1spectrum_change_handler: function(element) {
    var self = this ;
    var idElem ;
    var valElem ;
    var isSuccess ;
    var isWarning ;
    var isError ;
    var isOptional ;
    var isMandatory ;

    element = $(element) ;
    idElem = element.attr("id") ;
    valElem = element.val();
    console.log(`Change handler called for [${idElem}]=${valElem}`) ;
    if (idElem.split("-").slice(0, -1).join("-") == "add1spectrum-peaksMS-msPrecursorIon") {
      var index = idElem.split("-")[3] - 1 ;
      if (all_contexts[index] !== null && all_contexts[index] !== undefined) {
        all_contexts[index].sync_precursor_ion() ;
        if (all_contexts[index].hot_MS_Peaks != null) {
          all_contexts[index].hot_MS_Peaks.render()
        }
      }
    }
    isSuccess = self.is_success(element);
    isWarning = self.is_warning(element);
    isError = self.is_error(element);
    isOptional = self.is_optional(element);
    isMandatory = self.is_mandatory(element);

    switch(idElem) {
    case "add1spectrum-sample-type-{{ TAB_INDEX_PLACEHOLDER }}":
      if (valElem == "compound-ref") {
        $("#add1spectrum-sample-type-compound-ref-{{ TAB_INDEX_PLACEHOLDER }}").show();
        $("#add1spectrum-sample-type-compound-mix-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-sample-type-rcc-added-{{ TAB_INDEX_PLACEHOLDER }}").hide();
      } else if (valElem == "compound-mix") {
        $("#add1spectrum-sample-type-compound-mix-{{ TAB_INDEX_PLACEHOLDER }}").show();
        $("#add1spectrum-sample-type-compound-ref-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-sample-type-rcc-added-{{ TAB_INDEX_PLACEHOLDER }}").show();
        self.handsontableRefChemCpdAdded(null);
      }
      break;
    case "add1spectrum-chromatoLC-colConstructor-{{ TAB_INDEX_PLACEHOLDER }}":
      self.resetElemColor("add1spectrum-chromatoLC-colConstructorOther-{{ TAB_INDEX_PLACEHOLDER }}");
      if (valElem == "" || valElem == null || valElem != "other" ) {
        self.disableElem("add1spectrum-chromatoLC-colConstructorOther-{{ TAB_INDEX_PLACEHOLDER }}");
      } else {
        self.enableElem("add1spectrum-chromatoLC-colConstructorOther-{{ TAB_INDEX_PLACEHOLDER }}");
      }
      break;
    case "add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}":
      self.fulfillLCdata(valElem);
      break;
    case "add1spectrum-analyzserMS-ionizationMethod-pos-{{ TAB_INDEX_PLACEHOLDER }}":
      if ($("#add1spectrum-analyzserMS-ionizationMethod-pos-{{ TAB_INDEX_PLACEHOLDER }}").val() != null) {
        $($("#add1spectrum-peaksMS-polarity-{{ TAB_INDEX_PLACEHOLDER }} option")[1]).attr("disabled", false);
      }
      break;
    case "add1spectrum-analyzserMS-ionizationMethod-neg-{{ TAB_INDEX_PLACEHOLDER }}":
      if ($("#add1spectrum-analyzserMS-ionizationMethod-neg-{{ TAB_INDEX_PLACEHOLDER }}").val() != null) {
        $($("#add1spectrum-peaksMS-polarity-{{ TAB_INDEX_PLACEHOLDER }} option")[2]).attr("disabled", false);
      }
      break;
    }
    if ((isMandatory || isOptional) && (valElem == "" || valElem == null)) {
      if (isSuccess) {
        self.rm_success(element) ;
      } else if (isWarning) {
        self.rm_warning(element) ;
      } else if (isError) {
        self.rm_error(element) ;
      }
      if (isMandatory) {
        self.set_error(element) ;
      } else {
        self.set_warning(element) ;
      }
    }
    if (isMandatory && (valElem != "" && valElem != null)) {
      if (isError) {
        self.rm_error(element) ;
      }
      self.set_success(element) ;
    } else if (isOptional && valElem != "") {
      if (isWarning) {
        self.rm_warning(element) ;
      }
      self.set_success(element) ;
    }
    if (element.parent().children("input").size() == 2) {
      if (isMandatory) {
        if (isSuccess) {
          self.rm_success(element) ;
        } else if (isWarning) {
          self.rm_warning(element) ;
        } else if (isError) {
          self.rm_error(element) ;
        }
        if (element.parent().children("input").toArray().some(
          (el) => $(el).val() === null || $(el).val() === ""
        )) {
          self.set_error(element) ;
        } else {
          self.set_success(element) ;
        }
      } else if (isOptional) {
        isSuccess = self.is_success(element);
        isWarning = self.is_warning(element);
        isError = self.is_error(element);
        if (isSuccess) {
          self.rm_success(element)
        } else if (isWarning) {
          self.rm_warning(element) ;
        } else if (isError) {
          self.rm_error(element) ;
        }
        if (element.parent().children("input").toArray().some(
          (el) => ($(el).val() == null || $(el).val() == "")
        )) {
          self.set_warning(element) ;
        } else {
          self.set_success(element) ;
        }
      }
    }
    if (element.hasClass("one-or-more")) {
      // get parent class
      isSuccess = self.is_success(element);
      isWarning = self.is_warning(element);
      isError = self.is_error(element);
      // reset class
      if (isSuccess) {
        self.rm_success(element) ;
      } else if (isWarning) {
        self.rm_warning(element) ;
      } else if (isError) {
        self.rm_error(element) ;
      }
      isTmpSuccess = false;
      $.each(element.parent().children("input"), function(id, child){
        if ($(child).val() != null && $(child).val() != "") {
          isTmpSuccess = true;
        }
      });
      $.each(element.parent().children("select"), function(id, child){
        if ($(child).val() != null && $(child).val() != "") {
          isTmpSuccess = true;
        }
      });
      // end parkour
      element.parent().addClass(
        isTmpSuccess ? "has-success" : "has-error"
      );
    }
    // CHECK IF OK STEP 2
    if (element.hasClass("add1spectrum-sampleForm")) {
      var isBtnStep2OK = true;
      $.each($(self.prefix + ".add1spectrum-sampleForm"), (id, elem) => {
        if (self.is_error($(elem)) && $(elem).is(":visible")) {
          isBtnStep2OK = false;
        }
      });
      if (isBtnStep2OK) {
        self.rm_class($("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.set_class($("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
      } else {
        self.set_class($("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.rm_class($("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
      }
    }
    // CHECK IF OK STEP 3 - LC
    if (
      element.hasClass("add1spectrum-chromatoLCForm")
      && $("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}").is(":visible")
    ) {
      var isBtnStep3OK = true;
      $.each($(self.prefix+".add1spectrum-chromatoLCForm"), (id, elem) => {
        if (self.is_error($(elem)) && $(elem).is(":visible"))
          isBtnStep3OK = false;
      });
      if (isBtnStep3OK) {
        self.rm_class($("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.set_class($("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
      } else {
        self.set_class($("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.rm_class($("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
      }
    }
    // TODO CHECK IF OK STEP 3 - GC
    // CHECK IF OK STEP 4 - MS ANALYZER
    if (
      element.hasClass("add1spectrum-analyzerMSForm")
      && $("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}").is(":visible")
    ) {
      var isBtnStep4OK = true;
      $.each($(self.prefix+".add1spectrum-analyzerMSForm"), (id, elem) => {
        if (self.is_error($(elem)) && $(elem).is(":visible"))
          isBtnStep4OK = false;
      });
      if (isBtnStep4OK) {
        self.rm_class($("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.set_class($("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
      } else {
        self.set_class($("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.rm_class($("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
      }
    }
    // CHECK IF OK STEP 5 - PEAKS
    if (
      element.hasClass("add1spectrum-peaksMSForm-peaklist")
      && $("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}").is(":visible")
    ) {
      var isBtnStep5OK = true;
      $.each($(self.prefix+".add1spectrum-peaksMSForm-peaklist"), (id, elem) => {
        if (self.is_error($(elem)) && $(elem).is(":visible"))
          isBtnStep5OK = false;
      });
      if (isBtnStep5OK && (self.is_ms() || self.a_ion_parent_is_selected())) {
        self.rm_class($("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.set_class($("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
      } else {
        self.set_class($("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
        self.rm_class($("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
        $("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
      }
    }
    // CHECK IF OK STEP 6 - OTHER DATA
    if (
      element.hasClass("add1spectrum-otherForm")
      && $("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}").is(":visible")
    ) {
      self.checkIfEnableSubmit() ;
    }
  },

  a_ion_parent_is_selected: function() {
    return (this.get_selected_parent_ion_mz() !== null) ;
  },

  get_selected_parent_ion_index: function() {
    var curent_mz = this.get_selected_parent_ion_mz() ;
    if (curent_mz === null) {
      return null;
    }
    if (this.hot_MS_Peaks == undefined) {
      return null ;
    }
    var data = this.hot_MS_Peaks.getData() ;
    for (var i = 0 ; i < data.length ; i += 1) {
      if (Math.abs(data[i][0] - curent_mz) < 0.0001) {
        return i ;
      }
    }
    return null ;
  },

  get_selected_parent_ion_mz: function() {
    return $(
      "#add1spectrum-peaksMS-msPrecursorIon-{{ TAB_INDEX_PLACEHOLDER }}"
    ).val() || null ;
  },

  auto_set_spec_type: function() {
    console.log("auto_set_spec_type...") ;
    var self = this ;
    var id = `#set_${self.DEFAULT_DATA["spectrum_type"]}_spectrum_button` ;
    var element = $(self.prefix + id) ;
    if (element.length) {
      element.click() ;
      console.log(`auto_set_spec_type to ${self.DEFAULT_DATA["spectrum_type"]} ok.`)
    } else {
      console.log(element)
      console.log("Failed!")
    }
    if (self.DEFAULT_DATA["sample_type"]) {
      self.auto_set_sample_type(self) ;
    }
  },

  auto_set_sample_type: function() {
    console.log("auto_set_sample_type...") ;
    var self = this ;
    var id = "#add1spectrum-sample-type-{{ TAB_INDEX_PLACEHOLDER }}" ;
    var element = $(id) ;
    if (element.length) {
      element.val(self.DEFAULT_DATA["sample_type"]).change() ;
      console.log(`auto_set_sample_type to ${self.DEFAULT_DATA["sample_type"]} ok.`) ;
      if (self.DEFAULT_DATA["sample_type"] == "compound-ref") {
        $("#add1spectrum-sample-mixSolvent-{{ TAB_INDEX_PLACEHOLDER }}").val(
          "H2O/ethanol (75/25)"
        ).change() ;
      }
    } else {
      console.log(element)
      console.log("Failed!")
    }
    if (self.DEFAULT_DATA["inchikey"]) {
      setTimeout(() => self.auto_set_inchikey(self), 1000) ;
    }
  },

  auto_set_inchikey: function() {
    console.log("auto_set_inchikey...") ;
    var self = this ;
    var id ;
    var element ;
    self.inchikey = self.DEFAULT_DATA["inchikey"] ;
    if (self.is_ref()) {
      id = "#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}:text" ;
      element = $(id) ;
      if (element.length) {
        console.log(`auto_set_inchikey to ${self.inchikey} ok.`)
        element.val(self.inchikey).change() ;
        console.log(`Inchikey set!`) ;
      } else {
        console.log(element)
        console.log("Failed!")
      }
    } else {
      for (var index = 0 ; index < all_contexts.length ; index += 1) {
        if (all_contexts[index] === null || all_contexts[index] === undefined) {
          continue;
        }
        var inchikey = all_contexts[index].DEFAULT_DATA["inchikey"] ;
        id = `#container_RCC_ADDED-1 tbody:nth(0) tr:nth(${index}) td:nth(1)` ;
        element = $(id) ;
        if (element.length) {
          console.log(`auto_set_inchikey to ${inchikey} ok.`)
          self.hot_RCC_ADDED.setDataAtCell(index, 1, inchikey) ;
          element.innerHTML = inchikey ;
          element.change() ;
          console.log(element) ;
          console.log(`Inchikey set!`) ;
        } else {
          console.log(element)
          console.log("Failed!")
        }
      }
      console.log(self.hot_RCC_ADDED)
      self.hot_RCC_ADDED.render() ;
    }
    $("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}").click() ;
    if (self.DEFAULT_DATA["method"]) {
      setTimeout(() => self.auto_set_method(self), 1000) ;
    }
  },

  auto_set_method: function() {
    console.log("auto_set_method...") ;
    var self = this ;
    var id = "#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}" ;
    var element = $(id) ;
    element.length && element.val(self.DEFAULT_DATA["method"]).change() ;
    $("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}").click() ;
    setTimeout(() => {
      (() => {
        $("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}").click() ;
        console.log(`auto_set_method to ${self.DEFAULT_DATA["method"]} ok.`)
        if (self.DEFAULT_DATA["scan_type"]) {

          // The scan type needs to be skipped, as it is already defined
          // at build-time
          // The code is kept for future modifications of this behavior
          setTimeout(() => self.auto_set_scan_type(self, skip = true), 1000) ;
        }
      })(self)
    }, 1000) ;
  },

  auto_set_scan_type: function(skip = false) {
    var self = this ;
    if (!skip) {
      console.log("auto_set_scan_type...") ;
      var id = "#add1spectrum-peaksMS-msLevel-{{ TAB_INDEX_PLACEHOLDER }}" ;
      var element = $(id) ;
      if (element.length) {
        element.val(self.DEFAULT_DATA["scan_type"]).change() ;
        console.log(`auto_set_scan_type to ${self.DEFAULT_DATA["scan_type"]} ok.`)
      } else {
        console.log("Failed!")
      }
    }
    if (self.DEFAULT_DATA["polarity"]) {
      self.auto_set_polarity(self) ;
    }
  },

  auto_set_polarity: function() {
    console.log("auto_set_polarity...") ;
    var self = this ;
    var id = "#add1spectrum-peaksMS-polarity-{{ TAB_INDEX_PLACEHOLDER }}" ;
    var element = $(id) ;
    if (element.length) {
      element.val(self.DEFAULT_DATA["polarity"]).change() ;
      console.log(`auto_set_polarity to ${self.DEFAULT_DATA["polarity"]} ok.`)
    } else {
      console.log("Failed!")
    }
    if (self.DEFAULT_DATA["resolution"]) {
      self.auto_set_resolution(self) ;
    }
  },

  auto_set_resolution: function() {
    console.log("auto_set_resolution...") ;
    var self = this ;
    var id = "#add1spectrum-peaksMS-resolution-{{ TAB_INDEX_PLACEHOLDER }}" ;
    var element = $(id) ;
    if (element.length) {
      element.val(self.DEFAULT_DATA["resolution"]).change() ;
      console.log(`auto_set_resolution to ${self.DEFAULT_DATA["resolution"]} ok.`)
    } else {
      console.log("Failed!")
    }
    if (self.DEFAULT_DATA["next"] || true) {
      setTimeout(() => self.finish_initialized(self), 1000) ;
    }
  },

  finish_initialized: function() {
    var self = this ;
    if (ctx() === self) {
      self.initialized = true ;
    }
  },

  //USED IN HTML
  updateLCMSspectraViewer: function() {
    var self = this ;
    var tab_no ;
    console.log(`Updating spectral view for tab {{ TAB_INDEX_PLACEHOLDER }}`) ;
    // reset current viewer
    $("#containter-lcms-spectrum-preview-{{ TAB_INDEX_PLACEHOLDER }}").empty();
    // reset data.

    if (self.is_mix()) {
      tab_no = 1 ;
    } else {
      tab_no = {{ TAB_INDEX_PLACEHOLDER }} ;
    }
    var range_from = $(`#add1spectrum-peaksMS-rangeFrom-${tab_no}`) ;
    if ((spectrumMinPPM = Number(range_from.val())) == "") {
      spectrumMinPPM = 10000;
    }
    var range_to = $(`#add1spectrum-peaksMS-rangeTo-${tab_no}`) ;
    if ((spectrumMaxPPM = Number(range_to.val())) == "") {
      spectrumMaxPPM = 0;
    }
    maxGraph = 0;
    var localData = [];
    var localDataAnnot = [];
    // gather new data
    // TODO switch tab in function of technic
    $.each(self.hot_MS_Peaks.getData(), function() {
      if(this[0] != undefined && this[0] != "") {
        var x = (Number(this[0]));
        var y = Number(this[2]);
        var a = this[6];
        localData.push([(x-0.000001),-150]);
        localData.push([(x+0.000001),-150]);
        localData.push([x,y]);
        localDataAnnot[x] = a;
        if (x < spectrumMinPPM) {
          spectrumMinPPM = x;
        }
        if (x > spectrumMaxPPM) {
          spectrumMaxPPM = x;
        }
        if (y > maxGraph) {
          maxGraph = y;
        }
      }
    });
    
    // build new one
    spectrumMinPPM = spectrumMinPPM - (0.1 * spectrumMinPPM);
    spectrumMaxPPM = spectrumMaxPPM + (0.1 * spectrumMaxPPM);
    maxGraph = maxGraph + (0.1 * maxGraph);
    localData.sort();
    console.log(localData)
    // build graph
    $("#containter-lcms-spectrum-preview-{{ TAB_INDEX_PLACEHOLDER }}").highcharts({
      chart: {
        zoomType: "x",
        spacingRight: 10,
        spacingLeft: 10,
        type: "scatter"
      },
      title: {
        text: "Spectrum Preview",
        useHTML: true
      },
      subtitle: {
        text: (
          document.ontouchstart === undefined
          ? "Select area"
          : "Pinch the chart to zoom in"
        )
      },
      xAxis: {
        type: "number",
        title: {text: "m/z"},
        min: spectrumMinPPM,
        max: spectrumMaxPPM,
        labels: {
          formatter: function() {
            return (Math.abs(this.value) + "");
          }
        }
      },
      yAxis: {
        title: {text: "Relative Intensity (%)"},
        min: 0,
        max: maxGraph
      },
      tooltip: {
        crosshairs: true,
        formatter: function() {
          var compo = "";
          return (
            "<b>" + this.series.name
            + "</b><br/>m/z:" + Math.abs(this.x) + ""
            + ";<br/>Relative Intensity: " + this.y
            + "%;<br/>Annotation: " + localDataAnnot[ this.x]
            + ""
          );
        }
      },
      legend: {enabled: false},
      plotOptions: {scatter: {}},
      series: [{
        name: "preview",
        showInLegend: true,
        color: "#f00",
        lineColor: "#f00",
        pointInterval: 10,
        pointStart: 100,
        lineWidth : 2,
        marker: {
          enabled: true,
          radius: 2,
          lineColor: "#f00"
        },
        data: localData,
        zIndex: 10
      }]
    });
  },

  //USED HERE
  fulfillLCdata: function(jsonFileName) {
    var self = this ;
    var url = `{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/lc-methods/${jsonFileName}.json` ;
    $.getJSON(url, function(json) {
      // $.POST
      console.log(json);
      // lc chromato
      if (json.lc_chromatography != null) {
        [
          ["colConstructor", "column_constructor"],
          ["colConstructorOther", "column_constructor_other"],
          ["colName", "column_name"],
          ["colLength", "column_length"],
          ["colDiameter", "column_diameter"],
          ["colParticuleSize", "particule_size"],
          ["colTemperature", "column_temperature"],
          ["separationFlowRate", "separation_flow_rate"],
          ["separationSolvA", "separation_solvent_a"],
          ["separationSolvApH", "ph_solvent_a"],
          ["separationSolvB", "separation_solvent_b"],
          ["separationSolvBpH", "ph_solvent_b"]
        ].forEach((arr) => {
          var el ;
          console.log(arr)
          el = $(`#add1spectrum-chromatoLC-${arr[0]}-{{ TAB_INDEX_PLACEHOLDER }}`)
          el.val(json.lc_chromatography[arr[1]]) ;
          el.change()
        })
        try {
          $("#add1spectrum-chromatoLC-LCMode-{{ TAB_INDEX_PLACEHOLDER }}").val(json.lc_chromatography.LC_mode);
          $("#add1spectrum-chromatoLC-LCMode-{{ TAB_INDEX_PLACEHOLDER }}").change();
        } catch (e) {}
        var handsontableSeparationFlowRateData = [] ;
        if (json.lc_chromatography.separation_flow_gradient != null) {
          $.each(json.lc_chromatography.separation_flow_gradient, function() {
            var e = [
              "" + this.time,
              "" + this.solvA,
              "" + this.solvB
            ];
            handsontableSeparationFlowRateData.push(e);
          });
        } else {
          handsontableSeparationFlowRateData = null;
        }
        self.handsontableSeparationFlowRate(handsontableSeparationFlowRateData);
      }
      // ms_analyzer
      if (json.ms_analyzer != null) {
        $("#add1spectrum-analyzer-ms-instrument-{{ TAB_INDEX_PLACEHOLDER }}").val(json.ms_analyzer.instrument);
        $("#add1spectrum-analyzer-ms-instrument-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-analyzer-ms-model-{{ TAB_INDEX_PLACEHOLDER }}").val(json.ms_analyzer.model);
        $("#add1spectrum-analyzer-ms-model-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-analyzer-ms-resolutionFWHM-{{ TAB_INDEX_PLACEHOLDER }}").val(json.ms_analyzer.resolution_FWHM);
        $("#add1spectrum-analyzer-ms-resolutionFWHM-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-analyzer-ms-ionAnalyzerType-{{ TAB_INDEX_PLACEHOLDER }}").val(json.ms_analyzer.ion_analyzer_type);
        $("#add1spectrum-analyzer-ms-ionAnalyzerType-{{ TAB_INDEX_PLACEHOLDER }}").change();
      }
      if (json.molecule_ionization != null) {
        ["pos", "neg"].forEach((mode) => {
          if (json.molecule_ionization[`mode_${mode}`] != null) {
            [
              ["ionizationMethod", "ionisation_method"],
              ["sprayGazFlow", "spray_gaz_flow"],
              ["vaporizerGazFlow", "vaporizer_gaz_flow"],
              ["vaporizerTemperature", "vaporizer_temperature"],
              ["sourceGazFlow", "source_gaz_flow"],
              ["ionTransferTubeTemperatureOrTransferCapillaryTemperature", "transfer_tube_or_capillary_temperature"],
              ["highVoltageOrCoronaVoltage", "voltage"],
            ].forEach((tuple) => {
              var el ;
              var id = tuple[0] ;
              var key = tuple[1] ;
              el = $(`#add1spectrum-analyzserMS-${id}-${mode}-{{ TAB_INDEX_PLACEHOLDER }}`) ;
              console.log(el)
              el.val(json.molecule_ionization[`mode_${mode}`][key]);
              el.change() ;
            })
          }
        })
      }

      if (json.molecule_beamOrTrap != null) {
        if (json.molecule_beamOrTrap.ion_beam != null) {
          $("#add1spectrum-ionTrapBeam-type-{{ TAB_INDEX_PLACEHOLDER }}").val("beam").change();
          $("#add1spectrum-ionTrapBeam-ionGas-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_beam.ion_gas).change();
          $("#add1spectrum-ionTrapBeam-ionGasPressureValue-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_beam.ion_pressure_value).change();
          $("#add1spectrum-ionTrapBeam-ionGasPressureUnit-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_beam.ion_pressure_unit).change();
        }
        if (json.molecule_beamOrTrap.ion_trap != null) {
          $("#add1spectrum-ionTrapBeam-type-{{ TAB_INDEX_PLACEHOLDER }}").val("trap").change();
          $("#add1spectrum-ionTrapBeam-ionGas-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_trap.ion_gas).change();
          $("#add1spectrum-ionTrapBeam-ionGasPressureValue-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_trap.ion_pressure_value).change();
          $("#add1spectrum-ionTrapBeam-ionGasPressureUnit-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_trap.ion_pressure_unit).change();
          $("#add1spectrum-ionTrapBeam-ionNumber-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_trap.ion_number).change();
          $("#add1spectrum-ionTrapBeam-ionFrequencyShift-{{ TAB_INDEX_PLACEHOLDER }}").val(json.molecule_beamOrTrap.ion_trap.ion_freq_shift).change();
        }
      }
      // other
      if (json.other != null) {
        $("#add1spectrum-other-author-{{ TAB_INDEX_PLACEHOLDER }}").val(json.other.data_authors);
        $("#add1spectrum-other-author-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-other-validator-{{ TAB_INDEX_PLACEHOLDER }}").val(json.other.data_validator);
        $("#add1spectrum-other-validator-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-other-date-{{ TAB_INDEX_PLACEHOLDER }}").val(json.other.acquisition_date);
        $("#add1spectrum-other-date-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-other-owner-{{ TAB_INDEX_PLACEHOLDER }}").val(json.other.data_ownership);
        $("#add1spectrum-other-owner-{{ TAB_INDEX_PLACEHOLDER }}").change();
      }
    }).error(function(event, jqxhr, exception) {
      if (event.status == 404) {
        $("#alertBoxSelectTemplate-{{ TAB_INDEX_PLACEHOLDER }}").html(`
          <div class="alert alert-danger alert-dismissible" role="alert">
            <button type="button" class="close" data-dismiss="alert">
              <span aria-hidden="true">&times;</span>
              <span class="sr-only"><spring:message code="alert.close" text="Close" /></span>
            </button>
            <strong>
              <spring:message code="alert.strong.error" text="Error!" />
            </strong> unable to load pre-filled data!
          </div>
        `);
      }
    });
  },

  //USED HERE
  resetFromColors: function() {

    var self = this ;
    $.each($(self.prefix+".add1spectrum"), function(id, elem) {
      element = $(elem)
      self.rm_success(element) ;
      self.rm_warning(element) ;
      self.rm_error(element) ;
      if ($(elem).hasClass("is-mandatory") &&  ($(elem).val() == "" || $(elem).val() == null)) {
        self.set_error($(elem)) ;
      }
      if ($(elem).hasClass("is-optional") &&  ($(elem).val() == "" || $(elem).val() == null)) {
        self.set_warning($(elem)) ;
      }
      if ($(elem).val() != "" && $(elem).val() != null) {
        self.set_success($(elem)) ;
      }
    });
    $.each($(self.prefix+"button.switchStep"), function(id, elem) {
      if (!$(this).hasClass("btn-disabled")) {
        $(this).addClass("btn-disabled");
      }
      if ($(this).hasClass("btn-primary")) {
        $(this).removeClass("btn-primary");
      }
      $(this).prop("disabled", true);
    });

    // peak list: no data to check
    $("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("btn-disabled");
    $("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}").addClass("btn-primary");
    $("#btnSwitch-gotoStep5-ms-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);

    $("#add1spectrum-other-author-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
    $("#add1spectrum-other-validator-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
    $("#add1spectrum-other-date-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
    $("#add1spectrum-other-owner-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
    $("#add1spectrum-other-fileName-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
    $("#add1spectrum-other-fileSize-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
  },

  //USED IN HTML
  switchToStep: function(step) {

    var self = this ;
    switch(step) {
      case 2:
        // hide after step 2 / alt step 2
        $("#add1spectrum-chromatographyData-LC-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-chromatographyData-GC-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-analyserData-MS-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-peaksData-MS-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-otherData-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        if ($("#step1sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-question-circle")) {
          $("#step1sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-question-circle").addClass("fa-check-circle");
        }
        if (self.is_ms()) {
          $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").empty();
          $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
            '<option value="" selected="selected" disabled="disabled">choose in list&hellip;</option>'
          );
          $.getJSON("{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/list-lc-methods.json", function(data) {
            // load data from json
            $.each(data.methods,function() {
              if (this.name !== undefined) {
                if (this.value !== undefined) {
                  $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
                    `<option value="${this.value}">${this.name}</option>`
                  );
                } else {
                  $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
                    `<option disabled>${this.name}</option>`
                  );
                }
              }
            });
          });
        } else if (self.is_ms2()) {
          $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").empty();
          $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
            '<option value="" selected="selected" disabled="disabled">choose in list&hellip;</option>'
          );
          $.getJSON(
            "{{ PF_URL_PLACEHOLDER }}/webapp/resources/json/list-lc-msms-methods.json",
            function(data) {
              // load data from json
              $.each(data.methods, function() {
                if (this.name !== undefined) {
                  if (this.value !== undefined) {
                    $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
                      `<option value="${this.value}">${this.name}</option>`
                    );
                  } else {
                    $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
                      `<option disabled>${this.name}</option>`
                    );
                  }
                }
              });
            }
          );
        }
        // check panel to show
        if (self.isLC) {
          $("#add1spectrum-chromatographyData-LC-{{ TAB_INDEX_PLACEHOLDER }}").show();
          $("#linkActivateStep2-lc-{{ TAB_INDEX_PLACEHOLDER }}").trigger("click");
          var sign = $("#step2-lc-sign-{{ TAB_INDEX_PLACEHOLDER }}") ;
          self.rm_class(sign, "fa-check-circle") && self.set_class(sign, "fa-question-circle") ;
          if (!self.isSeparationFlowRateInit) {
            self.handsontableSeparationFlowRate(null);
            self.isSeparationFlowRateInit = true;
          }
        } else if (self.isGC) {
          $("#add1spectrum-chromatographyData-GC-{{ TAB_INDEX_PLACEHOLDER }}").show();
          $("#linkActivateStep2-gc-{{ TAB_INDEX_PLACEHOLDER }}").trigger("click");
          var sign = $("#step2-gc-sign-{{ TAB_INDEX_PLACEHOLDER }}") ;
          sign.removeClass("fa-check-circle").addClass("fa-question-circle");
          if ($("#step2-gc-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-check-circle")) {
          }
        } else if (self.isIC) {
          $("#add1spectrum-chromatographyData-IC-{{ TAB_INDEX_PLACEHOLDER }}").show();
          $("#linkActivateStep2-ic-{{ TAB_INDEX_PLACEHOLDER }}").trigger("click");
          if ($("#step2-ic-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-check-circle")) {
            $("#step2-ic-sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-check-circle").addClass("fa-question-circle");
          }
        }
        break;
      case 3:
        // hide after step 3 / alt step 3
        $("#add1spectrum-analyserData-MS-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-peaksData-MS-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-otherData-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        // step 2 ok 
        if ($("#step2-lc-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-question-circle")) {
          $("#step2-lc-sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-question-circle").addClass("fa-check-circle");
        }
        if ($("#step2-gc-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-question-circle")) {
          $("#step2-gc-sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-question-circle").addClass("fa-check-circle");
        }
        // check panel to show
        if (self.is_ms() || self.is_ms2()) {
          $("#add1spectrum-analyserData-MS-{{ TAB_INDEX_PLACEHOLDER }}").show();
          $("#linkActivateStep3-ms-{{ TAB_INDEX_PLACEHOLDER }}").trigger('click');
          // debug display
          [
            "add1spectrum-analyzserMS-sprayGazFlow-pos",
            "add1spectrum-analyzserMS-sprayGazFlow-neg",
            "add1spectrum-analyzserMS-vaporizerGazFlow-pos",
            "add1spectrum-analyzserMS-vaporizerGazFlow-neg",
            "add1spectrum-analyzserMS-vaporizerTemperature-pos",
            "add1spectrum-analyzserMS-vaporizerTemperature-neg",
            "add1spectrum-analyzserMS-sourceGazFlow-pos",
            "add1spectrum-analyzserMS-sourceGazFlow-neg",
            "add1spectrum-analyzserMS-ionTransferTubeTemperatureOrTransferCapillaryTemperature-pos",
            "add1spectrum-analyzserMS-ionTransferTubeTemperatureOrTransferCapillaryTemperature-neg",
            "add1spectrum-analyzserMS-highVoltageOrCoronaVoltage-pos",
            "add1spectrum-analyzserMS-highVoltageOrCoronaVoltage-neg"
          ].forEach((id) => {
            var element = $(`#id-{{ TAB_INDEX_PLACEHOLDER }}`)
            element.height(element.parent().children("span").height())
          })
          if ($("#step3-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-check-circle")) {
            $("#step3-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-check-circle").addClass("fa-question-circle");
          }
          // MSMS only
          $(self.prefix+".enable-if-ms").attr("disabled", !self.is_ms());
          $(self.prefix+".enable-if-msms").attr("disabled", !self.is_ms2());
        }
        // avoid display bug
        $("#add1spectrum-analyzer-ms-instrument-{{ TAB_INDEX_PLACEHOLDER }}").change();
        break;
      case 4:
        // hide after step 4 / alt step 4
        $("#add1spectrum-peaksData-MS-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#add1spectrum-otherData-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        // step 3 ok 
        if ($("#step3-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-question-circle")) {
          $("#step3-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-question-circle").addClass("fa-check-circle");
        }
        if (self.is_ms() || self.is_ms2()) {
          $("#add1spectrum-peaksData-MS-{{ TAB_INDEX_PLACEHOLDER }}").show();
          $("#linkActivateStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}").trigger("click");
          if ($("#step4-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-check-circle")) {
            $("#step4-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-check-circle").addClass("fa-question-circle");
          }
          // LC MS
          if (!self.isMSpeaksInit) {
            console.log(`self.is_mix(): ${self.is_mix()}`)
            if (self.is_mix()) {
              all_contexts.forEach((context, index) => {
                if (context === null) {
                  return;
                }
                context.handsontableMSpeaks(null) ;
                context.updateLCMSspectraViewer() ;
                context.isMSpeaksInit = true;
                $(context.prefix+".add1spectrum-peaksMSForm-peaklist-reset").val("").change();
              })
            } else {
              self.handsontableMSpeaks(null);
              self.isMSpeaksInit = true;
              $(self.prefix+".add1spectrum-peaksMSForm-peaklist-reset").val("").change();
            }
          }
        }
        // show ms tab
        setTimeout(() => $("#container_MS_Peaks-{{ TAB_INDEX_PLACEHOLDER }}").trigger("click"), 250);
        $("#add1spectrum-peaksMS-msLevel-{{ TAB_INDEX_PLACEHOLDER }}").change();
        break;
      case 5:
        // hide after step 5 / alt step 5
        $("#add1spectrum-otherData-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        // step 4 ok 
        if ($("#step4-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-question-circle")) {
          $("#step4-ms-sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-question-circle").addClass("fa-check-circle");
        }
        if ($("#step5sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-check-circle")) {
          $("#step5sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-check-circle").addClass("fa-question-circle");
        }
        $("#add1spectrum-otherData-{{ TAB_INDEX_PLACEHOLDER }}").show();
        $("#linkActivateStep5-{{ TAB_INDEX_PLACEHOLDER }}").trigger("click");
        // reset step 6 button
        self.checkIfEnableSubmit();
        $("#import1SpectrumLoadingBare-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        $("#import1SpectrumResults-{{ TAB_INDEX_PLACEHOLDER }}").hide();
        break;
      case 6:
        self.postOneSpectrumFrom();
        self.cptPeakListTab++;
        break;
      case 7:
      self.dumpOneSpectrumFrom();
      break;
    }
  },

  //USED HERE
  resetElemColor: function(idElem) {

    var self = this ;
    if ($(`#${idElem}`).parent().hasClass("has-success")) {
      $(`#${idElem}`).parent().removeClass("has-success") ;
    }
    if ($(`#${idElem}`).parent().hasClass("has-warning")) {
      $(`#${idElem}`).parent().removeClass("has-warning") ;
    }
    if ($(`#${idElem}`).parent().hasClass("has-error")) {
      $(`#${idElem}`).parent().removeClass("has-error") ;
    }
  },

  //USED HERE
  disableElem: function(idElem) {

    var self = this ;
    $(`#${idElem}`).prop("disabled", true) ;
    $(`#${idElem}`).val("") ;
    if ($(`#${idElem}`).hasClass("is-mandatory")) {
      $(`#${idElem}`).removeClass("is-mandatory") ;
    }
  },

  //USED HERE
  enableElem: function(idElem) {

    var self = this ;
    $(`#${idElem}`).prop("disabled", false) ;
    $(`#${idElem}`).parent().addClass("has-error") ;
    if (!$(`#${idElem}`).hasClass("is-mandatory")) {
      $(`#${idElem}`).addClass("is-mandatory") ;
    }
  },

  //USED HERE
  checkIfEnableSubmit: function() {

    var self = this ;
    var isBtnStep6OK = true;
    $.each($(self.prefix+".add1spectrum-otherForm"), (id, elem) => {
      if (self.is_error($(elem)) && $(elem).is(":visible")) {
        isBtnStep6OK = false;
      }
    });
    if (isBtnStep6OK) {
      self.rm_class($("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
      self.set_class($("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
      $("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
      self.rm_class($("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-disabled") ;
      self.set_class($("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}"), "btn-primary") ;
      $("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", false);
    } else {
      if (!$("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("btn-disabled")) {
        $("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}").addClass("btn-disabled");
      }
      if ($("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("btn-primary")) {
        $("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("btn-primary");
      }
      $("#btnSwitch-gotoStep6-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
      if (!$("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("btn-disabled")) {
        $("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}").addClass("btn-disabled");
      }
      if ($("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("btn-primary")) {
        $("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("btn-primary");
      }
      $("#btnSwitch-gotoStep7-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
    }
  },

  //USED IN HTML
  addOneSpectrum: function(type) {

    var self = this ;
     // unlock
    $(self.prefix+".add1spectrum-sampleForm").prop("disabled", false);
    $(self.prefix+".add1spectrum-chromatoLCForm").prop("disabled", false);
    $(self.prefix+".add1spectrum-analyzerMSForm").prop("disabled", false);
    $(self.prefix+".add1spectrum-otherForm").prop("disabled", false);
    $("#add1spectrum-chromatoLC-colConstructor-{{ TAB_INDEX_PLACEHOLDER }}").change();
    // reset
    self.isLC = false;
    self.isGC = false;
    self.isIC = false;
    $("#alertBoxSubmitSpectrum-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    // hide in all steps
    $(self.prefix+".opt-ms").hide();
    $(self.prefix+".opt-msms").hide();
    // hide step 2
    $("#add1spectrum-chromatographyData-LC-{{ TAB_INDEX_PLACEHOLDER }}").hide();
    $("#add1spectrum-chromatographyData-GC-{{ TAB_INDEX_PLACEHOLDER }}").hide();
    // hide step 3
    $("#add1spectrum-analyserData-MS-{{ TAB_INDEX_PLACEHOLDER }}").hide();
    $(self.prefix+".add1spectrum-ionTrap").hide();
    // hide step 4
    $("#add1spectrum-peaksData-MS-{{ TAB_INDEX_PLACEHOLDER }}").hide();
    // hide step 5
    $("#add1spectrum-otherData-{{ TAB_INDEX_PLACEHOLDER }}").hide();
    // reset field step 1
    $("#add1spectrum-sample-type-{{ TAB_INDEX_PLACEHOLDER }}").val("");
    $(self.prefix+".add1spectrum-sample-type-panel").hide();
    $(self.prefix+".add1spectrum-sampleForm").val("");
    $("#sample-bonus-display-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    // reset field step 2
    $(self.prefix+".add1spectrum-chromatoLCForm").val("");
    // reset field step 3
    $(self.prefix+".add1spectrum-analyzerMSForm").val("");
    // reset field step 4
    // reset peak lists / all tabs
    self.isSeparationFlowRateInit = false;
    self.isMSpeaksInit = false;
    $(self.prefix+".handsontable").html("");
    // reset field step 5 => NO!
    // set icon
    $("#step0sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-question-circle").addClass("fa-check-circle");
    if ($("#step1sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-check-circle")) {
      $("#step1sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-check-circle").addClass("fa-question-circle");
    }
    // collapse step 0 / uncollaspe step 1
    $("#linkActivateStep1-{{ TAB_INDEX_PLACEHOLDER }}").trigger("click");
    // show step 1 content
    $("#add1spectrum-sampleData-{{ TAB_INDEX_PLACEHOLDER }}").show();
    switch(type) {
    case 1:
      // TODO GC-MS stuff
      self.isGC = true;
      break;
    case 2:
      // LC-MS stuff
      self.isLC = true;
      $(self.prefix+".opt-ms").show();
      break;
    case 5:
      // LC-MSMS stuff
      self.isLC = true;
      $(self.prefix+".opt-ms").show();
      $(self.prefix+".opt-msms").show();
      break;
    case 6:
      // IC-MS stuff
      self.isIC = true;
      $(self.prefix+".opt-ms").show();
      break;
    case 7:
      // IC-MSMS stuff
      self.isIC = true;
      $(self.prefix+".opt-ms").show();
      $(self.prefix+".opt-msms").show();
      break;
    }
    self.resetFromColors();
    // reset json obj to submit form
    self.jsonSpectrumType = null;
    self.isJsonSpectrumTypeComplete = false;
    self.jsonSample = null;
    self.isJsonSampleComplete = false;
    self.isJsonRCCaddedComplete = false;
    self.jsonChromato = null;
    self.isJsonChromatoComplete = false;
    self.jsonAnalyzer = null;
    self.isJsonAnalyzerComplete = false;
    self.jsonPeaksList = [];
    self.isJsonPeaksListComplete = false;
    self.jsonOtherMetadata = null;
    self.isJsonOtherMetadataComplete = false;
    
    self.cptPeakListTab = 0;
    self.jsonAnalyzerAcquisition = [];
    self.idMetadataMap = {}
    self.listOfViewableSpectra = [];
    
    // spec MS
    self.jsonMolIonization = null;
    
    // spec MSMS
    self.jsonMolIonBeam = null;
    
    // try load cpd
    if (self.inchikey !== null) {
      self.loadJSCompound(self.inchikey);
    }
  },

  //USED HERE
  loadJSCompound: function(inchikey) {
    var self = this ;
    
    $("#add1spectrum-sample-type-{{ TAB_INDEX_PLACEHOLDER }}").val("compound-ref");
    $("#add1spectrum-sample-type-{{ TAB_INDEX_PLACEHOLDER }}").change();
    $("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").val(inchikey);
    $("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").change();
    if (inchidata[inchikey] !== null) {
      return (set_inchi_data(inchidata[inchikey]), {{ TAB_INDEX_PLACEHOLDER }}) ;
    }
    $.ajax({
      type: "get",
      url: "{{ PF_URL_PLACEHOLDER }}/webapp/get-cpd-data",
      data: "inchikey="+inchikey,
      dataType: "json",
      success: function(data) {
        if (data.success) {
          set_inchi_data(data) ;
        }
      },
      error : function(data) {
      }
    }).always(function() {
    });
  },

  //USED HERE
  handsontableSeparationFlowRate: function(data) {
    var self = this ;

    // reset
    $("#container_LC_SFG-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    // init
    var data_LC_SFG;
    if (data==null) {
      data_LC_SFG = [
       [ "", "", "" ],
       [ "", "", "" ],
       [ "", "", "" ],
       [ "", "", "" ],
       [ "", "", "" ],
       [ "", "", "" ],
       [ "", "", "" ],
       [ "", "", "" ],
       [ "", "", "" ],
     ];
    } else {
      data_LC_SFG = data;
    }
    
    var container_LC_SFG = document.getElementById("container_LC_SFG-{{ TAB_INDEX_PLACEHOLDER }}");
    self.hot_LC_SFG = new Handsontable(container_LC_SFG, {
      data : data_LC_SFG,
      minSpareRows : 1,
      colHeaders : true,
      colHeaders: ["time (min)", "solv. A (%)", "solv. B (%)"],
      contextMenu : false
    });
    Handsontable.Dom.addEvent(document.body, "click", function(e) {
      var element = e.target || e.srcElement;
      if (element.nodeName == "BUTTON"&& element.name == "dump") {
        var name = element.getAttribute("data-dump");
        var instance = element.getAttribute("data-instance");
        self.hot_LC_SFG = window[instance];
        console.log("data of " + name, self.hot_LC_SFG.getData());
      }
    });
    $("#container_LC_SFG table.htCore-{{ TAB_INDEX_PLACEHOLDER }}").css("width","100%");
  },

  //USED HERE
  handsontableMSpeaks: function(data) {
    console.log("handsontableMSpeaks")
    console.log(data)
    var self = this ;
    var data_MS_Peaks ;
    var container_MS_Peaks ;

    if (data != null) {
      data_MS_Peaks = data;
    } else {
      data_MS_Peaks = JSON.parse(JSON.stringify(self.DEFAULT_MS_PEAK_VALUES));
    }
    $("#container_MS_Peaks-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    container_MS_Peaks = document.getElementById(
      "container_MS_Peaks-{{ TAB_INDEX_PLACEHOLDER }}"
    );
    var colHeaders = [
      "m/z", "absolute intensity", "relative intensity (%)", "delta (ppm)",
      "composition", "attribution", "Validated"
    ]
    var columns = [
      {type: "numeric", format: "0.0000"},
      {type: "numeric", format: "0.00"},
      {type: "numeric", format: "0.00"},
      {type: "numeric", format: "0.0000"},
      {type: "text"},
      {type: "text"},
      {type: "checkbox"}
    ] ;
    if (self.is_ms2()) {
      colHeaders.push("Parent ion") ;
      columns.push({type: "checkbox"}) ;
    }
    self.hot_MS_Peaks = new Handsontable(container_MS_Peaks, {
      data: data_MS_Peaks,
      minSpareRows: 1,
      colHeaders: true,
      colHeaders: colHeaders,
      contextMenu: false,
      maxRows: data_MS_Peaks.length,
      minRows: data_MS_Peaks.length,
      columns: columns,
      afterChange: function(changes) {
        if (self.lock.precursor_ion) {
          return ;
        }
        self.lock.precursor_ion = true ;
        try {
          changes?.forEach(([row, prop, old, value]) => {
            var data ;
            var precursor_ion ;

            var data = self.hot_MS_Peaks.getData() ;
            if (prop !== 7 || value !== true || data === undefined) {
              return ;
            }
            for (var i = 0; i < data.length ; i += 1) {
              data[i][7] = false ;
            }
            data[row][7] = true ;
            precursor_ion = $(`#add1spectrum-peaksMS-msPrecursorIon-{{ TAB_INDEX_PLACEHOLDER }}`) ;
            console.log(`setting preco ion to ${data[row][0]}`) ;
            precursor_ion.val(data[row][0]) ;
            precursor_ion.change() ;
            self.hot_MS_Peaks.render() ;
          })
        } finally {
          self.lock.precursor_ion = false ;
        }
      }
    });
    Handsontable.Dom.addEvent(document.body, "click", (e) => {
      var element ;
      var name ;
      var instance ;

      element = e.target || e.srcElement ;
      if (element.nodeName == "BUTTON" && element.name == "dump") {
        name = element.getAttribute("data-dump") ;
        instance = element.getAttribute("data-instance") ;
        self.hot_MS_Peaks = window[instance] ;
        console.log("data of " + name, self.hot_MS_Peaks.getData()) ;
      }
    }) ;

    $("#container_MS_Peaks-{{ TAB_INDEX_PLACEHOLDER }} table.htCore").css(
      "width","100%"
    ) ;
    if (self.is_ms2()) {
      setTimeout(() => self.select_precursor_ion(), 200) ;
    }
  },

  change_tab: function() {
    var self = this ;
    setTimeout(() => self.auto_select_ion_parent(), 1000) ;
  },

  auto_select_ion_parent: function() {
    var self = this ;
    if (!self.a_ion_parent_is_selected()) {
      setTimeout(() => self.select_precursor_ion(), 1000) ;
    }
  },

  select_precursor_ion: function() {
    var self = this ;
    var data ;
    var precuirsor_ion ;

    if (self.hot_MS_Peaks == null) {
      return setTimeout(() => self.select_precursor_ion(), 200) ;
    }
    console.log("Selecting ion preco for tab {{ TAB_INDEX_PLACEHOLDER }}")
    data = self.hot_MS_Peaks.getData() ;
    for (var i = 0 ; i < data.length ; i += 1) {
      if (data[i][5] === "[M+H]+" || data[i][5] === "[M+H]-" || data[i][2] == 100.0) {
          precursor_ion = $("#add1spectrum-peaksMS-msPrecursorIon-{{ TAB_INDEX_PLACEHOLDER }}") ;
          precursor_ion.val(data[i][0]) ;
          precursor_ion.change() ;
          return ;
      }
    }
  },

  sync_precursor_ion: function() {
    var self = this ;
    var data ;

    if (self.lock.precursor_ion || self.hot_MS_Peaks == undefined) {
      return ;
    }
    self.lock.precursor_ion = true ;
    console.log("Syncing precursor ion")
    var val = $("#add1spectrum-peaksMS-msPrecursorIon-{{ TAB_INDEX_PLACEHOLDER }}").val() ;
    var data = self.hot_MS_Peaks.getData() ;
    for (var i = 0; i < data.length ; i += 1) {
      if (Math.abs(data[i][0] - val) < 0.0001) {
        for (var j = 0; j < data.length ; j += 1) {
          data[j][7] = false ;
        }
        data[i][7] = true ;
        self.hot_MS_Peaks.render() ;
        return ;
      }
    }
    self.lock.precursor_ion = false ;
  },

  // USED HERE
  handsontableRefChemCpdAdded: function(data) {
    var self = this ;
    // reset
    $("#container_RCC_ADDED-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    $("#sample-bonus-display-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    // init
    var data_RCC_ADDED, colHeaderData, container_RCC_ADDED;

    colHeaderData = [
      {data: "common name", type: "text"},
      {data: "<b>InChIKey</b>", type: "text"},
      {data: "composition", renderer: lightgrayRenderer},
      {data: "<b>concentration (&micro;g/ml)</b>", type: "text"},
      {data: "exact mass", renderer: lightgrayRenderer},
      {data: "(M+H)+ or (M-H)-", renderer: lightgrayRenderer}
    ] ;
    
    if (data == null) {
      data_RCC_ADDED = [
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
        [ "", "", "","", "", "" ],
      ];
    } else {
      container_RCC_ADDED = data;
    }

    container_RCC_ADDED = document.getElementById("container_RCC_ADDED-{{ TAB_INDEX_PLACEHOLDER }}");
    self.hot_RCC_ADDED = new Handsontable(container_RCC_ADDED, {
      data: data_RCC_ADDED,
      minSpareRows : 1,
      colHeaders : true,
      colHeaders: [
        "common name",
        "<b>InChIKey</b>",
        "composition",
        "<b>concentration (&micro;g/ml)</b>",
        "exact mass",
        "(M+H)+ or (M-H)-"
      ],
      contextMenu : false,
      columns: colHeaderData
    });
    function bindDumpButton_RCC_ADDED() {
      Handsontable.Dom.addEvent(document.body, "click", (e) => {
        var element = e.target || e.srcElement;
        if (element.nodeName == "BUTTON"&& element.name == "dump") {
          var name = element.getAttribute("data-dump");
          var instance = element.getAttribute("data-instance");
          self.hot_RCC_ADDED = window[instance];
          console.log("data of " + name, self.hot_RCC_ADDED.getData());
        }
      });
    }
    bindDumpButton_RCC_ADDED();
    $("#container_RCC_ADDED-{{ TAB_INDEX_PLACEHOLDER }} table.htCore").css("width","100%");
    // celect cell
    self.hot_RCC_ADDED.selectCell(0, 0);
    // add select listener
    self.hot_RCC_ADDED.addHook("afterSelection", (r, c) => self.hookSelection(r, c));
  },

  //USED HERE
  hookSelection: function(r, c) {
    var self = this ;
    if (c == 0 || c == 1 || c == 2) 
      self.pickChemicalCompound4Mix(r);
  },

  //USED HERE
  postOneSpectrumFrom: function() {
    var self = this ;
    $("#import1SpectrumLoadingBare-{{ TAB_INDEX_PLACEHOLDER }}").show();

    // II - form data -> json object
    self.loadFomDataIntoJsonObjects();
    // II.A - check if json object complete
    var alertMsg = self.getFormErrorMessage();
    
    if (alertMsg != "") {
      $("#alertBoxSubmitSpectrum-{{ TAB_INDEX_PLACEHOLDER }}").html(alertMsg);
      $("#import1SpectrumLoadingBare-{{ TAB_INDEX_PLACEHOLDER }}").hide();
      return false;
    }
    // all OK: lock!
    // lock sample
    $(self.prefix+".add1spectrum-sampleForm").prop("disabled", true);
    // lock chromato
    $(self.prefix+".add1spectrum-chromatoLCForm").prop("disabled", true);
    if (!$("#container_LC_SFG-{{ TAB_INDEX_PLACEHOLDER }}").is(":empty")) {
      self.hot_LC_SFG.updateSettings({
        cells: function(row, col, prop) {
          var cellProperties = {};
          cellProperties.readOnly = true;
          return cellProperties;
        }
      });
    }
    if (!$("#container_MS_Peaks-{{ TAB_INDEX_PLACEHOLDER }}").is(":empty")) {
      self.hot_MS_Peaks.updateSettings({
        cells: function(row, col, prop) {
          var cellProperties = {};
          cellProperties.readOnly = true;
          return cellProperties;
        }
      });
    }
    if (!$("#container_RCC_ADDED-{{ TAB_INDEX_PLACEHOLDER }}").is(":empty")) {
      self.hot_RCC_ADDED.updateSettings({
        cells: function(row, col, prop) {
          var cellProperties = {};
          cellProperties.readOnly = true;
          return cellProperties;
        }
      });
      self.hot_RCC_ADDED.removeHook(
        "afterSelection",
        (r, c) => self.hookSelection(r, c)
      );
    }

    // lock analyzer
    $(self.prefix+".add1spectrum-analyzerMSForm").prop("disabled", true);
    // lock other metadata field
    $(self.prefix+".add1spectrum-otherForm").prop("disabled", true);
    // lock switch btn
    $("#btnSwitch-gotoStep2-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
    $("#btnSwitch-gotoStep3-lc-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
    $("#btnSwitch-gotoStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}").prop("disabled", true);
    self.postSpectrumToServer() ;
  },

  postSpectrumToServer: function(jsonData, tab_index) {
    var self = this ;
    var base_peakdata ;
    var new_peakdata ;
    var is_ms2 = self.is_ms2() ;

    if (self.is_mix()) {
      if ({{ TAB_INDEX_PLACEHOLDER }} != 1) {
        return ;
      }
      jsonData = self.gatherJsonObjects() ;
      all_mix_data = Object.assign({}, jsonData) ;
      all_mix_data["peaklists"] = [] ;
      base_peakdata = Object.assign({}, jsonData["peaklists"][0]) ;
      all_contexts.forEach((context, index) => {
        if (context === null) {
          return;
        }
        new_peakdata = Object.assign({}, base_peakdata) ;
        context.loadFomDataIntoJsonObjects()
        if (is_ms2) {
          new_peakdata["precursor_ion"] = context.jsonPeaksList["precursor_ion"] ;
        }
        new_peakdata["peaklist"] = context.jsonPeaksList["peaklist"] ;
        all_mix_data["peaklists"].push(new_peakdata)
      })
    }
    // II.B - rebuild json full object (with all metadata or just id if already in base)
    if (jsonData == null) {
      jsonData = self.gatherJsonObjects();
    }
    // II.C - add id metadata (if exist)
    var json_array = [] ;
    if (!tab_index) {
      tab_index = {{ TAB_INDEX_PLACEHOLDER }} ;
    }
    json_array[tab_index-1] = jsonData ;
    
    // III - post json object
    // III.A - success
    self.sent_json = jsonData ;
    console.warn(
      "This data has been validated without going through the internal server!"
    )
    if ($("#step5sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-question-circle")) {
      $("#step5sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-question-circle").addClass("fa-check-circle");
    }
    if ($("#step5sign-{{ TAB_INDEX_PLACEHOLDER }}").hasClass("fa-spinner")) {
      $("#step5sign-{{ TAB_INDEX_PLACEHOLDER }}").removeClass("fa-spinner fa-spin").addClass("fa-check-circle");
    }
    $("#import1SpectrumLoadingBare-{{ TAB_INDEX_PLACEHOLDER }}").hide();
    $("#alertBoxSubmitSpectrum-{{ TAB_INDEX_PLACEHOLDER }}").html(`
      <div class="alert alert-success alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert">
          <span aria-hidden="true">&times;</span>
          <span class="sr-only">
            <spring:message code="alert.close" text="Close" />
          </span>
        </button>
        <strong>
          <spring:message code="alert.strong.info" text="Success!" />
        </strong> Spectrum ready to be sent!
      </div>
    `);
    return true;
  },

  //USED HERE
  loadFomDataIntoJsonObjects: function() {
    var self = this ;
    // I - Spectrum type
    self.isJsonSpectrumTypeComplete = false ;
    if (self.isGC && self.is_ms()) {
      self.jsonSpectrumType = "gc-ms" ;
    } else if (self.isLC && self.is_ms()) {
      self.jsonSpectrumType = "lc-ms" ;
    } else if (self.isLC && self.is_ms2()) {
      self.jsonSpectrumType = "lc-msms" ;
    } else if (self.isGC && self.is_ms()) {
      self.jsonSpectrumType = "ic-ms" ;
    } else if (self.isLC && self.is_ms()) {
      self.jsonSpectrumType = "ic-msms" ;
    }
    if (self.jsonSpectrumType != null && self.jsonSpectrumType != "") {
      self.isJsonSpectrumTypeComplete = true;
    }
    
    // II - Sample
    self.isJsonSampleComplete = true;
    self.isJsonRCCaddedComplete = true;
    self.jsonSample = {};

    switch($("#add1spectrum-sample-type-{{ TAB_INDEX_PLACEHOLDER }}").val()) {
    // II.A - chemical lib. compound
    case "compound-ref":
      if ($("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").val() == "") {
        return false;
      }
      self.jsonSample["sample_type"] = "reference-chemical-compound";
      self.jsonSample["inchikey"] = $("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").val();
      self.jsonSample["concentration"] = $("#add1spectrum-sample-concentration-{{ TAB_INDEX_PLACEHOLDER }}").val();
      if (self.is_ms()) {
        self.jsonSample["solvent"] = $("#add1spectrum-sample-lcmsSolvent-{{ TAB_INDEX_PLACEHOLDER }}").val();
      }
      self.isJsonSampleComplete = true;
      break;
      // II.B - chemical lib. compound mix
    case "compound-mix": 
      // solvent
      self.jsonSample["solvent"] = $("#add1spectrum-sample-mixSolvent-{{ TAB_INDEX_PLACEHOLDER }}").val();
      // cpd added
      self.jsonSample.inchikeys_list = self.getRCCADDED();
      self.jsonSample.concentrations_list = self.getRCCADDEDConcentration();
      if (self.jsonSample.inchikeys_list.length == 0 && !self.is_other_in_mix()) {
        self.isJsonRCCaddedComplete = false;
        console.log(`isJsonRCCaddedComplete: false`)
        return false;
      }
      self.isJsonSampleComplete = true;
      break;
    default:
      if (!self.is_other_in_mix()) {
        return false;
      } 
    }

    // III - Chromato
    self.isJsonChromatoComplete = true;
    self.jsonChromato = {};
    
    // III.A - no chromato
    // nope?

    // III.B - GC  
    if (self.isGC) {
      self.isJsonChromatoComplete = false;
      // TODO
    }

    // III.C - LC
    if (self.isLC) {
      self.isJsonChromatoComplete = true;
      self.jsonChromato = {};
      // check error
      $.each($(self.prefix+".add1spectrum-chromatoLCForm").parent(), function() {
        if ($(this).hasClass("has-error"))
          self.isJsonChromatoComplete = false;
      });
      if (
        !self.isJsonChromatoComplete
        && !self.is_other_in_mix()
      ) {
        console.log(`isJsonChromatoComplete: false`)
        return false;
      }
      var id = `#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}` ;
      self.jsonChromato["method"] = $(`${id} option:selected`).text();
      [
        ["column_constructor", "colConstructor"],
        ["column_constructor_other", "colConstructorOther"],
        ["column_name", "colName"],
        ["column_length", "colLength"],
        ["column_diameter", "colDiameter"],
        ["particule_size", "colParticuleSize"],
        ["column_temperature", "colTemperature"],
        ["mode", "LCMode"],
        ["separation_flow_rate", "separationFlowRate"],
        ["solvent_a", "separationSolvA"],
        ["solvent_a_ph", "separationSolvApH"],
        ["solvent_b", "separationSolvB"],
        ["solvent_b_ph", "separationSolvBApH"]
      ].forEach((field) => {
        id = `#add1spectrum-chromatoLC-${field[1]}-{{ TAB_INDEX_PLACEHOLDER }}` ;
        self.jsonChromato[field[0]] = $(id).val();
      })
      // fulfill json object
      
      jsonSFG = [];
      var formatData = {
        time: [],
        solvent_a_percent: [],
        solvent_b_percent: []
      };
      var uniq_times = [] ;
      $.each(self.hot_LC_SFG.getData(), function() {
        var time = this[0] ;
        if (time != "" && time !== null) {
          if (
            !isNaN(time)
            && !isNaN(this[1])
            && !isNaN(this[2])
            && ! (time in uniq_times)
          ) {
            formatData["time"].push(Number(time));
            formatData["solvent_a_percent"].push(Number(this[1]));
            formatData["solvent_b_percent"].push(Number(this[2]));
            uniq_times.push(time) ;
          }
        }
      });
      self.jsonChromato.separation_flow_gradient = formatData;
    }

    // III.D - IC  
    if (self.isIC) {
      self.isJsonChromatoComplete = false;
      // TODO
    }

    // IV - Analyzer
    self.isJsonAnalyzerComplete = true;
    self.isJsonAnalyzer = {};
    // IV.A - MS
    if (self.is_ms() || self.is_ms2()) {
      self.isJsonAnalyzerComplete = true;
      self.jsonAnalyzer = {};
      // check error
      $.each($(self.prefix+".add1spectrum-analyzerMSForm").parent(), function(){
        if ($(this).hasClass("has-error"))
          self.isJsonAnalyzerComplete = false;
      });
      if (
        !self.isJsonAnalyzerComplete
        && !self.is_other_in_mix()
      ) {
        console.log(`isJsonAnalyzerComplete: false`)
        return false;
      }
      
      // fulfill json object
      self.jsonAnalyzer["instrument_name"] = $("#add1spectrum-analyzer-ms-instrument-{{ TAB_INDEX_PLACEHOLDER }}").val();
      self.jsonAnalyzer["instrument_model"] = $("#add1spectrum-analyzer-ms-model-{{ TAB_INDEX_PLACEHOLDER }}").val();
      self.jsonAnalyzer["instrument_brand"] = $("#add1spectrum-analyzer-ms-model-{{ TAB_INDEX_PLACEHOLDER }}").val();
      self.jsonAnalyzer["ion_analyzer_type"] = $("#add1spectrum-analyzer-ms-ionAnalyzerType-{{ TAB_INDEX_PLACEHOLDER }}").val();
      
      if (self.is_ms2()) {
        // MSMS ion BEAM or TRAP
        self.jsonMolIonBeam = {}
        var jsonIonTrapBeam = {
          ion_gas: $("#add1spectrum-ionTrapBeam-ionGas-{{ TAB_INDEX_PLACEHOLDER }}").val(),
          ion_pressure_value: $("#add1spectrum-ionTrapBeam-ionGasPressureValue-{{ TAB_INDEX_PLACEHOLDER }}").val(),
          ion_pressure_unit: $("#add1spectrum-ionTrapBeam-ionGasPressureUnit-{{ TAB_INDEX_PLACEHOLDER }}").val()
        } ;
        var key = null ;
        if ($("#add1spectrum-ionTrapBeam-type-{{ TAB_INDEX_PLACEHOLDER }}").val() == "trap") {
          // sp
          jsonIonTrapBeam["ion_freq_shift"] = $("#add1spectrum-ionTrapBeam-ionFrequencyShift-{{ TAB_INDEX_PLACEHOLDER }}").val();
          jsonIonTrapBeam["ion_number"] = $("#add1spectrum-ionTrapBeam-ionNumber-{{ TAB_INDEX_PLACEHOLDER }}").val();
          key = "ion_trap" ;
        } else if ($("#add1spectrum-ionTrapBeam-type-{{ TAB_INDEX_PLACEHOLDER }}").val() == "beam") {
          key = "ion_beam_storage" ;
        }
        if (key !== null) {
          self.jsonMolIonBeam[key] = jsonIonTrapBeam;
        }
      }
      
      self.jsonMolIonization = {};
      var json_mode ;
      ["pos", "neg"].forEach((kind) => {
        json_mode = {} ;
        [
          ["ionisation_method", "ionizationMethod"],
          ["spray_gas_flow", "sprayGazFlow"],
          ["vaporizer_gas_flow", "vaporizerGazFlow"],
          ["vaporizer_temperature", "vaporizerTemperature"],
          ["source_gas_flow", "sourceGazFlow"],
          ["transfer_tube_or_capillary_temperature", "ionTransferTubeTemperatureOrTransferCapillaryTemperature"],
          ["high_voltage", "highVoltageOrCoronaVoltage"]
        ].forEach((field) => {
          var id = `#add1spectrum-analyzserMS-${field[1]}-${kind}-{{ TAB_INDEX_PLACEHOLDER }}` ;
          json_mode[field[0]] = $(id).val() ;
        })
        self.jsonMolIonization[`mode_${kind}`] = json_mode ;
      })
    }

    // IV.B - NMR
    if (self.is_ms() || self.is_ms2()) {
      self.isJsonPeaksListComplete = false;
      // init
      var peaklist = [];
      var peakdata = {};
      var spectrumData = {};
      // peaklist
      var ms_peak_data = self.hot_MS_Peaks.getData();
      $.each(ms_peak_data, function(index) {
        var data = ms_peak_data[index] ;
        var formatData = {};
        if (
          data[0] != ""
          && !isNaN(data[0])
            // && !isNaN(data[2])
          && (data[6] === "true" || data[6] === true)
        ) {
          peaklist.push({
            mz: Number(data[0]),
            ri: Number(data[2]),
            delta_ppm: Number(data[3]),
            composition: (data[4]),
            annotation: (data[5])
          });
          self.isJsonPeaksListComplete = true;
        }
      });
      // peak list data
      peakdata["scan_type"] = (
        self.is_ms2() ? "ms2" : "ms"
      );
      peakdata["polarity"] = $("#add1spectrum-peaksMS-polarity-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["resolution"] = $("#add1spectrum-peaksMS-resolution-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["curation"] = $("#add1spectrum-peaksMS-curation-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["mz_from"] = $("#add1spectrum-peaksMS-rangeFrom-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["mz_to"] = $("#add1spectrum-peaksMS-rangeTo-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["retention_min_time_from"] = $("#add1spectrum-peaksMS-rtMinFrom-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["retention_min_time_to"] = $("#add1spectrum-peaksMS-rtMinTo-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["rt_solv_from"] = $("#add1spectrum-peaksMS-rtSolvFrom-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["rt_solv_to"] = $("#add1spectrum-peaksMS-rtSolvTo-{{ TAB_INDEX_PLACEHOLDER }}").val();
      peakdata["resolution_FWHM"] = $("#add1spectrum-analyzer-ms-resolutionFWHM-{{ TAB_INDEX_PLACEHOLDER }}").val();
      if (self.is_ms2()) {
        var data = self.hot_MS_Peaks.getData() ;
        if (data.length != 0) {
          var selected_ion = self.get_selected_parent_ion_index() ;
          if (selected_ion !== null) {
            peakdata["precursor_ion"] = data[selected_ion][0] ;
            peakdata["precursor_spectrum_id"] = null ;
          } else {
            peakdata["precursor_ion"] = self.get_selected_parent_ion_mz() ;
            peakdata["precursor_spectrum_id"] = null ;
          }
        }
      }
      peakdata["peaklist"] = peaklist;
      self.jsonPeaksList = peakdata;
    }
    
    self.isJsonOtherMetadataComplete = true;
    self.jsonOtherMetadata = {};
    // check error
    $.each($(self.prefix+".add1spectrum-otherForm").parent(), function(){
      if ($(this).hasClass("has-error"))
        self.isJsonOtherMetadataComplete = false;
    });
    if (!self.isJsonOtherMetadataComplete && !self.is_other_in_mix()) {
      console.log(`isJsonOtherMetadataComplete: false`)
      return false;
    }
    self.jsonOtherMetadata["data_authors"] =  $("#add1spectrum-other-author-{{ TAB_INDEX_PLACEHOLDER }}").val();
    self.jsonOtherMetadata["data_validator"] =  $("#add1spectrum-other-validator-{{ TAB_INDEX_PLACEHOLDER }}").val();;
    self.jsonOtherMetadata["acquisition_date"] =  $("#add1spectrum-other-date-{{ TAB_INDEX_PLACEHOLDER }}").val();
    if (!self.jsonOtherMetadata["acquisition_date"]) {
      self.jsonOtherMetadata["acquisition_date"] = null ;
    }
    self.jsonOtherMetadata["data_ownership"] =  $("#add1spectrum-other-owner-{{ TAB_INDEX_PLACEHOLDER }}").val();
    self.jsonOtherMetadata["raw_file_name"] =  $("#add1spectrum-other-fileName-{{ TAB_INDEX_PLACEHOLDER }}").val();
    self.jsonOtherMetadata["raw_file_size"] =  $("#add1spectrum-other-fileSize-{{ TAB_INDEX_PLACEHOLDER }}").val();
    return true;
  },

  //USED HERE
  getFormErrorMessage: function() {
    var self = this ;
    var alertMsg = "";
    if (!self.isJsonSpectrumTypeComplete) {
      alertMsg = `
      <div class="alert alert-danger alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert">
          <span aria-hidden="true">&times;</span>
          <span class="sr-only">
            <spring:message code="alert.close" text="Close" />
          </span>
        </button>
        <strong>
          <spring:message code="alert.strong.error" text="Error!" />
        </strong> Error processing spectrum type!
      </div>` ;
    } else if (!self.isJsonSampleComplete) {
      alertMsg = `
      <div class="alert alert-danger alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert">
          <span aria-hidden="true">&times;</span>
          <span class="sr-only">
            <spring:message code="alert.close" text="Close" />
          </span>
        </button>
        <strong>
          <spring:message code="alert.strong.error" text="Error!" />
        </strong> Missing mandatory data into sample section!
        <br />
        <a
          href="#"
          onclick="$('#linkActivateStep1-{{ TAB_INDEX_PLACEHOLDER }}').trigger('click');"
        >Go to this section</a>
      </div>` ;
    } else if (!self.isJsonRCCaddedComplete) {
      alertMsg = `
      <div class="alert alert-danger alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert">
          <span aria-hidden="true">&times;</span>
          <span class="sr-only">
            <spring:message code="alert.close" text="Close" />
          </span>
        </button>
        <strong>
          <spring:message code="alert.strong.error" text="Error!" />
        </strong> Pease enter at least ONE compound in mix into sample section!
        <br />
        <a
          href="#"
          onclick="$('#linkActivateStep1-{{ TAB_INDEX_PLACEHOLDER }}').trigger('click');"
        >Go to this section</a>
      </div>`;
    } else if (!self.isJsonChromatoComplete) {
      alertMsg = `
      <div class="alert alert-danger alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert">
          <span aria-hidden="true">&times;</span>
          <span class="sr-only">
            <spring:message code="alert.close" text="Close" />
          </span>
        </button>
        <strong>
          <spring:message code="alert.strong.error" text="Error!" />
        </strong> Missing data in chromatography section!
      ` ;
      if (self.is_ms()) {
        alertMsg += `
        <br />
        <a
          href="#"
          onclick="$('#linkActivateStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}').trigger('click');"
        >Go to this section</a>`;
      }
      alertMsg += ' </div>';
    } else if (!self.isJsonPeaksListComplete) {
      alertMsg = `
      <div class="alert alert-danger alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert">
          <span aria-hidden="true">&times;</span>
          <span class="sr-only">
            <spring:message code="alert.close" text="Close" />
          </span>
        </button>
        <strong>
          <spring:message code="alert.strong.error" text="Error!" />
        </strong> Missing peaklist!
      ` ;
      if (self.is_ms()) {
        alertMsg += `
        <br />
        <a
          href="#"
          onclick="$('#linkActivateStep4-ms-{{ TAB_INDEX_PLACEHOLDER }}').trigger('click');"
        >Go to this section</a>`;
      }
      alertMsg += ' </div>';
    } else if (self.is_mix() && self.is_ms2()) {
      for (var i = 0 ; i < all_contexts.length ; i += 1) {
        if (all_contexts[i] === null || all_contexts[i] === undefined) {
          continue;
        }
        if (all_contexts[i].get_selected_parent_ion_index() === null) {
          return alertMsg + `
            <div class="alert alert-danger alert-dismissible" role="alert">
              <button type="button" class="close" data-dismiss="alert">
                <span aria-hidden="true">&times;</span>
                <span class="sr-only">
                  <spring:message code="alert.close" text="Close" />
                </span>
              </button>
              <strong>
                <spring:message code="alert.strong.error" text="Error!" />
              </strong> Select precursor ion in all peak lists!
            </div>
          `
        }
      }
    }
    // TODO other
    return alertMsg;
  },

  //USED HERE
  gatherJsonObjects: function() {
    var self = this ;
    var jsonData = {};
    if (self.is_mix()) {
      jsonData["sample_type"] = "mix_of_reference_chemical_compounds" ;
    } else {
      jsonData["sample_type"] = "reference_chemical_compound" ;
    }
    jsonData["spectrum_type"] = self.jsonSpectrumType.toUpperCase().replaceAll("-", "");
    jsonData["sample"] = self.jsonSample;
    if (self.isLC) {
      jsonData["chromatography"] = self.jsonChromato;
    } else if (self.isGC) {
      jsonData["chromatography"] = self.jsonChromato;
    } else if (self.isIC) {
      jsonData["chromatography"] = self.jsonChromato;
    } 
    if (self.is_ms()) {
      jsonData["analyzer"] = self.jsonAnalyzer;
      var molecule_ionization = self.jsonMolIonization;
      jsonData["ionization_mode_positive"] = molecule_ionization["mode_pos"] ;
      jsonData["ionization_mode_negative"] = molecule_ionization["mode_neg"] ;
      jsonData["peaklists"] = [self.jsonPeaksList] ;
    } else if (self.is_ms2()) {
      jsonData["analyzer"] = self.jsonAnalyzer;
      var molecule_ionization = self.jsonMolIonization;
      jsonData["ionization_mode_positive"] = molecule_ionization["mode_pos"] ;
      jsonData["ionization_mode_negative"] = molecule_ionization["mode_neg"] ;
      if (self.jsonMolIonBeam != null) {
        jsonData["ion_beam_storage"] = self.jsonMolIonBeam["ion_beam_storage"];
      }
      jsonData["peaklists"] = [self.jsonPeaksList] ;
    }
    jsonData["other_metadata"] = self.jsonOtherMetadata;
    return jsonData;
  },

  //USED IN HTML
  pickChemicalCompound: function() {
    var self = this ;
    self.singlePick = true;
    $("#modalPickCompound-{{ TAB_INDEX_PLACEHOLDER }}").modal("show");
    $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").focus();
  },

  //USED HERE
  pickChemicalCompound4Mix: function(rowNumber) {
    var self = this ;
    self.singlePick = false;
    self.multiPickLine = rowNumber;
    $("#modalPickCompound-{{ TAB_INDEX_PLACEHOLDER }}").modal("show");
    $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").focus();
  },

  //USED HERE
  searchAjax: function() {
    var self = this ;
    var results ;
    var rawQuery = $('#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}').val();
    if (rawQuery.length > 2) {
      return [] ;
    }
    results = [] ;
    $.ajax({ 
        type: "post",
        url: "{{ PF_URL_PLACEHOLDER }}/webapp/search",
        dataType: "json",
        async: false,
        data: "query=" + $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").val(),
        success: function(json) {
          if (json.success) {
            $.each(json.compoundNames, function(){
              results.push(this.name) ;
            }) ; 
            $.each(json.compounds, function(){
              if (this.inChIKey.indexOf(rawQuery)) {
                results.push(this.inChIKey) ;
              }
            }) ;
          }
      },
      error : function(xhr) {
        self.subjects = [] ;
        console.log(xhr) ;
      }
    }) ;
    return results ;
  },

  //USED HERE
  searchLocalCompound: function() {
    var self = this ;
    $("#load-step-1-{{ TAB_INDEX_PLACEHOLDER }}").show();
    $.ajax({ 
      type: "get",
      url: "{{ PF_URL_PLACEHOLDER }}/rest/v2/compounds",
      async: true,
      data: "limit=1&query=" + $('#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}').val() + "&query_filter=" + self.fitlerSearchLoadlCpd+"&token={{ PF_TOKEN_PLACEHOLDER }}",
      success: function(data) {
        data = data[0] ;
        var id = parseInt(data["id"]) ;
        var name = data["name"] ;
        var inchikey = data["inchikey"] ;
        var inchi = data["inchi"] ;
        data = `
    <div class="table-responsive">
      <table id="tabPickCpd-{{ TAB_INDEX_PLACEHOLDER }}" class="table table-bordered table-hover table-striped tablesorter" style="cursor: pointer;">
        <thead>
          <tr>
            <th class="header">Chemical Name <i class="fa fa-sort"></i></th>
            <th class="header">Monoisotopic Mass <i class="fa fa-sort"></i></th>
            <th class="header">Formula <i class="fa fa-sort"></i></th>
            <th class="header" style="">Structure</th>
          </tr>
        </thead>
        <tbody>
          <tr class="success" onclick="loadCompoundInForm(${id}, '${inchikey}', '${inchi}', '${data["formula"]}', '${data["exactMass"]}' , 100);">
            <td style="vertical-align: middle;">
              <span id="cpt-load-name-${id}-{{ TAB_INDEX_PLACEHOLDER }}">${name}</span> 
              <br><small style="white-space: nowrap;">${inchikey}</small>
            </td>
            <td style="vertical-align: middle;" class="compoundMass">${data["exactMass"]}</td>
            <td style="vertical-align: middle;" class="compoundFormula">${data["formula"]}</sub></td>
            <td><span class="avatar">
              <img class="compoundSVG" src="{{ PF_URL_PLACEHOLDER }}/webapp/image/generic/${inchikey}" alt="${name}">
              </span>
            </td>
          </tr>
        </tbody>
      </table>
    <small><sup><b>*</b></sup>: Generic Compounds (abstract "flat" compound without (+) or (-) center).</small>
    <` + "script" + ` type="text/javascript">
    $("#tabPickCpd-{{ TAB_INDEX_PLACEHOLDER }}").tablesorter();
    $.each($(self.prefix+".compoundFormula"), function(id, elem) {
      var rawFromula = $(elem).text();
      var formatedFormula = rawFromula;
      try {
        $.each($.unique( rawFromula.match(/\d+/g)), function(keyF, valF) {
          var re = new RegExp(valF,"g");
          formatedFormula = formatedFormula.replace(re, "<sub>" + valF + "</sub>");
        });
      } catch (e){}
      formatedFormula = formatedFormula.replace("</sub><sub>", "");
      $(elem).html(formatedFormula);
    });
    $.each($(self.prefix+".compoundMass"), function(id, elem) {
      var exactMass = parseFloat( $(elem).text());
      exactMass = roundNumber(exactMass,7)
      $(elem).html(exactMass);
    });
    </` + "script" + `>

      </div>
    <` + "script" + ` type="text/javascript">
    var listOfRefCompoundsMatch = null;

    loadCompoundInForm = function(id, inchikey, inchi, composition, exactMass, type) {
      if (ctx().modeEditSpectrum) {
        var name = $("#cpt-load-name-" + id + "-{{ TAB_INDEX_PLACEHOLDER }}").html();
        if (ctx().multiPickLine >= 0) {
          ctx().hot_RCC_ADDED.setDataAtCell(ctx().multiPickLine, 0, name);

          // restet form
          setTimeout(function(){
            $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").val("");
            $("#ok-step-1-{{ TAB_INDEX_PLACEHOLDER }}").html("");
          }, 200);
          // img
          var typeS = "chemical";
          if (type == 100)
            typeS = "generic";
          else if (type == 101)
            typeS = "chemical";
          // '<img class="mixRCCadd'+ctx().multiPickLine+' compoundSVGZoom" src="{{ PF_URL_PLACEHOLDER }}/webapp/image/'+typeS+'/'+inchikey+'" alt="'+name+'">'
          var currentCpt = { 
              "name": name,
              "type": typeS,
              "concentration": "?",
              "inchikey": inchikey
          }; 
          updatedCpdMixData[name] = currentCpt;
        }
        // display
        $("#modalPickCompound-{{ TAB_INDEX_PLACEHOLDER }}").modal("hide");
        $("#modalEditSpectrum-{{ TAB_INDEX_PLACEHOLDER }} .modal-dialog").show();
        return;
      } // else: add one spectrum
      var name = $("#cpt-load-name-" + id + "-{{ TAB_INDEX_PLACEHOLDER }}").html();
      if (ctx().singlePick) {
        $("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").val(inchikey);
        $("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-sample-inchi-{{ TAB_INDEX_PLACEHOLDER }}").val(inchi);
        $("#add1spectrum-sample-inchi-{{ TAB_INDEX_PLACEHOLDER }}").change();
        $("#add1spectrum-sample-commonName-{{ TAB_INDEX_PLACEHOLDER }}").val(name);
        $("#add1spectrum-sample-commonName-{{ TAB_INDEX_PLACEHOLDER }}").change();  

        $("#importspectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").val(inchikey);
        $("#importspectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").change();
      } else if (ctx().multiPickLine >= 0) {
        ctx().hot_RCC_ADDED.setDataAtCell(ctx().multiPickLine, 0, name);
        ctx().hot_RCC_ADDED.setDataAtCell(ctx().multiPickLine, 1, inchikey);
        ctx().hot_RCC_ADDED.setDataAtCell(ctx().multiPickLine, 2, composition);
        ctx().hot_RCC_ADDED.setDataAtCell(ctx().multiPickLine, 4, exactMass);
        // restet form
        setTimeout(function(){
          $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").val("");
          $("#ok-step-1-{{ TAB_INDEX_PLACEHOLDER }}").html("");
        }, 200);
      }
      var typeS = "chemical";
      if (type == 100)
        typeS = "generic";
      else if (type == 101)
        typeS = "chemical";
      if (ctx().singlePick)
        $("#sample-bonus-display-{{ TAB_INDEX_PLACEHOLDER }}").html('<img class="" src="{{ PF_URL_PLACEHOLDER }}/webapp/image/'+typeS+'/'+inchikey+'" alt="'+name+'">');
      else {
        // delete
        $(ctx().prefix+"img.mixRCCadd"+ctx().multiPickLine).remove();
        // add
        $("#sample-bonus-display-{{ TAB_INDEX_PLACEHOLDER }}").append('<img class="mixRCCadd'+ctx().multiPickLine+' compoundSVGZoom" src="{{ PF_URL_PLACEHOLDER }}/webapp/image/'+typeS+'/'+inchikey+'" alt="'+name+'">');
        $(ctx().prefix+"img.mixRCCadd"+ctx().multiPickLine+"").mouseenter(function() {
          $(this).removeClass("compoundSVGZoom");
        }).mouseleave(function() {
          $(this).addClass("compoundSVGZoom");
        });
      }
      $("#modalPickCompound-{{ TAB_INDEX_PLACEHOLDER }}").modal("hide");
    }
    </` + "script" + `></` + "div" + `>` ;
        $("#ok-step-1-{{ TAB_INDEX_PLACEHOLDER }}").html(data);
      },
      error : function(xhr) {
        // log
        console.log(xhr);
        // error
        $("#ok-step-1-{{ TAB_INDEX_PLACEHOLDER }}").html("Error: could not process request.");
      }
    }).always(function() {
      $("#load-step-1-{{ TAB_INDEX_PLACEHOLDER }}").hide();
    });
  },

  //USED HERE
  getRCCADDED: function() {
    var self = this ;
    jsonRCC_ADDED = [];
    $.each(self.hot_RCC_ADDED.getData(), function(){
      var formatData = {};
      if ("<b>InChIKey</b>" in this && this["<b>InChIKey</b>"]!= undefined && this["<b>InChIKey</b>"] != "") {
        jsonRCC_ADDED.push(this["<b>InChIKey</b>"]);
      }
    });
    return jsonRCC_ADDED;
  },

  //USED HERE
  getRCCADDEDConcentration: function() {
    var self = this ;
    jsonRCC_ADDED = [];
    $.each(self.hot_RCC_ADDED.getData(), function(){
      var formatData = {};
      if ("<b>InChIKey</b>" in this && this["<b>InChIKey</b>"]!= undefined && this["<b>InChIKey</b>"] != "") {
        jsonRCC_ADDED.push(this["<b>concentration (&micro;g/ml)</b>"]);
      }
    });
    return jsonRCC_ADDED;
  },

  //USED IN HTML
  clearLine: function() {
    var self = this ;
    // restet form
    setTimeout(function(){
      $("#add-one-cc-s1-value-{{ TAB_INDEX_PLACEHOLDER }}").val("");
      $("#ok-step-1-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    }, 200);
    $(self.prefix+"img.mixRCCadd"+self.multiPickLine).remove();
    if (self.singlePick) {
      $("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").val("");
      $("#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}").change();
      $("#add1spectrum-sample-inchi-{{ TAB_INDEX_PLACEHOLDER }}").val("");
      $("#add1spectrum-sample-inchi-{{ TAB_INDEX_PLACEHOLDER }}").change();
      $("#add1spectrum-sample-commonName-{{ TAB_INDEX_PLACEHOLDER }}").val("");
      $("#add1spectrum-sample-commonName-{{ TAB_INDEX_PLACEHOLDER }}").change();
      $("#sample-bonus-display-{{ TAB_INDEX_PLACEHOLDER }}").html("");
    } else if (self.multiPickLine >= 0) {
      for(var i = 0 ; i < 6 ; i += 1) {
        self.hot_RCC_ADDED.setDataAtCell(self.multiPickLine, i, "");
      }
    }
  },

  exit: function() {
    $.ajax({type: "get", url: "/quit", async: true, success: ()=>window.close()});
  },

} ;

$.ajax({
  type: "get",
  url: "{{ PF_URL_PLACEHOLDER }}/webapp/get-cpd-data?token={{ PF_TOKEN_PLACEHOLDER }}",
  data: "inchikey=" + "{{ INCHIKEY_PLACEHOLDER }}",
  dataType: "json",
  success: function(data) {
    if (data.success) {
      var self = context_{{ TAB_INDEX_PLACEHOLDER }} ;
      console.log(`inchikey {{ INCHIKEY_PLACEHOLDER }} found!!`)
      inchidata["{{ INCHIKEY_PLACEHOLDER }}"] = data ;
      self.init() ;
      self.fitlerSearchLoadlCpd = 5;
      self.inchikey = null;
      all_contexts[{{ TAB_INDEX_PLACEHOLDER }}] = self ;
    } else {
      no_success(
        {{ TAB_INDEX_PLACEHOLDER }},
        "{{ INCHIKEY_PLACEHOLDER }}",
        {{ DEFAULT_DATA }}["name"]
      ) ;
      all_contexts[{{ TAB_INDEX_PLACEHOLDER }}] = null ;
    }
  },
  error : function(data) {
    no_success(
      {{ TAB_INDEX_PLACEHOLDER }},
      "{{ INCHIKEY_PLACEHOLDER }}",
      {{ DEFAULT_DATA }}["name"]
    ) ;
    all_contexts[{{ TAB_INDEX_PLACEHOLDER }}] = null ;
  }
}).always(() => null);