# HG changeset patch
# User lain
# Date 1677852624 0
# Node ID b58b229c4cbffbe5e2bccc1557f78e52b89cc378
planemo upload commit 523a9c8df173302ad38e9f15e7d82eab01736551-dirty
diff -r 000000000000 -r b58b229c4cbf README.md
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/README.md Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,56 @@
+# MS to Peakforest
+
+
+Metadata
+--------
+
+ * **@name**: MS2PF
+ * **@version**: 1.1.0
+ * **@authors**: Lain Pavot (PFEM - INRAE - MetaboHUB)
+ * **@maintainers**: Lain Pavot (PFEM - INRAE - MetaboHUB)
+ * **@init date**: 2022, November
+ * **@main usage**:
+Generates peakforest forms, auto-filled with data and metadata provided
+with files or parametres.
+Lets you check data and metadata, correct, and send them to the peakforest
+instance of you choice.
+
+test
+----
+
+Test with FragNot data
+```sh
+input='Galaxy10-[Cmpd1-1__INCHIKEY___GIAZPLMMQOERPN-UHFFFAOYSA-N__RT___0..ABINITIOFRAGNOT_PForest.tabular].tabular'
+input="test-data/${input}"
+./server.py \
+ --input ''${input}'',''${input}'',''${input}'' \
+ --raw-metadata \'${input},${input},${input}\' \
+ --method cf_pfem_urine_qtof \
+ --peakforest-url https://metabohub.peakforest.org \
+ --scan-type ms \
+ --polarity positive \
+ --name 'test1,test2,test3'
+```
+
+Test with MS2Snoop data
+```sh
+input='out-smol-base.tsv'
+input="test-data/${input}"
+./server.py \
+ --input ''${input}'' \
+ --method cf_pfem_urine_qtof \
+ --pf_url https://nightly.peakforest.org \
+ --scan_type ms \
+ --polarity positive
+```
+
+Services provided
+-----------------
+
+ * Help and support: support@workflow4metabolomics.org
+
+
+License
+-------
+
+ * Cea Cnrs Inria Logiciel Libre License, version 2.1 (CECILL-2.1)
diff -r 000000000000 -r b58b229c4cbf add-one-spectrum-index.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/add-one-spectrum-index.js Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,2584 @@
+
+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 }},
+ 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() ;
+ },
+
+ populate_selects: function() {
+ var self = this ;
+ var choose_in_list ;
+
+ choose_in_list = `
+
+ choose in list…
+
+ ` ;
+ $("#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(
+ `${this.name} `
+ );
+ } else {
+ $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ }
+ }
+ });
+ },
+
+ populate_lc_columns: function(data) {
+ // load data from json
+ $.each(data.columns, function() {
+ $("#add1spectrum-chromatoLC-colConstructor-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ });
+ $("#add1spectrum-chromatoLC-colConstructor-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ 'Other '
+ );
+ },
+
+ populate_lc_solvents: function(data) {
+ // load data from json
+ $.each(data.solvents, function() {
+ $("#add1spectrum-chromatoLC-separationSolvA-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ $("#add1spectrum-chromatoLC-separationSolvB-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ });
+ },
+
+ 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(
+ `${this.name} `
+ );
+ $("#add1spectrum-analyzserMS-ionizationMethod-neg-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ } else {
+ $("#add1spectrum-analyzserMS-ionizationMethod-pos-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ $("#add1spectrum-analyzserMS-ionizationMethod-neg-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ }
+ }
+ });
+ },
+
+ populate_lcms_solvents: function(data) {
+ // load data from json
+ $.each(data.solvents, function () {
+ $("#add1spectrum-sample-lcmsSolvent-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ });
+ },
+
+ 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();
+ }
+ }) ;
+ $("#add1spectrum-peaksMS-msLevel-{{ TAB_INDEX_PLACEHOLDER }}").on("change", function() {
+ var v = $("#add1spectrum-peaksMS-msLevel-{{ TAB_INDEX_PLACEHOLDER }}").val();
+ $(self.prefix + ".disabled-if-ms-in-msms").attr(
+ "disabled",
+ (v == "ms2" || v == "ms3")
+ ) ;
+ $(self.prefix + ".enabled-if-ms-in-msms").attr(
+ "disabled",
+ !(v == "ms2" || v == "ms3")
+ ) ;
+ $(self.prefix + ".hidden-if-ms-in-msms").css(
+ "display",
+ !(v == "ms2" || v == "ms3") ? "none" : ""
+ ) ;
+ }) ;
+ },
+
+ 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 ;
+ 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 {
+ eslf.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_index() !== null) ;
+ },
+
+ get_selected_parent_ion_index: function() {
+ 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 (data[i][7] === "true" || data[i][7] === true) {
+ return i ;
+ }
+ }
+ return 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 ;
+ if (self.is_ref()) {
+ id = "#add1spectrum-sample-inchikey-{{ TAB_INDEX_PLACEHOLDER }}:text" ;
+ element = $(id) ;
+ if (element.length) {
+ console.log(`auto_set_inchikey to ${self.DEFAULT_DATA["inchikey"]} ok.`)
+ element.val(self.DEFAULT_DATA["inchikey"]).change() ;
+ console.log(`Inchikey set!`) ;
+ } else {
+ console.log(element)
+ console.log("Failed!")
+ }
+ } else {
+ for (var index = 0 ; index < all_contexts.length ; index += 1) {
+ 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"]) {
+ setTimeout(() => self.auto_set_scan_type(self), 1000) ;
+ }
+ })(self)
+ }, 1000) ;
+ },
+
+ auto_set_scan_type: function() {
+ console.log("auto_set_scan_type...") ;
+ var self = this ;
+ 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 (
+ "" + this.series.name
+ + " m/z:" + Math.abs(this.x) + ""
+ + "; Relative Intensity: " + this.y
+ + "%; 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(`
+
+
+ ×
+
+
+
+
+ unable to load pre-filled data!
+
+ `);
+ }
+ });
+ },
+
+ //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(
+ 'choose in list… '
+ );
+ $.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(
+ `${this.name} `
+ );
+ } else {
+ $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ }
+ }
+ });
+ });
+ } else if (self.is_ms2()) {
+ $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").empty();
+ $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ 'choose in list… '
+ );
+ $.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(
+ `${this.name} `
+ );
+ } else {
+ $("#add1spectrum-chromatoLC-method-{{ TAB_INDEX_PLACEHOLDER }}").append(
+ `${this.name} `
+ );
+ }
+ }
+ });
+ }
+ );
+ }
+ // 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) => {
+ 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]-") {
+ precursor_ion = $("#add1spectrum-peaksMS-msPrecursorIon-{{ TAB_INDEX_PLACEHOLDER }}") ;
+ console.log(precursor_ion)
+ 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: "InChIKey ", type: "text"},
+ {data: "composition", renderer: lightgrayRenderer},
+ {data: "concentration (µg/ml) ", 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",
+ "InChIKey ",
+ "composition",
+ "concentration (µg/ml) ",
+ "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]) ;
+ base_peakdata["msms_ms_precursor_ion"] = undefined ;
+ all_contexts.forEach((context, index) => {
+ new_peakdata = Object.assign({}, base_peakdata) ;
+ context.loadFomDataIntoJsonObjects()
+ if (is_ms2) {
+ new_peakdata["precursor_ion"] = context.jsonPeaksList["msms_ms_precursor_ion"]["m/z"] ;
+ }
+ 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(`
+
+
+ ×
+
+
+
+
+
+
+ Spectrum ready to be sent!
+
+ `);
+ 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: []
+ };
+ $.each(self.hot_LC_SFG.getData(), function(){
+ if (this[0]!="") {
+ if (!isNaN(this[0]) && !isNaN(this[1]) && !isNaN(this[2])) {
+ formatData["time"].push(Number(this[0]));
+ formatData["solvent_a_percent"].push(Number(this[1]));
+ formatData["solvent_b_percent"].push(Number(this[2]));
+ }
+ }
+ });
+ 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_gaz_flow", "sprayGazFlow"],
+ ["vaporizer_gaz_flow", "vaporizerGazFlow"],
+ ["vaporizer_temperature", "vaporizerTemperature"],
+ ["source_gaz_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]),
+ deltaPPM: Number(data[3]),
+ composition: (data[4]),
+ attribution: (data[5])
+ });
+ self.isJsonPeaksListComplete = true;
+ }
+ });
+ // peak list data
+ peakdata["ms_lvl"] = $("#add1spectrum-peaksMS-msLevel-{{ TAB_INDEX_PLACEHOLDER }}").val();
+ 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_range_from"] = $("#add1spectrum-peaksMS-rangeFrom-{{ TAB_INDEX_PLACEHOLDER }}").val();
+ peakdata["mz_range_to"] = $("#add1spectrum-peaksMS-rangeTo-{{ TAB_INDEX_PLACEHOLDER }}").val();
+ peakdata["rt_abs_from"] = $("#add1spectrum-peaksMS-rtMinFrom-{{ TAB_INDEX_PLACEHOLDER }}").val();
+ peakdata["rt_abs_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() ;
+ peakdata["msms_ms_precursor_ion"] = {
+ "m/z": data[selected_ion][0],
+ "abs_intensity": data[selected_ion][1],
+ "rel_intensity": data[selected_ion][2],
+ "attribution": data[selected_ion][5]
+ } ;
+ }
+ }
+ 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 = `
+
+
+ ×
+
+
+
+
+
+
+ Error processing spectrum type!
+
` ;
+ } else if (!self.isJsonSampleComplete) {
+ alertMsg = `
+ ` ;
+ } else if (!self.isJsonRCCaddedComplete) {
+ alertMsg = `
+
+
+ ×
+
+
+
+
+
+
+ Pease enter at least ONE compound in mix into sample section!
+
+
Go to this section
+
`;
+ } else if (!self.isJsonChromatoComplete) {
+ alertMsg = `
+
+
+ ×
+
+
+
+
+
+
+ Missing data in chromatography section!
+ ` ;
+ if (self.is_ms()) {
+ alertMsg += `
+
+
Go to this section `;
+ }
+ alertMsg += '
';
+ } else if (!self.isJsonPeaksListComplete) {
+ alertMsg = `
+
+
+ ×
+
+
+
+
+
+
+ Missing peaklist!
+ ` ;
+ if (self.is_ms()) {
+ alertMsg += `
+
+
Go to this section `;
+ }
+ alertMsg += '
';
+ } else if (self.is_mix() && self.is_ms2()) {
+ for (var i = 0 ; i < all_contexts.length ; i += 1) {
+ if (all_contexts[i].get_selected_parent_ion_index() === null) {
+ return alertMsg + `
+
+
+ ×
+
+
+
+
+
+
+ Select precursor ion in all peak lists!
+
+ `
+ }
+ }
+ }
+ // 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 = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${name}
+ ${inchikey}
+
+ ${data["exactMass"]}
+ ${data["formula"]}
+
+
+
+
+
+
+
+
* : Generic Compounds (abstract "flat" compound without (+) or (-) center).
+ <` + "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, "
" + valF + " ");
+ });
+ } catch (e){}
+ formatedFormula = formatedFormula.replace("
", "");
+ $(elem).html(formatedFormula);
+ });
+ $.each($(self.prefix+".compoundMass"), function(id, elem) {
+ var exactMass = parseFloat( $(elem).text());
+ exactMass = roundNumber(exactMass,7)
+ $(elem).html(exactMass);
+ });
+ ` + "script" + `>
+
+
+ <` + "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);
+ // ctx().hot_RCC_ADDED.setDataAtCell(ctx().multiPickLine, 1, inchikey);
+
+ // 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";
+ // ' '
+ 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(' ');
+ else {
+ // delete
+ $(ctx().prefix+"img.mixRCCadd"+ctx().multiPickLine).remove();
+ // add
+ $("#sample-bonus-display-{{ TAB_INDEX_PLACEHOLDER }}").append(' ');
+ $(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 ("InChIKey " in this && this["InChIKey "]!= undefined && this["InChIKey "] != "") {
+ jsonRCC_ADDED.push(this["InChIKey "]);
+ }
+ });
+ return jsonRCC_ADDED;
+ },
+
+ //USED HERE
+ getRCCADDEDConcentration: function() {
+ var self = this ;
+ jsonRCC_ADDED = [];
+ $.each(self.hot_RCC_ADDED.getData(), function(){
+ var formatData = {};
+ if ("InChIKey " in this && this["InChIKey "]!= undefined && this["InChIKey "] != "") {
+ jsonRCC_ADDED.push(this["concentration (µg/ml) "]);
+ }
+ });
+ 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.push(self) ;
+ } else {
+ no_success(
+ {{ TAB_INDEX_PLACEHOLDER }},
+ "{{ INCHIKEY_PLACEHOLDER }}",
+ {{ DEFAULT_DATA }}["name"]
+ ) ;
+ }
+ },
+ error : function(data) {
+ no_success(
+ {{ TAB_INDEX_PLACEHOLDER }},
+ "{{ INCHIKEY_PLACEHOLDER }}",
+ {{ DEFAULT_DATA }}["name"]
+ ) ;
+ }
+}).always(() => null);
diff -r 000000000000 -r b58b229c4cbf common.js
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/common.js Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,195 @@
+
+this.ctx = () => context;
+var all_contexts = [] ;
+var inchidata = {} ;
+var all_mix_data = {} ;
+function no_success(tab_index, inchi, data) {
+ console.log(`inchikey ${inchi} not found...`) ;
+ console.log(`disabling ${data} ...`)
+ disable_tab(
+ tab_index,
+ "red",
+ "This compound has not been found on peakforest"
+ ) ;
+}
+
+function disable_tab(tab_index, color, title) {
+ var element = $(`#open_tab_${tab_index}`) ;
+ element.attr("disabled", "disabled").off("click");
+ element.attr("onclick", null) ;
+ element.attr("title", title) ;
+ element.attr("data-toggle", null) ;
+ element.attr("href", null) ;
+ element.css("color", color) ;
+ element.css("cursor", "not-allowed") ;
+}
+
+function send_everything_to_peakforest(url, token) {
+ var bundles ;
+ if (context.is_mix()) {
+ bundles = [all_mix_data] ;
+ } else {
+ bundles = create_dataset_bundles() ;
+ }
+ bundles.forEach((bundle, index) => {
+ console.log(bundle)
+ $.ajax({
+ type: "post",
+ url: `${url}/rest/v2/spectrum?token=${token}`,
+ data: JSON.stringify(bundle),
+ contentType: "application/json"
+ })
+ })
+ // console.log(bundles)
+}
+
+function create_dataset_bundles() {
+ var bundles = [] ;
+ var data ;
+ all_contexts.forEach((context, index) => {
+ if ((data = context.sent_json) === null) {
+ return ;
+ }
+ if (bundles.length === 0) {
+ // console.log("First metadata!")
+ return bundles.push(data) ;
+ }
+ if (merge_in_bundle(bundles, data)) {
+ // console.log("Merged!")
+ } else {
+ // console.log("New metadata!")
+ }
+ }) ;
+ return bundles ;
+}
+
+function merge_in_bundle(bundles, data) {
+ for(var i = 0 ; i < bundles.length ; i += 1) {
+ if (
+ identical(bundles[i]["sample"], data["sample"])
+ && identical(bundles[i]["chromatography"], data["chromatography"])
+ && identical(bundles[i]["analyzer"], data["analyzer"])
+ && identical(bundles[i]["ionization_mode_positive"], data["ionization_mode_positive"])
+ && identical(bundles[i]["ionization_mode_negative"], data["ionization_mode_negative"])
+ && identical(bundles[i]["other_metadata"], data["other_metadata"])
+ ) {
+ bundles[i]["peaklists"].push(data["peaklists"][0]) ;
+ return true ;
+ } else {
+ continue ;
+ console.log(
+ "sample: "
+ + identical(bundles[i]["sample"], data["sample"])
+ )
+ console.log(
+ "chromatography: "
+ + identical(bundles[i]["chromatography"], data["chromatography"])
+ )
+ console.log(
+ "analyzer: "
+ + identical(bundles[i]["analyzer"], data["analyzer"])
+ )
+ console.log(
+ "ionization_mode_positive: "
+ + identical(bundles[i]["ionization_mode_positive"], data["ionization_mode_positive"])
+ )
+ console.log(
+ "ionization_mode_negative: "
+ + identical(bundles[i]["ionization_mode_negative"], data["ionization_mode_negative"])
+ )
+ console.log(
+ "other_metadata: "
+ + identical(bundles[i]["other_metadata"], data["other_metadata"])
+ )
+ }
+ }
+ bundles.push(data) ;
+ return false ;
+}
+
+function identical(left, right) {
+ if (typeof left !== typeof right) {
+ return false ;
+ }
+ if (left === null) {
+ return right === null ;
+ }
+ if (right === null) {
+ return left === null ;
+ }
+ switch (typeof left) {
+ case "array":
+ return identical_array(left, right) ;
+ break ;
+ case "object":
+ return identical_object(left, right) ;
+ break ;
+ default:
+ break ;
+ }
+ return (left === right)
+}
+
+function identical_array(left, right) {
+ if (right.length !== left.length) {
+ return false ;
+ }
+ for(var i = 0 ; i < left.length ; i += 1) {
+ if (!identical(left[i], right[i])) {
+ return false ;
+ }
+ }
+ return true ;
+}
+
+function identical_object(left, right) {
+ var left_keys ;
+
+ if (!(
+ share_keys(left, right)
+ && share_keys(right, left)
+ )) {
+ return true ;
+ }
+ left_keys = Object.keys(left) ;
+ for (var i = 0 ; i < left_keys.length ; i += 1){
+ if (!identical(left[left_keys[i]], right[left_keys[i]])) {
+ return false ;
+ }
+ }
+ return true ;
+}
+
+function share_keys(left, right) {
+ var left_keys ;
+ var right_keys ;
+
+ left_keys = Object.keys(left) ;
+ right_keys = Object.keys(right) ;
+ for(var i = 0 ; i < left_keys.length ; i += 1) {
+ if (!right_keys.includes(left_keys[i])) {
+ return false ;
+ }
+ }
+ return true ;
+}
+
+var set_inchi_data = function(data, tab_index) {
+ inchidata[data.inchikey] = data ;
+ $(`#add1spectrum-sample-inchi-${tab_index}`).val(data.inchi);
+ $(`#add1spectrum-sample-inchi-${tab_index}`).change();
+ $(`#add1spectrum-sample-commonName-${tab_index}`).val(data.name);
+ $(`#add1spectrum-sample-commonName-${tab_index}`).change();
+ $(`#sample-bonus-display-${tab_index}`).html(
+ ` `
+ );
+}
+
+var lightgrayRenderer = function(instance, td, row, col, prop, value, cellProperties) {
+ Handsontable.renderers.TextRenderer.apply(this, arguments);
+ td.style.backgroundColor = "#EEE";
+}
diff -r 000000000000 -r b58b229c4cbf compound-mix.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/compound-mix.html Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,36 @@
+
+
+
+
+
+ Precursor ion (M/Z)
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 000000000000 -r b58b229c4cbf compound-ref.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/compound-ref.html Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,660 @@
+
+
+
+
+
+
+ GC-MS spectrum
+ LC-MS spectrum
+ LC-MSMS spectrum
+
+
+
+
+
+
+
+
+
+
+
+
+ Sample Type
+
+ choose in list…
+ Ref. Chemical Compound
+
+
+
+
+
+
+
+
Reference compound added
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Chromatography Param.
+
+
+
+ Method
+
+
+
+
+ Column constructor
+ choose in list… Agilent Alltech Cil cluzeau Daicel Hypersil Interchim Macherey nagel Merck Phenomenex Shiseido Supelco (sigma-aldrich) Thermo Vydac Waters YMC Other
+
+
+ Column constructor (other)
+
+
+
+ Column name
+
+
+
+ Column length (mm)
+
+
+
+ Column diameter (mm)
+
+
+
+ Particule size (µm)
+
+
+
+ Column temperature (°C)
+
+
+
+ LC mode
+
+ choose in list…
+ Gradient
+ Isocratic
+
+
+
+ Separation flow rate (µL/min)
+
+
+
+ Separation solvent A
+ choose in list… 5% ACN + 0.1% FA in H2O 10% ACN + 0.1% FA in H2O 10mM (NH4)2CO3 / ACN (20/80) (v/v) Acetonitrile Acetonitrile + 0.1% Formic Acid H2O + 0.1% Formic Acid H2O, ammonium carbonate 10 mM, pH10.5 H2O, ammonium acetate 2.5 mM H2O / CH3OH / CH3CO2H (95/5/0.1) Methanol Methanol / H2O (1/1) Methanol / H2O (1/1), 0.1% FA Methanol / CH3CO2H (100/0.1) Methanol / ACN (60/40) ammonium acetate 2.5 mM
+
+
+ pH solvent A (if acqueous solvant)
+
+
+
+ Separation solvent B
+ choose in list… 5% ACN + 0.1% FA in H2O 10% ACN + 0.1% FA in H2O 10mM (NH4)2CO3 / ACN (20/80) (v/v) Acetonitrile Acetonitrile + 0.1% Formic Acid H2O + 0.1% Formic Acid H2O, ammonium carbonate 10 mM, pH10.5 H2O, ammonium acetate 2.5 mM H2O / CH3OH / CH3CO2H (95/5/0.1) Methanol Methanol / H2O (1/1) Methanol / H2O (1/1), 0.1% FA Methanol / CH3CO2H (100/0.1) Methanol / ACN (60/40) ammonium acetate 2.5 mM
+
+
+ pH solvent B (if acqueous solvant)
+
+
+
+
+
+
+
+
+
Separation flow gradient
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Analyzer
+
+
+
+ Instrument
+
+
+
+ Model
+
+
+
+
+
+
+
+
+
+
+
Molecule Ionization
+
+
+
+
+
+
+
+
+
Ion Storage / Ion Beam
+
+
+
+ Type (storage / beam)
+
+ choose in list…
+ Ion Trap
+ Ion Beam
+
+
+
+
+ Ion storage: Ion Trap (IT) and ICR.
+ Ion beam: Q or H collision Cell (QQQ, QQIT, QQ/TOF, Fusion).
+
+
+
+ Gas
+
+ He
+ N2
+ Ar
+
+
+
+ Gas pressure
+
+
+ choose in list…
+ mbar
+ a.u.
+
+
+
+ Frequency Shift (KHz)
+
+
+
+ Ion Number (AGC or ICC)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ scan type
+
+ choose in list…
+ ms
+ ms2
+
+
+
+
+ polarity
+
+ choose in list…
+ positive
+ negative
+
+
+
+ resolution
+
+ choose in list…
+ low
+ high
+
+
+
+ curation
+
+ no curation
+ Peaks RI > 1%
+ Top 50 peaks
+ Top 20 peaks
+ Top 10 peaks
+ Similar chromatographic profile
+
+
+
+
+
+
+
+
+ Isolation mode
+
+ choose in list…
+ IT
+ Q
+ TOF
+ ICR
+
+
+
+ Isolation window
+
+
+
+ qz isolation / activation (no unit)
+
+
+
+ Activation time (ms)
+
+
+
+ Mode
+
+ choose in list…
+ HCD
+ CID
+ ECD
+ ETD
+
+
+
+
+ Frag. energy
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Precursor ion (M/Z)
+
+
+
+
+
+
+
+
+
+
+ check
+ Next!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Validate this compound/mix!
+
+
+
+ View spectrum
+ Add new peaklist!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compound Name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 000000000000 -r b58b229c4cbf config.yml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/config.yml Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,250 @@
+##
+## when you see {{ something }} in a string, this means the string is
+## a template, and the "{{ something }}" will be replaced by its value
+## at runtime.
+## This is usefull to build strings from other strings.
+## to reference an item in a tree, you can use dots as branches:
+## {{ parameters.flags.help }}
+## will be extrapolated to "Show this help"
+##
+## But beware:
+## {{ parameters.mandatory }}
+## will be extrapolated to
+## "{'input': 'input file path'}"
+##
+
+## this config is used for debug.
+## it allows to define debug options before everything else is parsed
+__meta_config__:
+ __debug__: False
+ __debug_stream__: stderr
+ __only_root_debug__: False
+
+
+## the cli parameters
+parameters:
+ mandatory:
+ ## input is mandatory
+ input: input file path
+ flags:
+ ## help, verbose and version can be provided with no parameter.
+ help: Show this help
+ verbose: More verbose outputs
+ version: Show this tool's version
+ debug: show debug outputs
+ do_run_dry: Runs the whole process, without the server. Usefull for tests.
+ embed_js: Embed js in html file instead of using a separated js file.
+ firefox: Open firefox on the web page.
+ chromium: Open chromium or chrome on the web page.
+ optional:
+ ## these optional parameters need a value "--opt value --opt2 value2"
+ method: "default is {{ defaults.method }}"
+ spectrum_type: "default is {{ defaults.spectrum_type }}"
+ sample_type: "default is {{ defaults.sample_type }}"
+ resolution: "default is {{ defaults.resolution }}"
+ resolution: "default is {{ defaults.resolution }}"
+ name: The precursor name
+ peakforest.url: "default={{ defaults.peakforest.url }}"
+ peakforest.token: The token to comunicate with peakforest api
+ polarity: positive|negative
+ raw_metadata: example - 1-1__INCHIKEY__=QNAYBMKLOCPYGJ-REOHCLBHSA-N_L-Alanine_MS_POS_plasma_RT__=0.84_filtree.csv
+ scan_type: ms|msms|rmn
+ run_dry_html: when "--run-dry", provides the output directory for {{ generated.html }}
+ run_dry_js: when "--run-dry", provides the output directory for {{ generated.js }}
+ raw_metadata_sep: "raw metadata separator"
+ logging.std: "Either out, err, or anything else to not output"
+ logging.file.path: "The file path to output logs to"
+ validation: "Set the default validation to the provided value, TRUE or FALSE."
+ output_json: "Provide a path to output a JSON file."
+ meta:
+ ## meta info about the tool itself
+ author: Lain Pavot
+ version: 1.1.0
+ shortcuts:
+ ## to define things like: "we can use -p instead of --polarity"
+ peakforest.token: t
+ polarity: p
+ help: h
+ version: v
+ verbose: V
+ debug: d
+ logging.std: l
+
+## some default parameters
+## logging defines two elements: std and file.
+## std should be either empty, err or out.
+## it tells where to outputs logs:
+## - nowhere (empty value)
+## - in sterr (err)
+## - in stdout (out)
+## and file. Id a path is provided, add outputs to this file.
+## if append is true, outputs are appended to the file.
+## otherwise, the file is emptied each time the app runs.
+defaults:
+ peakforest:
+ url: https://nightly.peakforest.org
+ token: ''
+ spectrum_type: LC_MSMS
+ method: cf_pfem_urine_method1_qtof-msms
+ # api-msms-fia__idf-cea
+ # cf_pfem_plasma_method1_qtof-msms
+ # cf_pfem_urine_method1_qtof-msms
+ # lc-msms__test
+ scan_type: ms2
+ resolution: high
+ sample_type: compound-ref
+ # sample_type: compound-mix
+ polarity: positive
+ raw_metadata: ''
+ name: ''
+ run_dry_html:
+ run_dry_js:
+ raw_metadata_sep: ','
+ validation: "TRUE"
+ verbose: false
+ debug: true
+ logging:
+ std: out ## out || err
+ file:
+ path:
+ append: False
+ output_json: ''
+
+## token related info
+token:
+ ## do you use a file to store your token?
+ use_file: false
+ ## if so, what path the file is located at?
+ file_path: .token
+ ## if not, you can provide you token here
+ value:
+
+network:
+ ip: 0.0.0.0
+ port: 8000
+
+workdir:
+ ## create a tmp directory
+ create_tmp: true
+ ## works in the created tmp directory, or if not created, in /tmp
+ work_in_tmp: true
+ ## generate outputs in the created tmp directory, or if not created, in /tmp
+ generate_in_tmp: true
+
+## the templates paths
+templates:
+ ## meta is what wrapps the whole page.
+ main: meta.html
+ main_mix: meta-compound-mix.html
+ main_ref: meta-compound-ref.html
+ ## form is one instance of a pf form
+ # form: form.html
+ # form: compound-ref.html
+ form: form.html
+ form_mix: compound-mix.html
+ form_ref: compound-ref.html
+ ## one item of the tab list
+ tab_list: tab_list.html
+ ## the js for one form
+ js: add-one-spectrum-index.js
+ ## placeholders for the html templates.
+ ## this will not change the placeholders syntax for this file.
+ placeholders:
+ start: "{{ "
+ stop: " }}"
+
+generated:
+ ## what filename to give to the whole html file
+ html: pf.html
+ ## what filename to give to js files
+ js: add-one-spectrum-{{ index }}.js
+
+regex:
+ values:
+ ## reuse these smol regex in bigger regex!
+ spectrum_type: "NMR|LC_MS|LC_MSMS|MRM(_\\d+)?"
+ matrix: "[Uu]rine|[Pp]lasma|[Pp]las"
+ mode: "POS|NEG"
+ energy: "\\d+ev"
+ pool: "[Pp]ool\\d+"
+ rt: "\\d+\\.\\d+"
+ runs: "\\d+-\\d+"
+ inchikey: "[A-Z]{14}-[A-Z]{10}-[A-Z]"
+
+ ## the "INCHIKEY" word
+ ## one or more underscores
+ ## may be followed by a equal sign
+ ## captures in the "inchikey" variable:
+ ## 14, 10 and 1 letters
+ ## in caps
+ ## separated by a hyphen
+ inchikey: "INCHIKEY_+=?(?P{{ regex.values.inchikey }})"
+
+ ## method is one of values defined bellow, between underscores
+ spectrum_type: "_(?P{{ regex.values.method }})_"
+
+ ## matrix is one of values defined bellow, between underscores
+ matrix: "_(?P{{ regex.values.matrix }})_"
+
+ ## pool is one of values defined bellow, between underscores
+ pool: "_(?P{{ regex.values.pool }})_"
+
+ ## molecule everything between inchikey and method.
+ molecule: "{{ regex.inchikey }}_(?P.*?){{ regex.method }}"
+
+ ## mode is one of values defined bellow, between underscores
+ mode: "_(?P{{ regex.values.mode }})_"
+
+ ## energy is one of values defined bellow, between underscores
+ energy: "_(?P{{ regex.values.energy }})_"
+
+ ## - A underscore,
+ ## - the "RT" word,
+ ## - some underscore(s),
+ ## - an optional interrogation mark,
+ ## - the actual RT value is captured here,
+ ## - there is a underscore at the end
+ rt: "_RT_+=?(?P{{ regex.values.rt }})_"
+
+ ## "runs" is at the beginning, and ends with an underscore.
+ runs: "^(?P{{ regex.values.runs }})_"
+
+
+ ## BEGIN
+ ## anything
+ ## the inchikey
+ ## anything else can follow
+ ## END
+ # fragnot: ^.*{{ regex.inchikey }}.*$
+
+
+ ## This is the most exhaustive regex I came with to extract info from
+ ## fragnot files name.
+ # fragnot:
+ # ^
+ # .* (?# there may be anything at the begining)
+ # (?P\d+-\d+) (?# the run numbers)
+ # _+ (?# followed by anything - underscores usualy)
+ # INCHIKEY_+=?(?P{{ regex.inchikey }}) (?# we insert inchikey regex here - see above)
+ # _+ (?# there is one or more underscores)
+ # (?P.*?) (?# the molecule name follows the inchikey)
+ # _+ (?# there is one or more underscores)
+ # (?P{{ regex.method }}) (?# then, there is the method - nmr, ms or mrm???)
+ # _+ (?# there may be some underscores to separate)
+ # (?P{{ regex.matrix }})? (?# the matrix - urine or plasma)
+ # _* (?# there may be some underscores to separate)
+ # (?PPOS|NEG) (?# the acq mode - pos or neg)
+ # _+ (?# there may be some underscores to separate)
+ # (?P{{ regex.pool }})? (?# the pool - "Pool"+numbers, optional)
+ # _* (?# there may be some underscores to separate)
+ # (?P\d+ev)? (?# the energy - only for nmr, so it's optional)
+ # _* (?# there may be some underscores to separate)
+ # (?P{{ regex.pool }})? (?# the pool - sometimes the pool if *after* the energy...)
+ # _* (?# there may be some underscores to separate)
+ # (?P{{ regex.matrix }})? (?# the matrix is here, sometimes)
+ # _* (?# there may be anything here)
+ # RT_+=?(?P\d+\.\d+) (?# the retension time is a decimal number)
+ # _* (?# there may be anything at the end)
+ # (?P[fF]iltree)? (?# sometimes, "Filtree" appears, lets capture it)
+ # \.[ct]sv (?# the extension)
+ # $
\ No newline at end of file
diff -r 000000000000 -r b58b229c4cbf macros.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/macros.xml Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,202 @@
+
+ 1.1.0
+
+
+
+
+
+
+
+ alpha
+ nightly
+ metabohub
+
+
+
+ LC-MS
+ LC-MSMS
+ GC-MS
+
+
+
+
+
+
+ Compound Ref
+ Compound Mix
+
+
+ positive
+ negative
+ neutral
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 000000000000 -r b58b229c4cbf meta-compound-mix.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meta-compound-mix.html Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,1272 @@
+
+
+
+
+
+
+
+ PeakForest MetaboHub
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Close MS2PF
+
+
+
+
+
+
+
+
+ GC-MS spectrum
+ LC-MS spectrum
+ LC-MSMS spectrum
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sample Type
+
+
+ choose in list…
+
+ Mix of Ref. Chemical Compound
+
+
+
+
+
+
+
+ solvent
+
+ choose in list…
+ H2O/ethanol (75/25)
+
+
+
+
+
+
Reference compound added
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Chromatography Param.
+
+
+
+ Method
+
+
+
+
+ Column constructor
+
+ choose in list…
+
+
+
+
+ Column constructor (other)
+
+
+
+ Column name
+
+
+
+ Column length (mm)
+
+
+
+ Column diameter (mm)
+
+
+
+ Particule size (µm)
+
+
+
+ Column temperature (°C)
+
+
+
+ LC mode
+
+ choose in list…
+ Gradient
+ Isocratic
+
+
+
+ Separation flow rate (µL/min)
+
+
+
+ Separation solvent A
+
+ choose in list…
+
+
+
+
+ pH solvent A (if acqueous solvant)
+
+
+
+ Separation solvent B
+
+
+
+
+
+ pH solvent B (if acqueous solvant)
+
+
+
+
+
+
+
+
+
Separation flow gradient
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Analyzer
+
+
+
+ Instrument
+
+
+
+ Model
+
+
+
+
+
+
+
+
+
+
+
Molecule Ionization
+
+
+
+
+
+
+
+
+
Ion Storage / Ion Beam
+
+
+
+ Type (storage / beam)
+
+ choose in list…
+ Ion Trap
+ Ion Beam
+
+
+
+
+ Ion storage: Ion Trap (IT) and ICR.
+ Ion beam: Q or H collision Cell (QQQ, QQIT, QQ/TOF, Fusion).
+
+
+
+ Gas
+
+ He
+ N2
+ Ar
+
+
+
+ Gas pressure
+
+
+ choose in list…
+ mbar
+ a.u.
+
+
+
+ Frequency Shift (KHz)
+
+
+
+ Ion Number (AGC or ICC)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ scan type
+
+ choose in list…
+ ms
+ ms2
+
+
+
+
+ polarity
+
+ choose in list…
+ positive
+ negative
+
+
+
+ resolution
+
+ choose in list…
+ low
+ high
+
+
+
+ curation
+
+ no curation
+ Peaks RI > 1%
+ Top 50 peaks
+ Top 20 peaks
+ Top 10 peaks
+ Similar chromatographic profile
+
+
+
+
+
+
+
+
+ Isolation mode
+
+
+ choose in list…
+ IT
+ Q
+ TOF
+ ICR
+
+
+
+
+ Isolation window
+
+
+
+
+ qz isolation / activation (no unit)
+
+
+
+ Activation time (ms)
+
+
+
+
+ Mode
+
+
+ choose in list…
+ HCD
+ CID
+ ECD
+ ETD
+
+
+
+
+
+ Frag. energy
+
+
+
+
+
+
+
+
+ retention time (% solvant) from / to
+
+
+
+
+
+
+
+
+
+ {{ TAB_LIST_PLACEHOLDER }}
+
+
+ {{ ADD_SPECTRUM_FORM }}
+
+
+
+
+ check
+ Next!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Validate this compound/mix!
+
+
+
+
+ View spectrum
+
+
+ Add new peaklist!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compound Name
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Send everything to peakforest!
+
+
+ Close MS2PF
+
+
+
+
+
+
+
+
+
+
+ {{ EMBED_JS }}
+
+
+
\ No newline at end of file
diff -r 000000000000 -r b58b229c4cbf meta-compound-ref.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meta-compound-ref.html Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+ PeakForest MetaboHub
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Close MS2PF
+
+
+
+ {{ TAB_LIST_PLACEHOLDER }}
+
+
+ {{ ADD_SPECTRUM_FORM }}
+
+
+
+
+ Send everything to peakforest!
+
+ Close MS2PF
+
+
+
+
+
+
+
+
+
+
+ {{ EMBED_JS }}
+
+
+
\ No newline at end of file
diff -r 000000000000 -r b58b229c4cbf ms2pf_it.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/ms2pf_it.xml Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,144 @@
+
+
+ adds you MS spectrum to peakforest.
+
+
+ 0
+ macros.xml
+
+
+ python
+ pyyaml
+
+
+
+ 8000
+ /
+
+
+
+
+
+
+@MS2PF_COMMON_CMD@
+
+
+
+
+
+
+
+ do_output_json
+
+
+
+
+
+
+
+
diff -r 000000000000 -r b58b229c4cbf server.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server.py Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,1120 @@
+#!/usr/bin/env python3
+
+import atexit
+import csv
+import http.server
+import json
+import logging
+import os
+import re
+import shutil
+import socketserver
+import sys
+import tempfile
+import yaml
+
+TAB_LIST_PLACEHOLDER = "TAB_LIST_PLACEHOLDER"
+MS_PEAK_VALUES_PLACEHOLDER = "MS_PEAK_VALUES_PLACEHOLDER"
+COMPOUND_NAME_PLACEHOLDER = "COMPOUND_NAME_PLACEHOLDER"
+TAB_INDEX_PLACEHOLDER = "TAB_INDEX_PLACEHOLDER"
+EMBED_JS_PLACEHOLDER = "EMBED_JS"
+ACTIVE_TAB_PLACEHOLDER = "ACTIVE_TAB_PLACEHOLDER"
+ADD_SPECTRUM_FORM = "ADD_SPECTRUM_FORM"
+PRODUCE_JSON_PLACEHOLDER = "PRODUCE_JSON_PLACEHOLDER"
+
+COMPOUND_REF = "compound-ref"
+COMPOUND_MIX = "compound-mix"
+
+END_MS_PEAK_VALUES_PLACEHOLDER = " ]"
+MS_DATA_COLUMN_NUMBER = 9
+DEFAULT_MS_PEAK_VALUES = (
+ "[\n"
+ + (" [" + ','.join([' ""'] * MS_DATA_COLUMN_NUMBER) + "],\n") * 17
+ + END_MS_PEAK_VALUES_PLACEHOLDER
+)
+
+FRAGNOT_HEADER = {
+ "m/z": "fragment_mz",
+ "absolute_intensity": "abs_intensity",
+ "relative_intensity": "rel_intensity",
+ "theo_mass": "",
+ "delta_ppm": "ppm",
+ "rdbequiv": "",
+ "composition": "",
+ "attribution": "fragment",
+}
+
+MS_2_SNOOP_HEADER = {
+ "name": str,
+ "inchikey": str,
+ "composition": str,
+ "fragment": str,
+ "fragment_mz": str,
+ "ppm": str,
+ "fileid": str,
+ "correlation": str,
+ "abs_intensity": lambda x:float(x) * 100,
+ "rel_intensity": lambda x:float(x) * 100,
+ "valid_corelation": str
+}
+
+
+class ConfigException(ValueError):
+ """
+ An exception raised when something went wrong in the config and we
+ cannot continue - i.e: when there's no token for peakforest
+ """
+
+class YAMLConfig(dict):
+
+ """
+ Dictionary that handles key with dot in them:
+ test["truc.chose"]
+ is equivalant to
+ test["truc"]["chose"]
+ Assignation works too.
+ Add the possibility to use placeholders:
+ --- yaml
+ test: {{ truc.chose }}
+ truc:
+ chose: bidule
+ ---
+ here, test's value is "bidule"
+ """
+
+ def __init__(self, *args, **kwargs):
+ meta_conf = kwargs.pop("__meta_config__", {})
+ self._debug = meta_conf.get("__debug__", False)
+ self._stream_name = meta_conf.get("__debug_stream__", "stdout")
+ self._debug_stream = getattr(sys, self._stream_name)
+ self._only_root_debug = meta_conf.get("__only_root_debug__", False)
+ if "__root__" in kwargs:
+ if self._only_root_debug:
+ self._debug = False
+ self._name = kwargs.pop("__name__")
+ self._debugger("Is not root config.")
+ self._root = kwargs.pop("__root__")
+ else:
+ self._name = "root"
+ self._debugger("Is root config.")
+ self._root = self
+ super().__init__(*args, **kwargs)
+ for key, value in self.copy().items():
+ if isinstance(value, dict) and not isinstance(value, YAMLConfig):
+ self._debugger(f"Parsing sub-config for {key}")
+ self[key] = self._propagate(value, key)
+ self._replace_placeholders(self)
+ self._extract_defaults()
+
+ def _propagate(self, sub_dict, name):
+ if isinstance(sub_dict, dict) and not isinstance(sub_dict, self.__class__):
+ return YAMLConfig(
+ **sub_dict,
+ __name__=name,
+ __root__=self._root,
+ __meta_config__={
+ "__debug__": self._debug,
+ "__debug_stream__": self._stream_name,
+ "__only_root_debug__": self._only_root_debug,
+ }
+ )
+ return sub_dict
+
+ def _debugger(self, message):
+ if self._debug:
+ self._debug_stream.write(f"[{self._name}]: {message}\n")
+ self._debug_stream.flush()
+
+ def __getattr__(self, attr):
+ if attr in self:
+ return self[attr]
+ if '.' in attr:
+ attr, sub = attr.split('.', 1)
+ return getattr(getattr(self, attr), sub)
+ return super().__getattribute__(attr)
+
+ def _replace_placeholders(self, subpart):
+ self._debugger("Replacing placeholders...")
+ for sub_key, sub_item in subpart.copy().items():
+ if isinstance(sub_item, str):
+ for placeholder in re.findall("{{ (?P.*?) }}", sub_item):
+ if placeholder not in self._root:
+ self._debugger(f"Could not fine replacement for {placeholder}")
+ continue
+ replacement = self._root[placeholder]
+ if isinstance(replacement, str):
+ self._debugger(f"Found placeholder: {placeholder} -> {replacement}")
+ sub_item = sub_item.replace(
+ "{{ " + placeholder + " }}",
+ replacement
+ )
+ else:
+ self._debugger(f"Found placeholder: {placeholder} -> {replacement.__class__.__name__}")
+ sub_item = self._propagate(replacement, placeholder)
+ dict.__setitem__(subpart, sub_key, sub_item)
+ elif isinstance(sub_item, dict):
+ super().__setitem__(sub_key, self._propagate(sub_item, sub_key))
+
+ def _extract_defaults(self):
+ if self._root is not self:
+ return
+ if "defaults" not in self:
+ self._debugger("No defaults here.")
+ return
+ if "arguments" not in self:
+ self._debugger("Arguments creation...")
+ self["arguments"] = self._propagate({}, "arguments")
+ self._debugger("Populating arguments with defaults values")
+ for key, value in self.defaults.items():
+ if key not in self:
+ if isinstance(value, dict):
+ value = self._propagate(value, key)
+ self.arguments[key] = value
+ self._debugger(f"Default {key} = {value}")
+
+ def __setitem__(self, key, value):
+ if isinstance(value, dict):
+ value = self._propagate(value, key)
+ if "." not in key:
+ return super().__setitem__(key, value)
+ curent = self
+ key, subkey = key.rsplit(".", 1)
+ self[key][subkey] = value
+
+ def __getitem__(self, key):
+ if super().__contains__(key):
+ return super().__getitem__(key)
+ if "." not in key:
+ return super().__getitem__(key)
+ curent = self
+ while "." in key:
+ key, subkey = key.split(".", 1)
+ curent = curent[key]
+ key = subkey
+ if subkey not in curent:
+ curent[subkey] = self._propagate({}, subkey)
+ result = curent[subkey]
+ return result
+
+ def __contains__(self, key):
+ if "." not in key:
+ return super().__contains__(key)
+ key, subkey = key.split(".", 1)
+ if not super().__contains__(key):
+ return False
+ return subkey in self[key]
+
+ def copy(self):
+ return {
+ key: (
+ value if not isinstance(value, dict)
+ else value.copy()
+ ) for key, value in self.items()
+ }
+
+class YAMLParameters(YAMLConfig):
+
+ """
+ Parses parameters from the command line and put them
+ in the config.
+ Uses the config to know which parameter is recognized, or not,
+ to know the metadata (author, version),
+ which command is a flag, is optional, the help strings, etc...
+ Assigns default small parameter if not defined in the "shortcut"
+ section of the config file.
+ CLI config must be in the root section "parameters":
+ ---
+ parameters:
+ mandatory:
+ input: input file path
+ flags:
+ help: Show this help
+ optional:
+ method: "default is {{ defaults.method }}"
+ meta:
+ author: Lain Pavot
+ version: 1.1.0
+ shortcuts:
+ help: h
+ ## will autogenerate -i for input and -m for method
+ ---
+ default parameters are searched in the "default" root section.
+ """
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self._errors = list()
+ if not self.parameters.shortcuts:
+ self.parameters["shortcuts"] = YAMLConfig()
+ self._mandatory = self.parameters.mandatory
+ self._optional = self.parameters.optional
+ self._flags = {
+ flag: False
+ for flag in self.parameters.flags
+ }
+ self._all_params = self._optional.copy()
+ self._all_params.update(self._mandatory)
+ self._all_params.update(self._flags)
+ self._small_params = dict()
+ self._determine_small_params()
+
+ @property
+ def in_error(self):
+ return bool(self._errors)
+
+ @property
+ def sorted_keys(self):
+ return sorted(self._all_params.keys())
+
+ @property
+ def sorted_items(self):
+ return sorted(self._all_params.items())
+
+ def _determine_small_params(self, verbose=False):
+ self._small_params = (self.parameters.shortcuts or {}).copy()
+ chars = list(map(chr, range(97, 123))) + list(map(chr, range(65, 91)))
+ all_params = self._all_params.copy()
+ for long, short in self._small_params.items():
+ chars.remove(short)
+ del all_params[long]
+ for param in all_params.copy().keys():
+ for operation in (
+ lambda x:x[0], ## select first char
+ lambda x:x.split('-', 1)[-1][0], ## first char after -
+ lambda x:x.split('_', 1)[-1][0], ## first char after _
+ lambda x:x.split('.', 1)[-1][0], ## first char after .
+ lambda x:x[0].upper(), ## select first char
+ lambda x:x.split('-', 1)[-1][0].upper(), ## first char after -
+ lambda x:x.split('_', 1)[-1][0].upper(), ## first char after _
+ lambda x:x.split('.', 1)[-1][0].upper(), ## first char after .
+ lambda x: chars[0], ## first letter in the alphabet
+ ):
+ char = operation(param)
+ if char not in self._small_params.values():
+ self._small_params[param] = char
+ chars.remove(char)
+ del all_params[param]
+ break
+
+ def _get_parameter_index(self, parameter, original):
+ if f"--{parameter}" in sys.argv:
+ return sys.argv.index(f"--{parameter}")
+ parameter = self._small_params[original]
+ if f"-{parameter}" in sys.argv:
+ return sys.argv.index(f"-{parameter}")
+ return None
+
+ def as_parameter(self, string):
+ return (
+ string
+ .replace('.', '-')
+ .replace('_', '-')
+ )
+
+ def show_version(self):
+ print(self.parameters.meta.version)
+
+ def show_help(self):
+ parameters = [
+ f"-{self._small_params[arg]}|--{self.as_parameter(arg)} {arg}"
+ for arg in self._mandatory
+ ] + [
+ f"[-{self._small_params[arg]}|--{self.as_parameter(arg)} {arg}]"
+ for arg in self._optional
+ ] + [
+ f"[-{self._small_params[arg]}|--{self.as_parameter(arg)}]"
+ for arg in self._flags
+ ]
+ print(
+ f"Usage: {__file__} " + ' '.join(parameters)
+ + "\n\n"
+ + '\n'.join(
+ f" -{self._small_params[args]}|--{self.as_parameter(args)}: {help_str}"
+ for args, help_str in self.sorted_items
+ )
+ + "\n\n"
+ + '\n'.join(
+ f"{key}: {value}"
+ for key, value in self.parameters.meta.items()
+ )
+ )
+ sys.exit(0)
+
+ def parse_args(self):
+ errors = list()
+ for kind in ("mandatory", "optional", "flags"):
+ keys = list(sorted(getattr(self, f"_{kind}").keys()))
+ for original_param, actual_param in zip(
+ keys,
+ map(self.as_parameter, keys),
+ ):
+ if original_param in self.defaults:
+ self.arguments[original_param] = self.defaults[original_param]
+ elif kind == "flags":
+ self.arguments[original_param] = False
+ parser = getattr(self, f"parse_{kind}")
+ if (error := parser(original_param, actual_param)):
+ errors.append(error)
+ self._errors = errors
+ return self
+
+ def parse_mandatory(self, original, actual):
+ if (index := self._get_parameter_index(actual, original)) is None:
+ return f"The parameter --{actual} is mandatory."
+ if index == len(sys.argv) - 1:
+ return f"The parameter --{actual} needs a value."
+ self.arguments[original] = sys.argv[index + 1]
+
+ def parse_optional(self, original, actual):
+ if (index := self._get_parameter_index(actual, original)) is None:
+ return
+ if index == len(sys.argv) - 1:
+ return f"The parameter --{actual} needs a value."
+ self.arguments[original] = sys.argv[index + 1]
+
+ def parse_flags(self, original, actual):
+ if (index := self._get_parameter_index(actual, original)) is None:
+ return
+ self.arguments[original] = True
+
+def parse_config(**kwargs):
+ """
+ opens the config file, extract it using pyyaml's safe loader
+ and tries to extract and apply a maximum of informations/directives
+ from the config:
+ - token retrieval
+ - workdir management
+ - tempfile management
+ """
+ root_dir = os.path.dirname(os.path.abspath(__file__))
+ with open(os.path.join(root_dir, "config.yml")) as config_file:
+ config = YAMLConfig(
+ **yaml.load(config_file.read(), Loader=yaml.SafeLoader),
+ **kwargs
+ )
+
+ if not config.token.value:
+ if config.token.use_file:
+ if (not os.path.exists(path := config.token.file_path)):
+ raise ConfigException("Missing token value or token file.")
+ with open(path) as token_file:
+ config.token["value"] = token_file.read()
+ elif config.defaults.peakforest.token:
+ config.token["value"] = config.defaults.peakforest.token
+
+ if config.workdir.create_tmp:
+ tmp_dir = tempfile.mkdtemp()
+ atexit.register(lambda:shutil.rmtree(tmp_dir))
+ else:
+ tmp_dir = tempfile.gettempdir()
+ config.workdir["tmp_dir"] = tmp_dir
+
+ config["root_dir"] = root_dir
+ config["tab_list"] = []
+ config["form_template"] = os.path.join(root_dir, config.templates.form)
+ config["meta_template"] = os.path.join(root_dir, config.templates.main)
+ config["js_template"] = os.path.join(root_dir, config.templates.js)
+ config["tab_list_template"] = os.path.join(root_dir, config.templates.tab_list)
+ config["placeholders"] = dict()
+ config.placeholders[MS_PEAK_VALUES_PLACEHOLDER] = DEFAULT_MS_PEAK_VALUES
+ config.placeholders[TAB_INDEX_PLACEHOLDER] = "1"
+ config.placeholders[ACTIVE_TAB_PLACEHOLDER] = "active"
+ config.placeholders[ADD_SPECTRUM_FORM] = ""
+ config.placeholders[EMBED_JS_PLACEHOLDER] = ""
+ config.placeholders[TAB_LIST_PLACEHOLDER] = ""
+ config.placeholders["DEFAULT_MIN_MZ"] = "50"
+ config.placeholders["DEFAULT_MAX_MZ"] = "500"
+ config.placeholders["DEFAULT_RESOLUTION_LOW"] = ""
+ config.placeholders["DEFAULT_RESOLUTION_HIGH"] = "selected=\"selected\""
+ config.placeholders["DEFAULT_RESOLUTION_UNSET"] = ""
+ config.placeholders["DEFAULT_MIN_RT"] = "0.9"
+ config.placeholders["DEFAULT_MAX_RT"] = "1.4"
+ return config
+
+def parse_parameters(config):
+ """
+ parses command line and checks provided values are acceptable/usable.
+ Raises some error if not.
+ """
+ parameters = YAMLParameters(**config)
+ parameters.parse_args()
+
+ parameters["json_result"] = []
+
+ get_logger(parameters)
+
+ arguments = parameters.arguments
+ if arguments.help:
+ parameters.show_help()
+ sys.exit(0)
+
+ if arguments.version:
+ parameters.show_version()
+ sys.exit(0)
+
+ if parameters.in_error:
+ raise ValueError(
+ "Some errors occured during parameters extraction: \n"
+ + '\n'.join(parameters.errors)
+ )
+
+ if arguments.sample_type == COMPOUND_MIX:
+ parameters["form_template"] = os.path.join(
+ parameters["root_dir"],
+ parameters.templates.form_mix
+ )
+ parameters["meta_template"] = os.path.join(
+ parameters["root_dir"],
+ parameters.templates.main_mix
+ )
+ elif arguments.sample_type == COMPOUND_REF:
+ parameters["form_template"] = os.path.join(
+ parameters["root_dir"],
+ parameters.templates.form_ref
+ )
+ parameters["meta_template"] = os.path.join(
+ parameters["root_dir"],
+ parameters.templates.main_ref
+ )
+
+ arguments["produce_json"] = (
+ "output_json" in arguments
+ and arguments["output_json"] != ""
+ )
+ if arguments.produce_json:
+ parameters.placeholders[PRODUCE_JSON_PLACEHOLDER] = "true"
+ parameters.json_result = []
+ arguments["output_json"] = os.path.abspath(arguments["output_json"])
+ atexit.register(save_json, parameters)
+ else:
+ parameters.placeholders[PRODUCE_JSON_PLACEHOLDER] = "false"
+
+ if arguments.run_dry_html:
+ arguments["do_run_dry"] = True
+ parameters.generated["html"] = os.path.abspath(arguments.run_dry_html)
+
+ if arguments.run_dry_js:
+ arguments["do_run_dry"] = True
+ parameters.generated["js"] = os.path.abspath(arguments.run_dry_js)
+
+ if arguments.do_run_dry:
+ parameters.logger.info("Dry run. Server will ne be run.")
+ if arguments.run_dry_html:
+ parameters.logger.info(f"HTML file will be put in {arguments.run_dry_html}")
+ if arguments.run_dry_js:
+ parameters.logger.info(f"JS file will be put in {arguments.run_dry_js}")
+
+ if arguments.peakforest.token:
+ config.token["value"] = arguments.peakforest.token
+ if not config.token.value:
+ raise ConfigException(
+ "No token provided. We will not be able to connect to peakforest."
+ )
+
+ if os.path.exists(arguments.input):
+ single_file = True
+ file_paths = [arguments.input]
+ else:
+ path_list = arguments.input.split(',')
+ if all(map(os.path.exists, path_list)):
+ single_file = False
+ file_paths = path_list
+ else:
+ raise ValueError(
+ f"Some files cannot be found: "
+ + ', '.join(
+ path for path in path_list
+ if not os.path.exists(path)
+ )
+ )
+ arguments["input"] = list(map(os.path.abspath, file_paths))
+
+ if single_file:
+ arguments["name"] = [arguments.name]
+ arguments["raw_metadata"] = [arguments.raw_metadata]
+ parameters.logger.info(f"Single file processing: {arguments.input}")
+ else:
+ parameters.logger.info(f"Multiple file processing:")
+ arguments["raw_metadata"] = arguments.raw_metadata.split(
+ arguments.raw_metadata_sep
+ )
+ if not arguments.name:
+ arguments["name"] = arguments["raw_metadata"]
+ else:
+ arguments["name"] = arguments.name.split(',')
+ for i in range(len(arguments.name)):
+ parameters.logger.info(f" - file: {arguments.input[i]}")
+ parameters.logger.info(f" - name: {arguments.name[i]}")
+ parameters.logger.info(f" - metadata: {arguments.raw_metadata[i]}")
+ parameters.logger.info(f" ")
+ if (
+ len(arguments.name) != len(arguments.raw_metadata)
+ or len(arguments.name) != len(arguments.input)
+ ):
+ raise ValueError(
+ "name, raw_metadata and input parameters have different lengths: \n"
+ f"input is {len(arguments.input)} elements long, "
+ f"raw_metadata is {len(arguments.raw_metadata)} elements long "
+ f"and name is {len(arguments.name)} elements long."
+ )
+ if arguments.spectrum_type == "LC_MS":
+ arguments["scan_type"] = "ms"
+ elif arguments.spectrum_type == "LC_MSMS":
+ arguments["scan_type"] = "ms2"
+ if arguments.method == "test":
+ if arguments.spectrum_type == "LC_MS":
+ arguments["method"] = "cf_pfem_urine_qtof"
+ else:
+ arguments["method"] = "cf_pfem_urine_method1_qtof-msms"
+ if arguments["sample_type"] == COMPOUND_MIX:
+ check_mix_compound_files(parameters)
+ more_info_in_logs(parameters)
+ return parameters
+
+def check_mix_compound_files(parameters):
+ arguments = parameters.arguments
+ try:
+ numbarz = [
+ list(map(int, os.path.basename(metadata).split("_", 1)[0].split("-")))
+ for metadata in arguments.raw_metadata
+ ]
+ except ValueError:
+ parameters.logger.error(
+ "Metadata/file names does not start with `[0-9]+-[0-9]+_.*` . "
+ "This is necessary in the case of compounds mix."
+ )
+ sys.exit(-1)
+ runs, samples = zip(*numbarz)
+ if not all(runs[0] == i for i in runs[1:]):
+ parameters.logger.error(
+ "Run numbers in metadata/file names are not identical. "
+ "You mixed some files."
+ )
+ sys.exit(-1)
+ length = len(samples)
+ if list(sorted(samples)) != list(range(1, length+1)):
+ if not all(samples.count(i) == 1 for i in samples):
+ parameters.logger.error("Some samples are duplicated. ")
+ else:
+ parameters.logger.error("Some samples files are missing. ")
+ sys.exit(-1)
+
+def more_info_in_logs(config):
+ arguments = config.arguments
+ if arguments.embed_js:
+ config.logger.info(f"JS will be embed in HTML page to form a HTML bundle.")
+ else:
+ config.logger.info(f"JS are separated files, needed to be served.")
+ config.logger.info(f"Choosen parameters:")
+ config.logger.info(f" - method: {arguments.method}")
+ config.logger.info(f" - peakforest instance: {arguments.peakforest.url}")
+ config.logger.info(f" - polarity instance: {arguments.polarity}")
+ config.logger.info(f" - spectrum type: {arguments.spectrum_type}")
+ config.logger.info(f" - scan type: {arguments.scan_type}")
+ config.logger.info(f" - produce JSON: {arguments.produce_json}")
+ config.logger.info(f" - sample type: {arguments.sample_type}")
+
+def process_all_files(config):
+ """
+ for each file and its metadata, read and process them,
+ then fills the meta html template file with the whole result.
+ """
+ arguments = config.arguments
+ extra_defaults = [
+ process_fragnot_metadata(metadata, config)
+ for metadata in arguments.raw_metadata
+ ]
+ for i, name in enumerate(arguments.name):
+ extra_defaults[i]["name"] = name
+
+ if not extra_defaults:
+ extra_defaults = [{}] * len(arguments.input)
+
+ index = 0
+ for input_path, extra_default in zip(arguments.input, extra_defaults):
+ config.logger.info(f"Processing file at {input_path}...")
+ curent_defaults = arguments.copy()
+ curent_defaults.update(extra_default)
+ if config.arguments.verbose:
+ config.logger.info(
+ "[VERBOSE] Defaults for curent file: "
+ + ';'.join(f"{key}={value}" for key, value in curent_defaults.items())
+ )
+ tsv_content, tsv_data_extractor = read_input(input_path, config)
+ index = process_tsv(
+ tsv_content,
+ tsv_data_extractor,
+ config,
+ defaults_data = curent_defaults,
+ index = index+1,
+ )
+ if arguments.embed_js:
+ config.logger.info(f"Embeding JS in HTML file... ")
+ for index in range(len(config.tab_list)):
+ config.placeholders[EMBED_JS_PLACEHOLDER] += ""
+ config.placeholders[EMBED_JS_PLACEHOLDER] += "\n"
+ config.logger.info(f" - add-one-spectrum-{index+1}.js embed.")
+ config.placeholders[TAB_LIST_PLACEHOLDER] = "\n".join(config.tab_list)
+ else:
+ config.placeholders[EMBED_JS_PLACEHOLDER] += ""
+ config.placeholders[EMBED_JS_PLACEHOLDER] += "\n".join(
+ [""] + [
+ " "*12 + f""
+ for index in range(len(config.tab_list))
+ ]
+ )
+ config.placeholders[EMBED_JS_PLACEHOLDER] += "\n"
+ config.placeholders[TAB_LIST_PLACEHOLDER] = "\n".join(config.tab_list)
+
+ fill_template("meta_template", "pf_path", config)
+
+def fill_template(
+ template_name,
+ output_name,
+ config,
+ additional_placeholders=dict()
+):
+ """
+ Fills a template, replaces the placeholders.
+ Either outputs the result in a given file, or returns it if path is none.
+ """
+ template_path = config[template_name]
+ config.logger.debug(f"Filling template {template_name} at {template_path}...")
+ with open(template_path) as template_file:
+ template_content = template_file.read()
+ placeholders = config.placeholders.copy()
+ placeholders.update(additional_placeholders)
+ for placeholder, replacement in placeholders.items():
+ if not placeholder.startswith(config.templates.placeholders.start):
+ placeholder = placeholder.join((
+ config.templates.placeholders.start,
+ config.templates.placeholders.stop
+ ))
+ template_content = template_content.replace(placeholder, replacement)
+ if output_name is None:
+ config.logger.debug(f"Returning template content")
+ return template_content
+ output_path = config[output_name]
+ if "{{ index }}" in output_path:
+ index_value = additional_placeholders["{{ index }}"]
+ config.logger.debug(f"Changing index value for {index_value}")
+ output_path = output_path.replace("{{ index }}", index_value)
+ config.logger.debug(f"Full output path {output_path}")
+ with open(output_path, "w") as output_file:
+ output_file.write(template_content)
+
+def read_input(input_path, config):
+ """
+ reads a tsv file and determin its processor, based on its header.
+ """
+ with open(input_path) as input_file:
+ config.logger.info(f"Reading {input_path}...")
+ tsv_file = csv.reader(input_file, delimiter='\t')
+ header = next(tsv_file)
+ tsv_file = list(tsv_file)
+ config.logger.info(f"Header is: {', '.join(header)}")
+ if header == list(FRAGNOT_HEADER):
+ config.logger.info(f"Fragnot recognized.")
+ processor = fragnot_extractor
+ return uniformize_fragnot(tsv_file, header), processor
+ else:
+ config.logger.info(f"MS2Snoop recognized.")
+ processor = ms2snoop_extractor
+ return uniformize_ms2snoop(tsv_file, header), processor
+
+def uniformize_fragnot(content, header):
+ """
+ sorts fragnot data so they appear always in the same order
+ """
+ return sorted(content, key=lambda x:(float(x[0]), float(x[4])))
+
+def uniformize_ms2snoop(content, header):
+ """
+ sorts ms2snoop data so they appear always in the same order
+ """
+ return sorted(content, key=lambda x:(x[0], float(x[4])))
+
+def process_fragnot_metadata(raw_metadata, config):
+ """
+ Tries to extract informations from the metadata provided by fragnot
+ files names.
+ Heavily based on regex defined in conf file.
+ """
+ regex = config.regex.copy()
+ del regex["values"]
+ result = {}
+ config.logger.info(f"Extracting info from {raw_metadata}...")
+ count = 0
+ for name, expression in regex.items():
+ if (match := re.search(expression, raw_metadata)):
+ result[name] = match[name]
+ count += 1
+ did = "+ did"
+ else:
+ did = "- did not"
+ if config.arguments.verbose:
+ config.logger.info(f" {did} match {expression}")
+ config.logger.info(f"{count} useful informations extracted.")
+ return result
+
+def process_tsv(
+ tsv_content,
+ tsv_data_extractor,
+ config,
+ defaults_data={},
+ index=1
+):
+ """
+ processes one tsv file, containing one or multiple compounds.
+ Creation of the peak table for each compound
+ """
+ tsv_content = list(tsv_content)
+ curent_name, ms_data = get_ms_data(
+ tsv_content[0],
+ tsv_data_extractor,
+ defaults_data,
+ config
+ )
+ _, second_ms_data = get_ms_data(
+ tsv_content[1],
+ tsv_data_extractor,
+ defaults_data,
+ config
+ )
+ ms_peak_table = []
+ config.logger.info(f"Processing compound {curent_name}...")
+
+ for line in tsv_content:
+ name, new_ms_data = get_ms_data(line, tsv_data_extractor, defaults_data, config)
+ if name != curent_name:
+ new_compound(curent_name, index, ms_data, config, ms_peak_table)
+ curent_name = name
+ index += 1
+ config.logger.info(f"Processing compound {curent_name}...")
+ ms_peak_table = []
+ ms_data = new_ms_data
+ ms_peak_table.append(
+ ", ".join(
+ f'"{value}"' if value not in ("na", "NA")
+ else '""'
+ for value in (
+ ms_data["fragment_mz"],
+ ms_data["abs_intensity"],
+ ms_data["rel_intensity"],
+ ms_data["ppm"],
+ ms_data["composition"],
+ ms_data["fragment"],
+ str(ms_data["valid_corelation"] == "TRUE").lower(),
+ "true" if ms_data.get("correlation") == "1" else "false"
+ )
+ )
+ )
+ new_compound(curent_name, index, ms_data, config, ms_peak_table)
+ return index
+
+def get_ms_data(line, extractor, defaults, config):
+ ms_data = defaults.copy()
+ ms_data.update(extractor(config, *line))
+ return ms_data["name"], ms_data
+
+def new_compound(name, index, ms_data, config, ms_peak_table):
+ """
+ aggregates informations to form the peak table,
+ adds the compound to the tab list,
+ creates the js file for this tab
+ """
+ if len([x for x in ms_peak_table if x.split(", ")[7] == "\"true\""]) > 1:
+ for i in range(len(ms_peak_table)):
+ ms_peak_table[i] = ", ".join(
+ ms_peak_table[i].split(", ")[:-1] + [", \"false\""]
+ )
+ config.placeholders[MS_PEAK_VALUES_PLACEHOLDER] = f"""[
+ {','.join('['+line+']' for line in ms_peak_table)}
+ ]"""
+ tab_list = fill_template(
+ "tab_list_template",
+ None,
+ config, {
+ COMPOUND_NAME_PLACEHOLDER: name,
+ TAB_INDEX_PLACEHOLDER: str(index),
+ })
+ config.tab_list.append(tab_list)
+ create_js_file(index, ms_data, config)
+ config.placeholders[ADD_SPECTRUM_FORM] += fill_template(
+ "form_template",
+ None,
+ config,
+ {TAB_INDEX_PLACEHOLDER: str(index)},
+ )
+ if index == 1:
+ config.placeholders[ACTIVE_TAB_PLACEHOLDER] = ""
+
+def fragnot_extractor(config, *line):
+ """
+ Fragnot processor - extracts one fragnot line of content and
+ produces a uniformised output.
+ """
+ fragnot_data = {
+ FRAGNOT_HEADER[header]: line[i].strip()
+ for i, header in enumerate(FRAGNOT_HEADER)
+ }
+ fragnot_data["composition"] = "unknown"
+ fragnot_data["valid_corelation"] = config.arguments.validation
+ return fragnot_data
+
+def ms2snoop_extractor(config, *line):
+ """
+ Fragnot processor - extracts one ms2snoop line of content and
+ produces a uniformised output.
+ """
+ ms2snoop_data = {
+ header: MS_2_SNOOP_HEADER[header](line[i])
+ for i, header in enumerate(MS_2_SNOOP_HEADER)
+ }
+ return ms2snoop_data
+
+def create_js_file(index, ms_data, config):
+ """
+ fills the js template file for one tab (compound)
+ """
+ if (method := ms_data["method"]):
+ method = f'"{method}"'
+ else:
+ method = "null"
+ if config.arguments.verbose:
+ config.logger.info(
+ "[VERBOSE] "
+ + ';'.join(f"{key}={value}" for key, value in ms_data.items())
+ )
+ fill_template(
+ "js_template",
+ "js_file",
+ config,
+ {
+ TAB_INDEX_PLACEHOLDER: str(index),
+ "INCHIKEY_PLACEHOLDER": ms_data["inchikey"],
+ "DEFAULT_DATA": f"""{{
+ name: "{ms_data["name"]}",
+ inchikey: "{ms_data["inchikey"]}",
+ method: {method},
+ spectrum_type: "{ms_data["spectrum_type"]}",
+ scan_type: "{ms_data["scan_type"]}",
+ polarity: "{ms_data["polarity"]}",
+ resolution: "{ms_data["resolution"]}",
+ sample_type: "{ms_data["sample_type"]}",
+ }}""",
+ "{{ index }}": str(index)
+ },
+ )
+
+def prepare_workplace(config):
+ """
+ prepares the directory we will work in.
+ """
+ if config.workdir.work_in_tmp:
+ os.chdir(config.workdir.tmp_dir)
+ config.logger.info(f"Moving to {os.getcwd()}")
+ if config.workdir.generate_in_tmp:
+ gen_dir = config.workdir.tmp_dir
+ else:
+ gen_dir = tempfile.gettempdir()
+ config.workdir.tmp_dir = gen_dir
+ shutil.copy(os.path.join(config["root_dir"], "common.js"), gen_dir)
+ config.logger.info(f"Outputs will be generated in {config.workdir.tmp_dir}")
+ return gen_dir
+
+def get_hander_for(directory, config):
+ """
+ generates the handler class for the directory we provide.
+ """
+ config["json_result"] = [{}] * len(config.tab_list)
+
+ class HTTPHandler(http.server.SimpleHTTPRequestHandler):
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs, directory=directory)
+
+ def do_POST(self):
+ content_length = int(self.headers.get("Content-Length"))
+ json_bytes = self.rfile.read(content_length).decode("utf-8")
+ json_list = json.loads(json_bytes)
+ for i, obj in enumerate(json_list):
+ print(obj)
+ if obj:
+ config["json_result"][i] = obj
+ save_json(config)
+ self.send_head()
+ self.wfile.write(json_bytes.encode("utf-8"))
+ return
+
+ def do_GET(self):
+ if self.path == "/quit":
+ self.path = "/"
+ super().do_GET()
+ exit(0)
+ self.path = os.path.join(directory, self.path)
+ if self.path == "/":
+ self.path = config.generated.html
+ return super().do_GET()
+
+ return HTTPHandler
+
+
+def save_json(config):
+ json_string = json.dumps(config["json_result"])
+ print(json_string)
+ with open(config.arguments.output_json, "w") as json_file:
+ json_file.write(json_string)
+
+def run_server(config):
+ """
+ prepare and runs the server, with the handler for the given directory
+ """
+ ip, port = config.network.ip, config.network.port
+ config.logger.debug(f"IP and port: {ip}:{port}")
+ socketserver.TCPServer.allow_reuse_address = True
+ config.logger.debug(f"Allow reuse adress.")
+ handler = get_hander_for(config.workdir.tmp_dir, config)
+ config.logger.debug(f"Created server handler for {config.workdir.tmp_dir}")
+ config.logger.debug(
+ f"Content of directory {config.workdir.tmp_dir}: "
+ + "\n"
+ + '\n'.join(sorted(
+ f" - {path}"for path in os.listdir(config.workdir.tmp_dir)
+ ))
+ )
+ config.logger.debug(f"Creating TCP server...")
+ server = socketserver.TCPServer((ip, port), handler)
+ if ip == "0.0.0.0":
+ displayed_ip = "localhost"
+ else:
+ displayed_ip = ip
+ config.logger.debug(f"Serving...")
+ print()
+ print(f"http://{displayed_ip}:{port}")
+ server.serve_forever()
+
+def get_logger(config, dummy=False):
+ dummy_log = lambda msg:dummy and config.logger.info(msg)
+ arguments = config.arguments
+ if not dummy:
+ logger = logging.getLogger(__file__)
+ if arguments.debug:
+ dummy_log(f"Output debug info.")
+ level = logging.DEBUG
+ else:
+ level = logging.INFO
+ if not dummy:
+ logger.setLevel(level)
+ formatter = logging.Formatter(
+ "%(asctime)s - %(levelname)s - %(message)s"
+ )
+ if arguments.logging.std == "err":
+ dummy_log(f"Handler added to output logs in stderr.")
+ if not dummy:
+ handler = logging.StreamHandler(sys.stderr)
+ handler.setLevel(level)
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+ elif arguments.logging.std == "out":
+ dummy_log(f"Handler added to output logs in stdout.")
+ if not dummy:
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setLevel(level)
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+ else:
+ dummy_log(f"Logs will not be output in stderr not stdout.")
+ if (path := arguments.logging.file.path):
+ dummy_log(f"Add log file: {arguments.logging.file.path}.")
+ if not arguments.logging.file.append:
+ dummy_log(f"Log file content cleaned.")
+ with open(path, "w"):pass
+ else:
+ dummy_log(f"Logs appended to log file.")
+ if not dummy:
+ file_handler = logging.FileHandler(filename=path)
+ file_handler.setLevel(level)
+ file_handler.setFormatter(formatter)
+ logger.addHandler(file_handler)
+ if not dummy:
+ config["logger"] = logger
+ starting_sequence(logger)
+ get_logger(config, dummy=True)
+ return logger
+
+def starting_sequence(logger):
+ logger.info("*bip* *bop*")
+ logger.info("starting...")
+ logger.info("program...")
+ logger.info("MS2PF is running...")
+ logger.info("*bip* *bop* am a robot")
+ atexit.register(stoping_sequence, logger)
+
+def stoping_sequence(logger):
+ logger.info("*bip* *bop*")
+ logger.info("ending...")
+ logger.info("program...")
+ logger.info("MS2PF is shuting down...")
+ logger.info("...robot")
+ logger.info("*bip* *bop*")
+ logger.info("shutdown")
+ logger.info("...")
+
+if __name__ == "__main__":
+
+ base_config = parse_config()
+ config = parse_parameters(base_config)
+
+ """
+ The config contains result of the parsed config file.
+ """
+ arguments = config.arguments
+
+ config.logger.info(f"Starting MS2PF from {os.getcwd()}")
+
+ gen_dir = prepare_workplace(config)
+
+ config["pf_path"] = os.path.join(gen_dir, config.generated.html)
+ config.logger.info(f"HTML output file will be {config.pf_path}")
+ config["js_file"] = os.path.join(gen_dir, config.generated.js)
+ config.logger.info(f"JS output files will like {config.js_file}")
+ config.placeholders["PF_URL_PLACEHOLDER"] = arguments.peakforest.url
+ config.placeholders["PF_TOKEN_PLACEHOLDER"] = (
+ arguments.peakforest.token
+ or config.token.value
+ )
+ if (token := config.placeholders.PF_TOKEN_PLACEHOLDER):
+ config.logger.info(f"Using a token for authentification - length: {len(token)}")
+ else:
+ config.logger.info(f"No token provided for peakforest authentification.")
+
+ process_all_files(config)
+
+ if not arguments.do_run_dry:
+ config.logger.debug(f"Running the server.")
+ if arguments.firefox or arguments.chromium:
+ config.logger.debug(f"Running the server.")
+ import threading
+ import time
+ if arguments.firefox:
+ browser = "firefox"
+ else:
+ browser = "chromium"
+ if (ip := config.network.ip) == "0.0.0.0":
+ ip = "localhost"
+ adress = f"http://{ip}:{config.network.port}"
+ threading.Thread(
+ target=lambda:(
+ time.sleep(1),
+ os.system(f"{browser} {adress}")
+ ),
+ daemon=True
+ ).start()
+ run_server(config)
+ else:
+ config.logger.debug(f"Server not run.")
diff -r 000000000000 -r b58b229c4cbf tab_list.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tab_list.html Fri Mar 03 14:10:24 2023 +0000
@@ -0,0 +1,14 @@
+
+
+
+ {{ COMPOUND_NAME_PLACEHOLDER }}
+
+