diff --git a/js-i2b2/cells/plugins/MedCo/MedCo_ctrlr.js b/js-i2b2/cells/plugins/MedCo/MedCo_ctrlr.js index 49f2f56..913d3ab 100644 --- a/js-i2b2/cells/plugins/MedCo/MedCo_ctrlr.js +++ b/js-i2b2/cells/plugins/MedCo/MedCo_ctrlr.js @@ -1,322 +1,324 @@ /*********************** * @ProjectDescription Secure count query for sensitive genomic and clinical data with strong privacy guarantees. * @inherits i2b2 * @namespace i2b2.MedCo * @author LCA1 EPFL * @version 0.1 * -------------------------------------------------------------------------------------------------------------------- * This plugin is based on Tutorial plugin and examples on the webclient plugin development guide. */ i2b2.MedCo.Init = function(loadedDiv) { // setup model variables for this plugin // i2b2.MedCo.model.responseXML = ''; // i2b2.MedCo.model.responseString = ''; // i2b2.MedCo.model.requestQuery = ''; // i2b2.MedCo.model.requestPSet = ''; // i2b2.MedCo.model.requestQueryType = ''; // i2b2.MedCo.model.requestQueryName = ''; // i2b2.MedCo.model.prsRecord = undefined; // i2b2.MedCo.model.infoType = true; // i2b2.MedCo.model.varType = true; // i2b2.MedCo.view.tabId = 0; // set drag and drop // i2b2.sdx.Master.AttachType("medco-pset", "PRS", {dropTarget: true}); // i2b2.sdx.Master.setHandlerCustom("medco-pset", "PRS", "DropHandler", i2b2.MedCo.ctrlr.prsDropped); // register handlers for the medco query tool panels var panels = ["medcoQryToolPanel1", "medcoQryToolPanel2", "medcoQryToolPanel3"]; var eventRouterFunc = [ function (sdxData) {i2b2.MedCo.doDrop(sdxData, 0);}, function (sdxData) {i2b2.MedCo.doDrop(sdxData, 1);}, function (sdxData) {i2b2.MedCo.doDrop(sdxData, 2);}]; for (var i = 0; i < panels.length; i++) { var op_trgt = {dropTarget: true}; i2b2.sdx.Master.AttachType(panels[i], 'CONCPT', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'QM', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'QI', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'PRS', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'PRC', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'PR', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'QDEF', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'QGDEF', op_trgt); // i2b2.sdx.Master.AttachType(panels[i], 'XML', op_trgt); // register drop event handler i2b2.sdx.Master.setHandlerCustom(panels[i], 'CONCPT', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'QM', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'QI', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'PRS', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'PRC', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'PR', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'QDEF', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'QGDEF', 'DropHandler', eventRouterFunc[i]); // i2b2.sdx.Master.setHandlerCustom(panels[i], 'XML', 'DropHandler', eventRouterFunc[i]); } // manage YUI tabs i2b2.MedCo.view.yuiTabs = new YAHOO.widget.TabView("MedCo-TABS", {activeIndex: 0}); // put in an array all the (three) panels for easier access i2b2.MedCo.view.panels = document.getElementsByClassName("medcoQryToolPanel"); for (var i = 0 ; i < 3; i++){ i2b2.MedCo.view.panels[i].innerHTML = "" } // initialize empty parameter for the query (no panels content) i2b2.MedCo.model.panels = [[], [], []]; // three panels // POPUP init - // i2b2.MedCo.ctrlr.PopupInit(); + // i2b2.MedCo.ctrlr.PopupInit(); todo delete (old popup initialization) - // GENE POPUP + // POPUPS i2b2.MedCo.ctrlr.genePopup.init(); + i2b2.MedCo.ctrlr.variantNamePopup.init(); + // store how many responses I am waiting for (I have to wait to receive all the variants before sending the query) i2b2.MedCo.ctrlr.variantsQueryCounter = 0; }; i2b2.MedCo.Unload = function() { // purge old data i2b2.MedCo.model = {}; i2b2.MedCo.view = {}; return true; }; i2b2.MedCo.doDrop = function(sdxData, nPanel) { sdxData = sdxData[0]; // only interested in first record // save the info to our local data model i2b2.MedCo.model.panels[nPanel].push(sdxData); // show the info to the user i2b2.MedCo.view.panels[nPanel].innerHTML += sdxData.sdxInfo.sdxDisplayName + "<br>"; // CHECK: some usefull functions: // alert(i2b2.h.getXNodeVal(sdxData.origData.xmlOrig, "level")) // alert(Object.getOwnPropertyNames(sdxData.origData)); // optimization to prevent requerying the hive for new results if the input dataset has not changed // i2b2.ExampTabs.model.dirtyResultsData = true; // TODO if is "Genomic annotations" then open a popup to insert the annotations if (sdxData.sdxInfo.sdxDisplayName == "Laboratory Tests"){ i2b2.MedCo.popupShow(nPanel); }; }; i2b2.MedCo.ctrlr.clear = function(){ for (i = 0; i < i2b2.MedCo.view.panels.length; i++){ i2b2.MedCo.view.panels[i].innerHTML = ""; }; i2b2.MedCo.model.panels = [[], [], []]; }; i2b2.MedCo.ctrlr.run = function(){ // show the loading gif document.getElementById("MED-plainResult").innerHTML = "<img id=\"MED-loadingGif\" width=\"20px\" src=\"assets/images/spin.gif\">"; document.getElementById("MED-loadingGif").style.display = 'block'; // wait until you receive all the variants you requested while (i2b2.MedCo.popup.variantsQueryCounter != 0) { // try again later to run the query setTimeout(i2b2.MedCo.ctrlr.run, 500); return } // todo delete. just checking the variables correspond with the ones in the panels // for (var i = 0; i<3; i++){ // alert(i2b2.MedCo.model.panels[i].map(function(e) { // if (typeof e === 'object'){ // return e.sdxInfo.sdxDisplayName // }else{ // return e // } // } // ) // ); // } // callback processor to run the query from definition this.MedCocallback = new i2b2_scopedCallback(); this.MedCocallback.scope = this; this.MedCocallback.callback = function(results) { try{ // alert("full message" + JSON.stringify(results)); if (results.error) { alert(results.errorMsg); return; } else { // // "results" object contains the following attributes: // // refXML: xmlDomObject <--- for data processing // // msgRequest: xml (string) // // msgResponse: xml (string) // // error: boolean // // errorStatus: string [only with error=true] // // errorMsg: string [only with error=true] // alert("response" + JSON.stringify(results.msgResponse)); // hide the loading gif document.getElementById("MED-loadingGif").style.display = 'none'; // show the patient count var qi_list = results.refXML.getElementsByTagName('query_result_instance'); patientCount = i2b2.h.getXNodeVal(qi_list[0], 'set_size'); document.getElementById("MED-plainResult").innerHTML = patientCount; } } catch(e){ alert("exception") } }; this.MedCoparams = {}; this.MedCoparams.result_wait_time = 180; this.MedCoparams.psm_query_definition = i2b2.MedCo.ctrlr.QueryDefinition("MedCo_query"); // chose a name for the query // show the query logdiv = document.getElementById("mylog"); logdiv.innerHTML= i2b2.h.Escape(this.MedCoparams.psm_query_definition); this.MedCoparams.psm_result_output = i2b2.MedCo.ctrlr.ResultOutput; i2b2.CRC.ajax.runQueryInstance_fromQueryDefinition("PLUGIN:MedCo", this.MedCoparams, this.MedCocallback); }; i2b2.MedCo.ctrlr.ResultOutput = "<result_output_list><result_output priority_index=\"9\" name=\"patient_count_xml\"/>\n</result_output_list>\n"; // return the query xml i2b2.MedCo.ctrlr.QueryDefinition = function (name){ //"<query_definition>\n\t<query_name>undefined</query_name>\n\t<query_timing>ANY</query_timing>\n\t<specificity_scale>0</specificity_scale>\n\t<panel>\n\t\t<panel_number>1</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<hlevel>1</hlevel>\n\t\t\t<item_name>Procedures</item_name>\n\t\t\t<item_key>\\\\i2b2_PROC\\i2b2\\Procedures\\</item_key>\n\t\t\t<tooltip>Procedures</tooltip>\n\t\t\t<class>ENC</class>\n\t\t\t<item_icon>FA</item_icon>\n\t\t\t<item_is_synonym>false</item_is_synonym>\n\t\t</item>\n\t</panel>\n</query_definition>\n" // get the time of the query var d = new Date(); var time = d.getHours().toString() + ":" + d.getMinutes().toString() + ":" + d.getSeconds().toString(); var queryxml = "<query_definition>\n\t<query_name>" + name + "@" + time + "</query_name>\n\t<query_timing>ANY</query_timing>\n\t<specificity_scale>0</specificity_scale>\n\t"; // hardcoded query1 (result should be 102) // queryxml += "<panel>\n\t\t<panel_number>1</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<hlevel>1</hlevel>\n\t\t\t<item_name>Procedures</item_name>\n\t\t\t<item_key>\\\\i2b2_PROC\\i2b2\\Procedures\\</item_key>\n\t\t\t<tooltip>Procedures</tooltip>\n\t\t\t<class>ENC</class>\n\t\t\t<item_icon>FA</item_icon>\n\t\t\t<item_is_synonym>false</item_is_synonym>\n\t\t</item>\n\t</panel>"; // hardcoded query2 (result should be 36) // queryxml += "<panel>\n\t\t<panel_number>1</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<hlevel>2</hlevel>\n\t\t\t<item_name>Circulatory system</item_name>\n\t\t\t<item_key>\\\\i2b2_DIAG\\i2b2\\Diagnoses\\Circulatory system (390-459)\\</item_key>\n\t\t\t<tooltip>Diagnoses \\ Circulatory system</tooltip>\n\t\t\t<class>ENC</class>\n\t\t\t<item_icon>FA</item_icon>\n\t\t\t<item_is_synonym>false</item_is_synonym>\n\t\t</item>\n\t</panel>\n\t"; // queryxml += "<panel>\n\t\t<panel_number>2</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<hlevel>2</hlevel>\n\t\t\t<item_name>Affymetrix HG-U133</item_name>\n\t\t\t<item_key>\\\\i2b2_EXPR\\i2b2\\Expression Profiles Data\\Affymetrix HG-U133\\</item_key>\n\t\t\t<tooltip>Expression Profiles Data\\Affymetrix HG-U133</tooltip>\n\t\t\t<class>ENC</class>\n\t\t\t<item_icon>FA</item_icon>\n\t\t\t<item_is_synonym>false</item_is_synonym>\n\t\t</item>\n\t\t<item>\n\t\t\t<hlevel>2</hlevel>\n\t\t\t<item_name>Skin diseases</item_name>\n\t\t\t<item_key>\\\\i2b2_DIAG\\i2b2\\Diagnoses\\Skin diseases (680-709)\\</item_key>\n\t\t\t<tooltip>Diagnoses \\ Skin diseases</tooltip>\n\t\t\t<class>ENC</class>\n\t\t\t<item_icon>FA</item_icon>\n\t\t\t<item_is_synonym>false</item_is_synonym>\n\t\t</item>\n\t</panel>\n\t"; // queryxml += "<panel>\n\t\t<panel_number>3</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<hlevel>3</hlevel>\n\t\t\t<item_name>Diagnostic and nonsurgical procedures</item_name>\n\t\t\t<item_key>\\\\i2b2_PROC\\i2b2\\Procedures\\PRC\\ICD9 (Inpatient)\\(87-99) Diagnostic and nonsurgical procedures\\</item_key>\n\t\t\t<tooltip>Procedures \\ ICD9 (Inpatient) \\ Diagnostic and nonsurgical procedures</tooltip>\n\t\t\t<class>ENC</class>\n\t\t\t<item_icon>FA</item_icon>\n\t\t\t<item_is_synonym>false</item_is_synonym>\n\t\t</item>\n\t</panel>\n" // hardcoded query2 it run even if there is only the key for the concepts // queryxml += "<panel>\n\t\t<panel_number>1</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<item_key>\\\\i2b2_DIAG\\i2b2\\Diagnoses\\Circulatory system (390-459)\\</item_key>\n\t\t</item>\n\t</panel>\n\t"; // queryxml += "<panel>\n\t\t<panel_number>2</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<item_key>\\\\i2b2_EXPR\\i2b2\\Expression Profiles Data\\Affymetrix HG-U133\\</item_key>\n\t\t</item>\n\t\t<item>\n\t\t\t<item_key>\\\\i2b2_DIAG\\i2b2\\Diagnoses\\Skin diseases (680-709)\\</item_key>\n\t\t</item>\n\t</panel>\n\t"; // queryxml += "<panel>\n\t\t<panel_number>3</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t<item>\n\t\t\t<item_key>\\\\i2b2_PROC\\i2b2\\Procedures\\PRC\\ICD9 (Inpatient)\\(87-99) Diagnostic and nonsurgical procedures\\</item_key>\n\t\t</item>\n\t</panel>\n" for (i = 0 ; i < 3; i++){ // there are 3 panels params = i2b2.MedCo.model.panels[i]; nparams = params.length; if (nparams != 0) { // if in the panel there are no parameters the go to the next panel // open a panel object in which we put all its concepts queryxml += "<panel>\n\t\t<panel_number>" + i + "</panel_number>\n\t\t<panel_accuracy_scale>100</panel_accuracy_scale>\n\t\t<invert>0</invert>\n\t\t<panel_timing>ANY</panel_timing>\n\t\t<total_item_occurrences>1</total_item_occurrences>\n\t\t"; for (j = 0; j < nparams; j++){ // inters an item object for every concept queryxml += "\t\t<item>\n"; sdxData = params[j]; switch(sdxData.sdxInfo.sdxType) { // copied from js-i2b2/cells/CRC/CRC_ctrlr_QryTool.js case "QM": if(sdxData.origData.id.startsWith("masterid")) // BUG FIX: WEBCLIENT-149 queryxml += '\t\t\t<item_key>' + sdxData.origData.id + '</item_key>\n'; else queryxml += '\t\t\t<item_key>masterid:' + sdxData.origData.id + '</item_key>\n'; queryxml += '\t\t\t<item_name>' + i2b2.h.Escape(sdxData.origData.title) + '</item_name>\n'; queryxml += '\t\t\t<tooltip>' + i2b2.h.Escape(sdxData.origData.name) + '</tooltip>\n'; queryxml += '\t\t\t<item_is_synonym>false</item_is_synonym>\n'; queryxml += '\t\t\t<hlevel>0</hlevel>\n'; break; case "PRS": queryxml += '\t\t\t<item_key>patient_set_coll_id:' + sdxData.sdxInfo.sdxKeyValue + '</item_key>\n'; queryxml += '\t\t\t<item_name>' + i2b2.h.Escape(sdxData.sdxInfo.sdxDisplayName) + '</item_name>\n'; queryxml += '\t\t\t<tooltip>' + i2b2.h.Escape(sdxData.sdxInfo.sdxDisplayName) + '</tooltip>\n'; queryxml += '\t\t\t<item_is_synonym>false</item_is_synonym>\n'; queryxml += '\t\t\t<hlevel>0</hlevel>\n'; break; case "ENS": queryxml += '\t\t\t<item_key>patient_set_enc_id:' + sdxData.sdxInfo.sdxKeyValue + '</item_key>\n'; queryxml += '\t\t\t<item_name>' + i2b2.h.Escape(sdxData.sdxInfo.sdxDisplayName) + '</item_name>\n'; queryxml += '\t\t\t<tooltip>' + i2b2.h.Escape(sdxData.sdxInfo.sdxDisplayName) + '</tooltip>\n'; queryxml += '\t\t\t<item_is_synonym>false</item_is_synonym>\n'; queryxml += '\t\t\t<hlevel>0</hlevel>\n'; break; default: if (sdxData.origData.isModifier) { var modParent = sdxData.origData.parent; var level = sdxData.origData.level; var key = sdxData.origData.parent.key; var name = (sdxData.origData.parent.name != null ? i2b2.h.Escape(sdxData.origData.parent.name) : i2b2.h.Escape(sdxData.origData.name)) ; var tooltip = sdxData.origData.tooltip; var itemicon = sdxData.origData.hasChildren; while (modParent != null) { if (modParent.isModifier) { modParent = modParent.parent; } else { level = modParent.level; key = modParent.key; name = modParent.name; tooltip = modParent.tooltip; itemicon = modParent.hasChildren; break; } } // queryxml += '\t\t\t<hlevel>' + level + '</hlevel>\n'; queryxml += '\t\t\t<item_key>' + key + '</item_key>\n'; // queryxml += '\t\t\t<item_name>' + i2b2.h.Escape(name) + '</item_name>\n'; // // (sdxData.origData.newName != null ? sdxData.origData.newName : sdxData.origData.name) + '</item_name>\n'; // queryxml += '\t\t\t<tooltip>' + i2b2.h.Escape(tooltip) + '</tooltip>\n'; // queryxml += '\t\t\t<item_icon>' + itemicon + '</item_icon>\n'; // queryxml += '\t\t\t<class>ENC</class>\n'; queryxml += '\t\t\t\t<constrain_by_modifier>\n'; queryxml += '\t\t\t\t\t<modifier_name>' + sdxData.origData.name + '</modifier_name>\n'; queryxml += '\t\t\t\t\t<applied_path>' + sdxData.origData.applied_path + '</applied_path>\n'; queryxml += '\t\t\t\t\t<modifier_key>' + sdxData.origData.key + '</modifier_key>\n'; if (sdxData.ModValues) { queryxml += i2b2.CRC.view.modLabvaluesCtlr.getModLabValuesForXML(sdxData.ModValues); } queryxml += '\t\t\t\t</constrain_by_modifier>\n'; } else { sdxData.origData.key = (sdxData.origData.key).replace(/</g,"<"); // sdxData.origData.name = (sdxData.origData.name).replace(/</g,"<"); // if (undefined != sdxData.origData.tooltip) // sdxData.origData.tooltip = (sdxData.origData.tooltip).replace(/</g,"<"); // queryxml += '\t\t\t<hlevel>' + sdxData.origData.level + '</hlevel>\n'; // //s += '\t\t\t<item_name>' + (sdxData.origData.newName != null ? i2b2.h.Escape(sdxData.origData.newName) : i2b2.h.Escape(sdxData.origData.name)) + '</item_name>\n'; // queryxml += '\t\t\t<item_name>' + (sdxData.origData.name != null ? i2b2.h.Escape(sdxData.origData.name) : i2b2.h.Escape(sdxData.origData.newName)) + '</item_name>\n'; queryxml += '\t\t\t<item_key>' + sdxData.origData.key + '</item_key>\n'; // queryxml += '\t\t\t<tooltip>' + i2b2.h.Escape(sdxData.origData.tooltip) + '</tooltip>\n'; // BUG FIX: WEBCLIENT-135 (Escape tooltip) // queryxml += '\t\t\t<class>ENC</class>\n'; // queryxml += '\t\t\t<item_icon>' + sdxData.origData.hasChildren + '</item_icon>\n'; } try { var t = i2b2.h.XPath(sdxData.origData.xmlOrig,'descendant::synonym_cd/text()'); t = (t[0].nodeValue=="Y"); } catch(e) { var t = "false"; } queryxml += '\t\t\t<item_is_synonym>'+t+'</item_is_synonym>\n'; if (sdxData.LabValues && !jQuery.isEmptyObject(sdxData.LabValues)) { queryxml += i2b2.CRC.view.modLabvaluesCtlr.getModLabValuesForXML(sdxData.LabValues); } break; } queryxml += '\t\t</item>\n'; } queryxml +="\n\t</panel>\n" } } queryxml += "\n</query_definition>\n"; return queryxml }; function backslashX2(str) { return str.replace("\\", "\\\\"); } // whole harcoded query, should return 13 // <query_definition> <query_name>query3@9:47:2</query_name> <query_timing>ANY</query_timing> <specificity_scale>0</specificity_scale> <panel> <panel_number>0</panel_number> <panel_accuracy_scale>100</panel_accuracy_scale> <invert>0</invert> <panel_timing>ANY</panel_timing> <total_item_occurrences>1</total_item_occurrences> <item> <item_key>\\i2b2_PROC\i2b2\Procedures\PRC\ICD9 (Inpatient)\(87-99) Diagnostic and nonsurgical procedures\</item_key> <item_is_synonym>false</item_is_synonym> </item> </panel> <panel> <panel_number>1</panel_number> <panel_accuracy_scale>100</panel_accuracy_scale> <invert>0</invert> <panel_timing>ANY</panel_timing> <total_item_occurrences>1</total_item_occurrences> <item> <item_key>\\i2b2_PROV\i2b2\Providers\Emergency\</item_key> <item_is_synonym>false</item_is_synonym> </item> </panel> </query_definition> \ No newline at end of file diff --git a/js-i2b2/cells/plugins/MedCo/assets/injected_screens.html b/js-i2b2/cells/plugins/MedCo/assets/injected_screens.html index d761012..b2f8a7e 100644 --- a/js-i2b2/cells/plugins/MedCo/assets/injected_screens.html +++ b/js-i2b2/cells/plugins/MedCo/assets/injected_screens.html @@ -1,239 +1,254 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <body> <div id='MedCo-mainDiv'> <div id="MedCo-TABS" class="yui-navset"> <!--tabs definitions--> <ul class="yui-nav"> <li id="MedCo-TAB0" class="selected"><a href="#MedCo-TAB0"><em>Secure Query Dashboard</em></a></li> <!--<li id="MedCo-TAB1"><a href="#MedCo-TAB1"><em>Genomic Annotations Attributes</em></a></li>--> <!--<li id="MedCo-TAB2"><a href="#MedCo-TAB2"><em>Clinical Ontology Attributes</em></a></li>--> <li id="MedCo-TAB3"><a href="#MedCo-TAB3"><em>Plugin Help</em></a></li> </ul> <!-- tabs definition --> <div class="yui-content" id="MedCo-CONTENT"> <!-- Secure Query DashBoard tab --> <div class="MedCo-Dashboard"> <!-- run - reset - drop patient set - query for query status - decrypt result --> <div class="MedCo-ControlButtons"> - <!-- Popup --> - <div id="annoMessage" class="popupMessage"> - <div> - <h1>Annotations</h1> - <div style="margin: 5px 10px 10px 10px"> - <label> - Select an annotation: - <input type="search" id="searchAnnotationBox"> - <select id="annotationList" onchange="i2b2.MedCo.ctrlr.loadAnnotationValues()"> - - </select> - </label> - - <br> - - <label> - Select a value: - <input type="search" id="searchAnnotationValueBox"> - <!--<div id="MED-loadingValues" style="float:left;"></div>--> - <!--todo often too many values (20 000) the select is useless and slow--> - <!--<select id="annotationValueList">--> + <!-- old popup todo delete <!– Popup –>--> + <!--<div id="annoMessage" class="popupMessage">--> + <!--<div>--> + <!--<h1>Annotations</h1>--> + <!--<div style="margin: 5px 10px 10px 10px">--> + <!--<label>--> + <!--Select an annotation:--> + <!--<input type="search" id="searchAnnotationBox">--> + <!--<select id="annotationList" onchange="i2b2.MedCo.ctrlr.loadAnnotationValues()">--> <!--</select>--> - - <!--use span for inline text--> - <span id="selectedAnnotationValue"></span> - </label> + <!--</label>--> <!--<br>--> - <!--a textbox to write down annotations--> <!--<label>--> - <!--Write the annotations separated by a ';':--> - <!--<input--> - <!--id="written_annotations"--> - <!--type="text"--> - <!--value="annotation x"--> - <!--onkeypress="i2b2.MedCo.popupEnterPressed(event)">--> + <!--Select a value:--> + <!--<input type="search" id="searchAnnotationValueBox">--> + <!--<!–<div id="MED-loadingValues" style="float:left;"></div>–>--> + <!--<!–todo often too many values (20 000) the select is useless and slow–>--> + <!--<!–<select id="annotationValueList">–>--> + + <!--<!–</select>–>--> + + <!--<!–use span for inline text–>--> + <!--<span id="selectedAnnotationValue"></span>--> <!--</label>--> - <div> - <input type="button" value="Ok" onclick="i2b2.MedCo.popupOk()" style="float: left"> - <input type="button" value="Cancel" onclick="i2b2.MedCo.popupHide()" style="float: right"> - </div> - </div> + <!--<!–<br>–>--> + + <!--<!–a textbox to write down annotations–>--> + <!--<!–<label>–>--> + <!--<!–Write the annotations separated by a ';':–>--> + <!--<!–<input–>--> + <!--<!–id="written_annotations"–>--> + <!--<!–type="text"–>--> + <!--<!–value="annotation x"–>--> + <!--<!–onkeypress="i2b2.MedCo.popupEnterPressed(event)">–>--> + <!--<!–</label>–>--> + + <!--<div>--> + <!--<input type="button" value="Ok" onclick="i2b2.MedCo.popupOk()" style="float: left">--> + <!--<input type="button" value="Cancel" onclick="i2b2.MedCo.popupHide()" style="float: right">--> + <!--</div>--> + <!--</div>--> - </div> - </div> - <!-- --> - - <input type="button" onclick="i2b2.MedCo.ctrlr.genePopup.show(1);" value="show"/> - - <!-- popup2 --> - <div id="MedCo_genePopup" style="display:none;"> - <div class="hd">Search by Gene</div> - <div class="bd" id="modifier-viewer-body1"> - <p> - Use the gene name box to specify the variant for which to search. When you - begin typing in the search box below, a dropdown list will appear after you - type the first characters. - </p> - - <table class="MedCo_popupTable"> - <tr> - <th> Gene Name* </th> - <td> - <input type="search" id="searchGeneInputBox"> - </td> - <td> - <!-- todo I should update too when the user clicks the already selected option --> - <select id="geneList" onchange=" - document.querySelector('#searchGeneInputBox').value = this.options[this.selectedIndex].text;"> - </select> - </td> - </tr> - - <!--<tr>--> - <!--<td colspan="3">--> - <!--<br>--> - <!--<p>Please note the zygosity options in the dropdown list</p>--> - <!--</td>--> - <!--</tr>--> - - <tr> - <th>Zygosity*</th> - <td> - <select id="zygosityList"> - <option value="Any"> - Any - </option> - <option value="Heterozygous"> - Heterozygous - </option> - <option value="Homozygous"> - Homozygous - </option> - <option value="Unknown"> - Unknown - </option> - </select> - </td> - </tr> - <tr> - <th>Consequence</th> - <td> ? </td> - </tr> - </table> - <!--<center>--> - <!--<input type="submit" value="OK" onClick="alert('OKHTML');">--> - <!--<input type="submit" value="Cancel" onClick="i2b2.MedCo.ctrlr.genePopup.popup.hide();">--> - <!--</center>--> - </div> - <div class="ft"></div> - </div> - <!-- --> + <!--</div>--> + <!--</div>--> + <!--<!– –>--> + + <input type="button" onclick="i2b2.MedCo.ctrlr.genePopup.show(1);" value="show gene popup"/> + <input type="button" onclick="i2b2.MedCo.ctrlr.variantNamePopup.show(1);" value="show variant name popup"/> <h2 class="medcoQryToolTitle">Drop concepts here</h2> <div class="medcoQryToolPanels"> <div> <!--<div class="droptrgtlbl">Drop concepts here</div>--> <div id="medcoQryToolPanel1" class="medcoQryToolPanel droptrgt SDX-PRS"> <p id="panel1content"> </p> </div> <div id="medcoQryToolPanel2" class="medcoQryToolPanel droptrgt SDX-PRS"> <p id="panel2content"> </p> </div> <div id="medcoQryToolPanel3" class="medcoQryToolPanel droptrgt SDX-PRS"> <p id="panel3content"> </p> </div> <!--<!–Show chosen annotations–>--> <!--<div style="background-color: aliceblue; height: 100%; " class="medcoQryToolPanel">--> <!--<h3>Chosen annotations: </h3>--> <!--<p id="chosen_annotations"> </p>--> <!--<input type="button" value="Clear" onclick="i2b2.MedCo.Clear()">--> <!--</div>--> <!--<!– –>--> </div> </div> <div> <div style="padding-top: 10px"> <div class="MED-Buttons"> <div class="runButton"><a href="JavaScript:i2b2.MedCo.ctrlr.run()">Run Query</a></div> <div class="resetButton"><a href="JavaScript:i2b2.MedCo.ctrlr.clear()">Clear</a></div> </div> <table class="MED-resultTable"> <tbody> <tr> <td>Number of patients</td> </tr> <tr> <td id="MED-plainResult"> - </td> </tr> </tbody> </table> <!--<div class="statusBox"><a href="JavaScript:i2b2.MedCo.ctrlr.queryStatus()">Query Status</a></div>--> <!-- status info goes into lower status div in i2b2 --> </div> </div> <div id="mylog" style="overflow: scroll; width: 100%; height: 100%;"> </div> </div> </div> <!-- Genomic Annotations Attributes tab --> <!--<div>--> <!--<div id="byGene" style="disply:block;">--> <!--<div class="label">Genomic Annotations Search</div>--> <!--<input type="string" name="gene_input" id="gene_input" class="medco-input"/>--> <!--</div>--> <!--<div id="annotations_display">--> <!--<!– dynamically inserted annotations text –>--> <!--<!– TODO: autocompletion in text bow –>--> <!--</div>--> <!--</div>--> <!-- Clinical Ontology Attributes tab --> <!--<div>--> <!--<div id="secure_ontology_selector">--> <!--<!– dynamically inserted ontology query builder –>--> <!--</div>--> <!--</div>--> <!-- Plugin Help tab --> <div> <div class="MedCo-MainContent"> <div class="MedCo-MainContentPad"> </div> </div> </div> + <!-- gene popup --> + <div id="MedCo_genePopup" style="visibility: collapse;"> + <div class="hd">Search by Gene</div> + <div class="bd"> + <p> + Use the gene name box to specify the variant for which to search. When you + begin typing in the search box below, the dropdown list will be populated with + some matching options. Regular expressions are accepted. + </p> + + <table class="MedCo_popupTable"> + <tr> + <th> Gene Name* </th> + <td> + <input type="search" id="searchGeneInputBox"> + </td> + <td> + <!-- todo I should update too when the user clicks the already selected option --> + <select id="geneList" onchange=" + document.querySelector('#searchGeneInputBox').value = this.options[this.selectedIndex].text;"> + </select> + </td> + </tr> + + <tr> + <th>Zygosity*</th> + <td colspan="2"> + <div id="zygosityListGenePopup"> + <label><input type="checkbox" id="heterozygousGenePopup">Heterozygous</label> + <label><input type="checkbox" id="homozygousGenePopup">Homozygous</label> + <label><input type="checkbox" id="unknownGenePopup">Unknown</label> + </div> + </td> + </tr> + </table> + </div> + </div> + <!-- --> + + <!-- variant name popup --> + <div id="MedCo_variantNamePopup" style="visibility: collapse;"> + <div class="hd">Search by variant name</div> + <div class="bd"> + <p> + Use the variant name box to specify the variant for which to search. When you + begin typing in the search box below, the dropdown list will be populated with + some matching options. Regular expressions are accepted. + </p> + + <table class="MedCo_popupTable"> + <tr> + <th> Variant Name* </th> + <td> + <input type="search" id="searchVariantNameInputBox"> + </td> + <td> + <!-- todo I should update too when the user clicks the already selected option --> + <select id="variantNameList" onchange=" + document.querySelector('#searchGeneInputBox').value = this.options[this.selectedIndex].text;"> + </select> + </td> + </tr> + + <tr> + <th>Zygosity*</th> + <td colspan="2"> + <div id="zygosityListVariantNamePopup"> + <label><input type="checkbox" id="heterozygousVariantNamePopup">Heterozygous</label> + <label><input type="checkbox" id="homozygousVariantNamePopup">Homozygous</label> + <label><input type="checkbox" id="unknownVariantNamePopup">Unknown</label> + </div> + </td> + </tr> + </table> + </div> + </div> + <!-- --> + </div> </div> </div> </body> </html> diff --git a/js-i2b2/cells/plugins/MedCo/assets/vwMedCo.css b/js-i2b2/cells/plugins/MedCo/assets/vwMedCo.css index afefd25..3509557 100644 --- a/js-i2b2/cells/plugins/MedCo/assets/vwMedCo.css +++ b/js-i2b2/cells/plugins/MedCo/assets/vwMedCo.css @@ -1,388 +1,418 @@ /*** CSS for main plugin wrapper ***/ DIV#MedCo-mainDiv { padding: 0px; } /*** CSS for tab background ***/ DIV#MedCo-TABS DIV.yui-content { background: #FFF; } DIV#MedCo-TABS DIV.MedCo-Dashboard { background:#FFF; border:solid #63758C; border-width:1px 0; overflow:auto; height:100%; } DIV#GEN-TABS DIV.GEN-MainContentPad { padding:5px 10px; overflow:hidden; } DIV#GEN-TABS DIV.GEN-QueryDefinitionPad { background:#FFF; padding:0px 20px; margin-bottom:30px; overflow:hidden; } DIV#GEN-TABS DIV.GEN-VariantDefinition { float:left; overflow:hidden; } DIV#GEN-TABS DIV.GEN-Buttons, DIV#GEN-TABS DIV.GEN-ResultTypes { padding-left:20px; margin-bottom:10px; overflow:hidden; } /*** CSS for the Enter Note and View Results tabs ***/ DIV#GEN-TABS .gen-input { padding: 2px 10px; background: #DEEBEF; margin-top: 17px; margin-bottom: 2px; text-align:left; width: 500px; height: 28px; border: 1px solid #63758C; overflow:hidden; float:left; } DIV#GEN-TABS DIV.label { padding: 8px 0px; width:80px; height:16px; overflow:hidden; text-align:right; float: left; font-weight:bold; color:#666; margin: 15px 10px 0px 0px; } DIV#GEN-TABS DIV.label2 { padding: 2px 0px; width:80px; height:16px; overflow:hidden; text-align:right; float: left; font-weight:bold; color:#666; margin: 15px 10px 0px 0px; } DIV#GEN-TABS DIV.label3 { width:80px; height:16px; overflow:hidden; text-align:right; float: left; font-weight:bold; color:#666; padding:0px 20px 5px 0px; } DIV#GEN-TABS select.gen-select { width:200px; height:20px; overflow:hidden; float:left; background: #DEEBEF; margin-top: 15px; border: 1px solid #63758C; } DIV#GEN-TABS DIV.radio { padding: 6px 0px; width:120px; height:20px; overflow:hidden; text-align:right; float: left; font-weight:bold; color:#666; margin: 15px 0px 0px 0px; } DIV#GEN-TABS DIV.droptrgt { padding: 5px 10px; background: #DEEBEF; margin-top: 15px; text-align:left; border: 1px solid #63758C; width:300px; overflow:hidden; white-space:nowrap; } DIV#GEN-TABS DIV.dropresult { padding: 5px 10px; background: #DEEBEF; margin-bottom: 15px; text-align:left; border: 1px solid #63758C; width:300px; overflow:hidden; white-space:nowrap; } DIV#GEN-TABS DIV.closeButton { opacity:0.5; background: url('close.gif'); background-size:12px 12px; background-repeat: no-repeat; height:12px; width:12px; float:right; margin:2px -2px 0px 4px; } DIV#GEN-TABS DIV.loading { background: url('spin.gif'); background-size:16px 16px; background-repeat: no-repeat; height:16px; width:16px; margin:0px 5px; float:left; } DIV#GEN-TABS DIV.progress { margin:0px 0px 10px 0px; } DIV#GEN-TABS DIV.resetBox, DIV#GEN-TABS DIV.runBox { position:relative; xdisplay:none; background:#6677AA; border:1px solid #667788; color:#FFFFFF; font-weight:bold; font-family:arial,helvetica; font-size:11px; height:16px; line-height:16px; text-align:center; color:#FFF; cursor:pointer; float: left; margin:0px 5px 0px 0px; width:72px; xz-index:5; overflow:hidden; } DIV#GEN-TABS DIV.resetBox a, DIV#GEN-TABS DIV.runBox a { color:#FFF; display:block; text-decoration:none; } DIV#GEN-TABS DIV.resetBox a:hover, DIV#GEN-TABS DIV.runBox a:hover { background-color:#7687bf; } /*** CSS for the Plugin Help tab ***/ DIV#GEN-TABS H1 { margin:0 0 10px 0; font-size:16px; color:#42558C; font-weight:bold; } DIV#GEN-TABS H2 { margin:10px 0 10px 0; font-size:13px; color:#42558C; font-weight:bold; } DIV#GEN-TABS HR { margin:0; } -/*Added 11/09/2017*/ +/*!*Added 11/09/2017*!*/ + +/*!*Popup*!*/ +/*.popupBackground {*/ + /*display: none;*/ + /*opacity: .75;*/ + /*filter: alpha(opacity=75);*/ + /*-ms-filter: "alpha(opacity=75)";*/ + /*-khtml-opacity: .75;*/ + /*-moz-opacity: .75;*/ + /*background: #B8B8B8;*/ + /*position: absolute;*/ + /*left: 0px;*/ + /*top: 0px;*/ + /*height: 100%;*/ + /*width: 100%;*/ + /*z-index:990*/ +/*}*/ -/*Popup*/ -.popupBackground { - display: none; - opacity: .75; - filter: alpha(opacity=75); - -ms-filter: "alpha(opacity=75)"; - -khtml-opacity: .75; - -moz-opacity: .75; - background: #B8B8B8; - position: absolute; - left: 0px; - top: 0px; - height: 100%; - width: 100%; - z-index:990 -} - -.popupMessage { - display: none; - position: absolute; - left: 50%; - top: 50%; - /*height: 250px;*/ - /*width: 550px;*/ - /*margin-top should be half of the height*/ - margin-top: -125px; - /*margin-left should be half of the width*/ - margin-left: -275px; - background: #BBCCEE; - border: 1px solid #ccc; - box-shadow: 3px 3px 7px #777; - -webkit-box-shadow: 3px 3px 7px #777; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - z-index:999 -} - -.popupMessage h1{ - text-align:center; - background:#6677AA; - border:1px solid #314763; - color:#FFFFFF !important; - font-size:11px; - font-weight:bold; - height:13px; - line-height:12px; - padding: 5px; -} +/*.popupMessage {*/ + /*display: none;*/ + /*position: absolute;*/ + /*left: 50%;*/ + /*top: 50%;*/ + /*!*height: 250px;*!*/ + /*!*width: 550px;*!*/ + /*!*margin-top should be half of the height*!*/ + /*margin-top: -125px;*/ + /*!*margin-left should be half of the width*!*/ + /*margin-left: -275px;*/ + /*background: #BBCCEE;*/ + /*border: 1px solid #ccc;*/ + /*box-shadow: 3px 3px 7px #777;*/ + /*-webkit-box-shadow: 3px 3px 7px #777;*/ + /*-moz-border-radius: 5px;*/ + /*-webkit-border-radius: 5px;*/ + /*z-index:999*/ +/*}*/ -.popupMessage input[type="button"]{ - width: 100px; - margin: 5px; -} +/*.popupMessage h1{*/ + /*text-align:center;*/ + /*background:#6677AA;*/ + /*border:1px solid #314763;*/ + /*color:#FFFFFF !important;*/ + /*font-size:11px;*/ + /*font-weight:bold;*/ + /*height:13px;*/ + /*line-height:12px;*/ + /*padding: 5px;*/ +/*}*/ + +/*.popupMessage input[type="button"]{*/ + /*width: 100px;*/ + /*margin: 5px;*/ +/*}*/ /*div#selected_annotations label{*/ /*display: inline-block;*/ /*vertical-align: middle;*/ /*}*/ /*div#selected_annotations label input{*/ /*vertical-align: middle;*/ /*}*/ -/*POPUP 2*/ +/* POPUPS */ .hd { color: #FFFFFF !important; background: transparent !important; background-image: url(images/top_hive.gif) !important; background-repeat: repeat-x !important; font-size:14px !important; font-weight:bold !important; cursor: move !important; } .bd { background: #EFEFFF !important; background:#FFF; border:solid #63758C; border-width:1px 0; overflow:auto; height:100%; } +.MedCo_popupTable{ + border-spacing: 0px 15px; +} + +.MedCo_popupTable th{ + width: auto; +} + .MedCo_popupTable tr td { width: 400px; } .MedCo_popupTable tr td *{ width: 100%; } +#zygosityListGenePopup, +#zygosityListVariantNamePopup{ + margin: auto; + width: auto; + vertical-align: middle; + float: left; + border: 2px solid #d5d5d5; +} + +#zygosityListGenePopup label, +#zygosityListVariantNamePopup label{ + margin-left: 10px; + margin-right: 7px; + width: auto; + float: left; +} + +#zygosityListGenePopup input, +#zygosityListVariantNamePopup input{ + width: auto; + vertical-align: middle; +} /*reset and run Buttons*/ DIV#MedCo-TABS DIV.MED-Buttons { padding-left:20px; margin-bottom:10px; overflow:hidden; } DIV#MedCo-TABS DIV.resetButton, DIV#MedCo-TABS DIV.runButton { position:relative; xdisplay:none; background:#6677AA; border:1px solid #667788; color:#FFFFFF; font-weight:bold; font-family:arial,helvetica; font-size:11px; height:16px; line-height:16px; text-align:center; color:#FFF; cursor:pointer; float: left; margin:0px 5px 0px 0px; width:72px; xz-index:5; overflow:hidden; } DIV#MedCo-TABS DIV.resetButton a, DIV#MedCo-TABS DIV.runButton a { color:#FFF; display:block; text-decoration:none; } DIV#MedCo-TABS DIV.resetButton a:hover, DIV#MedCo-TABS DIV.runButton a:hover { background-color:#7687bf; } /*Result*/ DIV#MedCo-TABS table.MED-resultTable{ width: 400px; margin-left: auto; margin-right: auto; } /*"Number of patient"*/ DIV#MedCo-TABS table.MED-resultTable tr:first-child td{ background-color: #B0C4DE; color: black; text-align: center; vertical-align: middle; } /*count*/ DIV#MedCo-TABS table.MED-resultTable tr:last-child td{ background-color: #B0C4DE; color: darkblue; text-align: center; vertical-align: middle; font-size: 45px; } /*loading query gif*/ img#MED-loadingGif { width:47px; height:47px; display: none; text-align: center; vertical-align: middle; margin-left: auto; margin-right: auto; } diff --git a/js-i2b2/cells/plugins/MedCo/php/getAnnotationValues.php b/js-i2b2/cells/plugins/MedCo/php/getAnnotationValues.php index a1146ab..d052db4 100644 --- a/js-i2b2/cells/plugins/MedCo/php/getAnnotationValues.php +++ b/js-i2b2/cells/plugins/MedCo/php/getAnnotationValues.php @@ -1,22 +1,22 @@ <?php $conn = pg_connect("host=localhost port=5432 dbname=i2b2 user=postgres password=admin"); if (!$conn) { echo "Error while connecting to the postgres database"; exit; } // get the row which contains all the values of the passed annotation -$query = "SELECT annotation_values FROM shrine_ont.genomic_annotations_metadata WHERE annotation_id='". htmlspecialchars($_GET["annotation_name"]) . "'"; +$query = "SELECT annotation_values FROM shrine_ont.genomic_annotations_metadata WHERE annotation_id='". $_GET["annotation_name"] . "'"; $result = pg_query($conn, $query); if (!$result) { echo "An error occurred.\n"; exit; } // just tell to which annotation these values correspond (in case of concurrent requests there may be inconsistencies) echo $_GET["annotation_name"] . "$%$"; while ($row = pg_fetch_row($result)) { echo "$row[0]"; } diff --git a/js-i2b2/cells/plugins/MedCo/php/getGenes.php b/js-i2b2/cells/plugins/MedCo/php/getGenes.php index 35f4ee5..4f9f4cc 100644 --- a/js-i2b2/cells/plugins/MedCo/php/getGenes.php +++ b/js-i2b2/cells/plugins/MedCo/php/getGenes.php @@ -1,40 +1,40 @@ <?php // case sensitive % stands for .* //select * //from shrine_ont.gene_values //where gene_value LIKE '%A1%' // //LIMIT 20 // case insensitive with regex //select * //from shrine_ont.gene_values //where gene_value ~* '.*a1.*' //LIMIT 20 $conn = pg_connect("host=localhost port=5432 dbname=i2b2 user=postgres password=admin"); if (!$conn) { echo "Error while connecting to the postgres database"; exit; } // get the row which contains all the values of the passed annotation $query = "SELECT gene_value FROM shrine_ont.gene_values -WHERE gene_value ~* '.*" . htmlspecialchars($_GET["gene"]) .".*' -LIMIT " . htmlspecialchars($_GET["limit"]); +WHERE gene_value ~* '.*" . $_GET["gene"] .".*' +LIMIT " . $_GET["limit"]; $result = pg_query($conn, $query); if (!$result) { echo "An error occurred.\n"; exit; } // In json format return the list of genes $geneList = ""; while ($row = pg_fetch_row($result)) { $geneList .= "\"$row[0]\","; } // drop the last comma and concatenate in json format echo "[" . substr($geneList, 0, -1) . "]"; \ No newline at end of file diff --git a/js-i2b2/cells/plugins/MedCo/php/getGenes.php b/js-i2b2/cells/plugins/MedCo/php/getVariantNames.php similarity index 54% copy from js-i2b2/cells/plugins/MedCo/php/getGenes.php copy to js-i2b2/cells/plugins/MedCo/php/getVariantNames.php index 35f4ee5..a8f9cd9 100644 --- a/js-i2b2/cells/plugins/MedCo/php/getGenes.php +++ b/js-i2b2/cells/plugins/MedCo/php/getVariantNames.php @@ -1,40 +1,36 @@ <?php -// case sensitive % stands for .* -//select * -//from shrine_ont.gene_values -//where gene_value LIKE '%A1%' // -//LIMIT 20 - // case insensitive with regex -//select * -//from shrine_ont.gene_values -//where gene_value ~* '.*a1.*' +//select variant_name +//from shrine_ont.variant_names +//where variant_name ~* '.*a1.*' //LIMIT 20 $conn = pg_connect("host=localhost port=5432 dbname=i2b2 user=postgres password=admin"); if (!$conn) { echo "Error while connecting to the postgres database"; exit; } +// escape the ? for regex query +$variant_name = str_replace("?", "\?", $_GET["variant_name"]); // get the row which contains all the values of the passed annotation $query = - "SELECT gene_value -FROM shrine_ont.gene_values -WHERE gene_value ~* '.*" . htmlspecialchars($_GET["gene"]) .".*' -LIMIT " . htmlspecialchars($_GET["limit"]); + "SELECT variant_name +FROM shrine_ont.variant_names +WHERE variant_name ~* '.*" . $variant_name .".*' +LIMIT " . $_GET["limit"]; $result = pg_query($conn, $query); if (!$result) { echo "An error occurred.\n"; exit; } // In json format return the list of genes -$geneList = ""; +$variantNames = ""; while ($row = pg_fetch_row($result)) { - $geneList .= "\"$row[0]\","; + $variantNames .= "\"$row[0]\","; } // drop the last comma and concatenate in json format -echo "[" . substr($geneList, 0, -1) . "]"; \ No newline at end of file +echo "[" . substr($variantNames, 0, -1) . "]"; \ No newline at end of file diff --git a/js-i2b2/cells/plugins/MedCo/php/getVariants.php b/js-i2b2/cells/plugins/MedCo/php/getVariants.php index 9e07bc6..caa4f69 100644 --- a/js-i2b2/cells/plugins/MedCo/php/getVariants.php +++ b/js-i2b2/cells/plugins/MedCo/php/getVariants.php @@ -1,56 +1,75 @@ <?php // query_type define is we are searching by: // - old is the old version that uses the first version of the schema // - Gene + Zygosity // - ... + $query = ""; -switch(htmlspecialchars($_GET["query_type"])){ +switch($_GET["query_type"]){ case "gene_and_zygosity": + // case insensitive regex query // select variant_id // from shrine_ont.genomic_annotations_new - // where annotations ~* 'CTBP2P1;Homozygous;' + // where annotations ~* '^CTBP2P1;(Homozygous|Unknown);' + + $zigosity = $_GET["zygosity"]; // array of zygosity options, put them in the query separated by | (or) $query = "SELECT variant_id " . "FROM shrine_ont.genomic_annotations_new " . - "WHERE annotations ~* '" . htmlspecialchars($_GET["gene_name"]) . ";" . htmlspecialchars($_GET["zygosyty"]) .";'";; + "WHERE annotations ~* '^" . $_GET["gene_name"] . + ";(" . join('|', $zigosity) .");'"; + break; + + case "variantName_and_zygosity": + // case insensitive regex query + // select variant_id + // from shrine_ont.genomic_annotations_new + /* where variant_name='Y:59022489:?>A'*/ + + $zigosity = $_GET["zygosity"]; + + $query = "SELECT variant_id " . + "FROM shrine_ont.genomic_annotations_new " . + "WHERE variant_name='" . $_GET["variant_name"] ."' AND " . + "annotations ~* '" . "(" . join('|', $zigosity) .")'"; break; case "old": //select variant_id //from shrine_ont.genomic_annotations //where variant_annotations ->> 'Start_Position' = '5239176' $query = "SELECT variant_id FROM shrine_ont.genomic_annotations -WHERE variant_annotations ->> '". htmlspecialchars($_GET["annotation_name"]) . "' = '" . htmlspecialchars($_GET["annotation_value"]) ."'"; +WHERE variant_annotations ->> '". $_GET["annotation_name"] . "' = '" . $_GET["annotation_value"] ."'"; break; default: echo "Error: query type not recognized"; return; } $conn = pg_connect("host=localhost port=5432 dbname=i2b2 user=postgres password=admin"); if (!$conn) { echo "Error while connecting to the postgres database"; exit; } $result = pg_query($conn, $query); if (!$result) { echo "An error occurred.\n"; exit; } // In json format return both the panel number and the list of variants echo "{ \"panel_number\" :" . $_GET["panel_number"] . ", \"variants\" : "; $variantList = ""; while ($row = pg_fetch_row($result)) { $variantList .= "\"$row[0]\","; } // drop the last comma echo "[" . substr($variantList, 0, -1) . "]}"; \ No newline at end of file diff --git a/js-i2b2/cells/plugins/MedCo/popup_ctrlr.js b/js-i2b2/cells/plugins/MedCo/popup_ctrlr.js index 8763fa9..e36bcfa 100644 --- a/js-i2b2/cells/plugins/MedCo/popup_ctrlr.js +++ b/js-i2b2/cells/plugins/MedCo/popup_ctrlr.js @@ -1,654 +1,938 @@ i2b2.MedCo.popup = {}; // check the paths are correct i2b2.MedCo.popup.getAnnotationPath = 'js-i2b2/cells/plugins/MedCo/getAnnotations.php'; // in getAnnotationValuesPath append a variable called 'annotation_name' to specify the annotation i2b2.MedCo.popup.getAnnotationValuesPath = 'js-i2b2/cells/plugins/MedCo/getAnnotationValues.php'; // in getVariantsPath append two variables 'annotation_name' and 'annotation_value' to respectively specify // the name and the value fo the annotation. Moreover, a variable 'panel_number' is needed too so to know // to which panel correspond the received response. i2b2.MedCo.popup.getVariantsPath = 'js-i2b2/cells/plugins/MedCo/getVariants.php'; // GENE POPUP i2b2.MedCo.ctrlr.genePopup = { dialog: null, // variable to access easily the popup popup: $("MedCo_genePopup"), // input box in which the user will write. It is an <input type="search"> element geneInputBox: document.querySelector("#searchGeneInputBox"), // selection list to display the matching genes. It is a <select> element geneList: document.querySelector("#geneList"), // selection list with the 4 predefined options - zygosityList: document.querySelector("#zygosityList"), + zygosityList: { + heterozygousCheckbox:null, + homozygousCheckbox:null, + unknownCheckbox:null + }, // variable used for the popup to know to which panel it is bound panelNumber: 0, // todo set this when opening the popup (at the drag) // initialize the gene popup init: function(){ var context = i2b2.MedCo.ctrlr.genePopup; context.popup = $("MedCo_genePopup"); context.geneInputBox = document.querySelector("#searchGeneInputBox"); context.geneList = document.querySelector("#geneList"); - context.zygosityList = document.querySelector("#zygosityList"); + + // the three checkboxes + context.zygosityList.heterozygousCheckbox = document.querySelector("#heterozygousGenePopup"); + context.zygosityList.homozygousCheckbox = document.querySelector("#homozygousGenePopup"); + context.zygosityList.unknownCheckbox = document.querySelector("#unknownGenePopup"); // update the scrolldown list every time the user digits chars context.geneInputBox .addEventListener("keyup", context.getGenes.run); context.panelNumber = 0; context.getGenes.path = 'js-i2b2/cells/plugins/MedCo/php/getGenes.php'; context.getVariants.path = 'js-i2b2/cells/plugins/MedCo/php/getVariants.php'; var handleCancel = function() { this.cancel(); }; var handleOk = function() { var context = i2b2.MedCo.ctrlr.genePopup; // validate the fields if (context.geneList.options.length < 1){ // todo: can the user not put any gene name and just search by zygosity? (most probably too many variants) // if the drop down list is empty then - alert("Please, write down a gene name and pick one form the dropdown list."); + alert("Please, write down a gene name and pick one choice form the dropdown list."); + return; + } + if (context.zygosityList.heterozygousCheckbox.checked == false && + context.zygosityList.homozygousCheckbox.checked == false && + context.zygosityList.unknownCheckbox.checked == false) { + alert("Please, select at least one zygosity option."); return; } if (context.geneInputBox.value.toLowerCase() != context.geneList.options[context.geneList.selectedIndex].text.toLowerCase()){ // if it is different then the user has still to pick one from the dropdown list alert("Please, pick a gene name from the dropdown list."); return; } // run the query to retrieve all the annotations with the specified gene and zygosyty i2b2.MedCo.ctrlr.genePopup.getVariants.run(); this.hide() }; context.dialog = new YAHOO.widget.SimpleDialog("MedCo_genePopup", { draggable: true, zindex: 10000, width: "500px", // height: "200px", autofillheight: "body", constraintoviewport: true, context: ["showbtn", "tl", "bl"], fixedcenter: true, modal: true, buttons: [{ text: "OK", handler: handleOk, isDefault: true }, { text: "Cancel", handler: handleCancel }] }); }, // show the popup // panelNumber: specifies with which panel is the popup related show: function(panelNumber) { var context = i2b2.MedCo.ctrlr.genePopup; context.panelNumber = panelNumber; // context.clear(); context.popup.show(); context.dialog.render(document.body); context.dialog.show(); }, // // hide the popup, not needed (events already registered to the various buttons) // hide: function(){ // i2b2.MedCo.ctrlr.genePopup.popup.hide(); // i2b2.MedCo.ctrlr.genePopup.dialog.cancel(); // }, // clear (empty) all the elements clear: function(){ // i2b2.MedCo.ctrlr.genePopup.geneInputBox.value = ""; // var list = i2b2.MedCo.ctrlr.genePopup.geneList; // while (list.hasChildNodes()) { // list.removeChild(list.lastChild); // } // todo clear fields? }, // get the genes names from the database getGenes: { // Store some variables I need to efficiently manage the request // path for the php request to retrieve the genes path: 'js-i2b2/cells/plugins/MedCo/getGenes.php', // if previousGene (which stores the "old" geneInputBox content) stays the same for a certain period // of time then the user stopped writing => I retrieve from the database the matching genes previousGene: "", // here I store the last executed query so to avoid repeating it lastGeneQueried: "", // here I store the current timeout (so that I can stop it when I want) timeoutGene: null, run: function () { var context = i2b2.MedCo.ctrlr.genePopup.getGenes; // (call run until the user stops writing) // stop the previous call (every new digits trigger a getGenes() call) clearTimeout(context.timeoutGene); // take the current value and check if it is equal to the previous one var currGene = i2b2.MedCo.ctrlr.genePopup.geneInputBox.value.replace(/\s/g, ''); // remove whitespaces if (currGene == ""){ // if it is empty then just empty the dropdown list var list = i2b2.MedCo.ctrlr.genePopup.geneList; while (list.hasChildNodes()) { list.removeChild(list.lastChild); } + context.lastGeneQueried = ""; return; } if (currGene == context.lastGeneQueried) { - // if it is equal to the previous query then do nothing - context.lastGeneQueried = ""; + // if it is equal to the previous queried then I already have all the matching ones => do nothing return; } if (currGene != context.previousGene) { // if they were different then wait for the user to finish to write context.previousGene = currGene; context.timeoutGene = setTimeout(context.run, 500); return; } // If you ended up here then the user stopped writing and we can execute the query context.lastGeneQueried = currGene; // store the current query so to avoid repeating it var success = function (responseText) { var list = i2b2.MedCo.ctrlr.genePopup.geneList; // remove all the previous genes from the dropdown list while (list.hasChildNodes()) { list.removeChild(list.lastChild); } // todo sort the genes var receivedGenes = JSON.parse(responseText); for (var i = 0; i < receivedGenes.length; i++) { var opt = document.createElement("option"); opt.value = receivedGenes[i]; opt.innerHTML = receivedGenes[i]; list.appendChild(opt); } // if there was only one match the copy that in the text box if (receivedGenes.length == 1) { i2b2.MedCo.ctrlr.genePopup.geneInputBox.value = receivedGenes[0]; } }; var error = function (err) { alert("Error when trying to retrieve the gene values from the database: " + err) }; var phpQuery = context.path + "?gene=" + currGene + "&limit=20"; // todo is it ok 20? i2b2.MedCo.ctrlr.phpGETRequest(success, error, phpQuery); } }, // run the query to retrieve the id of the variants getVariants: { path: 'js-i2b2/cells/plugins/MedCo/getVariants.php', run: function () { var context = i2b2.MedCo.ctrlr.genePopup; var geneName = context.geneInputBox.value; - var zygosyty = context.zygosityList.options[context.zygosityList.selectedIndex].text; + var zygosyty = []; + if (context.zygosityList.heterozygousCheckbox.checked == true) { + zygosyty.push("Heterozygous") + } + if (context.zygosityList.homozygousCheckbox.checked == true) { + zygosyty.push("Homozygous") + } + if (context.zygosityList.unknownCheckbox.checked == true) { + zygosyty.push("Unknown") + } + var queryType = "gene_and_zygosity"; // used at the server side to know how to build the query var success = function (responseText) { + alert(responseText) var response = JSON.parse(responseText); for(var i=0; i<response.variants.length; i++) { i2b2.MedCo.model.panels[response.panel_number].push(response.variants[i]); } // I received the response so decrease the counter i2b2.MedCo.popup.variantsQueryCounter -= 1; }; var error = function (err) { - alert("Error when trying to retrieve the gene values from the database: " + err) + alert("Error when trying to retrieve the variants from the database: " + err) }; // increase the number of responses I should wait for i2b2.MedCo.ctrlr.variantsQueryCounter += 1; // better pass the panel number too. It will be returned with the response so that I bind it to a // specific panel. (if the query is very slow it could happen that the user starts two queries in parallel // which are related to two different panels). var phpQuery = context.getVariants.path + "?query_type=" + queryType + "&panel_number=" + context.panelNumber + "&gene_name=" + geneName + - "&zygosyty=" + zygosyty; + "&zygosity[]=" + zygosyty.join("&zygosity[]="); // build an array of zygosity options i2b2.MedCo.ctrlr.phpGETRequest(success, error, phpQuery); } } }; -// Manage the php requests. -// success: function that takes as input the response form the server -// error: function that takes as input the error code returned by the server -// phpQuery: string that contains the path and the parameters of the request -i2b2.MedCo.ctrlr.phpGETRequest = function (success, error, phpQuery) { - // create the request object to send the request and manage the response - var req = false; - try { - // most browsers - req = new XMLHttpRequest(); - } catch (e) { - // IE - try { - req = new ActiveXObject("Msxml2.XMLHTTP"); - } catch (e) { - // try an older version - try { - req = new ActiveXObject("Microsoft.XMLHTTP"); - } catch (e) { - return false; - } - } - } - // if the http request obj has not been created then return - if (!req) return false; +// VARIANT NAME POPUP +i2b2.MedCo.ctrlr.variantNamePopup = { + dialog: null, + // variable to access easily the popup + popup: $("MedCo_variantNamePopup"), - // update the request object to act when receiving the response - req.onreadystatechange = function () { - if (req.readyState == 4) { - return req.status === 200 ? - success(req.responseText) : error(req.status); - } - }; + // input box in which the user will write. It is an <input type="search"> element + variantNameInputBox: document.querySelector("#searchVariantNameInputBox"), - req.open("GET", phpQuery, true); - req.send(null); - return req; -}; + // selection list to display the matching VARIANT NAMES. It is a <select> element + variantNameList: document.querySelector("#variantNameList"), + // selection list with the 4 predefined options + zygosityList: { + heterozygousCheckbox:null, + homozygousCheckbox:null, + unknownCheckbox:null + }, -// initialize the popup: load the names of the annotations and register handlers to manage the automatic completion -i2b2.MedCo.ctrlr.PopupInit = function (){ - // get the element to register the event handler (auto completion) - var searchAnnotationBox = document.querySelector("#searchAnnotationBox"); - var annotations = document.querySelector("#annotationList"); // this will be loaded with all the annotations - - var searchAnnotationValueBox = document.querySelector("#searchAnnotationValueBox"); - var selectedAnnotationValue = document.querySelector("#selectedAnnotationValue"); - // (inefficient) var annotationValues = document.querySelector("#annotationValueList"); // this will be loaded with all the values an annotation can assume - - // load annotations from database (that will be shown when opening the popup) - // the annotations name are loaded immediately (they are not too many) while the values of an annotation - // are loaded only when that annotation is selected - i2b2.MedCo.ctrlr.loadAnnotations(); - - // autocompletion function, e is an <input type="search"> object, list is a <select> object - function autoCompletionAnnotation (e, list) { - var text = e.target.value; - var lowerText = text.toLowerCase(); - var options = list.options; - var initialOption = options[list.selectedIndex].text; - var goodMatch = false; - for (var i = 0; i < options.length; i++) { - var option = options[i]; - var optionText = option.text; - var regex = new RegExp("^" + text, "i"); - var match = optionText.match(regex); - // best match - if (match){ // if it starts the same the select this one - option.selected = true; - break; - } - // good match (still looking for a best match) - var contains = optionText.indexOf(text) != -1; - if(contains) { - option.selected = true; - goodMatch = true; - } - if (!goodMatch) { // if no good match was found then try this too - // worse match (still looking for a good or best match) - var lowerOptionText = optionText.toLowerCase(); - contains = lowerOptionText.indexOf(lowerText) != -1; - if (contains) { // it contains the string select this one but go on with looking for a better match - option.selected = true; - } - } - option.selectedIndex = 0; - } - // if the selected annotation changed then reload its values - var currOption = options[list.selectedIndex].text; - if (initialOption != currOption) { - // want to reduce the number of "loadAnnotationValues", if after some time the option didn't changed - // then I suppose the user stopped typing - setTimeout( - function(){ - if(currOption == list.options[list.selectedIndex].text) - i2b2.MedCo.ctrlr.loadAnnotationValues() - }, 500); - } - } + // variable used for the popup to know to which panel it is bound + panelNumber: 0, // todo set this when opening the popup (at the drag) - // showValue is an html object in which we will show the value - function autoCompletionAnnotationValue (e, showValue) { - var text = e.target.value; - var lowerText = text.toLowerCase(); - var values = i2b2.MedCo.popup.annotationValues; // list of possible values []string - var goodMatch = false; - for (var i = 0; i < values.length; i++) { - var valueText = values[i]; - var regex = new RegExp("^" + text, "i"); - var match = valueText.match(regex); - // best match - if (match){ // if it starts the same the select this one - showValue.innerHTML = valueText; - break; - } - // good match (still looking for a best match) - var contains = valueText.indexOf(text) != -1; - if(contains) { - showValue.innerHTML = valueText; - goodMatch = true; - } - if (!goodMatch) { // if no good match was found then try this too - // worse match (still looking for a good or best match) - var lowerValueText = valueText.toLowerCase(); - contains = lowerValueText.indexOf(lowerText) != -1; - if (contains) { // it contains the string select this one but go on with looking for a better match - showValue.innerHTML = valueText; + // initialize the variant popup + init: function(){ + var context = i2b2.MedCo.ctrlr.variantNamePopup; - } - } - } - } + context.popup = $("MedCo_variantNamePopup"); + context.variantNameInputBox = document.querySelector("#searchVariantNameInputBox"); + context.variantNameList = document.querySelector("#variantNameList"); - // autocomplete the annotation name when entered - searchAnnotationBox.addEventListener("keyup", function (e) {autoCompletionAnnotation(e, annotations)}); + // the three checkboxes + context.zygosityList.heterozygousCheckbox = document.querySelector("#heterozygousVariantNamePopup"); + context.zygosityList.homozygousCheckbox = document.querySelector("#homozygousVariantNamePopup"); + context.zygosityList.unknownCheckbox = document.querySelector("#unknownVariantNamePopup"); - // autocomplete the annotation value when entered - searchAnnotationValueBox.addEventListener("keyup", function (e) {autoCompletionAnnotationValue(e, selectedAnnotationValue)}); + // update the scrolldown list every time the user digits chars + context.variantNameInputBox + .addEventListener("keyup", + context.getVariantNames.run + ); + context.panelNumber = 0; - // variable used for the popup to know to which panel it is bound - i2b2.MedCo.popup.panelNumber = 0; - //variable to know which is the latest pending request sent for annotation values retrieval (the previous ones will be dropped) - i2b2.MedCo.popup.latestAnnotationRequest = ""; + context.getVariantNames.path = 'js-i2b2/cells/plugins/MedCo/php/getVariantNames.php'; + context.getVariants.path = 'js-i2b2/cells/plugins/MedCo/php/getVariants.php'; - // store the current loaded annotation values - i2b2.MedCo.popup.annotationValues = []; + var handleCancel = function() { + this.cancel(); + }; - // a counter used to count how many queries the client sent and is still waiting for a response. - // while this counter is > 0 the query cannot be built - i2b2.MedCo.popup.variantsQueryCounter = 0; -}; + var handleOk = function() { + var context = i2b2.MedCo.ctrlr.variantNamePopup; -i2b2.MedCo.popupShow = function (panelNumber) { - i2b2.MedCo.popup.panelNumber = panelNumber; - var messageBox=document.getElementById("annoMessage"); - // Center the messageBox - // alert(messageBox.style.clientWidth) - // messageBox.style.marginTop=-messageBox.style.height/2; - // messageBox.style.marginLeft=-messageBox.style.width/2; - - // Show message box (and background) - document.getElementById("MedCo_popupBackground").style.display="block"; - messageBox.style.display="block"; -}; + // validate the fields + if (context.variantNameList.options.length < 1){ + // if the drop down list is empty then + alert("Please, write down a variant name and pick one choice form the dropdown list."); + return; + } + if (context.zygosityList.heterozygousCheckbox.checked == false && + context.zygosityList.homozygousCheckbox.checked == false && + context.zygosityList.unknownCheckbox.checked == false) { + alert("Please, select at least one zygosity option."); + return; + } + if (context.variantNameInputBox.value.toLowerCase() != + context.variantNameList.options[context.variantNameList.selectedIndex].text.toLowerCase()){ + // if it is different then the user has still to pick one from the dropdown list + alert("Please, pick a variant name from the dropdown list."); + return; -i2b2.MedCo.popupHide = function (){ - document.getElementById("MedCo_popupBackground").style.display="none"; - document.getElementById("annoMessage").style.display="none"; -}; + } -// i2b2.MedCo.popupEnterPressed = function (e) { -// e = e || window.event; -// if (e.keyCode == 13) // if enter is pressed ... -// { -// i2b2.MedCo.popupOk() -// } -// }; + // run the query to retrieve all the annotations with the specified variant name and zygosyty + i2b2.MedCo.ctrlr.variantNamePopup.getVariants.run(); + this.hide() + }; -i2b2.MedCo.popupOk = function(){ - // chosenAnnotationsElem = document.getElementById("chosen_annotations"); - // chosenAnnotationsElem.innerHTML = ""; + context.dialog = new YAHOO.widget.SimpleDialog("MedCo_variantNamePopup", { + draggable: true, + zindex: 10000, + width: "500px", + // height: "200px", + autofillheight: "body", + constraintoviewport: true, + context: ["showbtn", "tl", "bl"], + fixedcenter: true, + modal: true, + buttons: [{ + text: "OK", + handler: handleOk, + isDefault: true + }, { + text: "Cancel", + handler: handleCancel + }] + }); + }, - // var annotations = document.querySelector("#annotationList"); - // var selectedAnnotation = annotations.options[annotations.selectedIndex].text; - // - // var selectedAnnotationValue = document.querySelector("#selectedAnnotationValue").innerHTML; - // var annotationValues = document.querySelector("#annotationValueList"); - // var selectedAnnotationValue = annotationValues.options[annotationValues.selectedIndex].text; + // show the popup + // panelNumber: specifies with which panel is the popup related + show: function(panelNumber) { + var context = i2b2.MedCo.ctrlr.variantNamePopup; + context.panelNumber = panelNumber; + // context.clear(); + context.popup.show(); + context.dialog.render(document.body); + context.dialog.show(); + }, - // var annoVal = selectedAnnotation+":"+selectedAnnotationValue; + // // hide the popup, not needed (events already registered to the various buttons) + // hide: function(){ + // i2b2.MedCo.ctrlr.variantNamePopup.popup.hide(); + // i2b2.MedCo.ctrlr.variantNamePopup.dialog.cancel(); + // }, - // i2b2.MedCo.model.chosenAnnotations[i2b2.MedCo.popup.panelNumber].push(annoVal); + // clear (empty) all the elements + clear: function(){ + // i2b2.MedCo.ctrlr.variantNamePopup.variantNameInputBox.value = ""; + // var list = i2b2.MedCo.ctrlr.variantNamePopup.variantNameList; + // while (list.hasChildNodes()) { + // list.removeChild(list.lastChild); + // } + // todo clear fields? + }, - // i2b2.MedCo.view.panels[i2b2.MedCo.popup.panelNumber].innerHTML += annoVal + "<br>"; + // get the variant names from the database + getVariantNames: { + // Store some variables I need to efficiently manage the request + // path for the php request to retrieve the variant names + path: 'js-i2b2/cells/plugins/MedCo/php/getVariantNames.php', + // if previousVariant (which stores the "old" variantNameInputBox content) stays the same for a certain period + // of time then the user stopped writing => I retrieve from the database the matching variant names + previousVariantName: "", + // here I store the last executed query so to avoid repeating it + lastVariantQueried: "", + // here I store the current timeout (so that I can stop it when I want) + timeoutVariant: null, + run: function () { + var context = i2b2.MedCo.ctrlr.variantNamePopup.getVariantNames; - i2b2.MedCo.ctrlr.loadVariants(); // send php request - i2b2.MedCo.popupHide(); -}; + // (call run until the user stops writing) + // stop the previous call (every new digits trigger a getVariantNames() call) + clearTimeout(context.timeoutVariant); + // take the current value and check if it is equal to the previous one + var currVariantName = i2b2.MedCo.ctrlr.variantNamePopup.variantNameInputBox.value.replace(/\s/g, ''); // remove whitespaces + if (currVariantName == ""){ + // if it is empty then just empty the dropdown list + var list = i2b2.MedCo.ctrlr.variantNamePopup.variantNameList; + while (list.hasChildNodes()) { + list.removeChild(list.lastChild); + } + context.lastVariantQueried = ""; + return; + } + if (currVariantName == context.lastVariantQueried) { + // if it is equal to the previous query then do nothing + return; + } + if (currVariantName != context.previousVariantName) { + // if they are different then wait for the user to finish to write + context.previousVariantName = currVariantName; + context.timeoutVariant = setTimeout(context.run, 500); + return; + } -// MANAGE PHP REQUEST + // If you ended up here then the user stopped writing and we can execute the query + context.lastVariantQueried = currVariantName; // store the current query so to avoid repeating it -// load the annotations from the database (done only when initializing the popup!) -i2b2.MedCo.ctrlr.loadAnnotations = function () { - // create the request object to send the request and manage the response - var req = false; - try{ - // most browsers - req = new XMLHttpRequest(); - } catch (e){ - // IE - try{ - req = new ActiveXObject("Msxml2.XMLHTTP"); - } catch(e) { - // try an older version - try{ - req = new ActiveXObject("Microsoft.XMLHTTP"); - } catch(e) { - return false; - } - } - } - // if the http request obj has not been created then return - if (!req) return false; + var success = function (responseText) { + var list = i2b2.MedCo.ctrlr.variantNamePopup.variantNameList; + // remove all the previous variant names from the dropdown list + while (list.hasChildNodes()) { + list.removeChild(list.lastChild); + } + // todo sort the variant names + var receivedVariantNames= JSON.parse(responseText); + for (var i = 0; i < receivedVariantNames.length; i++) { + var opt = document.createElement("option"); + opt.value = receivedVariantNames[i]; + opt.innerHTML = receivedVariantNames[i]; + list.appendChild(opt); + } - // define two functions to manage the result received by the server - var success = function (responseText) { - // load the popup with the annotation names (you receive a json list of strings) - var annotations = document.querySelector("#annotationList"); + // if there was only one match the copy that in the text box + if (receivedVariantNames.length == 1) { + i2b2.MedCo.ctrlr.variantNamePopup.variantNameInputBox.value = receivedVariantNames[0]; + } + }; + var error = function (err) { + alert("Error when trying to retrieve the variant names from the database: " + err) + }; - // remove all children - while (annotations.hasChildNodes()) { - annotations.removeChild(annotations.lastChild); - } - // todo sort the annotations - var receivedAnnotations = JSON.parse(responseText); - for(var i=0; i<receivedAnnotations.length; i++) - { - var opt = document.createElement("option"); - opt.value = receivedAnnotations[i]; - opt.innerHTML = receivedAnnotations[i]; - annotations.appendChild(opt); + var phpQuery = + context.path + + "?variant_name=" + currVariantName + + "&limit=20"; // todo is it ok 20? + i2b2.MedCo.ctrlr.phpGETRequest(success, error, phpQuery); } - i2b2.MedCo.ctrlr.loadAnnotationValues(); - }; - var error = function (err) { - alert("Error when trying to retrieve the annotations from the database." + err) - }; + }, - // update the request object to act when receiving the response - req.onreadystatechange = function(){ - if(req.readyState == 4) { - return req.status === 200 ? - success(req.responseText) : error(req.status); - } - }; + // run the query to retrieve the id of the variants + getVariants: { + path: 'js-i2b2/cells/plugins/MedCo/php/getVariants.php', - req.open("GET", i2b2.MedCo.popup.getAnnotationPath, true); - req.send(null); - return req; -}; + run: function () { + var context = i2b2.MedCo.ctrlr.variantNamePopup; -i2b2.MedCo.ctrlr.loadAnnotationValues = function (){ - // just reset the two elements relative to the annotation value - var selectedAnnotationValue = document.querySelector("#selectedAnnotationValue"); - selectedAnnotationValue.innerHTML = ""; - var searchAnnotationValueBox = document.querySelector("#searchAnnotationValueBox"); - searchAnnotationValueBox.innerHTML = ""; - - // don't use the select anymore - // var annotationValues = document.querySelector("#annotationValueList"); - // // remove all options - // while (annotationValues.firstChild) { - // annotationValues.removeChild(annotationValues.firstChild); - // } - - // show that we are loading the values - // document.getElementById("MED-loadingValues").innerHTML = "<img id=\"MED-LoadingValuesGif\" width=\"15px\" src=\"assets/images/spin.gif\">"; - // document.getElementById("MED-LoadingValuesGif").style.display = 'block'; - - // create the request object to send the request and manage the response - var req = false; - try{ - // most browsers - req = new XMLHttpRequest(); - } catch (e){ - // IE - try{ - req = new ActiveXObject("Msxml2.XMLHTTP"); - } catch(e) { - // try an older version - try{ - req = new ActiveXObject("Microsoft.XMLHTTP"); - } catch(e) { - return false; + var variantName = context.variantNameInputBox.value; + var zygosyty = []; + if (context.zygosityList.heterozygousCheckbox.checked == true) { + zygosyty.push("Heterozygous") + } + if (context.zygosityList.homozygousCheckbox.checked == true) { + zygosyty.push("Homozygous") + } + if (context.zygosityList.unknownCheckbox.checked == true) { + zygosyty.push("Unknown") } - } - } - // if the http request obj has not been created then return - if (!req) return false; - - // define two functions to manage the result received by the server - var success = function (responseText) { - // $%$ is used as delimeter (AnnotationName$%$[val1,...,valn]) - var response = responseText.split("$%$"); - if (response[0] != i2b2.MedCo.popup.latestAnnotationRequest){ - // if I received an old response just ignore it - return - } - var receivedValues = JSON.parse(response[1].slice(1, -1)); - // load the annotation values in the popup - // var annotationValues = document.querySelector("#annotationValueList"); // don't use anymore the select - i2b2.MedCo.popup.annotationValues = []; - for(var i = 0; i < receivedValues.length; i++) - { - i2b2.MedCo.popup.annotationValues.push(receivedValues[i].toString()); - // var opt = document.createElement("option"); - // opt.value = receivedValues[i]; - // opt.innerHTML = receivedValues[i]; - // annotationValues.appendChild(opt); - } - // hide the loading gif - // document.getElementById("MED-LoadingValuesGif").style.display = 'none'; - }; - var error = function (err) { - alert("Error when trying to retrieve the values of the annotation from the database."+err) - }; + var queryType = "variantName_and_zygosity"; // used at the server side to know how to build the query - // update the request object to act when receiving the response - req.onreadystatechange = function(){ - if(req.readyState == 4) { - return req.status === 200 ? - success(req.responseText) : error(req.status); - } - }; + var success = function (responseText) { + alert(responseText); // todo delete + var response = JSON.parse(responseText); + for(var i=0; i<response.variants.length; i++) + { + i2b2.MedCo.model.panels[response.panel_number].push(response.variants[i]); + } + // I received the response so decrease the counter + i2b2.MedCo.popup.variantsQueryCounter -= 1; + }; + var error = function (err) { + alert("Error when trying to retrieve the variants from the database: " + err) + }; - // get the selected annotation - var annotations = document.querySelector("#annotationList"); - var selectedAnnotation = annotations.options[annotations.selectedIndex].value; - // store it so that I will know if the answer is the most recent - i2b2.MedCo.popup.latestAnnotationRequest = selectedAnnotation; + // increase the number of responses I should wait for + i2b2.MedCo.ctrlr.variantsQueryCounter += 1; - req.open("GET", i2b2.MedCo.popup.getAnnotationValuesPath + "?annotation_name=" + selectedAnnotation , true); - req.send(null); - return req; + // better pass the panel number too. It will be returned with the response so that I bind it to a + // specific panel. (if the query is very slow it could happen that the user starts two queries in parallel + // which are related to two different panels). + var phpQuery = + context.getVariants.path + + "?query_type=" + queryType + + "&panel_number=" + context.panelNumber + + "&variant_name=" + variantName + + "&zygosity[]=" + zygosyty.join("&zygosity[]="); // build an array of zygosity options + i2b2.MedCo.ctrlr.phpGETRequest(success, error, phpQuery); + } + } }; -i2b2.MedCo.ctrlr.loadVariants = function (){ +// Manage the php requests. +// success: function that takes as input the response form the server +// error: function that takes as input the error code returned by the server +// phpQuery: string that contains the path and the parameters of the request +i2b2.MedCo.ctrlr.phpGETRequest = function (success, error, phpQuery) { // create the request object to send the request and manage the response var req = false; - try{ + try { // most browsers req = new XMLHttpRequest(); - } catch (e){ + } catch (e) { // IE - try{ + try { req = new ActiveXObject("Msxml2.XMLHTTP"); - } catch(e) { + } catch (e) { // try an older version - try{ + try { req = new ActiveXObject("Microsoft.XMLHTTP"); - } catch(e) { + } catch (e) { return false; } } } // if the http request obj has not been created then return if (!req) return false; - // define two functions to manage the result received by the server - var success = function (responseText) { - var response = JSON.parse(responseText); - for(var i=0; i<response.variants.length; i++) - { - i2b2.MedCo.model.panels[response.panel_number].push(response.variants[i]); - } - // I received the response so decrease the counter - i2b2.MedCo.popup.variantsQueryCounter -= 1; - }; - var error = function (err) { - alert("Error when trying to retrieve the variants from the database."+err) - }; // update the request object to act when receiving the response - req.onreadystatechange = function(){ - if(req.readyState == 4) { + req.onreadystatechange = function () { + if (req.readyState == 4) { return req.status === 200 ? success(req.responseText) : error(req.status); } }; - // just write down that there is one more response we are waiting for - i2b2.MedCo.popup.variantsQueryCounter += 1; + req.open("GET", phpQuery, true); + req.send(null); + return req; +}; - var annotations = document.querySelector("#annotationList"); - var selectedAnnotation = annotations.options[annotations.selectedIndex].value; - var selectedValue = document.querySelector("#selectedAnnotationValue").innerHTML; - req.open("GET", i2b2.MedCo.popup.getVariantsPath + - "?annotation_name=" + selectedAnnotation + - "&annotation_value=" + selectedValue + - "&panel_number=" + i2b2.MedCo.popup.panelNumber, true); - req.send(null); - return req; -}; \ No newline at end of file +// OLD POPUP, TODO DELETE +// // initialize the popup: load the names of the annotations and register handlers to manage the automatic completion +// i2b2.MedCo.ctrlr.PopupInit = function (){ +// // get the element to register the event handler (auto completion) +// var searchAnnotationBox = document.querySelector("#searchAnnotationBox"); +// var annotations = document.querySelector("#annotationList"); // this will be loaded with all the annotations +// +// var searchAnnotationValueBox = document.querySelector("#searchAnnotationValueBox"); +// var selectedAnnotationValue = document.querySelector("#selectedAnnotationValue"); +// // (inefficient) var annotationValues = document.querySelector("#annotationValueList"); // this will be loaded with all the values an annotation can assume +// +// // load annotations from database (that will be shown when opening the popup) +// // the annotations name are loaded immediately (they are not too many) while the values of an annotation +// // are loaded only when that annotation is selected +// i2b2.MedCo.ctrlr.loadAnnotations(); +// +// // autocompletion function, e is an <input type="search"> object, list is a <select> object +// function autoCompletionAnnotation (e, list) { +// var text = e.target.value; +// var lowerText = text.toLowerCase(); +// var options = list.options; +// var initialOption = options[list.selectedIndex].text; +// var goodMatch = false; +// for (var i = 0; i < options.length; i++) { +// var option = options[i]; +// var optionText = option.text; +// var regex = new RegExp("^" + text, "i"); +// var match = optionText.match(regex); +// // best match +// if (match){ // if it starts the same the select this one +// option.selected = true; +// break; +// } +// // good match (still looking for a best match) +// var contains = optionText.indexOf(text) != -1; +// if(contains) { +// option.selected = true; +// goodMatch = true; +// } +// if (!goodMatch) { // if no good match was found then try this too +// // worse match (still looking for a good or best match) +// var lowerOptionText = optionText.toLowerCase(); +// contains = lowerOptionText.indexOf(lowerText) != -1; +// if (contains) { // it contains the string select this one but go on with looking for a better match +// option.selected = true; +// } +// } +// option.selectedIndex = 0; +// } +// // if the selected annotation changed then reload its values +// var currOption = options[list.selectedIndex].text; +// if (initialOption != currOption) { +// // want to reduce the number of "loadAnnotationValues", if after some time the option didn't changed +// // then I suppose the user stopped typing +// setTimeout( +// function(){ +// if(currOption == list.options[list.selectedIndex].text) +// i2b2.MedCo.ctrlr.loadAnnotationValues() +// }, 500); +// } +// } +// +// // showValue is an html object in which we will show the value +// function autoCompletionAnnotationValue (e, showValue) { +// var text = e.target.value; +// var lowerText = text.toLowerCase(); +// var values = i2b2.MedCo.popup.annotationValues; // list of possible values []string +// var goodMatch = false; +// for (var i = 0; i < values.length; i++) { +// var valueText = values[i]; +// var regex = new RegExp("^" + text, "i"); +// var match = valueText.match(regex); +// // best match +// if (match){ // if it starts the same the select this one +// showValue.innerHTML = valueText; +// break; +// } +// // good match (still looking for a best match) +// var contains = valueText.indexOf(text) != -1; +// if(contains) { +// showValue.innerHTML = valueText; +// goodMatch = true; +// } +// if (!goodMatch) { // if no good match was found then try this too +// // worse match (still looking for a good or best match) +// var lowerValueText = valueText.toLowerCase(); +// contains = lowerValueText.indexOf(lowerText) != -1; +// if (contains) { // it contains the string select this one but go on with looking for a better match +// showValue.innerHTML = valueText; +// +// } +// } +// } +// } +// +// // autocomplete the annotation name when entered +// searchAnnotationBox.addEventListener("keyup", function (e) {autoCompletionAnnotation(e, annotations)}); +// +// // autocomplete the annotation value when entered +// searchAnnotationValueBox.addEventListener("keyup", function (e) {autoCompletionAnnotationValue(e, selectedAnnotationValue)}); +// +// +// // variable used for the popup to know to which panel it is bound +// i2b2.MedCo.popup.panelNumber = 0; +// //variable to know which is the latest pending request sent for annotation values retrieval (the previous ones will be dropped) +// i2b2.MedCo.popup.latestAnnotationRequest = ""; +// +// // store the current loaded annotation values +// i2b2.MedCo.popup.annotationValues = []; +// +// // a counter used to count how many queries the client sent and is still waiting for a response. +// // while this counter is > 0 the query cannot be built +// i2b2.MedCo.popup.variantsQueryCounter = 0; +// }; +// +// i2b2.MedCo.popupShow = function (panelNumber) { +// i2b2.MedCo.popup.panelNumber = panelNumber; +// var messageBox=document.getElementById("annoMessage"); +// // Center the messageBox +// // alert(messageBox.style.clientWidth) +// // messageBox.style.marginTop=-messageBox.style.height/2; +// // messageBox.style.marginLeft=-messageBox.style.width/2; +// +// // Show message box (and background) +// document.getElementById("MedCo_popupBackground").style.display="block"; +// messageBox.style.display="block"; +// }; +// +// i2b2.MedCo.popupHide = function (){ +// document.getElementById("MedCo_popupBackground").style.display="none"; +// document.getElementById("annoMessage").style.display="none"; +// }; +// +// // i2b2.MedCo.popupEnterPressed = function (e) { +// // e = e || window.event; +// // if (e.keyCode == 13) // if enter is pressed ... +// // { +// // i2b2.MedCo.popupOk() +// // } +// // }; +// +// i2b2.MedCo.popupOk = function(){ +// // chosenAnnotationsElem = document.getElementById("chosen_annotations"); +// // chosenAnnotationsElem.innerHTML = ""; +// +// // var annotations = document.querySelector("#annotationList"); +// // var selectedAnnotation = annotations.options[annotations.selectedIndex].text; +// // +// // var selectedAnnotationValue = document.querySelector("#selectedAnnotationValue").innerHTML; +// // var annotationValues = document.querySelector("#annotationValueList"); +// // var selectedAnnotationValue = annotationValues.options[annotationValues.selectedIndex].text; +// +// +// // var annoVal = selectedAnnotation+":"+selectedAnnotationValue; +// +// // i2b2.MedCo.model.chosenAnnotations[i2b2.MedCo.popup.panelNumber].push(annoVal); +// +// // i2b2.MedCo.view.panels[i2b2.MedCo.popup.panelNumber].innerHTML += annoVal + "<br>"; +// +// +// i2b2.MedCo.ctrlr.loadVariants(); // send php request +// i2b2.MedCo.popupHide(); +// }; +// +// // MANAGE PHP REQUEST +// +// // load the annotations from the database (done only when initializing the popup!) +// i2b2.MedCo.ctrlr.loadAnnotations = function () { +// // create the request object to send the request and manage the response +// var req = false; +// try{ +// // most browsers +// req = new XMLHttpRequest(); +// } catch (e){ +// // IE +// try{ +// req = new ActiveXObject("Msxml2.XMLHTTP"); +// } catch(e) { +// // try an older version +// try{ +// req = new ActiveXObject("Microsoft.XMLHTTP"); +// } catch(e) { +// return false; +// } +// } +// } +// // if the http request obj has not been created then return +// if (!req) return false; +// +// // define two functions to manage the result received by the server +// var success = function (responseText) { +// // load the popup with the annotation names (you receive a json list of strings) +// var annotations = document.querySelector("#annotationList"); +// +// // remove all children +// while (annotations.hasChildNodes()) { +// annotations.removeChild(annotations.lastChild); +// } +// // todo sort the annotations +// var receivedAnnotations = JSON.parse(responseText); +// for(var i=0; i<receivedAnnotations.length; i++) +// { +// var opt = document.createElement("option"); +// opt.value = receivedAnnotations[i]; +// opt.innerHTML = receivedAnnotations[i]; +// annotations.appendChild(opt); +// } +// i2b2.MedCo.ctrlr.loadAnnotationValues(); +// }; +// var error = function (err) { +// alert("Error when trying to retrieve the annotations from the database." + err) +// }; +// +// // update the request object to act when receiving the response +// req.onreadystatechange = function(){ +// if(req.readyState == 4) { +// return req.status === 200 ? +// success(req.responseText) : error(req.status); +// } +// }; +// +// req.open("GET", i2b2.MedCo.popup.getAnnotationPath, true); +// req.send(null); +// return req; +// }; +// +// i2b2.MedCo.ctrlr.loadAnnotationValues = function (){ +// // just reset the two elements relative to the annotation value +// var selectedAnnotationValue = document.querySelector("#selectedAnnotationValue"); +// selectedAnnotationValue.innerHTML = ""; +// var searchAnnotationValueBox = document.querySelector("#searchAnnotationValueBox"); +// searchAnnotationValueBox.innerHTML = ""; +// +// // don't use the select anymore +// // var annotationValues = document.querySelector("#annotationValueList"); +// // // remove all options +// // while (annotationValues.firstChild) { +// // annotationValues.removeChild(annotationValues.firstChild); +// // } +// +// // show that we are loading the values +// // document.getElementById("MED-loadingValues").innerHTML = "<img id=\"MED-LoadingValuesGif\" width=\"15px\" src=\"assets/images/spin.gif\">"; +// // document.getElementById("MED-LoadingValuesGif").style.display = 'block'; +// +// // create the request object to send the request and manage the response +// var req = false; +// try{ +// // most browsers +// req = new XMLHttpRequest(); +// } catch (e){ +// // IE +// try{ +// req = new ActiveXObject("Msxml2.XMLHTTP"); +// } catch(e) { +// // try an older version +// try{ +// req = new ActiveXObject("Microsoft.XMLHTTP"); +// } catch(e) { +// return false; +// } +// } +// } +// // if the http request obj has not been created then return +// if (!req) return false; +// +// // define two functions to manage the result received by the server +// var success = function (responseText) { +// // $%$ is used as delimeter (AnnotationName$%$[val1,...,valn]) +// var response = responseText.split("$%$"); +// if (response[0] != i2b2.MedCo.popup.latestAnnotationRequest){ +// // if I received an old response just ignore it +// return +// } +// +// var receivedValues = JSON.parse(response[1].slice(1, -1)); +// // load the annotation values in the popup +// // var annotationValues = document.querySelector("#annotationValueList"); // don't use anymore the select +// i2b2.MedCo.popup.annotationValues = []; +// for(var i = 0; i < receivedValues.length; i++) +// { +// i2b2.MedCo.popup.annotationValues.push(receivedValues[i].toString()); +// // var opt = document.createElement("option"); +// // opt.value = receivedValues[i]; +// // opt.innerHTML = receivedValues[i]; +// // annotationValues.appendChild(opt); +// } +// // hide the loading gif +// // document.getElementById("MED-LoadingValuesGif").style.display = 'none'; +// }; +// var error = function (err) { +// alert("Error when trying to retrieve the values of the annotation from the database."+err) +// }; +// +// // update the request object to act when receiving the response +// req.onreadystatechange = function(){ +// if(req.readyState == 4) { +// return req.status === 200 ? +// success(req.responseText) : error(req.status); +// } +// }; +// +// // get the selected annotation +// var annotations = document.querySelector("#annotationList"); +// var selectedAnnotation = annotations.options[annotations.selectedIndex].value; +// // store it so that I will know if the answer is the most recent +// i2b2.MedCo.popup.latestAnnotationRequest = selectedAnnotation; +// +// req.open("GET", i2b2.MedCo.popup.getAnnotationValuesPath + "?annotation_name=" + selectedAnnotation , true); +// req.send(null); +// return req; +// }; +// +// +// i2b2.MedCo.ctrlr.loadVariants = function (){ +// // create the request object to send the request and manage the response +// var req = false; +// try{ +// // most browsers +// req = new XMLHttpRequest(); +// } catch (e){ +// // IE +// try{ +// req = new ActiveXObject("Msxml2.XMLHTTP"); +// } catch(e) { +// // try an older version +// try{ +// req = new ActiveXObject("Microsoft.XMLHTTP"); +// } catch(e) { +// return false; +// } +// } +// } +// // if the http request obj has not been created then return +// if (!req) return false; +// +// // define two functions to manage the result received by the server +// var success = function (responseText) { +// var response = JSON.parse(responseText); +// for(var i=0; i<response.variants.length; i++) +// { +// i2b2.MedCo.model.panels[response.panel_number].push(response.variants[i]); +// } +// // I received the response so decrease the counter +// i2b2.MedCo.popup.variantsQueryCounter -= 1; +// }; +// var error = function (err) { +// alert("Error when trying to retrieve the variants from the database."+err) +// }; +// +// // update the request object to act when receiving the response +// req.onreadystatechange = function(){ +// if(req.readyState == 4) { +// return req.status === 200 ? +// success(req.responseText) : error(req.status); +// } +// }; +// +// // just write down that there is one more response we are waiting for +// i2b2.MedCo.popup.variantsQueryCounter += 1; +// +// var annotations = document.querySelector("#annotationList"); +// var selectedAnnotation = annotations.options[annotations.selectedIndex].value; +// +// var selectedValue = document.querySelector("#selectedAnnotationValue").innerHTML; +// +// req.open("GET", i2b2.MedCo.popup.getVariantsPath + +// "?annotation_name=" + selectedAnnotation + +// "&annotation_value=" + selectedValue + +// "&panel_number=" + i2b2.MedCo.popup.panelNumber, true); +// req.send(null); +// return req; +// }; \ No newline at end of file