|
@@ -0,0 +1,3834 @@
|
|
|
|
+const config=new Object();
|
|
|
|
+
|
|
|
|
+function clear(){
|
|
|
|
+ let el=config.document.getElementById(config.debugId);
|
|
|
|
+ if (el===null) {
|
|
|
|
+ //alert("Debug section not initialized");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ config.document.getElementById(config.debugId).value="";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function print(msg){
|
|
|
|
+ let el=config.document.getElementById(config.debugId);
|
|
|
|
+ if (el===null) {
|
|
|
|
+ //alert("Debug section not initialized. Message: "+msg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ el.value+="\n"+msg;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function makeQuery(containerName,queryName,fieldName,filterArray){
|
|
|
|
+ //generates an instruction entry that looks up queryName from container and stores
|
|
|
|
+ //the resulting table to fieldName potentially using filterArray
|
|
|
|
+ let e=new Object();
|
|
|
|
+ e.containerName=containerName;
|
|
|
|
+ e.queryName=queryName;
|
|
|
|
+ e.fieldName=fieldName;
|
|
|
|
+ e.filterArray=filterArray;
|
|
|
|
+ return e;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getDataFromQueries(queryArray,cb){
|
|
|
|
+ //queryArray should contain elements with
|
|
|
|
+ //- fieldName to set the data variable
|
|
|
|
+ //- containerName to select container (data,config,CRF)
|
|
|
|
+ //- queryName to select query
|
|
|
|
+ //- filterArray to perform filtering, empty array works
|
|
|
|
+ //- callback cb to be called with no arguments
|
|
|
|
+ //
|
|
|
|
+ afterQuery(new Object(),-1,queryArray,cb);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterQuery(data,id,queryArray,cb){
|
|
|
|
+ //queryArray should contain elements with
|
|
|
|
+ //- fieldName to set the data variable
|
|
|
|
+ //- containerName to select container (data,config,CRF)
|
|
|
|
+ //- queryName to select query
|
|
|
|
+ //- filterArray to perform filtering, empty array works
|
|
|
|
+ //- callback cb to be called with no arguments
|
|
|
|
+ //
|
|
|
|
+ //it should be called with id -1.
|
|
|
|
+ //
|
|
|
|
+ print('afterQuery['+id+']: ');
|
|
|
|
+
|
|
|
|
+ if (id>-1){
|
|
|
|
+ let fieldName=queryArray[id].fieldName;
|
|
|
|
+ print('afterQuery['+fieldName+']: '+data.rows.length);
|
|
|
|
+ config.formConfig[fieldName]=data;
|
|
|
|
+ }
|
|
|
|
+ id+=1;
|
|
|
|
+ if (id==queryArray.length) {
|
|
|
|
+ cb();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let e=queryArray[id];
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.containerPath=getContainer(e.containerName);
|
|
|
|
+ qconfig.schemaName="lists";
|
|
|
|
+ if ("schemaName" in e){
|
|
|
|
+ print('afterQuery: schemaName='+e.schemaName);
|
|
|
|
+ qconfig.schemaName=e.schemaName;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ("columns" in e){
|
|
|
|
+ print('afterQuery: columns='+e.columns);
|
|
|
|
+ qconfig.columns=e.columns;
|
|
|
|
+ }
|
|
|
|
+ qconfig.queryName=e.queryName;
|
|
|
|
+ //this should point to configuration container
|
|
|
|
+ //don't filter -> so we can pick up other forms (say registration) later on
|
|
|
|
+ //qconfig.filterArray=[LABKEY.Filter.create('Key',config.formId)];
|
|
|
|
+ if ("filterArray" in e)
|
|
|
|
+ qconfig.filterArray=e.filterArray;
|
|
|
|
+
|
|
|
|
+ //qconfig.filterArray=[LABKEY.Filter.create('formStatus',1)]
|
|
|
|
+ qconfig.success=function(data){afterQuery(data,id,queryArray,cb);};
|
|
|
|
+ qconfig.failure=doNothing;
|
|
|
|
+ LABKEY.Query.selectRows(qconfig);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function getCRFrefFirst(){
|
|
|
|
+ //crfRef is part of html call and gets stored in the page
|
|
|
|
+ return config.document.getElementById(config.crfRefId).innerHTML;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function getCRFref(){
|
|
|
|
+ //'crfRefId'
|
|
|
|
+ return config.formConfig.crfEntry['entryId'];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getCRFrefData(){
|
|
|
|
+ let parentCrf=config.formConfig.crfEntry['parentCrf'];
|
|
|
|
+ if (parentCrf!=undefined) return parentCrf;
|
|
|
|
+ return getCRFref();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function onFailure(errorInfo, options, responseObj){
|
|
|
|
+
|
|
|
|
+ if (errorInfo && errorInfo.exception)
|
|
|
|
+ alert("Failure: " + errorInfo.exception);
|
|
|
|
+ else
|
|
|
|
+ alert("Failure: " + responseObj.statusText);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function doNothing(){
|
|
|
|
+ print('doNothing called');
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateDebugSection(){
|
|
|
|
+ //let debug=true;
|
|
|
|
+ //if (debug) print("generateDebugSection "+sectionName);
|
|
|
|
+
|
|
|
|
+ let formName=config.debugDiv;
|
|
|
|
+ let sectionName="debugSection";
|
|
|
|
+ let sectionTitle="Debug Messages";
|
|
|
|
+ let tb=config.document.createElement('table');
|
|
|
|
+ tb.className='t2';
|
|
|
|
+ let row=tb.insertRow();
|
|
|
|
+ let cell=config.document.createElement('th');
|
|
|
|
+ row.appendChild(cell);
|
|
|
|
+ cell.setAttribute("colspan","4");
|
|
|
|
+ cell.style.fontSize="20px";
|
|
|
|
+ cell.style.textAlign="center";
|
|
|
|
+ let cellData=config.document.createTextNode(sectionTitle);
|
|
|
|
+ cell.appendChild(cellData);
|
|
|
|
+ cell=row.insertCell();
|
|
|
|
+ let input=config.document.createElement("input");
|
|
|
|
+ input.type="button";
|
|
|
|
+ input.id="toggle"+sectionName+"VisbilityButton";
|
|
|
|
+ input.onclick=function(){toggleVisibility(sectionName,input.id)};
|
|
|
|
+ cell.appendChild(input);
|
|
|
|
+ config.document.getElementById(formName).appendChild(tb);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let div=config.document.createElement('div');
|
|
|
|
+ div.id=sectionName;
|
|
|
|
+ config.document.getElementById(formName).appendChild(div);
|
|
|
|
+
|
|
|
|
+ //start open (for debug)
|
|
|
|
+
|
|
|
|
+ //input.value="Hide";
|
|
|
|
+ //div.style.display="block";
|
|
|
|
+
|
|
|
|
+ //start hidden (for production)
|
|
|
|
+ input.value="Show";
|
|
|
|
+ div.style.display="none";
|
|
|
|
+
|
|
|
|
+ let debugArea=config.document.createElement('textarea');
|
|
|
|
+ debugArea.rows=10;
|
|
|
|
+ debugArea.cols=95;
|
|
|
|
+ debugArea.id=config.debugId;
|
|
|
|
+ div.appendChild(debugArea);
|
|
|
|
+
|
|
|
|
+ //print('ver: 0.10');
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function getAdditionalData(formSetupEntry){
|
|
|
|
+
|
|
|
|
+ let queryName=config.formConfig.queryMap[formSetupEntry['queryName']];
|
|
|
|
+ let fName='[getAdditionalData/'+queryName+']';
|
|
|
|
+ print(fName);
|
|
|
|
+
|
|
|
|
+ if (queryName in config.formConfig.additionalData){
|
|
|
|
+ print(fName+': Returning preset value');
|
|
|
|
+ return config.formConfig.additionalData[queryName];
|
|
|
|
+ }
|
|
|
|
+ print(fName+': generating');
|
|
|
|
+ config.formConfig.additionalData[queryName]=new Object();
|
|
|
|
+ //takes address, so further changes will be to the newly created object
|
|
|
|
+ let ad=config.formConfig.additionalData[queryName];
|
|
|
|
+
|
|
|
|
+ if (formSetupEntry["showFlag"]==="NONE") {
|
|
|
|
+ print(fName+": empty");
|
|
|
|
+ return ad;
|
|
|
|
+ }
|
|
|
|
+ if (formSetupEntry["showFlag"]==="REVIEW") {
|
|
|
|
+ //abuse additionalData to signal different segment
|
|
|
|
+ print(fName+": generateReport");
|
|
|
|
+ ad.isReview=true;
|
|
|
|
+ return ad;
|
|
|
|
+ }
|
|
|
|
+ print(fName+': setting values');
|
|
|
|
+ ad.showFlag=formSetupEntry["showFlag"];
|
|
|
|
+ ad.showFlagValue=formSetupEntry["showFlagValue"];
|
|
|
|
+ //variables associated with target query
|
|
|
|
+ let qVars=formSetupEntry["showQuery"].split(';');
|
|
|
|
+ ad.queryName=qVars[0];
|
|
|
|
+ //remove first element
|
|
|
|
+ qVars.shift();
|
|
|
|
+ //join back to string for parsing
|
|
|
|
+ let code=qVars.join(";");
|
|
|
|
+ //if empty string, set to undefined for parseCode
|
|
|
|
+ if (code.length==0){
|
|
|
|
+ code=undefined;
|
|
|
|
+ }
|
|
|
|
+ //parse var=value pairs
|
|
|
|
+ ad.variableDefinition=parseCode(code);
|
|
|
|
+ //print for debugging
|
|
|
|
+ for (let f in ad.variableDefinition){
|
|
|
|
+ let v=ad.variableDefinition[f];
|
|
|
|
+ print(fName+': adding ['+f+']='+v);
|
|
|
|
+ }
|
|
|
|
+ ad.filters=new Object();
|
|
|
|
+ ad.filters['crfRef']=getCRFref();
|
|
|
|
+ let msg=fName+": flag "+ad.showFlag;
|
|
|
|
+ msg+=" value "+ad.showFlagValue;
|
|
|
|
+ msg+=" query "+ad.queryName;
|
|
|
|
+ print(msg);
|
|
|
|
+ return ad;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateSetup(){
|
|
|
|
+ let setup=new Object();
|
|
|
|
+ //setVariables contains special variables that have a
|
|
|
|
+ //preset value in a specified table:
|
|
|
|
+ //A.) these values won't appear in the form
|
|
|
|
+ //B.) will be submitted with value specified to the database
|
|
|
|
+ //make sure setVariables object is present in an object
|
|
|
|
+ setup.setVariables=new Object();
|
|
|
|
+ return setup;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function fullAccessSetup(sectionId,listName){
|
|
|
|
+ //generate setup object whcih should contain fields:
|
|
|
|
+ //readonlyFlag - whether the dataset is writeable
|
|
|
|
+ //filters - selection fields that allow creation of LABKEY.Filter.create()
|
|
|
|
+ //getInputId - formating of unique ids for html elements
|
|
|
|
+ //addApply - whether a submit/Save button is generated
|
|
|
|
+ //unique - whether entries in list are unique
|
|
|
|
+
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug) print("fullAccessSetup");
|
|
|
|
+
|
|
|
|
+ let setup=generateSetup();
|
|
|
|
+ setup.queryName=listName;
|
|
|
|
+ setup.readonlyFlag=function(vName){return false};
|
|
|
|
+ setup.filters=new Object();
|
|
|
|
+ setup.filters['crfRef']=getCRFref();
|
|
|
|
+ setup.getInputId=function(vName){return sectionId+"_"+vName;}
|
|
|
|
+ setup.addApply="Save";
|
|
|
|
+ setup.isReview=false;
|
|
|
|
+ setup.sectionId=sectionId;
|
|
|
|
+ return setup;
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function readonlySetup(sectionId,listName){
|
|
|
|
+ //see definition of setup object above
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug) print("readonlySetup");
|
|
|
|
+
|
|
|
|
+ let setup=generateSetup();
|
|
|
|
+ setup.queryName=listName;
|
|
|
|
+ setup.readonlyFlag=function(vName){return true};
|
|
|
|
+ setup.filters=new Object();
|
|
|
|
+ setup.filters['crfRef']=getCRFref();
|
|
|
|
+ setup.getInputId=function(vName){return sectionId+'_'+vName;}
|
|
|
|
+ setup.isReview=false;
|
|
|
|
+ setup.sectionId=sectionId;
|
|
|
|
+ return setup;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getSetup(sectionId,listName,writeAccess=true){
|
|
|
|
+ //change to section granulated permission of type EDIT, COMMENT, READ
|
|
|
|
+ //let formStatus=config.formConfig.formStatus;
|
|
|
|
+ //equivalent to READ
|
|
|
|
+
|
|
|
|
+ if (!writeAccess)
|
|
|
|
+ //if (formStatus=="Submitted")
|
|
|
|
+ return readonlySetup(sectionId,listName);
|
|
|
|
+ //if (formStatus=="Approved")
|
|
|
|
+ // return readonlySetup(listName);
|
|
|
|
+ return fullAccessSetup(sectionId,listName);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function parseVariableDefinition(formSetupEntry){
|
|
|
|
+ let fName='parseVariableDefinition['+formSetupEntry['title']+']';
|
|
|
|
+ let code=formSetupEntry['variableDefinition'];
|
|
|
|
+ print(fName+' '+code);
|
|
|
|
+ return parseCode(code);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function parseCode(code){
|
|
|
|
+ //helper function to decode content of variableDefinition
|
|
|
|
+ //to a JS object
|
|
|
|
+ //
|
|
|
|
+ //should contain semicolon split var=value pairs
|
|
|
|
+ let vars=new Object();
|
|
|
|
+ if (code==undefined)
|
|
|
|
+ //variableDefinition field is empty, return empyt object
|
|
|
|
+ return vars;
|
|
|
|
+ let ar=code.split(';');
|
|
|
|
+ for (let i=0;i<ar.length;i++){
|
|
|
|
+ q=ar[i].split('=');
|
|
|
|
+ vars[q[0]]=q[1];
|
|
|
|
+ }
|
|
|
|
+ return vars;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function setHelp(setup,formSetupEntry){
|
|
|
|
+ let helpRows=config.formConfig.help.rows;
|
|
|
|
+ for (let i=0;i<helpRows.length;i++){
|
|
|
|
+ let eh=helpRows[i];
|
|
|
|
+ if (eh['query']==formSetupEntry['queryName']){
|
|
|
|
+ if (!("help" in setup)){
|
|
|
|
+ setup["help"]=new Object();
|
|
|
|
+ setup["help"].rows=new Array();
|
|
|
|
+ }
|
|
|
|
+ setup["help"].rows.push(eh);
|
|
|
|
+ print('Adding help to '+config.formConfig.queryMap[eh['query']]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //this updates setup
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function generateSection(formSetupEntry){
|
|
|
|
+
|
|
|
|
+ //generates a (hideable) section according to setup in formEntrySetup
|
|
|
|
+
|
|
|
|
+ let listName=config.formConfig.queryMap[formSetupEntry['queryName']];
|
|
|
|
+ let sectionId='section'+formSetupEntry['Key'];
|
|
|
|
+ let fName='[generateSection/'+listName+'/'+sectionId+']';
|
|
|
|
+ let sectionTitle=formSetupEntry['title'];
|
|
|
|
+ let accessModeColumn=config.formConfig.operator+'Mode';
|
|
|
|
+ let accessMode=formSetupEntry[accessModeColumn];
|
|
|
|
+ //this will fix it for later use as well
|
|
|
|
+ let additionalData=getAdditionalData(formSetupEntry);
|
|
|
|
+ print(fName);
|
|
|
|
+
|
|
|
|
+ let formName=config.masterForm;//this is HTML designator of area on page
|
|
|
|
+ let debug=true;
|
|
|
|
+ let tb=config.document.createElement('table');
|
|
|
|
+ tb.className='t2';
|
|
|
|
+ let row=tb.insertRow();
|
|
|
|
+ let cell=config.document.createElement('th');
|
|
|
|
+ row.appendChild(cell);
|
|
|
|
+ cell.setAttribute("colspan","4");
|
|
|
|
+ cell.style.fontSize="20px";
|
|
|
|
+ cell.style.textAlign="center";
|
|
|
|
+ let cellData=config.document.createTextNode(sectionTitle);
|
|
|
|
+ cell.appendChild(cellData);
|
|
|
|
+ cell=row.insertCell();
|
|
|
|
+ let input=config.document.createElement("input");
|
|
|
|
+ input.type="button";
|
|
|
|
+ input.value="Show";
|
|
|
|
+ input.id="toggle"+sectionId+"VisbilityButton";
|
|
|
|
+ input.onclick=function(){toggleVisibility(sectionId,input.id)};
|
|
|
|
+ //toggleVisibilityArgumentList changed!
|
|
|
|
+ cell.appendChild(input);
|
|
|
|
+ config.document.getElementById(formName).appendChild(tb);
|
|
|
|
+
|
|
|
|
+ let div=config.document.createElement('div');
|
|
|
|
+ //relabel this to allow multiple entries for the same list
|
|
|
|
+ div.id=sectionId;
|
|
|
|
+ div.style.display="none";
|
|
|
|
+ config.document.getElementById(formName).appendChild(div);
|
|
|
|
+
|
|
|
|
+ let divTable=config.document.createElement('div');
|
|
|
|
+ divTable.id=sectionId+"Table";
|
|
|
|
+ div.appendChild(divTable);
|
|
|
|
+
|
|
|
|
+ if ("showFlag" in additionalData) {
|
|
|
|
+
|
|
|
|
+ additionalData.divName=sectionId+"SubDiv";
|
|
|
|
+ additionalData.divQueryName=sectionId+"SubDivList";
|
|
|
|
+
|
|
|
|
+ let div1=config.document.createElement('div');
|
|
|
|
+ div1.id=additionalData.divName;
|
|
|
|
+ div1.style.display="none";
|
|
|
|
+ div.appendChild(div1);
|
|
|
|
+
|
|
|
|
+ let div2=config.document.createElement('div');
|
|
|
|
+ div2.id=additionalData.divQueryName;
|
|
|
|
+ div1.appendChild(div2);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ if (debug) print(fName+" master table");
|
|
|
|
+
|
|
|
|
+ let writeMode=accessMode=="EDIT";
|
|
|
|
+
|
|
|
|
+ //setup stores some common values that get passed to generateTable
|
|
|
|
+ //most significantly, whether fields are changeable or not
|
|
|
|
+
|
|
|
|
+ if ("isReview" in additionalData){
|
|
|
|
+ generateReviewSection(listName,div.id,generateReviewSectionCB);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //master table is unique per visit
|
|
|
|
+
|
|
|
|
+ let setup=getSetup(sectionId,listName,writeMode);
|
|
|
|
+
|
|
|
|
+ setup.unique=true;
|
|
|
|
+
|
|
|
|
+ setHelp(setup,formSetupEntry);
|
|
|
|
+
|
|
|
|
+ //set variables from formSetup variableDefinition field
|
|
|
|
+ //to setup.setVariables
|
|
|
|
+ setup.setVariables=parseVariableDefinition(formSetupEntry);
|
|
|
|
+ for (x in setup.setVariables){
|
|
|
|
+ print(fName+' setVariables '+x+':'+setup.setVariables[x]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ generateTable(listName,divTable.id,additionalData,setup);
|
|
|
|
+
|
|
|
|
+ if (debug) print(fName+" master table: done");
|
|
|
|
+
|
|
|
|
+ let generateSubTable=true;
|
|
|
|
+ //generateSubTable equivalent to read/write access to section
|
|
|
|
+ if (accessMode != "EDIT")
|
|
|
|
+ generateSubTable=false;
|
|
|
|
+
|
|
|
|
+ if (! ("showFlag" in additionalData) ) generateSubTable=false;
|
|
|
|
+
|
|
|
|
+ if (generateSubTable){
|
|
|
|
+ let qName=additionalData.queryName;
|
|
|
|
+ let dName=additionalData.divName;
|
|
|
|
+
|
|
|
|
+ let subsectionId='sub'+sectionId;
|
|
|
|
+ let subSetup=fullAccessSetup(subsectionId,qName);
|
|
|
|
+
|
|
|
|
+ //only set master query for additionalData
|
|
|
|
+ subSetup.masterQuery=listName;
|
|
|
|
+ //if (readonly) setup=readonlySetup(config);
|
|
|
|
+ generateTable(qName,dName,additionalData,subSetup);
|
|
|
|
+ //generateTable(formSetupEntry,qName,dName,additionalData,setup);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ print(fName+" generate review");
|
|
|
|
+
|
|
|
|
+ let divReviewList=config.document.createElement('div');
|
|
|
|
+ divReviewList.id=sectionId+"ReviewList";
|
|
|
|
+ div.appendChild(divReviewList);
|
|
|
|
+
|
|
|
|
+ let divReview=config.document.createElement('div');
|
|
|
|
+ divReview.id=sectionId+"Review";
|
|
|
|
+ div.appendChild(divReview);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //assume we already have listId (content of config.setupQueryName is listId)
|
|
|
|
+ //we need listName also
|
|
|
|
+ //qconfig.queryName=config.setupQueryName;
|
|
|
|
+ generateReview(divReview.id,divReviewList.id,listName,accessMode);
|
|
|
|
+ //generateReview depends on listName
|
|
|
|
+
|
|
|
|
+ print(fName+" generate review complete");
|
|
|
|
+
|
|
|
|
+ if (accessMode!='GENERATE') return;
|
|
|
|
+ print('Adding generate button');
|
|
|
|
+ //add generateButton
|
|
|
|
+ let divGenerateButton=config.document.createElement('div');
|
|
|
|
+ divGenerateButton.id=sectionId+'GenerateButton';
|
|
|
|
+ div.appendChild(divGenerateButton);
|
|
|
|
+ print('Adding generate button completed to here');
|
|
|
|
+ let cb=function(){onGenerateQuery(listName);};
|
|
|
|
+ generateButton(divGenerateButton.id,'Generate','Generate '+listName,'XX',cb);
|
|
|
|
+ print('Adding generate button completed');
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//>>>>reviewSection associated routines
|
|
|
|
+
|
|
|
|
+function parseResponseXML(){
|
|
|
|
+ //print(config.config,'Status:' +this.status);
|
|
|
|
+ print('Status:'+this.status);
|
|
|
|
+ if (this.status!=200) return;
|
|
|
|
+ config.loadFileConfig.json=JSON.parse(this.responseText);
|
|
|
|
+ config.loadFileConfig.cb();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function loadFile(){
|
|
|
|
+ print('YY: '+config.loadFileConfig.url);
|
|
|
|
+
|
|
|
|
+ let connRequest=new XMLHttpRequest();
|
|
|
|
+ connRequest.addEventListener("loadend",parseResponseXML);
|
|
|
|
+ //function(e){parseResponseXML(e,config);});
|
|
|
|
+ connRequest.open("GET", config.loadFileConfig.url);
|
|
|
|
+ connRequest.send();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function getBasePath(){
|
|
|
|
+ let server=LABKEY.ActionURL.getBaseURL();
|
|
|
|
+ let basePath=server+"_webdav";
|
|
|
|
+ basePath+=LABKEY.ActionURL.getContainer();
|
|
|
|
+ return basePath;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function generateReviewSection(listName,id,callback){
|
|
|
|
+ //callback should be generateReviewSectionCB and it takes no arguments
|
|
|
|
+ print("generateReviewSection");
|
|
|
|
+ //need base path
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ config.loadFileConfig=new Object();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ config.loadFileConfig.cb=callback;
|
|
|
|
+ config.loadFileConfig.id=id;
|
|
|
|
+ config.loadFileConfig.url=getBasePath()+'/@files/reportSetup/'+listName+'.json';
|
|
|
|
+ loadFile();
|
|
|
|
+ //load file and continue in the next function
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function generateErrorMessage(id,listName,msg){
|
|
|
|
+ print('generateErrorMessage:');
|
|
|
|
+ let eid=listName+"_errorMsg";
|
|
|
|
+ let el=config.document.getElementById(eid);
|
|
|
|
+ if (el===null){
|
|
|
|
+ el=config.document.createElement("p");
|
|
|
|
+ config.document.getElementById(id).appendChild(el);
|
|
|
|
+ }
|
|
|
|
+ el.innerHTML=msg;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function clearErrorMessage(listName){
|
|
|
|
+ let eid=listName+"_errorMsg";
|
|
|
|
+ let el=config.document.getElementById(eid);
|
|
|
|
+ if (el===null) return;
|
|
|
|
+ el.remove();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getParticipantCode(pid){
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ selectRows.schemaName='lists';
|
|
|
|
+ //we should now which form we are in
|
|
|
|
+ let mfId=config.formConfig.form['masterQuery'];
|
|
|
|
+ selectRows.queryName=config.formConfig.queryMap[mfId];
|
|
|
|
+ //point to data container
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //selectRows.queryName='PET';
|
|
|
|
+ pid.afterId=setParticipantCode;
|
|
|
|
+ pid.participantField=config.formConfig.studyData["SubjectColumnName"];
|
|
|
|
+ selectRows.success=function(data){afterRegistration(pid,data);}
|
|
|
|
+ selectRows.filterArray=[LABKEY.Filter.create("crfRef",getCRFref())];
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function visitCodeFromVisitId(visitId){
|
|
|
|
+ if (visitId<0) return "NONE";
|
|
|
|
+ let project=getContainer('data');
|
|
|
|
+ print('visitCodeFromVisitId: '+project.search('retro'));
|
|
|
|
+ if (project.search('retro')>-1)
|
|
|
|
+ visitId-=1;
|
|
|
|
+ return 'VISIT_'+visitId.toString();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function replaceSlash(x){
|
|
|
|
+ return x.replace(/\//,'_');
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function setParticipantCode(pid){
|
|
|
|
+ let fName='[setParticipantCode]';
|
|
|
|
+ let rows=pid.registration.rows;
|
|
|
|
+ //pick from study
|
|
|
|
+ let participantField=config.formConfig.studyData["SubjectColumnName"];
|
|
|
|
+ if (rows.length==1){
|
|
|
|
+ print(fName+': '+rows[0][participantField]+'/'+rows[0].visitId);
|
|
|
|
+ let visitCode=visitCodeFromVisitId(rows[0].visitId);
|
|
|
|
+ print('setParticipantCode: '+pid.participantId+'/'+visitCode);
|
|
|
|
+ pid.participantCode=replaceSlash(pid.participantId);
|
|
|
|
+ pid.visitCode=visitCode;
|
|
|
|
+ }
|
|
|
|
+ generateReviewSection2(pid);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function generateReviewSectionCB(){
|
|
|
|
+
|
|
|
|
+ let listName=config.loadFileConfig.listName;
|
|
|
|
+ let id=config.loadFileConfig.id;
|
|
|
|
+
|
|
|
|
+ clearErrorMessage(listName);
|
|
|
|
+
|
|
|
|
+ let pid=new Object();
|
|
|
|
+ pid.participantCode="NONE";
|
|
|
|
+ pid.visitCode="NONE";
|
|
|
|
+ getParticipantCode(pid);
|
|
|
|
+ print('Get participant code sent');
|
|
|
|
+ //involves database search, continue after callback
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getValueFromElement(id,defaultValue){
|
|
|
|
+ let e=config.document.getElementById(id);
|
|
|
|
+ if (e!=null){
|
|
|
|
+ defaultValue=e.innerHTML;
|
|
|
|
+ }
|
|
|
|
+ return defaultValue;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function pickParticipantCodeFromPage(){
|
|
|
|
+ let pid=new Object();
|
|
|
|
+ pid.participantCode=getValueFromElement("participantCode","NIX-LJU-D2002-IRAE-A000");
|
|
|
|
+ pid.visitCode=getValueFromElement("visitCode","VISIT_1");
|
|
|
|
+ generateReviewSection2(pid);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function patternReplace(src,replacements,values){
|
|
|
|
+
|
|
|
|
+ for (rep in replacements){
|
|
|
|
+ let txt1=src.replace(new RegExp(rep),values[replacements[rep]]);
|
|
|
|
+ src=txt1;
|
|
|
|
+ }
|
|
|
|
+ return src;
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function plotImage(cell,k,row,rowVariable,obj,pid){
|
|
|
|
+ let baseDir=patternReplace(obj.imageDir,obj.replacements,pid);
|
|
|
|
+ print('Base dir: '+pid.basePath);
|
|
|
|
+ pid[obj.variable]=obj.values[k];
|
|
|
|
+ cell.id=pid[obj.variable]+"_"+rowVariable+pid[rowVariable];
|
|
|
|
+ let img=null;
|
|
|
|
+ let imgId=cell.id+'_img_';
|
|
|
|
+ img=config.document.getElementById(imgId);
|
|
|
|
+ if (img===null){
|
|
|
|
+ img=config.document.createElement('img');
|
|
|
|
+ img.id=imgId;
|
|
|
|
+ cell.appendChild(img);
|
|
|
|
+ }
|
|
|
|
+ let imgSrc=patternReplace(obj.file,obj.replacements,pid);
|
|
|
|
+ print('Image: '+imgSrc);
|
|
|
|
+ let imagePath=pid.basePath+'/'+baseDir+'/'+imgSrc;
|
|
|
|
+
|
|
|
|
+ img.src=imagePath;
|
|
|
|
+ img.width="300";
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function showReport(cell,k,row,rowVariable,obj,pid){
|
|
|
|
+
|
|
|
|
+ cell.width="300px";
|
|
|
|
+ cell.id='report_'+obj.values[k]+"_"+rowVariable+pid[rowVariable];
|
|
|
|
+ let reportConfig=new Object();
|
|
|
|
+ reportConfig.partName="Report";
|
|
|
|
+ reportConfig.renderTo=cell.id;
|
|
|
|
+ //reportConfig.showFrame=false;
|
|
|
|
+ //reportConfig.width="300";
|
|
|
|
+ reportConfig.frame="none";
|
|
|
|
+ reportConfig.partConfig=new Object();
|
|
|
|
+ reportConfig.partConfig.width="300";
|
|
|
|
+ reportConfig.partConfig.title="R Report";
|
|
|
|
+ reportConfig.partConfig.reportName=obj.values[k];
|
|
|
|
+ for (f in obj.parameters){
|
|
|
|
+ reportConfig.partConfig[f]=pid[f];
|
|
|
|
+ }
|
|
|
|
+ reportConfig.partConfig.showSection="myscatterplot";
|
|
|
|
+ let reportWebPartRenderer = new LABKEY.WebPart(reportConfig);
|
|
|
|
+ print('Render to: '+reportConfig.renderTo);
|
|
|
|
+ reportWebPartRenderer.render();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function showProbability(cell,k,row,rowSetup,j,obj,pid){
|
|
|
|
+ print('showProbability: '+rowSetup);
|
|
|
|
+ let rowVariable=rowSetup.variable;
|
|
|
|
+ cell.id='prob_'+obj.values[k]+"_"+rowVariable+pid[rowVariable];
|
|
|
|
+
|
|
|
|
+ let probDensity=new Object();
|
|
|
|
+ probDensity.mean=rowSetup.mean[j];
|
|
|
|
+ probDensity.sigma=rowSetup.sigma[j];
|
|
|
|
+
|
|
|
|
+ print('showProbability: mean '+probDensity.mean+' sigma '+probDensity.sigma);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ probDensity.func=obj.values[k];
|
|
|
|
+ probDensity.organCode=pid.organCode;
|
|
|
|
+ pid[obj.variable]=rowSetup[obj.variable][j];
|
|
|
|
+ probDensity.percentile=pid.percentile;
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ selectRows.queryName=obj.queryName;
|
|
|
|
+ selectRows.schemaName="study";
|
|
|
|
+ selectRows.filterArray=[];
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+ for (let f in obj.filters){
|
|
|
|
+ selectRows.filterArray.push(
|
|
|
|
+ LABKEY.Filter.create(f,pid[obj.filters[f]]));
|
|
|
|
+ print('Filter ['+f+']: '+pid[obj.filters[f]]);
|
|
|
|
+ }
|
|
|
|
+ selectRows.success=function(data){
|
|
|
|
+ drawProbability(data,cell,obj,pid,probDensity);}
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function erf(x){
|
|
|
|
+ let fx=[0,0.02,0.04,0.06,0.08,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,
|
|
|
|
+ 1,1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2,
|
|
|
|
+ 2.1,2.2,2.3,2.4,2.5,3,3.5];
|
|
|
|
+ let fy=[0,0.222702589,0.328626759,0.428392355,0.520499878,
|
|
|
|
+ 0.603856091,0.677801194,0.742100965,0.796908212,
|
|
|
|
+ 0.842700793,0.880205070,0.910313978,0.934007945,
|
|
|
|
+ 0.952285120,0.966105146,0.976348383,
|
|
|
|
+ 0.983790459,0.989090502,0.992790429,0.995322265,
|
|
|
|
+ 0.997020533,0.998137154,0.998856823,0.999311486,
|
|
|
|
+ 0.999593048,0.999977910,0.999999257];
|
|
|
|
+ let n=32;
|
|
|
|
+ let i0=n-1;
|
|
|
|
+
|
|
|
|
+ for (let i=1;i<n;i++){
|
|
|
|
+ if (Math.abs(x)>fx[i]) continue;
|
|
|
|
+ i0=i-1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ let fval=1;
|
|
|
|
+ if (i0<n-1){
|
|
|
|
+ //interpolate
|
|
|
|
+ let y1=fy[i0+1];
|
|
|
|
+ let y0=fy[i0];
|
|
|
|
+ let x1=fx[i0+1];
|
|
|
|
+ let x0=fx[i0];
|
|
|
|
+ fval=y0+(y1-y0)/(x1-x0)*(Math.abs(x)-x0);
|
|
|
|
+ }
|
|
|
|
+ print('Erf: '+fval);
|
|
|
|
+ if (x<0) return -fval;
|
|
|
|
+ return fval;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function setLine(fbox,name,value,fontSize){
|
|
|
|
+ let fpId=fbox.id+name;
|
|
|
|
+ let fp=config.document.getElementById(fpId);
|
|
|
|
+ if (fp===null){
|
|
|
|
+ fp=config.document.createElement("p");
|
|
|
|
+ fp.id=fpId;
|
|
|
|
+ fbox.appendChild(fp);
|
|
|
|
+ }
|
|
|
|
+ fp.classList.add("center");
|
|
|
|
+ fp.style.textAlign="center";
|
|
|
|
+ fp.style.fontSize=fontSize;
|
|
|
|
+ fp.innerText=value;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function drawProbability(data,cell,obj,pid,probDensity){
|
|
|
|
+ print('drawProbability');
|
|
|
|
+ if (data.rows.length!=1){
|
|
|
|
+ print("drawProbability row length mismatch: "+data.rows.length);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //possible mismatch; I assume the dataset will have a field called value
|
|
|
|
+ let val=data.rows[0].value;
|
|
|
|
+
|
|
|
|
+ let prob=0;
|
|
|
|
+ let fz=-100;
|
|
|
|
+
|
|
|
|
+ if (probDensity.func=="gaus"){
|
|
|
|
+ fz=(val-probDensity.mean)/probDensity.sigma/Math.sqrt(2);
|
|
|
|
+ prob=0.5+0.5*erf(fz);
|
|
|
|
+ }
|
|
|
|
+ let color="red";
|
|
|
|
+ let fzx=fz*Math.sqrt(2);
|
|
|
|
+ print('drawProbability '+fzx);
|
|
|
|
+
|
|
|
|
+ for (let i=1;i<obj.intervals.n;i++){
|
|
|
|
+ if (fzx>obj.intervals.zlimits[i]) continue;
|
|
|
|
+ color=obj.intervals.colors[i-1];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let fboxId=cell.id+'_fbox_';
|
|
|
|
+ let fbox=config.document.getElementById(fboxId);
|
|
|
|
+ if (fbox===null){
|
|
|
|
+ fbox=config.document.createElement("div");
|
|
|
|
+ fbox.id=fboxId;
|
|
|
|
+ cell.appendChild(fbox);
|
|
|
|
+ }
|
|
|
|
+ fbox.style.backgroundColor=color;
|
|
|
|
+ fbox.style.width="180px";
|
|
|
|
+ fbox.style.height="180px";
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ print('organCode '+probDensity.organCode);
|
|
|
|
+ let organName="Lung";
|
|
|
|
+
|
|
|
|
+ if (probDensity.organCode==4){
|
|
|
|
+ organName="Thyroid";
|
|
|
|
+ }
|
|
|
|
+ if (probDensity.organCode==5){
|
|
|
|
+ organName="Bowel";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ setLine(fbox,'_fp4_',organName,"16px");
|
|
|
|
+ setLine(fbox,'_fp_',val.toPrecision(3),"25px");
|
|
|
|
+ setLine(fbox,'_fp1_',"SUV("+probDensity.percentile+"%)","16px");
|
|
|
|
+ setLine(fbox,'_fp2_',fzx.toPrecision(3),"25px");
|
|
|
|
+ setLine(fbox,'_fp3_',"z-value","16px");
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateReviewSection2(pid){
|
|
|
|
+
|
|
|
|
+ let listName=config.loadFileConfig.listName;
|
|
|
|
+ let id=config.loadFileConfig.id;
|
|
|
|
+
|
|
|
|
+ print('generateReviewSection2: '+pid.participantCode+'/'+
|
|
|
|
+ pid.visitCode);
|
|
|
|
+ if (pid.participantCode=="NONE" || pid.visitCode=="NONE"){
|
|
|
|
+ generateErrorMessage(id,listName,
|
|
|
|
+ "ParticipantId/visitId not set");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ print('JSON: '+config.loadFileConfig.json);
|
|
|
|
+
|
|
|
|
+ let json=config.loadFileConfig.json;
|
|
|
|
+ let nrows=json.rows.values.length;
|
|
|
|
+ let ncol=json.columns.length;
|
|
|
|
+
|
|
|
|
+ pid.basePath=getBasePath()+"/@files";
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let el=config.document.getElementById(id);
|
|
|
|
+ let tableId=id+'_Table';
|
|
|
|
+ let table=config.document.getElementById(tableId);
|
|
|
|
+ if (table==null){
|
|
|
|
+ table=config.document.createElement('table');
|
|
|
|
+ table.id=tableId;
|
|
|
|
+ el.appendChild(table);
|
|
|
|
+ }
|
|
|
|
+ table.style.tableLayout="fixed";
|
|
|
|
+ table.style.columnWidth="300px";
|
|
|
|
+
|
|
|
|
+ for (let i=0;i<nrows;i++){
|
|
|
|
+ pid[json.rows.variable]=json.rows.values[i];
|
|
|
|
+ //let organ=organs[i];
|
|
|
|
+ let row=null;
|
|
|
|
+ if (i<table.rows.length)
|
|
|
|
+ row=table.rows[i];
|
|
|
|
+ else
|
|
|
|
+ row=table.insertRow();
|
|
|
|
+
|
|
|
|
+ let ic=0;
|
|
|
|
+ for (let j=0;j<ncol;j++){
|
|
|
|
+ let obj=json.columns[j];
|
|
|
|
+ let nv=obj.values.length;
|
|
|
|
+ for (let k=0;k<nv;k++){
|
|
|
|
+ let cell=null;
|
|
|
|
+ if (ic<row.cells.length)
|
|
|
|
+ cell=row.cells[ic];
|
|
|
|
+ else
|
|
|
|
+ cell=row.insertCell();
|
|
|
|
+ if (obj.display=="image")
|
|
|
|
+ plotImage(cell,k,row,json.rows.variable,obj,pid);
|
|
|
|
+ if (obj.display=="report")
|
|
|
|
+ showReport(cell,k,row,json.rows.variable,obj,pid);
|
|
|
|
+ if (obj.display=="probability"){
|
|
|
|
+ showProbability(cell,k,row,json.rows,i,obj,pid);
|
|
|
|
+ }
|
|
|
|
+ ic++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+///>>>>>>>>>>>>>>end of reviewSection(REPORT)
|
|
|
|
+
|
|
|
|
+function generateReview(divReviewId,divReviewListId, listName, accessMode){
|
|
|
|
+ let listId=config.formConfig.fields[listName].queryId;
|
|
|
|
+
|
|
|
|
+ //listId is a number->should it be queryName?
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug) print("Generate review for: "+listId+'/'+listName);
|
|
|
|
+
|
|
|
|
+ let reviewSetup=generateSetup();
|
|
|
|
+ reviewSetup.readonlyFlag=function(vName){
|
|
|
|
+ if (vName=="queryName") return true;
|
|
|
|
+ if (vName=="queryname") return true;
|
|
|
|
+ if (vName=="ModifiedBy") return true;
|
|
|
|
+ return false;};
|
|
|
|
+ reviewSetup.addApply="Add Review";
|
|
|
|
+
|
|
|
|
+ let generateTableFlag=true;
|
|
|
|
+ let formStatus=config.formConfig.formStatus;
|
|
|
|
+ //COMMENTS allowed or not
|
|
|
|
+ //three levels of access: EDIT, COMMENT, READ
|
|
|
|
+ if (accessMode == "READ"){
|
|
|
|
+ //if (formStatus == "Approved" ){
|
|
|
|
+ delete reviewSetup.addApply;
|
|
|
|
+ reviewSetup.readonlyFlag=function(vName){return false;}
|
|
|
|
+ generateTableFlag=false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ reviewSetup.filters=new Object();
|
|
|
|
+ reviewSetup.filters["crfRef"]=getCRFref();
|
|
|
|
+
|
|
|
|
+ reviewSetup.filters["queryName"]=listId;//entry in reviewComments list is queryname, all in small caps
|
|
|
|
+ //needs listName, in argument
|
|
|
|
+
|
|
|
|
+ reviewSetup.getInputId=function(vName){return divReviewId+"_add"+vName};
|
|
|
|
+ reviewSetup.divReviewListId=divReviewListId;
|
|
|
|
+ reviewSetup.isReview=true;
|
|
|
|
+
|
|
|
|
+ if (debug) {
|
|
|
|
+ let msg="Review: divId: "+divReviewId;
|
|
|
|
+ //msg+=" inputId: "+reviewSetup.getInputId;
|
|
|
|
+ print(msg);
|
|
|
|
+ }
|
|
|
|
+ updateListDisplay(divReviewListId,"reviewComments",reviewSetup.filters,true);
|
|
|
|
+
|
|
|
|
+ if (! generateTableFlag) return;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ generateTable("reviewComments",divReviewId,new Object(),reviewSetup);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//>>>>>>>>>>trigger visibility of additional lists
|
|
|
|
+
|
|
|
|
+function setListVisibility(input,setup,readonlyFlag){
|
|
|
|
+ let debug=true;
|
|
|
|
+ let fName="[setListVisibility/"+setup.queryName+"]";
|
|
|
|
+ print(fName);
|
|
|
|
+ let additionalData=config.formConfig.additionalData[setup.queryName];
|
|
|
|
+
|
|
|
|
+ let x = config.document.getElementById(additionalData.divName);
|
|
|
|
+ if (debug) print(fName+": Div: "+x);
|
|
|
|
+ x.style.display="none";
|
|
|
|
+
|
|
|
|
+ let sText;
|
|
|
|
+ if ("setVariable" in input){
|
|
|
|
+ sText=input.setVariable;
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ if (readonlyFlag) sText=input.innerText;
|
|
|
|
+ else sText=input.options[input.selectedIndex].text;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (debug) print(fName+": Selected option text: "+sText);
|
|
|
|
+
|
|
|
|
+ if (sText == additionalData.showFlagValue){
|
|
|
|
+ let filters=new Object();
|
|
|
|
+ if ("filters" in additionalData) filters=additionalData.filters;
|
|
|
|
+ x.style.display = "block";
|
|
|
|
+ updateListDisplay(additionalData.divQueryName,
|
|
|
|
+ additionalData.queryName,filters,readonlyFlag);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//>>have list refresh when data is added (not optimal yet)
|
|
|
|
+
|
|
|
|
+function updateListDisplay(divName,queryName,filters,readonlyFlag){
|
|
|
|
+ //use Labkey.QueryWebPart to show list
|
|
|
|
+
|
|
|
|
+ let debug=true;
|
|
|
|
+ let fName="[updateListDisplay]";
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print(fName+": Query - "+queryName
|
|
|
|
+ +" div - "+divName);
|
|
|
|
+
|
|
|
|
+ if (divName=="NONE") return;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let crfRef=getCRFref();
|
|
|
|
+ let div=config.document.getElementById(divName);
|
|
|
|
+ print(fName+": setting border");
|
|
|
|
+ div.style.border="thin solid black";
|
|
|
|
+ div.style.width="800px";
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print(fName+": generating WebPart: "+queryName);
|
|
|
|
+
|
|
|
|
+ var qconfig=new Object();
|
|
|
|
+ qconfig.renderTo=divName;
|
|
|
|
+ //point to data container
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.queryName=queryName;
|
|
|
|
+ qconfig.buttonBarPosition='top';
|
|
|
|
+ qconfig.filters=[];
|
|
|
|
+ for (f in filters){
|
|
|
|
+ qconfig.filters.push(LABKEY.Filter.create(f, filters[f]));
|
|
|
|
+ }
|
|
|
|
+ qconfig.success=updateSuccess;
|
|
|
|
+ qconfig.failure=updateFailure;
|
|
|
|
+ //show only print button
|
|
|
|
+ if (readonlyFlag){
|
|
|
|
+ qconfig.buttonBar=new Object();
|
|
|
|
+ qconfig.buttonBar.items=["print"];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ LABKEY.QueryWebPart(qconfig);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function updateSuccess(data){
|
|
|
|
+ print("Update success");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function updateFailure(data){
|
|
|
|
+ print("Update failed");
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function toggleVisibility(sectionId,buttonName){
|
|
|
|
+ let fName='[toggleVisibility/'+sectionId+']';
|
|
|
|
+ print(fName);
|
|
|
|
+
|
|
|
|
+ let x = config.document.getElementById(sectionId);
|
|
|
|
+ if (x.style.display === "none") {
|
|
|
|
+ //exclude non data sections (like debug)...
|
|
|
|
+ print(fName+': issuing setData(populateSection)');
|
|
|
|
+ x.style.display = "block";
|
|
|
|
+ config.document.getElementById(buttonName).value="Hide";
|
|
|
|
+ let cb=function(){populateSection(sectionId);};
|
|
|
|
+ setData(cb);
|
|
|
|
+
|
|
|
|
+ } else {
|
|
|
|
+ x.style.display = "none";
|
|
|
|
+ config.document.getElementById(buttonName).value="Show";
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateButtonBU(divName,title,buttonName,callback,
|
|
|
|
+ callbackParameters){
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug) print("generateButtonBU");
|
|
|
|
+
|
|
|
|
+ let tb=config.document.createElement('table');
|
|
|
|
+ tb.className="t2";
|
|
|
|
+
|
|
|
|
+ let r1=tb.insertRow();
|
|
|
|
+ th=config.document.createElement('th');
|
|
|
|
+ r1.appendChild(th);
|
|
|
|
+ th.innerHTML=title;
|
|
|
|
+ //*!*
|
|
|
|
+ let c2=r1.insertCell();
|
|
|
|
+ let i1=config.document.createElement("input");
|
|
|
|
+ i1.type="button";
|
|
|
|
+ i1.value=buttonName;
|
|
|
|
+ i1.style.fontSize="20px";
|
|
|
|
+ i1.onclick=function(){callback(callbackParameters);}
|
|
|
|
+ c2.appendChild(i1);
|
|
|
|
+
|
|
|
|
+ let c1=r1.insertCell();
|
|
|
|
+ c1.setAttribute("colspan","1");
|
|
|
|
+ c1.id=callbackParameters.submitReportId;
|
|
|
|
+
|
|
|
|
+ let el=config.document.getElementById(divName);
|
|
|
|
+ if (debug) print("generateButton: element["+divName+"]: "+el);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ el.appendChild(tb);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateButton(divName,caption,label,callbackLabel,callback){
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug) print("generateButtonX");
|
|
|
|
+
|
|
|
|
+ let tb=config.document.createElement('table');
|
|
|
|
+ tb.className="t2";
|
|
|
|
+
|
|
|
|
+ let r1=tb.insertRow();
|
|
|
|
+ th=config.document.createElement('th');
|
|
|
|
+ r1.appendChild(th);
|
|
|
|
+ th.innerHTML=caption;
|
|
|
|
+ //*!*
|
|
|
|
+ let c2=r1.insertCell();
|
|
|
|
+ let i1=config.document.createElement("input");
|
|
|
|
+ i1.type="button";
|
|
|
|
+ i1.value=label;
|
|
|
|
+ i1.style.fontSize="20px";
|
|
|
|
+ i1.onclick=callback;
|
|
|
|
+ i1.id='button_'+callbackLabel;
|
|
|
|
+ c2.appendChild(i1);
|
|
|
|
+
|
|
|
|
+ let c1=r1.insertCell();
|
|
|
|
+ c1.setAttribute("colspan","1");
|
|
|
|
+ //this is only for saveReview?
|
|
|
|
+ c1.id=divName+'_reportField';
|
|
|
|
+ //c1.id=config.submitReportId;
|
|
|
|
+
|
|
|
|
+ let el=config.document.getElementById(divName);
|
|
|
|
+ if (debug) print("generateButton: element["+divName+"]: "+el);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ el.appendChild(tb);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateSubQuery(input, setup, readonlyFlag){
|
|
|
|
+ let fName="[generateSubQuery]";
|
|
|
|
+ if (setup.isReview) return;
|
|
|
|
+
|
|
|
|
+ if (!(setup.queryName in config.formConfig.additionalData)){
|
|
|
|
+ print(fName+': no additionalData entry (probably a subquery)');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let additionalData=config.formConfig.additionalData[setup.queryName];
|
|
|
|
+ if (!("showFlag" in additionalData))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ print(fName);
|
|
|
|
+
|
|
|
|
+ let expId=setup.getInputId(additionalData.showFlag);
|
|
|
|
+ if (expId!=input.id) {
|
|
|
|
+ print(fName+": ignoring field "+input.id+"/"+expId);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ print(fName+": Setting onChange to "+input.id);
|
|
|
|
+ if (!readonlyFlag)
|
|
|
|
+ input.onchange=function(){setListVisibility(input,setup,readonlyFlag)};
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//>>populate fields
|
|
|
|
+//
|
|
|
|
+//
|
|
|
|
+//split to field generation and field population
|
|
|
|
+//
|
|
|
|
+function addFieldRow(tb,field,setup,additionalData){
|
|
|
|
+
|
|
|
|
+ let fName="[addFieldRow/"+setup.queryName+':'+field.name+']';
|
|
|
|
+
|
|
|
|
+ let vName=field.name;
|
|
|
|
+ let vType=field.type;
|
|
|
|
+ let isLookup=("lookup" in field);
|
|
|
|
+ print(fName+": ["+vName+"/"+vType+'/'+isLookup+"]");
|
|
|
|
+
|
|
|
|
+ let row=tb.insertRow();
|
|
|
|
+ let cell=config.document.createElement('th');
|
|
|
|
+ row.appendChild(cell);
|
|
|
|
+
|
|
|
|
+ let text = config.document.createTextNode(field.shortCaption);
|
|
|
|
+ cell.appendChild(text);
|
|
|
|
+ let cell1=row.insertCell();
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let input=null;
|
|
|
|
+ cell1.colSpan="3";
|
|
|
|
+
|
|
|
|
+ let readonlyFlag=setup.readonlyFlag(vName);
|
|
|
|
+
|
|
|
|
+ print(fName+' inputType '+field.inputType);
|
|
|
|
+ //set the html input object
|
|
|
|
+ while (1){
|
|
|
|
+
|
|
|
|
+ if (readonlyFlag){
|
|
|
|
+ input=config.document.createElement('label');
|
|
|
|
+ input.innerText='Loading';
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //lookup
|
|
|
|
+ if (isLookup){
|
|
|
|
+ input = config.document.createElement("select");
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //date
|
|
|
|
+ if (vType=="date"){
|
|
|
|
+ input = config.document.createElement("input");
|
|
|
|
+ input.type="date";
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //string
|
|
|
|
+ if (vType=="string"){
|
|
|
|
+ //we have to make sure UNDEF is carried to below
|
|
|
|
+ //since we are adapting file to either show
|
|
|
|
+ //current file or allow user to select a file
|
|
|
|
+ //
|
|
|
|
+ //TODO change this so one can always select file
|
|
|
|
+ //but also show the selected file
|
|
|
|
+
|
|
|
|
+ if(vName.search("reviewComment")>-1){
|
|
|
|
+ input = config.document.createElement("textarea");
|
|
|
|
+ input.cols="65";
|
|
|
|
+ input.rows="5";
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (field.inputType=="textarea"){
|
|
|
|
+ input = config.document.createElement("textarea");
|
|
|
|
+ input.cols="65";
|
|
|
|
+ input.rows="5";
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ input=config.document.createElement('input');
|
|
|
|
+ input.type="text";
|
|
|
|
+
|
|
|
|
+ if (vName.search('_file_')<0) break;
|
|
|
|
+ cell1.setAttribute('colspan',"1");
|
|
|
|
+ let cell2=row.insertCell();
|
|
|
|
+ cell2.setAttribute('colspan',"2");
|
|
|
|
+ let input1=config.document.createElement('input');
|
|
|
|
+ input1.type="file";
|
|
|
|
+ input1.id=setup.getInputId(vName)+'_file_';
|
|
|
|
+ cell2.appendChild(input1);
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (vType=="float"){
|
|
|
|
+ input = config.document.createElement("input");
|
|
|
|
+ input.type="text";
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (vType=="boolean"){
|
|
|
|
+ input = config.document.createElement("input");
|
|
|
|
+ input.type="checkbox";
|
|
|
|
+ print("Creating checkbox");
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ input.id=setup.getInputId(vName);
|
|
|
|
+ cell1.appendChild(input);
|
|
|
|
+ print(fName+': adding element '+input.id);
|
|
|
|
+ print(fName+': listing element '+config.document.getElementById(input.id));
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //connect associated list
|
|
|
|
+ generateSubQuery(input,setup,readonlyFlag);
|
|
|
|
+
|
|
|
|
+ if (readonlyFlag) {
|
|
|
|
+ print(fName+': exiting(readonlyFlag)');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!isLookup) {
|
|
|
|
+ print(fName+': exiting (not lookup)');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let lookup=field["lookup"];
|
|
|
|
+
|
|
|
|
+ //get all values from config.formConfig.lookup[X]
|
|
|
|
+ let lObject=config.formConfig.lookup[lookup.queryName];
|
|
|
|
+
|
|
|
|
+ //debug
|
|
|
|
+ print(fName+": query: "+lookup.queryName);
|
|
|
|
+ print(fName+": ElementId: "+input.id);
|
|
|
|
+ print(fName+": No of options: " +lObject.LUT.length);
|
|
|
|
+ print(fName+": Element: "+input);
|
|
|
|
+
|
|
|
|
+ //set the lut value (input is text label) for readonly
|
|
|
|
+ input.style.textAlign="center";
|
|
|
|
+ //input.style.textAlignLast="center";
|
|
|
|
+
|
|
|
|
+ //clear existing fields from input
|
|
|
|
+ for(let i = input.options.length; i >= 0; i--) {
|
|
|
|
+ input.remove(i);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //create option -1
|
|
|
|
+ let opt = config.document.createElement("option");
|
|
|
|
+ opt.text = "<Select>";
|
|
|
|
+ opt.value = -1;
|
|
|
|
+ input.options[0] = opt;
|
|
|
|
+ print(fName+": Adding <Select>");
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //add other, label them with LUT
|
|
|
|
+ for (let v in lObject.LUT) {
|
|
|
|
+ print(fName+': populating '+v+': '+lObject.LUT[v]);
|
|
|
|
+
|
|
|
|
+ let opt = config.document.createElement("option");
|
|
|
|
+ opt.text = lObject.LUT[v];
|
|
|
|
+ opt.value = v;
|
|
|
|
+ input.options[input.options.length] = opt;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ input.selectedIndex=0;
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function selectEntry(entryRows,setVariables){
|
|
|
|
+ let fName='[selectEntry]';
|
|
|
|
+ for (let i=0;i<entryRows.length;i++){
|
|
|
|
+ let tE=entryRows[i];
|
|
|
|
+ //this could be empty, end will be reached
|
|
|
|
+ let doContinue=false;
|
|
|
|
+ for (v in setVariables){
|
|
|
|
+ print(fName+' '+v+' '+tE[v]+'/'+setVariables[v]);
|
|
|
|
+ if (tE[v]!=setVariables[v]){
|
|
|
|
+ doContinue=true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (doContinue) continue;
|
|
|
|
+ return tE;
|
|
|
|
+ }
|
|
|
|
+ let tE=Object();
|
|
|
|
+ tE['notValid']=true;
|
|
|
|
+ return tE;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function populateFieldRow(entry,field,setup){
|
|
|
|
+
|
|
|
|
+ if (!(field.name in setup.setVariables))
|
|
|
|
+ populateField(entry,field,setup);
|
|
|
|
+ populateSubQuery(entry,field,setup);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function populateSubQuery(entry,field,setup){
|
|
|
|
+ let fName='[populateSubQuery/'+setup.queryName+':'+field.name+']';
|
|
|
|
+ if (setup.isReview) return;
|
|
|
|
+
|
|
|
|
+ if (!(setup.queryName in config.formConfig.additionalData)){
|
|
|
|
+ let msg=fName+': no additionalData entry for '+setup.queryName;
|
|
|
|
+ msg+=' (probably a subquery)';
|
|
|
|
+ print(msg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //find if field is connected to a sub array
|
|
|
|
+ //find queryName
|
|
|
|
+ //
|
|
|
|
+ let additionalData=config.formConfig.additionalData[setup.queryName];
|
|
|
|
+ print(fName);
|
|
|
|
+ //let flag=additionalData.showFlag;
|
|
|
|
+
|
|
|
|
+ if (!("showFlag" in additionalData)) return;
|
|
|
|
+ let eId=setup.getInputId(additionalData.showFlag);
|
|
|
|
+ let id=setup.getInputId(field.name);
|
|
|
|
+
|
|
|
|
+ if (eId!=id) {
|
|
|
|
+ print(fName+": X ignoring field "+id+"/"+eId);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ print(fName+': id '+id);
|
|
|
|
+ //hard to estimate readonlyFlag
|
|
|
|
+ //
|
|
|
|
+ let readonlyFlag=setup.readonlyFlag(field.name);
|
|
|
|
+
|
|
|
|
+ let input=config.document.getElementById(id);
|
|
|
|
+ if (input){
|
|
|
|
+ let eType=input.nodeName.toLowerCase();
|
|
|
|
+ readonlyFlag=eType!="select";
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ input=new Object();
|
|
|
|
+ input.setVariable=getLookupLabel(field,setup.setVariables[field.name])
|
|
|
|
+ }
|
|
|
|
+ setListVisibility(input,setup,readonlyFlag);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getLookupLabel(field,value){
|
|
|
|
+ let lookup=field["lookup"];
|
|
|
|
+ //get all values from config.formConfig.lookup[X]
|
|
|
|
+ let lObject=config.formConfig.lookup[lookup.queryName];
|
|
|
|
+ return lObject.LUT[value];
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function populateField(entry,field,setup){
|
|
|
|
+
|
|
|
|
+ let vName=field.name;
|
|
|
|
+ let fName='[populateFieldName/'+vName+']';
|
|
|
|
+
|
|
|
|
+ let varValue="UNDEF";
|
|
|
|
+
|
|
|
|
+ //if (vName in setup.filters) varValue=setup.filters[vName];
|
|
|
|
+ if (vName in entry) varValue=entry[vName];
|
|
|
|
+ //if part of the filter, set it to value
|
|
|
|
+ if (vName in setup.filters) varValue=setup.filters[vName];
|
|
|
|
+
|
|
|
|
+ let isLookup=("lookup" in field);
|
|
|
|
+
|
|
|
|
+ print(fName+' v='+varValue+'/'+isLookup+' ['+
|
|
|
|
+ setup.getInputId(field.name)+']');
|
|
|
|
+
|
|
|
|
+ let vType=field.type;
|
|
|
|
+ let id=setup.getInputId(vName);
|
|
|
|
+ let input=config.document.getElementById(id);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //date
|
|
|
|
+ if (vType=="date"){
|
|
|
|
+ if (varValue==="UNDEF") varValue=new Date();
|
|
|
|
+ else varValue=new Date(varValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //lookup for readonly
|
|
|
|
+ if (isLookup && varValue!="UNDEF"){
|
|
|
|
+ varValue=getLookupLabel(field,varValue);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ print('Element: '+input);
|
|
|
|
+ //figure out the element type
|
|
|
|
+ let eType=input.nodeName.toLowerCase();
|
|
|
|
+ print('Element type: '+eType);
|
|
|
|
+ print('Value '+varValue);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //change varValue for printing
|
|
|
|
+ if (varValue=="UNDEF") varValue="";
|
|
|
|
+ //HTMLTextArea, createElement(textArea)
|
|
|
|
+ if (eType==="textarea"){
|
|
|
|
+ input.value=varValue;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //Text, createTextNode
|
|
|
|
+ if (eType==="#text"){
|
|
|
|
+ input.nodeValue=varValue;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //HTMLLabelElement, createElement('label')
|
|
|
|
+ if (eType==="label"){
|
|
|
|
+ input.innerText=varValue;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //HTMLSelectElement, createElement('select')
|
|
|
|
+ if (eType==="select"){
|
|
|
|
+ input.selectedIndex=0;
|
|
|
|
+ for (let i=0;i<input.options.length;i++){
|
|
|
|
+ let v=input.options[i].text;
|
|
|
|
+ if (v!=varValue) continue;
|
|
|
|
+ input.selectedIndex=i;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (eType!="input"){
|
|
|
|
+ print('Unknown type: '+eType+' encountered, igonring');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //HTMLInputElement
|
|
|
|
+ let type=input.type;
|
|
|
|
+
|
|
|
|
+ if (type=="date"){
|
|
|
|
+ input.valueAsDate=varValue;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //string,float
|
|
|
|
+ if (type=="text"){
|
|
|
|
+ input.value=varValue;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //boolean
|
|
|
|
+ if (type=="checkbox"){
|
|
|
|
+ input.checked=varValue;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ print('Unknown input type: '+type+'. Ignoring.');
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function populateTable(listName,writeMode,setup){
|
|
|
|
+//function populateTable(formSetupEntry){
|
|
|
|
+ //let listName=config.formConfig.queryMap[formSetupEntry['queryName']];
|
|
|
|
+ //let accessMode=config.formConfig.operator+'Mode';
|
|
|
|
+ //let writeMode=formSetupEntry[accessMode]=='EDIT';
|
|
|
|
+
|
|
|
|
+ let fName='[populateTable/'+listName+']';
|
|
|
|
+ print(fName+' setup '+setup);
|
|
|
|
+
|
|
|
|
+ //data snapshot
|
|
|
|
+ let fQuery=config.formConfig.dataQueries[listName];
|
|
|
|
+
|
|
|
|
+ //here I assume that listName was parsed during setDataLayout and setData
|
|
|
|
+ //so that rows was set (even if they are empty)
|
|
|
|
+ print(fName+"]: nrows "+fQuery.rows.length);
|
|
|
|
+
|
|
|
|
+ //this makes sure that matching versus set variables is performed
|
|
|
|
+ //only entry with matching value of setVariable will be selected
|
|
|
|
+ let entry=selectEntry(fQuery.rows,setup.setVariables);
|
|
|
|
+
|
|
|
|
+ let fields=fQuery.fields;
|
|
|
|
+ let helpRows=new Array();
|
|
|
|
+
|
|
|
|
+ for (f in fields){
|
|
|
|
+ let field=fields[f];
|
|
|
|
+ //each field is a new row
|
|
|
|
+ print(fName+": Adding field: "+f+'/'+field.name+' hidden: '+field.hidden);
|
|
|
|
+ if (field.hidden) continue;
|
|
|
|
+ if (field.name=="crfRef") continue;
|
|
|
|
+ populateFieldRow(entry,field,setup);
|
|
|
|
+ let helpItem=getHelpItem(field,setup);
|
|
|
|
+ if (helpItem) helpRows.push(helpItem);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ populateHelp(listName,helpRows,setup);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getHelpVar(queryName,code,setup){
|
|
|
|
+ let fName='[getHelpVar]';
|
|
|
|
+ print(fName+' code '+code);
|
|
|
|
+ let subs=code.match(/_[^_]*_/g);
|
|
|
|
+ if (!subs){
|
|
|
|
+ print(fName+' no match for '+code);
|
|
|
|
+ return code;
|
|
|
|
+ }
|
|
|
|
+ let rpc=new Object();
|
|
|
|
+ for (let i=0;i<subs.length;i++){
|
|
|
|
+ let c=subs[i].replace(/_/g,'');
|
|
|
|
+ print(fName+' ['+i+'] '+c);
|
|
|
|
+ let qf=c.match(/\[[^\]]*\]/g);
|
|
|
|
+ let lField=undefined;
|
|
|
|
+ if (qf){
|
|
|
|
+ qf[0]=qf[0].replace(/[\[\]]/g,'');
|
|
|
|
+ lField=qf[0];
|
|
|
|
+ print(fName+' lField '+lField);
|
|
|
|
+ }
|
|
|
|
+ //drop field
|
|
|
|
+ c=c.replace(/\[[^\]]*\]/,'');
|
|
|
|
+
|
|
|
|
+ //field in lookup (if not lookup.keyColumn)
|
|
|
|
+ //query
|
|
|
|
+ let query=queryName;
|
|
|
|
+ let vField=c;
|
|
|
|
+ let qq=c.split(':');
|
|
|
|
+ if (qq.length>1){
|
|
|
|
+ query=qq[0];
|
|
|
|
+ vField=qq[1];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let value='';
|
|
|
|
+ if (vField in setup.setVariables){
|
|
|
|
+ value=setup.setVariables[vField];
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ //robustify
|
|
|
|
+ if (!(query in config.formConfig.dataQueries)){
|
|
|
|
+ print(fName+' query '+query+' not available, check configuration');
|
|
|
|
+ return "INVALID";
|
|
|
|
+ }
|
|
|
|
+ if (config.formConfig.dataQueries[query].rows.length==0){
|
|
|
|
+ print(fName+' returning INVALID');
|
|
|
|
+ return "INVALID";
|
|
|
|
+ }
|
|
|
|
+ value=config.formConfig.dataQueries[query].rows[0][vField];
|
|
|
|
+ }
|
|
|
|
+ print(fName+' query '+query+' vField '+vField+' value '+value);
|
|
|
|
+ if (lField==undefined){
|
|
|
|
+ rpc[subs[i]]=value;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ let fQuery=config.formConfig.dataQueries[query];
|
|
|
|
+ //variable vField must be a lookup
|
|
|
|
+ //let field=fQuery.fields[vField];
|
|
|
|
+ let field=undefined;
|
|
|
|
+ for (let f in fQuery.fields){
|
|
|
|
+ if (fQuery.fields[f].name==vField){
|
|
|
|
+ field=fQuery.fields[f];
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ let lookup=config.formConfig.lookup[field.lookup.queryName];
|
|
|
|
+
|
|
|
|
+ for (let j=0;j<lookup.rows.length;j++){
|
|
|
|
+ let o=lookup.rows[j];
|
|
|
|
+ if (o[lookup.keyColumn]==value){
|
|
|
|
+ rpc[subs[i]]=o[lField];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ for (let x in rpc){
|
|
|
|
+ code=code.replace(x,rpc[x]);
|
|
|
|
+ }
|
|
|
|
+ print(fName+' returning '+code);
|
|
|
|
+ return code;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getHelpItem(field,setup){
|
|
|
|
+ if (!("help" in setup)) return undefined;
|
|
|
|
+
|
|
|
|
+ let fName='[getHelpItem]';
|
|
|
|
+ print(fName);
|
|
|
|
+
|
|
|
|
+ for (let i=0;i<setup["help"].rows.length;i++){
|
|
|
|
+ if (setup["help"].rows[i]["variable"]==field.name){
|
|
|
|
+ helpItem=new Object();
|
|
|
|
+ helpItem.setup=setup["help"].rows[i];
|
|
|
|
+ helpItem.field=field;
|
|
|
|
+ print(fName+' adding help for '+field.name);
|
|
|
|
+ return helpItem;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return undefined;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateHelp(tb,helpRows,setup){
|
|
|
|
+ let fName='[generateHelp]';
|
|
|
|
+ for (let i=0; i<helpRows.length; i++){
|
|
|
|
+ let eh=helpRows[i];
|
|
|
|
+ let row=tb.insertRow();
|
|
|
|
+ let th=config.document.createElement('th');
|
|
|
|
+ row.appendChild(th);
|
|
|
|
+ th.innerHTML=eh.setup['helpTitle'];
|
|
|
|
+ let cell=row.insertCell();
|
|
|
|
+ cell.setAttribute('colspan','3');
|
|
|
|
+ let el=config.document.createElement('textarea');
|
|
|
|
+ //el.id=sectionId+'_help';
|
|
|
|
+ el.cols="70";
|
|
|
|
+ el.rows="10";
|
|
|
|
+ el.value="Loading";
|
|
|
|
+ el.id=setup.sectionId+"_help"+eh.setup['Key'];
|
|
|
|
+ print(fName+' creating '+el.id);
|
|
|
|
+ cell.appendChild(el);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function populateHelp(listName,helpRows,setup){
|
|
|
|
+ let fName='[populateHelp]';
|
|
|
|
+ print(fName);
|
|
|
|
+ for (let i=0; i<helpRows.length; i++){
|
|
|
|
+ let eh=helpRows[i];
|
|
|
|
+ let id=setup.sectionId+'_help'+eh.setup['Key']
|
|
|
|
+ let el=config.document.getElementById(id);
|
|
|
|
+ let lookup=eh.field['lookup'];
|
|
|
|
+ let qName=lookup.queryName;
|
|
|
|
+ let tLookup=config.formConfig.lookup[qName];
|
|
|
|
+ let varName=getHelpVar(listName,eh.setup['fieldDescriptor'],setup);
|
|
|
|
+ if (varName=="INVALID"){
|
|
|
|
+ el.value="Please select patient/timepoint";
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ let text="";
|
|
|
|
+ for (let j=0;j<tLookup.rows.length;j++){
|
|
|
|
+ //print(tLookup.rows[j][tLookup.keyColumn]+' '+tLookup.rows[j][tLookup.displayColumn]+
|
|
|
|
+ //' '+tLookup.rows[j][varName]);
|
|
|
|
+ text+=tLookup.rows[j][tLookup.displayColumn]+" - "+tLookup.rows[j][varName]+"\n";
|
|
|
|
+ }
|
|
|
|
+ print(fName+' setting '+id+': '+el);
|
|
|
|
+ el.value=text;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function generateTable(listName,divName,additionalData,setup){
|
|
|
|
+ let debug=true;
|
|
|
|
+ let fName="[generateTable/"+listName+"]";
|
|
|
|
+ if (debug) print(fName);
|
|
|
|
+
|
|
|
|
+ //is listName and setup.queryName a duplicate of the same value
|
|
|
|
+ print(fName+': setup.queryName '+setup.queryName);
|
|
|
|
+ //assume data is set in config.formConfig.dataQueries[data.queryName].rows;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //data snapshot
|
|
|
|
+ let fQuery=config.formConfig.dataQueries[listName];
|
|
|
|
+
|
|
|
|
+ //here I assume that listName was parsed during setDataLayout and setData
|
|
|
|
+ //so that rows was set (even if they are empty)
|
|
|
|
+ print(fName+": Nrows "+fQuery.rows.length);
|
|
|
|
+
|
|
|
|
+ let entry=selectEntry(fQuery.rows,setup.setVariables);
|
|
|
|
+
|
|
|
|
+ let tb=config.document.createElement('table');
|
|
|
|
+ tb.className="t2";
|
|
|
|
+ config.document.getElementById(divName).appendChild(tb);
|
|
|
|
+
|
|
|
|
+ //this are the fields (probably constant)
|
|
|
|
+ let fields=fQuery.fields;
|
|
|
|
+ let helpRows=new Array();
|
|
|
|
+
|
|
|
|
+ for (f in fields){
|
|
|
|
+ let field=fields[f];
|
|
|
|
+ //each field is a new row
|
|
|
|
+ print(fName+": Adding field: "+f+'/'+field.name);
|
|
|
|
+ if (field.hidden) continue;
|
|
|
|
+ if (field.name=="crfRef") continue;
|
|
|
|
+ //do not expose fields indicated in setVariables
|
|
|
|
+ if (field.name in setup.setVariables) continue;
|
|
|
|
+ addFieldRow(tb,field,setup,additionalData);
|
|
|
|
+ populateFieldRow(entry,field,setup);
|
|
|
|
+ let helpItem=getHelpItem(field,setup);
|
|
|
|
+ if (helpItem) helpRows.push(helpItem);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ generateHelp(tb,helpRows,setup);
|
|
|
|
+ populateHelp(listName,helpRows,setup);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //add comment field
|
|
|
|
+ if (!("addApply" in setup)) {
|
|
|
|
+ print(fName+"generateTable: done");
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let row=tb.insertRow();
|
|
|
|
+
|
|
|
|
+ let th=config.document.createElement('th');
|
|
|
|
+ row.appendChild(th);
|
|
|
|
+ th.innerHTML=setup.addApply;
|
|
|
|
+ let cell=row.insertCell();
|
|
|
|
+ //cell.setAttribute("colspan","2");
|
|
|
|
+ let input=config.document.createElement("input");
|
|
|
|
+ input.type="button";
|
|
|
|
+ input.value=setup.addApply;
|
|
|
|
+ cell.appendChild(input);
|
|
|
|
+ let cell1=row.insertCell();
|
|
|
|
+ cell1.setAttribute("colspan","2");
|
|
|
|
+ cell1.id=setup.getInputId("rerviewLastSave");
|
|
|
|
+ cell1.innerHTML="No recent update";
|
|
|
|
+ //saveReview is a generic name for saving content of the html page to a list entry
|
|
|
|
+ input.onclick=function(){saveReview(listName,cell1.id,setup)};
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function saveReview(queryName,elementId,setup){
|
|
|
|
+ //loads any queryName
|
|
|
|
+
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug) print("saveReview: elementId "+elementId+" queryName "+queryName);
|
|
|
|
+ let useInsert=false;
|
|
|
|
+
|
|
|
|
+ if (!("unique" in setup)) useInsert=true;
|
|
|
|
+
|
|
|
|
+ let fQuery=config.formConfig.dataQueries[queryName];
|
|
|
|
+
|
|
|
|
+ let entry=selectEntry(fQuery.rows,setup.setVariables);
|
|
|
|
+
|
|
|
|
+ if ("notValid" in entry) useInsert=true;
|
|
|
|
+
|
|
|
|
+ if (useInsert) entry=new Object();
|
|
|
|
+
|
|
|
|
+ entry.crfRef=getCRFrefData();
|
|
|
|
+
|
|
|
|
+ if (debug) print("Set crfRef="+entry.crfRef);
|
|
|
|
+
|
|
|
|
+ //if ("queryName" in setup.filters) {
|
|
|
|
+ // entry.queryName=setup.filters["queryName"];
|
|
|
|
+ // if (debug) print("Setting queryName: "+entry.queryName);
|
|
|
|
+ //}
|
|
|
|
+
|
|
|
|
+ let fields=fQuery.fields;
|
|
|
|
+ for (f in fields){
|
|
|
|
+
|
|
|
|
+ let field=fields[f];
|
|
|
|
+ if (debug) print("saveReview field: "+field.name);
|
|
|
|
+ if (field.hidden) continue;
|
|
|
|
+
|
|
|
|
+ let vName=field.name;
|
|
|
|
+ let vType=field.type;
|
|
|
|
+
|
|
|
|
+ if (debug) print("vType: "+vType);
|
|
|
|
+
|
|
|
|
+ if (vName=="crfRef") continue;
|
|
|
|
+ //need to save queryName for reviewComments
|
|
|
|
+
|
|
|
|
+ let eId=setup.getInputId(vName);
|
|
|
|
+
|
|
|
|
+ let el=config.document.getElementById(eId);
|
|
|
|
+
|
|
|
|
+ if (!el) {
|
|
|
|
+ if (debug) print("saveReview element: "+eId+" not found");
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (debug) print("saveReview element: "+eId);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let eType=el.nodeName.toLowerCase();
|
|
|
|
+
|
|
|
|
+ if (eType==="select"){
|
|
|
|
+ entry[vName]=el.options[el.selectedIndex].value;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (eType==="td"){
|
|
|
|
+ entry[vName]=el.innerText;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (vType=="date"){
|
|
|
|
+ let date=el.valueAsDate;
|
|
|
|
+ if (date==="null") continue;
|
|
|
|
+ date.setUTCHours(12);
|
|
|
|
+ entry[vName]=date.toString();
|
|
|
|
+ print("Setting date to "+entry[vName]);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (vType=="string"){
|
|
|
|
+ entry[vName]=el.value;
|
|
|
|
+
|
|
|
|
+ if (vName.search('_file_')<0)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ //upload file
|
|
|
|
+ let id1=eId+'_file_';
|
|
|
|
+ let input1=config.document.getElementById(id1);
|
|
|
|
+ print('Attachment field: '+input1.value);
|
|
|
|
+ //entry[vName]=el.files[0].stream();
|
|
|
|
+ let ctx=new Object();
|
|
|
|
+ ctx['dirName']='consent';
|
|
|
|
+ ctx['ID']=entry['crfRef'];
|
|
|
|
+ //should point to data container
|
|
|
|
+ ctx['project']=getContainer('data');
|
|
|
|
+ //need ID->crf!
|
|
|
|
+ //assume crfRef will get set before this
|
|
|
|
+ //element is encountered
|
|
|
|
+ uploadFile(input1,ctx);
|
|
|
|
+ let fv=el.value;
|
|
|
|
+ let suf=fv.split('.').pop();
|
|
|
|
+ entry[vName]=entry['crfRef']+'.'+suf;
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ if (vType=="float" || vType=="int"){
|
|
|
|
+ entry[vName]=el.value;
|
|
|
|
+ if (vName=="queryName") {
|
|
|
|
+ print('Parsing queryName: '+el.innerText);
|
|
|
|
+ entry[vName]=config.formConfig.fields[el.innerText].queryId;
|
|
|
|
+ //use queryMap lookup
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (vType=="boolean"){
|
|
|
|
+ entry[vName]=el.checked;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //update values from setup.setVariables
|
|
|
|
+ for (v in setup.setVariables){
|
|
|
|
+ entry[v]=setup.setVariables[v];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.rows=[entry];
|
|
|
|
+ //should point to data container
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.queryName=queryName;
|
|
|
|
+
|
|
|
|
+ //only update comments
|
|
|
|
+ print("modifyRows: useInsert "+useInsert);
|
|
|
|
+ qconfig.success=function(data){updateLastSavedFlag(data,setup,elementId)};
|
|
|
|
+ if (!useInsert){
|
|
|
|
+ LABKEY.Query.updateRows(qconfig);
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ LABKEY.Query.insertRows(qconfig);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function updateLastSavedFlag(data,setup,elementId){
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug) print("Update last saved flag to "+elementId);
|
|
|
|
+ let el=config.document.getElementById(elementId);
|
|
|
|
+ let dt=new Date();
|
|
|
|
+ el.innerHTML="Last saved "+dt.toString();
|
|
|
|
+ if (data.queryName=="reviewComments"){
|
|
|
|
+ updateListDisplay(setup.divReviewListId,"reviewComments",setup.filters,true);
|
|
|
|
+ }
|
|
|
|
+ //refresh stored data!
|
|
|
|
+ let writeMode=!setup.readonlyFlag();
|
|
|
|
+ if ("unique" in setup)
|
|
|
|
+ setData(function (){populateTable(data.queryName,writeMode,setup);});
|
|
|
|
+ if ("masterQuery" in setup){
|
|
|
|
+ let ad=config.formConfig.additionalData[setup.masterQuery];
|
|
|
|
+ print('Updating list display: '+setup.queryName+'/'+ad.queryName);
|
|
|
|
+ updateListDisplay(ad.divQueryName,ad.queryName,ad.filters,false);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//******************************************upload to database *********************
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function onDatabaseUpload(){
|
|
|
|
+ let fName='[onDatabaseUpload]';
|
|
|
|
+ print(fName);
|
|
|
|
+ config.upload=new Object();
|
|
|
|
+ //figure out the participantId
|
|
|
|
+
|
|
|
|
+ let masterQueryId=config.formConfig.form["masterQuery"];
|
|
|
|
+ print(fName+': master query: '+masterQueryId);
|
|
|
|
+ let pidClass=new Object();
|
|
|
|
+ pidClass.afterId=afterParticipantId;
|
|
|
|
+ //use stored name of participantField
|
|
|
|
+ //for migrating data from lists to study
|
|
|
|
+ //this is to avoid conflicts in column assignments
|
|
|
|
+ //since datasets contain all fields of a list plus
|
|
|
|
+ //default fields of which participantId is one
|
|
|
|
+ pidClass.participantField=config.registrationParticipantIdField;
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.queryName=config.formConfig.queryMap[masterQueryId];
|
|
|
|
+ //queryMap holds mapping for queries in visit;
|
|
|
|
+ //masterQuery should be one of them, so this is safe.
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.filterArray=[LABKEY.Filter.create('crfRef',getCRFref())];
|
|
|
|
+ qconfig.success=function(data){afterRegistration(data,pidClass);};
|
|
|
|
+ LABKEY.Query.selectRows(qconfig);
|
|
|
|
+ //waitForCompleteUpload(config);//
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterRegistration(data,fc){
|
|
|
|
+ let fName='[afterRegistration/'+data.queryName+']';
|
|
|
|
+ print(fName+": rows:"+data.rows.length);
|
|
|
|
+ fc.registration=data;
|
|
|
|
+ let registrationData=fc.registration;
|
|
|
|
+ clearErr();
|
|
|
|
+ if (registrationData.rows.length!=1){
|
|
|
|
+ let msg=fName+": ERROR: Found "+registrationData.rows.length;
|
|
|
|
+ msg+=" registration entries for crfrefid "+getCRFref();
|
|
|
|
+ print(msg);
|
|
|
|
+ fc.afterId(fc);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ print(fName+'registration participant field: '+fc.participantField);
|
|
|
|
+ fc.participantId=registrationData.rows[0][fc.participantField];
|
|
|
|
+ //could be a lookup field (particularly for studies)
|
|
|
|
+ print('ID: '+fc.participantId);
|
|
|
|
+ let fields=registrationData.metaData.fields;
|
|
|
|
+ let field="NONE";
|
|
|
|
+ for (f in fields){
|
|
|
|
+ if (fields[f]["name"]==fc.participantField)
|
|
|
|
+ field=fields[f];
|
|
|
|
+ }
|
|
|
|
+ if ("lookup" in field){
|
|
|
|
+ let pid=fc.participantId;
|
|
|
|
+ print("Using lookup for participantId: "+pid);
|
|
|
|
+ let lookup=field["lookup"];
|
|
|
|
+ print("Lookup: ["+lookup.schemaName+','+lookup.queryName+']');
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ //should point to data container
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.schemaName=lookup.schemaName;
|
|
|
|
+ qconfig.queryName=lookup.queryName;
|
|
|
|
+ qconfig.filterArray=
|
|
|
|
+ [LABKEY.Filter.create(lookup.keyColumn,pid)];
|
|
|
|
+ qconfig.success=function(data){
|
|
|
|
+ afterRegistrationLookup(data,lookup.displayColumn,fc)};
|
|
|
|
+ LABKEY.Query.selectRows(qconfig);
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ //afterParticipantId(configUpload);
|
|
|
|
+ fc.afterId(fc);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterRegistrationLookup(data,displayColumn,fc){
|
|
|
|
+ print("afterRegistrationLookup");
|
|
|
|
+ let entry=data.rows[0];
|
|
|
|
+ fc.participantId=entry[displayColumn];
|
|
|
|
+ print('Setting to '+fc.participantId);
|
|
|
|
+ fc.afterId(fc);
|
|
|
|
+ //afterParticipantId(configUpload);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function afterParticipantId(fc){
|
|
|
|
+ print("Setting participantId to "+fc.participantId);
|
|
|
|
+ config.upload.participantId=fc.participantId;
|
|
|
|
+ //another select rows to update all queries from setup
|
|
|
|
+ //just use registration for test
|
|
|
|
+ let formSetupRows=config.formConfig.formSetupRows;
|
|
|
|
+ config.upload.queries=new Array();
|
|
|
|
+ print("Form rows: "+formSetupRows.length);
|
|
|
|
+ for (let i=0;i<formSetupRows.length;i++){
|
|
|
|
+ let entry=formSetupRows[i];
|
|
|
|
+ //skip reviews
|
|
|
|
+ if (entry.showFlag=="REVIEW") continue;
|
|
|
|
+ //use lookup table to convert from id to name
|
|
|
|
+ let queryName=config.formConfig.queryMap[entry.queryName];
|
|
|
|
+ config.upload.queries.push({queryName:queryName,queryStatus:"QUEUED"});
|
|
|
|
+ print('form ['+i+']='+queryName+' '+entry.showFlag+'/'+entry.showQuery);
|
|
|
|
+ if (entry.showQuery=="NONE")
|
|
|
|
+ continue;
|
|
|
|
+ config.upload.queries.push({queryName:entry.showQuery,queryStatus:"QUEUED"});
|
|
|
|
+ }
|
|
|
|
+ //add reviews
|
|
|
|
+ config.upload.queries.push({queryName:"reviewComments",queryStatus:"QUEUED"});
|
|
|
|
+ config.upload.queryId=0;
|
|
|
|
+ copyToDataset();
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function copyToDataset(){
|
|
|
|
+ let fName='[copyToDataset]: ';
|
|
|
|
+ print(fName+'['+config.upload.queryId+'/'+config.upload.queries.length+']');
|
|
|
|
+ //watch dog + scheduler
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ //watchdog part
|
|
|
|
+ if (config.upload.queryId==config.upload.queries.length) {
|
|
|
|
+ print(fName+'completing');
|
|
|
|
+ let targetStatus=config.formConfig.targetStatus['onDatabaseUpload'];
|
|
|
|
+ let targetRecipient=config.formConfig.targetRecipient['onDatabaseUpload'];
|
|
|
|
+ let action=new Object();
|
|
|
|
+ action.name='onDatabaseUpload';
|
|
|
|
+ action.cb=function(data){sendEmail(data,targetRecipient,redirect,'Form uploaded');}
|
|
|
|
+ updateFlag(targetStatus,action);//Approved
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //scheduler
|
|
|
|
+ let queryName=config.upload.queries[config.upload.queryId].queryName;
|
|
|
|
+ print("copyToDataset["+config.upload.queryId+"/"+
|
|
|
|
+ config.upload.queries.length+"]: "+queryName);
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.queryName=queryName;
|
|
|
|
+ qconfig.schemaName="lists";
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.filterArray=[LABKEY.Filter.create('crfRef',getCRFref())];
|
|
|
|
+ qconfig.success=afterListData;
|
|
|
|
+ LABKEY.Query.selectRows(qconfig);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterListData(data){
|
|
|
|
+ let fName='[afterListData]: ';
|
|
|
|
+
|
|
|
|
+ let queryName=config.upload.queries[config.upload.queryId].queryName;
|
|
|
|
+ print(fName+" ["+queryName+"/list]: "+data.rows.length+" entries");
|
|
|
|
+ config.upload.queries[config.upload.queryId].listData=data;
|
|
|
|
+ let id=config.upload.participantId;
|
|
|
|
+
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.queryName=queryName;
|
|
|
|
+ qconfig.schemaName="study";
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.filterArray=[LABKEY.Filter.create('crfRef',getCRFref())];
|
|
|
|
+ qconfig.filterArray.push(LABKEY.Filter.create('ParticipantId',id));
|
|
|
|
+ qconfig.success=afterStudyData;
|
|
|
|
+ LABKEY.Query.selectRows(qconfig);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function afterStudyData(data){
|
|
|
|
+
|
|
|
|
+ let fName='[afterStudyData]: ';
|
|
|
|
+ let queryObj=config.upload.queries[config.upload.queryId];
|
|
|
|
+ queryObj.studyData=data;
|
|
|
|
+
|
|
|
|
+ let msg=fName+"["+queryObj.queryName+"/study]: "+data.rows.length+" entries";
|
|
|
|
+ print(msg);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let listRows=queryObj.listData.rows;
|
|
|
|
+ //skip uploading an empty set
|
|
|
|
+ if (listRows.length==0){
|
|
|
|
+ printErr("List "+queryObj.queryName+" empty.");
|
|
|
|
+ queryObj.queryStatus="DONE";
|
|
|
|
+ config.upload.queryId+=1;
|
|
|
|
+ //back to watchdog
|
|
|
|
+ copyToDataset();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let studyRows=queryObj.studyData.rows;
|
|
|
|
+
|
|
|
|
+ for (let i=0;i<studyRows.length;i++){
|
|
|
|
+ let entry=studyRows[i];
|
|
|
|
+ //
|
|
|
|
+ if (! (i<listRows.length) ) continue;
|
|
|
|
+ let entryList=listRows[i];
|
|
|
|
+ //keeps study only variables (ParticipantId, SequenceNum)
|
|
|
|
+ for (let f in entryList) {
|
|
|
|
+ entry[f]=entryList[f];
|
|
|
|
+ print(fName+"Copying ["+f+"]: "+entry[f]+"/"+entryList[f]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ print(fName+' copying completed');
|
|
|
|
+
|
|
|
|
+ if (studyRows.length>0) {
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.queryName=queryObj.queryName;
|
|
|
|
+ qconfig.schemaName="study";
|
|
|
|
+ qconfig.rows=studyRows;
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.success=afterStudyUpload;
|
|
|
|
+ LABKEY.Query.updateRows(qconfig);
|
|
|
|
+ print(fName+'updateRows sent');
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ let data=new Object();
|
|
|
|
+ data.rows=new Array();
|
|
|
|
+ afterStudyUpload(data);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterStudyUpload(data){
|
|
|
|
+ let fName='[afterStudyUpload] ';
|
|
|
|
+ print(fName);
|
|
|
|
+ //let participantField=config.participantField;
|
|
|
|
+ let participantField=config.formConfig.studyData["SubjectColumnName"];
|
|
|
|
+ print(fName+' participantField: '+participantField);
|
|
|
|
+
|
|
|
|
+ let queryObj=config.upload.queries[config.upload.queryId];
|
|
|
|
+ let queryName=queryObj.queryName;
|
|
|
|
+ printErr("Updated "+data.rows.length+" rows to "+queryName);
|
|
|
|
+
|
|
|
|
+ let studyRows=queryObj.studyData.rows;
|
|
|
|
+ let listRows=queryObj.listData.rows;
|
|
|
|
+
|
|
|
|
+ let rows=new Array();
|
|
|
|
+ //also updating existing rows, if they exist
|
|
|
|
+ for (let i=studyRows.length;i<listRows.length;i++){
|
|
|
|
+ let entry=listRows[i];
|
|
|
|
+ //make sure you have the participantField right
|
|
|
|
+ //
|
|
|
|
+ entry[participantField]=config.upload.participantId;
|
|
|
|
+ entry.crfRef=getCRFref();
|
|
|
|
+ entry.SequenceNum=getCRFref();
|
|
|
|
+ entry.SequenceNum=entry.SequenceNum % 1000000000;
|
|
|
|
+
|
|
|
|
+ if (listRows.length>1){
|
|
|
|
+ entry.SequenceNum+=i/100;
|
|
|
|
+ }
|
|
|
|
+ print( "Adding sequence number "+entry.SequenceNum);
|
|
|
|
+ rows.push(entry);
|
|
|
|
+ }
|
|
|
|
+ if (rows.length>0){
|
|
|
|
+
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.queryName=queryName;
|
|
|
|
+ qconfig.schemaName="study";
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.success=afterListUpload;
|
|
|
|
+ qconfig.rows=rows;
|
|
|
|
+ LABKEY.Query.insertRows(qconfig);
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ let data=new Object();
|
|
|
|
+ data.rows=rows;
|
|
|
|
+ afterListUpload(data);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterListUpload(data){
|
|
|
|
+
|
|
|
|
+ let queryObj=config.upload.queries[config.upload.queryId];
|
|
|
|
+ let queryName=queryObj.queryName;
|
|
|
|
+ printErr("Inserted "+data.rows.length+" rows to "+queryName);
|
|
|
|
+ queryObj.queryStatus="DONE";
|
|
|
|
+ config.upload.queryId+=1;
|
|
|
|
+ copyToDataset();
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//*************************update for further review *************************
|
|
|
|
+
|
|
|
|
+function onUpdateForReview(){
|
|
|
|
+ let targetStatus=config.formConfig.targetStatus['onUpdateForReview'];
|
|
|
|
+ let targetRecipient=config.formConfig.targetRecipient['onUpdateForReview'];
|
|
|
|
+ let action=new Object();
|
|
|
|
+ action.name='onUpdateForReview';
|
|
|
|
+ action.cb=function(data){sendEmail(data,targetRecipient,redirect,'Form updated for review');};
|
|
|
|
+
|
|
|
|
+ updateFlag(targetStatus,action);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function updateFlag(flag,action){
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.queryName='crfEntry';
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.success=function(data){setFlag(data,flag,action);}
|
|
|
|
+ qconfig.filterArray=[LABKEY.Filter.create("entryId",getCRFref())];
|
|
|
|
+ LABKEY.Query.selectRows(qconfig);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function setFlag(data,flag,action){
|
|
|
|
+ let fName='[setFlag]';
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (data.rows.length!=1){
|
|
|
|
+ let msg=fName+": ERROR: Found "+data.rows.length;
|
|
|
|
+ msg+=" entries for crfrefid "+getCRFref();
|
|
|
|
+ print(msg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ let entry=data.rows[0];
|
|
|
|
+ entry.FormStatus=flag;
|
|
|
|
+ let uId=config.formConfig.currentUser.UserId;
|
|
|
|
+ entry[config.formConfig.operator]=uId;
|
|
|
|
+
|
|
|
|
+ print(fName+': Form: '+entry.Form);
|
|
|
|
+ print(fName+": set form status to "+entry.FormStatus);
|
|
|
|
+
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.queryName='crfEntry';
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.rows=[entry];
|
|
|
|
+ //qconfig.success=function(data){completeWithFlag(data,flag);}
|
|
|
|
+ qconfig.success=function(data){completeWithFlag(data,action);};
|
|
|
|
+ LABKEY.Query.updateRows(qconfig);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function completeWithFlag(data,action){
|
|
|
|
+ let fName='[completeWithFlag]';
|
|
|
|
+ print(fName+': nrows '+data.rows.length);
|
|
|
|
+
|
|
|
|
+ let fentry=data.rows[0];
|
|
|
|
+ print(fName+': form status '+fentry.FormStatus);
|
|
|
|
+ print(fName+': form '+fentry.Form);
|
|
|
|
+
|
|
|
|
+ let entry=new Object();
|
|
|
|
+ entry.entryId=getCRFref();
|
|
|
|
+ entry.submissionDate=new Date();
|
|
|
|
+ entry.FormStatus=fentry.FormStatus;
|
|
|
|
+ entry.User=config.formConfig.currentUser.UserId;
|
|
|
|
+ entry.Form=fentry.Form;
|
|
|
|
+ entry.operator=config.formConfig.operator;
|
|
|
|
+ entry.action=action.name;
|
|
|
|
+
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.queryName='crfStatus';
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.rows=[entry];
|
|
|
|
+ //qconfig.success=function(data){completeWithFlag(data,flag);}
|
|
|
|
+ qconfig.success=action.cb;
|
|
|
|
+ LABKEY.Query.insertRows(qconfig);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//************************************************ submit *******************************************
|
|
|
|
+
|
|
|
|
+function onSubmit(){
|
|
|
|
+ //update list storage and change status
|
|
|
|
+
|
|
|
|
+ let debug=true;
|
|
|
|
+ hideErr();
|
|
|
|
+ clearErr();
|
|
|
|
+ printErr("onSubmit");
|
|
|
|
+
|
|
|
|
+ setData(verifyData);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function verifyData(){
|
|
|
|
+ let queries=config.formConfig.dataQueries;
|
|
|
|
+ for (q in queries){
|
|
|
|
+ let qData=queries[q];
|
|
|
|
+ if (q=="reviewComments") continue;
|
|
|
|
+ //if it doesn't have additionalData, it is a sub query
|
|
|
|
+ if (!(q in config.formConfig.additionalData))
|
|
|
|
+ continue;
|
|
|
|
+ if (qData.rows.length<1){
|
|
|
|
+ printErr('Missing entry for query '+q);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ let targetStatus=config.formConfig.targetStatus['onSubmit'];
|
|
|
|
+ let targetRecipient=config.formConfig.targetRecipient['onSubmit'];
|
|
|
|
+ print('verifyStatus: targetStatus: '+targetStatus);
|
|
|
|
+ let fName='verifyStatus';
|
|
|
|
+ //useful for debug
|
|
|
|
+ //let finalStep=doNothing;
|
|
|
|
+ //production mode
|
|
|
|
+ let finalStep=redirect;
|
|
|
|
+
|
|
|
|
+ let action=new Object();
|
|
|
|
+ action.name='onSubmit';
|
|
|
|
+ action.cb=function(data){sendEmail(data,targetRecipient,finalStep,'Form sumbitted');};
|
|
|
|
+ updateFlag(targetStatus,action);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getEmail(recipientCode){
|
|
|
|
+
|
|
|
|
+ print('getEmail w/'+recipientCode);
|
|
|
|
+ let recipients=new Array();
|
|
|
|
+ let typeTo=LABKEY.Message.recipientType.to;
|
|
|
|
+ let create=LABKEY.Message.createRecipient;
|
|
|
|
+ let currentUser=config.formConfig.currentUser;
|
|
|
|
+ let formCreator=config.formConfig.formCreator;
|
|
|
|
+ let currentSite=config.formConfig.currentSite;
|
|
|
|
+ let userRows=config.formConfig.userRows;
|
|
|
|
+ let parentUser=undefined;
|
|
|
|
+ if ("parentCrfData" in config.formConfig){
|
|
|
|
+ let parentCrf=config.formConfig.parentCrfData;
|
|
|
|
+ parentUser=getUser(parentCrf.rows[0].UserId,'parentUser');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let recipientCategories=recipientCode.split(',');
|
|
|
|
+ for (let i=0;i<recipientCategories.length;i++){
|
|
|
|
+
|
|
|
|
+ let recipient=recipientCategories[i];
|
|
|
|
+ print('Checking '+recipient);
|
|
|
|
+ if (recipient=='crfEditor'){
|
|
|
|
+ print('Adding :'+formCreator.Email);
|
|
|
|
+ recipients.push(create(typeTo,formCreator.Email));
|
|
|
|
+ if (parentUser==undefined) continue;
|
|
|
|
+ print('Adding :'+parentUser.Email);
|
|
|
|
+ recipients.push(create(typeTo,parentUser.Email));
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ //Monitor or Sponsor
|
|
|
|
+ let fList=recipient+'s';
|
|
|
|
+ let fRows=config.formConfig[fList];
|
|
|
|
+ for (let i=0;i<fRows.length;i++){
|
|
|
|
+ print('Checking '+fRows[i].User+'/'+fRows[i].Site);
|
|
|
|
+ if (fRows[i].Site!=currentSite.siteNumber) continue;
|
|
|
|
+ for (let j=0;j<userRows.length;j++){
|
|
|
|
+ if (userRows[j].UserId!=fRows[i].User) continue;
|
|
|
|
+ print('Adding :'+userRows[j].Email);
|
|
|
|
+ recipients.push(create(typeTo,userRows[j].Email));
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return recipients;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function sendEmail(data,recipient='crfEditor',cb=redirect,subj='Form submitted'){
|
|
|
|
+
|
|
|
|
+ print('sendEmail; recipient: '+recipient);
|
|
|
|
+
|
|
|
|
+ let st=config.formConfig.settings;
|
|
|
|
+ let cvar='sendEmail';
|
|
|
|
+ if (cvar in st){
|
|
|
|
+ print(cvar+' set to '+st[cvar]);
|
|
|
|
+ if (st[cvar]=='FALSE'){
|
|
|
|
+ print('Skipping sending emails');
|
|
|
|
+ redirect();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ print('send email '+data.rows.length);
|
|
|
|
+ let crf=data.rows[0]['entryId'];
|
|
|
|
+ let formId=data.rows[0]['Form'];
|
|
|
|
+ let link=LABKEY.ActionURL.getBaseURL();
|
|
|
|
+ link+=LABKEY.ActionURL.getContainer();
|
|
|
|
+ link+='/crf-visit.view?';
|
|
|
|
+ link+='entryId='+crf;
|
|
|
|
+ link+='&formId='+formId;
|
|
|
|
+ link+='&role='+recipient;
|
|
|
|
+
|
|
|
|
+ //debug
|
|
|
|
+ let recipients=getEmail(recipient);
|
|
|
|
+ //from crfManagers list
|
|
|
|
+
|
|
|
|
+ let typeHtml=LABKEY.Message.msgType.html;
|
|
|
|
+ let typePlain=LABKEY.Message.msgType.plain;
|
|
|
|
+ let msg1=LABKEY.Message.createMsgContent(typePlain,link);
|
|
|
|
+
|
|
|
|
+ //let cb=doNothing;
|
|
|
|
+ //let cb=redirect;
|
|
|
|
+ LABKEY.Message.sendMessage({
|
|
|
|
+ msgFrom:'labkey@fmf.uni-lj.si',
|
|
|
|
+ msgSubject:subj,
|
|
|
|
+ msgRecipients:recipients,
|
|
|
|
+ msgContent:[msg1],
|
|
|
|
+ success: cb
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function hideErr(){
|
|
|
|
+ let el=config.document.getElementById("errorDiv");
|
|
|
|
+ el.style.display="none";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function clearErr(){
|
|
|
|
+ let el=config.document.getElementById("errorTxt");
|
|
|
|
+ el.value="";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function showErr(){
|
|
|
|
+ let el=config.document.getElementById("errorDiv");
|
|
|
|
+ el.style.display="block";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function printErr(msg){
|
|
|
|
+ showErr();
|
|
|
|
+ el=config.document.getElementById("errorTxt");
|
|
|
|
+ el.style.color="red";
|
|
|
|
+ el.value+="\n"+msg;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//**************************************************
|
|
|
|
+//
|
|
|
|
+function onRemoveCRF(){
|
|
|
|
+ let debug=true;
|
|
|
|
+
|
|
|
|
+ if (debug){
|
|
|
|
+ print("Removing CRF");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ //points to data container
|
|
|
|
+ selectRows.containerPath=getContainer('config');
|
|
|
|
+ selectRows.schemaName="lists";
|
|
|
|
+ selectRows.queryName="inputLists";
|
|
|
|
+ selectRows.success=afterInputLists;
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterInputLists(data){
|
|
|
|
+ let debug=true;
|
|
|
|
+ if (debug)
|
|
|
|
+ print("After input lists");
|
|
|
|
+ config.inputLists=data;
|
|
|
|
+ config.inputListsIterator=0;
|
|
|
|
+
|
|
|
|
+ removeCRFLoop();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function removeCRFLoop(){
|
|
|
|
+ let debug=true;
|
|
|
|
+
|
|
|
|
+ let i=config.inputListsIterator;
|
|
|
|
+ let iMax=config.inputLists.rows.length;
|
|
|
|
+ //in fact, we are adding two additional passages of the loop, one for
|
|
|
|
+ //crfEntry, the second for the same query, but using parentCrf as the
|
|
|
|
+ //selection variable
|
|
|
|
+ let iTotal=iMax+1;
|
|
|
|
+ //let iTotal=iMax+1;
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print("removeCRFLoop ["+i+"/"+iMax+"]");
|
|
|
|
+
|
|
|
|
+ if (i>iTotal){
|
|
|
|
+ if (0) return;
|
|
|
|
+ redirect();
|
|
|
|
+ }
|
|
|
|
+ let queryName="crfEntry";
|
|
|
|
+ let idVar="entryId";
|
|
|
|
+ let idValue=getCRFref();
|
|
|
|
+
|
|
|
|
+ if (i<iMax){
|
|
|
|
+ //in all but crfEntry, variable is called crfRef
|
|
|
|
+ queryName=config.inputLists.rows[i].queryName;
|
|
|
|
+ idVar="crfRef";
|
|
|
|
+ }
|
|
|
|
+ //for i=iMax and i=iMax+1, query is crfEntry.
|
|
|
|
+
|
|
|
|
+ //delete also crfEntries where parentCrf is set to crf that we are deleting
|
|
|
|
+ if (i==iTotal){
|
|
|
|
+ idVar='parentCrf';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print("["+i+"/"+iMax+"] "+queryName+":"+idVar+'/'+idValue);
|
|
|
|
+
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ //points to data container
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+ selectRows.schemaName="lists";
|
|
|
|
+ selectRows.queryName=queryName;
|
|
|
|
+ selectRows.filterArray=[LABKEY.Filter.create(idVar,idValue)];
|
|
|
|
+ selectRows.success=removeListCRF;
|
|
|
|
+ selectRows.failure=skipListCRF;
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function removeListCRF(data){
|
|
|
|
+ let debug=true;
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print(data.queryName+": "+data.rows.length);
|
|
|
|
+
|
|
|
|
+ config.inputListsIterator+=1;
|
|
|
|
+
|
|
|
|
+ if (data.rows.length==0){
|
|
|
|
+ removeCRFLoop();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let deleteRows=new Object();
|
|
|
|
+ //points to data container
|
|
|
|
+ deleteRows.containerPath=getContainer('data');
|
|
|
|
+ deleteRows.schemaName=data.schemaName;
|
|
|
|
+ deleteRows.queryName=data.queryName;
|
|
|
|
+ deleteRows.success=function(data){removeCRFLoop()};
|
|
|
|
+ deleteRows.rows=data.rows;
|
|
|
|
+ LABKEY.Query.deleteRows(deleteRows);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function skipListCRF(errorInfo){
|
|
|
|
+ let debug=true;
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print("Error in removeCRF: "+errorInfo.exception);
|
|
|
|
+
|
|
|
|
+ config.inputListsIterator+=1;
|
|
|
|
+
|
|
|
|
+ removeCRFLoop();
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function redirect(){
|
|
|
|
+
|
|
|
|
+ let debug=false;
|
|
|
|
+ let formUrl="begin";
|
|
|
|
+ let params=new Object();
|
|
|
|
+ params.name=formUrl;
|
|
|
|
+ params.pageId="CRF";
|
|
|
|
+
|
|
|
|
+ //points to crf container
|
|
|
|
+ let containerPath=getContainer('CRF');
|
|
|
|
+
|
|
|
|
+ // This changes the page after building the URL.
|
|
|
|
+ //Note that the wiki page destination name is set in params.
|
|
|
|
+
|
|
|
|
+ var homeURL = LABKEY.ActionURL.buildURL(
|
|
|
|
+ "project", formUrl , containerPath, params);
|
|
|
|
+ print("Redirecting to "+homeURL);
|
|
|
|
+ if (debug) return;
|
|
|
|
+ window.location = homeURL;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//printing section
|
|
|
|
+
|
|
|
|
+function checkBlob(){
|
|
|
|
+ print("checkBlob: "+config.blob);
|
|
|
|
+ if (config.blob) {
|
|
|
|
+ clearInterval(config.blobInterval);
|
|
|
|
+ config.a.href = config.window.URL.createObjectURL(config.blob);
|
|
|
|
+ print("HREF: "+config.a.href);
|
|
|
|
+ config.a.download = 'test.pdf';
|
|
|
|
+ config.a.click();
|
|
|
|
+ config.window.URL.revokeObjectURL(config.a.href);
|
|
|
|
+ }
|
|
|
|
+ config.count=config.count+1;
|
|
|
|
+ print("Eval: "+config.count);
|
|
|
|
+ if (config.count>100){
|
|
|
|
+ clearInterval(config.blobInterval);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function printForm(){
|
|
|
|
+
|
|
|
|
+ config.doc=new PDFDocument();
|
|
|
|
+ //config.doc.end();
|
|
|
|
+ let stream = config.doc.pipe(blobStream()).on("finish",function(){
|
|
|
|
+ config.blob=stream.toBlob("application/pdf");});
|
|
|
|
+
|
|
|
|
+ print("BLob: "+config.blob);
|
|
|
|
+ config.a = config.document.createElement("a");
|
|
|
|
+ config.document.body.appendChild(config.a);
|
|
|
|
+ config.a.innerHTML="Download PDF";
|
|
|
|
+ config.a.style = "display: none";
|
|
|
|
+ config.count=0;
|
|
|
|
+ //run until blob is set
|
|
|
|
+ config.blobInterval=setInterval(checkBlob,1000);
|
|
|
|
+
|
|
|
|
+ //pick data from crfForm list
|
|
|
|
+ print("Printing form");
|
|
|
|
+ printHeader();
|
|
|
|
+ setData(formatPrintData);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function printHeader(){
|
|
|
|
+ config.doc.fontSize(25).text(config.formConfig.form['formName']);
|
|
|
|
+ config.doc.moveDown();
|
|
|
|
+ let crfEntry=config.formConfig.crfEntry;
|
|
|
|
+ let site=config.formConfig.currentSite;
|
|
|
|
+ let val=new Object();
|
|
|
|
+ let user=config.formConfig.user;
|
|
|
|
+ val['A']={o:crfEntry,f:'EudraCTNumber',t:'Eudra CT Number'};
|
|
|
|
+ val['B']={o:crfEntry,f:'StudyCoordinator',t:'Study Coordinator'};
|
|
|
|
+ val['C']={o:crfEntry,f:'StudySponsor',t:'Study Sponsor'};
|
|
|
|
+ val['D']={o:site,f:'siteName',t:'Site'};
|
|
|
|
+ val['E']={o:site,f:'sitePhone',t:'Phone'};
|
|
|
|
+ val['F']={o:user,f:'DisplayName',t:'Investigator'};
|
|
|
|
+
|
|
|
|
+ for (let f in val){
|
|
|
|
+ print('Printing for '+f);
|
|
|
|
+ let e=val[f];
|
|
|
|
+ let entry=new Object();
|
|
|
|
+ entry[f]=e.o[e.f];
|
|
|
|
+ printPDF(entry,
|
|
|
|
+ {name:f,caption:e.t,type:'string'},null);
|
|
|
|
+ }
|
|
|
|
+ config.doc.moveDown();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function formatPrintData(){
|
|
|
|
+ qS=config.formConfig.dataQueries;
|
|
|
|
+ for (let q in qS){
|
|
|
|
+ print('Setting up '+q);
|
|
|
|
+ let qData=qS[q];
|
|
|
|
+ print('Number of rows: '+qData.rows.length);
|
|
|
|
+ if (qData.rows.length>0){
|
|
|
|
+ config.doc.fontSize(20).text(qData.title);
|
|
|
|
+ }
|
|
|
|
+ for (let i=0;i<qData.rows.length;i++){
|
|
|
|
+ let entry=qData.rows[i];
|
|
|
|
+ for (let f in qData.fields){
|
|
|
|
+ let field=qData.fields[f];
|
|
|
|
+ let lookup=null;
|
|
|
|
+ if (field.lookup){
|
|
|
|
+ lookup=config.formConfig.lookup[field.lookup.queryName];
|
|
|
|
+ }
|
|
|
|
+ if (field.hidden) continue;
|
|
|
|
+ printPDF(entry,field,lookup);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ config.doc.moveDown();
|
|
|
|
+ }
|
|
|
|
+ print("All done");
|
|
|
|
+ config.doc.end();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function printPDF(entry,field,lookup){
|
|
|
|
+ //object field should have a name, type, caption
|
|
|
|
+ //entry should have field.name
|
|
|
|
+ //lookup is null or has a lookup table LUT
|
|
|
|
+ //for value v of entry[field.name]
|
|
|
|
+ //
|
|
|
|
+ //the total width of a A4 page is 598 px,
|
|
|
|
+ //left margin is 72. With a right margin of 50,
|
|
|
|
+ //the total available with is 476 px.
|
|
|
|
+
|
|
|
|
+ let w=476;
|
|
|
|
+ let spacing=25;
|
|
|
|
+ let w1=(w-spacing)*0.5;
|
|
|
|
+ let fontSize=14;
|
|
|
|
+
|
|
|
|
+ print('printPDF: entry['+field.name+']='+entry[field.name]);
|
|
|
|
+ let v=entry[field.name];
|
|
|
|
+ if (lookup!=null){
|
|
|
|
+ v=lookup.LUT[v];
|
|
|
|
+ }
|
|
|
|
+ print('printPDF: field type:'+field.type);
|
|
|
|
+ if (field.type=="date"){
|
|
|
|
+ let d=new Date(v);
|
|
|
|
+ v=d.getDate()+'/'+(d.getMonth()+1)+'/'+d.getFullYear();
|
|
|
|
+ }
|
|
|
|
+ if (v===null) v=' / ';
|
|
|
|
+ if (v===undefined) v=' / ';
|
|
|
|
+
|
|
|
|
+ //measure text
|
|
|
|
+ let label=field.caption;
|
|
|
|
+ let opt={width:w1};
|
|
|
|
+ config.doc.fontSize(fontSize);
|
|
|
|
+
|
|
|
|
+ //for more eloquent display the height of the text
|
|
|
|
+ //can be measured prior to output
|
|
|
|
+ //use currentLineHeight to scale height
|
|
|
|
+ //let lineH=config.doc.currentLineHeight(1);
|
|
|
|
+ //let h=config.doc.heightOfString(label,opt)/lineH;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //print label
|
|
|
|
+ config.doc.font('Courier').text(label,opt);
|
|
|
|
+
|
|
|
|
+ //align last row of description w/ first row of value
|
|
|
|
+ config.doc.moveUp();
|
|
|
|
+
|
|
|
|
+ //store x value for later use
|
|
|
|
+ let tx=config.doc.x;
|
|
|
|
+ let ty=config.doc.y;
|
|
|
|
+
|
|
|
|
+ //shift for value output
|
|
|
|
+ config.doc.x+=w1+spacing;
|
|
|
|
+
|
|
|
|
+ config.doc.font('Courier-Bold').text(v,opt);
|
|
|
|
+
|
|
|
|
+ //restore x value
|
|
|
|
+ config.doc.x=tx;
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//master section, entry point from html files
|
|
|
|
+
|
|
|
|
+function generateMasterForm(){
|
|
|
|
+
|
|
|
|
+ generateDebugSection();
|
|
|
|
+ //read enviroment from lists disperesed on labkey
|
|
|
|
+ setFormConfig();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//helper function to set basic parameters on web page
|
|
|
|
+//(fields defined in html file)
|
|
|
|
+function populateBasicData(){
|
|
|
|
+
|
|
|
|
+ config.document.getElementById('version').innerText=
|
|
|
|
+ config.formConfig.softwareVersion;
|
|
|
|
+ config.document.getElementById('eudraCTNumber').innerText=
|
|
|
|
+ config.formConfig.crfEntry.EudraCTNumber;
|
|
|
|
+ config.document.getElementById('studyCoordinator').innerText=
|
|
|
|
+ config.formConfig.crfEntry.StudyCoordinator;
|
|
|
|
+ config.document.getElementById('studySponsor').innerText=
|
|
|
|
+ config.formConfig.crfEntry.StudySponsor;
|
|
|
|
+ config.document.getElementById('siteName').innerText=
|
|
|
|
+ config.formConfig.currentSite['siteName'];
|
|
|
|
+ config.document.getElementById('sitePhone').innerText=
|
|
|
|
+ config.formConfig.currentSite['sitePhone'];
|
|
|
|
+ config.document.getElementById('investigatorName').innerText=
|
|
|
|
+ config.formConfig.user['DisplayName'];
|
|
|
|
+ let h1=config.formConfig.form['formName'];
|
|
|
|
+ config.document.getElementById('formTitle').innerText=h1;
|
|
|
|
+ print('Setting title to '+h1);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+//come here after the layout is read from labkey page
|
|
|
|
+//
|
|
|
|
+function generateErrorMsg(msg){
|
|
|
|
+ let txt=config.document.createElement('p');
|
|
|
|
+ txt.innerText=msg;
|
|
|
|
+ config.document.getElementById(config.masterForm).appendChild(txt);
|
|
|
|
+ generateButton("submitDiv",'Exit','Exit','redirect',redirect);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getUser(id,field){
|
|
|
|
+ if (field in config.formConfig) return config.formConfig[field];
|
|
|
|
+ let uRows=config.formConfig.userRows;
|
|
|
|
+ for (let i=0;i<uRows.length;i++){
|
|
|
|
+ let userId=uRows[i].UserId;
|
|
|
|
+ if (userId!=id) continue;
|
|
|
|
+ config.formConfig[field]=uRows[i];
|
|
|
|
+ return config.formConfig[field];
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function afterConfig(){
|
|
|
|
+
|
|
|
|
+ let debug=true;
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print("afterConfig");
|
|
|
|
+
|
|
|
|
+ populateBasicData();
|
|
|
|
+
|
|
|
|
+ //check if user has permission on the form
|
|
|
|
+ let currentUser=getUser(LABKEY.Security.currentUser.id,'currentUser');
|
|
|
|
+ let currentSite=config.formConfig.currentSite;
|
|
|
|
+ let formCreator=getUser(config.formConfig.crfEntry.UserId,'formCreator');
|
|
|
|
+ let formCreatorId=formCreator.UserId;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //let formSite=config.formConfig.crfEntry.Site;
|
|
|
|
+ let fList=config.formConfig.operator+'s';
|
|
|
|
+ let fRows=config.formConfig[fList];
|
|
|
|
+ //let currentSiteId=-1;
|
|
|
|
+
|
|
|
|
+ //depending on operator mode, we should decide what is right
|
|
|
|
+ let operator=config.formConfig.operator;
|
|
|
|
+ if (operator=='crfEditor'){
|
|
|
|
+ //editor can only edit its own forms
|
|
|
|
+ if (currentUser.UserId!=formCreatorId){
|
|
|
|
+ let msg='User '+currentUser.DisplayName;
|
|
|
|
+ msg+=' has no permission on this form';
|
|
|
|
+ generateErrorMsg(msg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (operator=='crfMonitor' || operator=='crfSponsor'){
|
|
|
|
+ //monitor can look at forms based on his site
|
|
|
|
+ //find monitor line
|
|
|
|
+ let operatorSites=new Array();
|
|
|
|
+ for (let i=0;i<fRows.length;i++){
|
|
|
|
+ if (fRows[i].User!=currentUser.UserId) continue;
|
|
|
|
+ operatorSites.push(fRows[i].Site);
|
|
|
|
+ }
|
|
|
|
+ print('operator Site: '+operatorSites.length);
|
|
|
|
+ if (operatorSites.length==0){
|
|
|
|
+ let msg='User '+currentUser.DisplayName;
|
|
|
|
+ msg+=' is not a '+operator;
|
|
|
|
+ generateErrorMsg(msg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let selectedSite=-1;
|
|
|
|
+ let siteCandidates="[";
|
|
|
|
+ for (let i=0;i<operatorSites.length;i++){
|
|
|
|
+ if (i>0) siteCandidates+=", ";
|
|
|
|
+ siteCandidates+=operatorSites[i];
|
|
|
|
+ if (operatorSites[i]!=currentSite.siteNumber) continue;
|
|
|
|
+ selectedSite=currentSite.siteNumber;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ siteCandidates+="]";
|
|
|
|
+ if (selectedSite==-1){
|
|
|
|
+ let msg='User '+currentUser.DisplayName;
|
|
|
|
+ msg+=' is not a '+operator+' for site ';
|
|
|
|
+ msg+=currentSite.siteName+'('+currentSite.siteNumber+')';
|
|
|
|
+ msg+='/'+siteCandidates;
|
|
|
|
+ generateErrorMsg(msg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ print('User '+currentUser.DisplayName+'/'+
|
|
|
|
+ config.formConfig.currentSite['siteName']+
|
|
|
|
+ ' acting as '+config.formConfig.operator);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let rows=config.formConfig.crfButtons.rows;
|
|
|
|
+ config.formConfig.targetStatus=new Array();
|
|
|
|
+ config.formConfig.targetRecipient=new Array();
|
|
|
|
+
|
|
|
|
+ for (let i=0; i<rows.length; i++){
|
|
|
|
+ let action=rows[i].action;//String
|
|
|
|
+ let tstatus=rows[i].targetFormStatus;
|
|
|
|
+ let trecip=rows[i].targetRecipient;
|
|
|
|
+ config.formConfig.targetStatus[action]=tstatus;
|
|
|
|
+ config.formConfig.targetRecipient[action]=trecip;
|
|
|
|
+ }
|
|
|
|
+ let formStatus=config.formConfig.formStatus;
|
|
|
|
+
|
|
|
|
+ //let functionArray=new Array();
|
|
|
|
+
|
|
|
|
+ print("Generating buttons for formStatus \""+ formStatus+"\"");
|
|
|
|
+
|
|
|
|
+ let buttonRows=config.formConfig.crfButtons.rows;
|
|
|
|
+ for (let i=0;i<buttonRows.length;i++){
|
|
|
|
+ let bt=buttonRows[i];
|
|
|
|
+ if (typeof window[bt.action]==="function"){
|
|
|
|
+ generateButton("submitDiv",bt.caption,bt.label,bt.action,
|
|
|
|
+ window[bt.action]);
|
|
|
|
+ }
|
|
|
|
+ else{
|
|
|
|
+ print('No match for function :'+bt.action+
|
|
|
|
+ ' obj: '+window[bt.action]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ print('Here');
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //here we should get data. For now, just initialize objects that will hold data
|
|
|
|
+ setDataLayout(afterDataLayout);//callback is afterDataLayout
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterDataLayout(){
|
|
|
|
+
|
|
|
|
+ setData(afterData);//callback is afterData
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterData(){
|
|
|
|
+ let fName='afterData';
|
|
|
|
+ //operatorBasedAccessMode
|
|
|
|
+ let accessMode=config.formConfig.operator+'Mode';
|
|
|
|
+ let rowsSetup=config.formConfig.formSetupRows;
|
|
|
|
+ print(fName+' list of sections');
|
|
|
|
+ for (let i=0;i<rowsSetup.length;i++){
|
|
|
|
+ let entry=rowsSetup[i];
|
|
|
|
+ let queryName=config.formConfig.queryMap[entry['queryName']];
|
|
|
|
+ print(fName+'\t'+queryName);
|
|
|
|
+ }
|
|
|
|
+ for (let i=0;i<rowsSetup.length;i++){
|
|
|
|
+ let entry=rowsSetup[i];
|
|
|
|
+ let queryName=config.formConfig.queryMap[entry['queryName']];
|
|
|
|
+ print(fName+" ["+queryName+"]: showFlag: "+entry["showFlag"]);
|
|
|
|
+ print(fName+" ["+queryName+"]: accessMode: "+entry[accessMode]);
|
|
|
|
+
|
|
|
|
+ const nData=config.formConfig.dataQueries[queryName].rows.length;
|
|
|
|
+
|
|
|
|
+ print(fName+" ["+queryName+"]: nData: "+nData);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ //skip sections
|
|
|
|
+ //also from fields
|
|
|
|
+ if (entry[accessMode]=="NONE") continue;
|
|
|
|
+ //skip readonly empty records
|
|
|
|
+ //if (entry[accessMode]=="READ" && nData==0) continue;
|
|
|
|
+
|
|
|
|
+ //let additionalData=new Object();
|
|
|
|
+ //setAdditionalData(additionalData,entry);
|
|
|
|
+ //section fits one dataset/list
|
|
|
|
+ generateSection(entry);
|
|
|
|
+ //generateSection(queryName,entry["title"],entry[accessMode],
|
|
|
|
+ // additionalData);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function findSetupRow(sectionId){
|
|
|
|
+ let rowsSetup=config.formConfig.formSetupRows;
|
|
|
|
+ let key=sectionId.replace('section','');
|
|
|
|
+ for (let i=0;i<rowsSetup.length;i++){
|
|
|
|
+ let e=rowsSetup[i];
|
|
|
|
+ //let queryName1=config.formConfig.queryMap[e['queryName']];
|
|
|
|
+ if (e.formName!=config.formId) continue;
|
|
|
|
+ if (e['Key']==key) return e;
|
|
|
|
+ //if (queryName1!=queryName) continue;
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function populateSection(sectionId){
|
|
|
|
+ //queryName should be found from setup
|
|
|
|
+ let fName='[populateSection/'+sectionId+']';
|
|
|
|
+ print(fName);
|
|
|
|
+
|
|
|
|
+ let entry=findSetupRow(sectionId);
|
|
|
|
+ //ignore names without associated entry in formSetup
|
|
|
|
+ if (entry==undefined){
|
|
|
|
+ print(fName+': no matching FormSetup entry found');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let queryName=config.formConfig.queryMap[entry['queryName']];
|
|
|
|
+ //populate comes after generate, we should be pretty safe in taking
|
|
|
|
+ //already generated additionalData
|
|
|
|
+
|
|
|
|
+ if (!(queryName in config.formConfig.additionalData)){
|
|
|
|
+ print(fName+': no additionalData generated for '+queryName);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let additionalData=config.formConfig.additionalData[queryName];
|
|
|
|
+ print(fName+': using additionalData '+additionalData);
|
|
|
|
+ if ("isReview" in additionalData){
|
|
|
|
+ generateReviewSection(queryName,queryName,generateReviewSectionCB);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let accessMode=config.formConfig.operator+'Mode';
|
|
|
|
+ let aM=entry[accessMode];
|
|
|
|
+ print(fName+': accessMode '+aM);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if (aM!='GENERATE'){
|
|
|
|
+ let writeMode=(aM=='EDIT');
|
|
|
|
+ print(fName+': writeMode '+writeMode);
|
|
|
|
+ let setup=getSetup(sectionId,queryName,writeMode);
|
|
|
|
+ setup.setVariables=parseVariableDefinition(entry);
|
|
|
|
+ setHelp(setup,entry);
|
|
|
|
+ populateTable(queryName,writeMode,setup);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //deal with generate
|
|
|
|
+ //
|
|
|
|
+ //already available -> shift to READ mode
|
|
|
|
+ let divTable=sectionId+'Table';
|
|
|
|
+ let divObj=config.document.getElementById(divTable);
|
|
|
|
+ let divRev=config.document.getElementById(sectionId+'Review');
|
|
|
|
+ let divRLi=config.document.getElementById(sectionId+'ReviewList');
|
|
|
|
+ let divGBu=config.document.getElementById(sectionId+'GenerateButton');
|
|
|
|
+
|
|
|
|
+ print('div GBU: '+divGBu);
|
|
|
|
+ divObj.style.display="block";
|
|
|
|
+ divRev.style.display="block";
|
|
|
|
+ divRLi.style.display="block";
|
|
|
|
+ if (divGBu!=undefined) divGBu.style.display="none";
|
|
|
|
+
|
|
|
|
+ let nData=config.formConfig.dataQueries[queryName].rows.length;
|
|
|
|
+ print('['+queryName+']: nrows '+nData);
|
|
|
|
+ if (nData>0){
|
|
|
|
+ let setup=getSetup(sectionId,queryName,false);
|
|
|
|
+ setup.setVariables=parseVariableDefinition(entry);
|
|
|
|
+ //this fails for setVariables, although they are available via entry['variableDefinition']
|
|
|
|
+ populateTable(queryName,false,setup);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //hide table
|
|
|
|
+ divObj.style.display="none";
|
|
|
|
+ divRev.style.display="none";
|
|
|
|
+ divRLi.style.display="none";
|
|
|
|
+ if (divGBu!=undefined) divGBu.style.display="block";
|
|
|
|
+ //add buttons?
|
|
|
|
+ //is button already generated?
|
|
|
|
+
|
|
|
|
+ //populateTable(entry);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//******* generateQuery infrastructure *********************
|
|
|
|
+
|
|
|
|
+function onGenerateQuery(queryName){
|
|
|
|
+ print('onGenerateQuery '+queryName);
|
|
|
|
+//
|
|
|
|
+ let cfgRows=config.formConfig.generateConfigData.rows;
|
|
|
|
+// //queryName to queryId?
|
|
|
|
+ let queryId=config.formConfig.fields[queryName].queryId;
|
|
|
|
+ let cfgRow=undefined;
|
|
|
|
+
|
|
|
|
+ for (let i=0;i<cfgRows.length;i++){
|
|
|
|
+ if (cfgRows[i].queryId!=queryId) continue;
|
|
|
|
+ cfgRow=cfgRows[i];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (cfgRow==undefined){
|
|
|
|
+ print('generateConfig for queryName['+queryId+']='+queryName+' not found');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ //add config to the list
|
|
|
|
+ if (!("generateConfig" in config.formConfig)){
|
|
|
|
+ config.formConfig.generateConfig=new Object();
|
|
|
|
+ }
|
|
|
|
+ config.formConfig.generateConfig[queryName]=cfgRow;
|
|
|
|
+
|
|
|
|
+ if (!("generateForm" in config.formConfig)){
|
|
|
|
+ config.formConfig.generateForm=new Object();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+//
|
|
|
|
+ let formRows=config.formConfig.formRows;
|
|
|
|
+ let formId=cfgRow.formId;
|
|
|
|
+ for (let i=0;i<formRows.length;i++){
|
|
|
|
+ if (formRows[i].Key==formId) {
|
|
|
|
+ config.formConfig.generateForm[queryName]=formRows[i];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //print('XcfgRow '+config.formConfig.generateForm[queryName]);
|
|
|
|
+//
|
|
|
|
+// //check if all required datasets were at least saved
|
|
|
|
+ checkGenerationFields(queryName);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function checkGenerationFields(queryName){
|
|
|
|
+ let genForm=config.formConfig.generateForm[queryName];
|
|
|
|
+ let genCfg=config.formConfig.generateConfig[queryName];
|
|
|
|
+ let mailRecipient=genCfg.emailRecipient;
|
|
|
|
+
|
|
|
|
+ //list of queries that are part of Registration form
|
|
|
|
+ print('checkRegistrationFields');
|
|
|
|
+ print('setRecipient: '+mailRecipient);
|
|
|
|
+ let formId=genForm.Key;
|
|
|
|
+ print("Checking form w/id "+formId);
|
|
|
|
+ let selectGenerationRows=selectFormSetupRows(formId);
|
|
|
|
+ //registration rows
|
|
|
|
+ for (let i=0;i<selectGenerationRows.length;i++){
|
|
|
|
+ let row=selectGenerationRows[i];
|
|
|
|
+ let queryId=row.queryName;
|
|
|
|
+ let fQueryName=config.formConfig.queryMap[queryId];
|
|
|
|
+ if (fQueryName==queryName) continue;
|
|
|
|
+ let fQuery=config.formConfig.dataQueries[fQueryName];
|
|
|
|
+ print('Checking '+fQueryName+' nrows: '+fQuery.rows.length);
|
|
|
|
+ if (fQuery.rows.length==0){
|
|
|
|
+ generateError(queryName,fQueryName);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ generateMessage(queryName,'Vailidation OK');
|
|
|
|
+ print('callback: set recipient: '+mailRecipient);
|
|
|
|
+ let cb=function(){prepareForm(queryName,formId,mailRecipient);};
|
|
|
|
+ generateListEntry(formId,queryName,cb);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function prepareForm(queryName,formId,mailRecipient){
|
|
|
|
+
|
|
|
|
+ print('prepareForm: recipient '+mailRecipient);
|
|
|
|
+//
|
|
|
|
+// return;
|
|
|
|
+ //look for existing registration entry
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ //inputLists should be in configuration container
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+ selectRows.schemaName='lists';
|
|
|
|
+ selectRows.queryName='crfEntry';
|
|
|
|
+ selectRows.success=function(data){generateForm(data,queryName,mailRecipient);};
|
|
|
|
+ let formFilter=LABKEY.Filter.create('Form',formId);
|
|
|
|
+ let parentCrfFilter=LABKEY.Filter.create('parentCrf',getCRFref());
|
|
|
|
+
|
|
|
|
+ selectRows.filterArray=[formFilter,parentCrfFilter];
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateError(queryName,fQueryName){
|
|
|
|
+ let elName=queryName+'GenerateButton'+'_reportField';
|
|
|
|
+ let el=config.document.getElementById(elName);
|
|
|
|
+ el.innerText='Error: '+fQueryName+' was not set';
|
|
|
|
+ el.style.color='red';
|
|
|
|
+}
|
|
|
|
+function generateMessage(queryName,msg){
|
|
|
|
+ let elName=queryName+'GenerateButton'+'_reportField';
|
|
|
|
+ let el=config.document.getElementById(elName);
|
|
|
|
+ el.innerText=msg;
|
|
|
|
+ el.style.color='green';
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function generateForm(data,queryName,mailRecipient){
|
|
|
|
+
|
|
|
|
+ print('generateForm, recpioent: '+mailRecipient);
|
|
|
|
+//
|
|
|
|
+ const nData=data.rows.length;
|
|
|
|
+ print('Registration: '+nData+' rows');
|
|
|
|
+
|
|
|
|
+ let formRow=config.formConfig.generateForm[queryName];
|
|
|
|
+
|
|
|
|
+ //we have to generate masterQuery with parentCrf and crfRef
|
|
|
|
+ //and crfEntry with new entryId and parentCrf equal to crfRef
|
|
|
|
+ if (nData>0) {
|
|
|
|
+ generateMessage(queryName,'Registration already generated.');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ let formId=formRow.Key;
|
|
|
|
+ let formName=formRow.formName;
|
|
|
|
+ let crfBase=config.formConfig.crfEntry;
|
|
|
|
+ let crfEntry=new Object();
|
|
|
|
+ //add new reference
|
|
|
|
+ crfEntry.entryId=Date.now();
|
|
|
|
+ crfEntry.parentCrf=getCRFref();
|
|
|
|
+ crfEntry["Date"]=new Date();
|
|
|
|
+ crfEntry["View"]="[VIEW]";
|
|
|
|
+ crfEntry.formStatus=1;//In progress
|
|
|
|
+// //set other variables
|
|
|
|
+ //requires studyData as part of formConfig
|
|
|
|
+// let studyData=config.formConfig.studyData;
|
|
|
|
+ print('Adding study: '+crfBase.EudraCTNumber);
|
|
|
|
+ crfEntry.EudraCTNumber=crfBase.EudraCTNumber;
|
|
|
|
+ crfEntry.StudyCoordinator=crfBase.StudyCoordinator;
|
|
|
|
+ crfEntry.StudySponsor=crfBase.StudySponsor;
|
|
|
|
+ crfEntry.RegulatoryNumber=crfBase.RegulatoryNumber;
|
|
|
|
+//
|
|
|
|
+// //find sponsor for site
|
|
|
|
+ let site=crfBase.Site;
|
|
|
|
+ let crfSponsors=config.formConfig.crfSponsors;
|
|
|
|
+ let users=config.formConfig.userRows;
|
|
|
|
+ for (let i=0;i<crfSponsors.length;i++){
|
|
|
|
+ //print('Checking for site '+crfSponsors[i].Site);
|
|
|
|
+ if (crfSponsors[i].Site!=site) continue;
|
|
|
|
+ config.formConfig.sponsorId=crfSponsors[i].User;
|
|
|
|
+ //print('Setting id '+config.formConfig.sponsorId);
|
|
|
|
+ //finds first
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ for (let j=0;j<users.length;j++){
|
|
|
|
+ if (config.formConfig.sponsorId!=users[j].UserId) continue;
|
|
|
|
+ config.formConfig.sponsor=users[j];
|
|
|
|
+ //finds first (should be unique)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ print('Selecting '+config.formConfig.sponsor.DisplayName+' as sponsor');
|
|
|
|
+ //different user than the original form...
|
|
|
|
+ //should be set to the study sponsor
|
|
|
|
+ crfEntry.UserId=config.formConfig.sponsor.UserId;
|
|
|
|
+ crfEntry.Site=site;
|
|
|
|
+// //set formId to one found through registration search
|
|
|
|
+ crfEntry.Form=formId;
|
|
|
|
+////
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.queryName='crfEntry';
|
|
|
|
+ qconfig.success=function(data){sendEmail(data,mailRecipient,doNothing,formName+' generated');}
|
|
|
|
+ qconfig.rows=[crfEntry];
|
|
|
|
+ LABKEY.Query.insertRows(qconfig);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+//
|
|
|
|
+function generateListEntry(formId,queryName,cb){
|
|
|
|
+
|
|
|
|
+ //check if registration was already generated
|
|
|
|
+
|
|
|
|
+ let formRows=config.formConfig.formRows;
|
|
|
|
+ let qForm=undefined;
|
|
|
|
+ for (let i=0;i<formRows.length;i++){
|
|
|
|
+ if (formRows[i].Key!=formId) continue;
|
|
|
|
+ qForm=formRows[i];
|
|
|
|
+ }
|
|
|
|
+ let nData=config.formConfig.dataQueries[queryName].rows.length
|
|
|
|
+ if (nData>0) return;
|
|
|
|
+ //only generate record for parentCrfRef
|
|
|
|
+
|
|
|
|
+ //let qArray=new Array();
|
|
|
|
+ //let e1=new Object();
|
|
|
|
+ //e1.crfRef=data.rows[0].entryId;
|
|
|
|
+ //e1.submissionDate=new Date();
|
|
|
|
+ //only for registration
|
|
|
|
+ //e1.registrationStatus=0;
|
|
|
|
+ //qArray.push(e1);
|
|
|
|
+
|
|
|
|
+ let e2=new Object();
|
|
|
|
+ e2.crfRef=getCRFref();
|
|
|
|
+ e2.registrationStatus=0;
|
|
|
|
+ e2.submissionDate=new Date();
|
|
|
|
+ print('set values');
|
|
|
|
+
|
|
|
|
+ let qconfig=new Object();
|
|
|
|
+ qconfig.containerPath=getContainer('data');
|
|
|
|
+ qconfig.schemaName='lists';
|
|
|
|
+ qconfig.queryName=queryName;
|
|
|
|
+ qconfig.success=cb;
|
|
|
|
+ qconfig.rows=[e2]
|
|
|
|
+ LABKEY.Query.insertRows(qconfig);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// ******************** end form generator (Registration) ********************
|
|
|
|
+
|
|
|
|
+//jump to populate table/generate review, etc defined at the begining of the file
|
|
|
|
+
|
|
|
|
+function setContainer(label,container){
|
|
|
|
+ if (!(config.formConfig.hasOwnProperty('container'))){
|
|
|
|
+ config.formConfig.container=new Array();
|
|
|
|
+ }
|
|
|
|
+ config.formConfig.container[label]=container;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function getContainer(label){
|
|
|
|
+ return config.formConfig.container[label];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//entry point from generateMasterForm
|
|
|
|
+function setFormConfig(){
|
|
|
|
+
|
|
|
|
+ //add object to store form related data
|
|
|
|
+ config.formConfig=new Object();
|
|
|
|
+
|
|
|
|
+ config.formConfig.softwareVersion='0.15.14';
|
|
|
|
+
|
|
|
|
+ let debug=true;
|
|
|
|
+
|
|
|
|
+ if (debug)
|
|
|
|
+ print("generateMasterForm1");
|
|
|
|
+
|
|
|
|
+ //set containers for data and configuration
|
|
|
|
+
|
|
|
|
+ //TODO: set this from a query
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ setContainer('data',LABKEY.ActionURL.getContainer());
|
|
|
|
+ setContainer('config',LABKEY.ActionURL.getContainer());
|
|
|
|
+ setContainer('CRF',LABKEY.ActionURL.getContainer());
|
|
|
|
+
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ //this is local data
|
|
|
|
+ selectRows.containerPath=getContainer('CRF');
|
|
|
|
+ selectRows.schemaName='lists';
|
|
|
|
+ selectRows.queryName='crfSettings';
|
|
|
|
+ //store form related data to this object
|
|
|
|
+ selectRows.success=afterSettings;
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function afterSettings(data){
|
|
|
|
+
|
|
|
|
+ config.formConfig.settings=new Array();
|
|
|
|
+ for (let i=0;i<data.rows.length;i++){
|
|
|
|
+ let n=data.rows[i]['name'];
|
|
|
|
+ let v=data.rows[i]['value'];
|
|
|
|
+ config.formConfig.settings[n]=v;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let st=config.formConfig.settings;
|
|
|
|
+ print('afterSettings');
|
|
|
|
+ for (let k in st){
|
|
|
|
+ print('\t'+k+'='+st[k]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //if ('dataContainer' in st){
|
|
|
|
+ // setContainer('data',st['dataContainer']);
|
|
|
|
+ //}
|
|
|
|
+ let vname='configContainer';
|
|
|
|
+ if (vname in st){
|
|
|
|
+ setContainer('config',st[vname]);
|
|
|
|
+ }
|
|
|
|
+ print('Config: '+getContainer('config'));
|
|
|
|
+ print('Data: '+getContainer('data'));
|
|
|
|
+
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ //this is local data
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+ selectRows.schemaName='lists';
|
|
|
|
+ selectRows.queryName='crfEntry';
|
|
|
|
+ //use first-> we must first establish link to the rigth crf entry
|
|
|
|
+ selectRows.filterArray=[LABKEY.Filter.create('entryId',getCRFrefFirst())];
|
|
|
|
+ //store form related data to this object
|
|
|
|
+ selectRows.success=afterCRFEntry;
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterCRFEntry(data){
|
|
|
|
+ config.formConfig.crfEntry=data.rows[0];
|
|
|
|
+ print("Setting crfEntry (x) to "+config.formConfig.crfEntry["entryId"]);
|
|
|
|
+ //for empty records or those with parentCrf not set, parentCrf comes up as null
|
|
|
|
+ //nevertheless, with two equal signs, check against undefined also works
|
|
|
|
+ print('parentCrf set to '+config.formConfig.crfEntry.parentCrf);
|
|
|
|
+
|
|
|
|
+ collectData();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function collectData(){
|
|
|
|
+
|
|
|
|
+ let varLabel='sourceFormStatus';
|
|
|
|
+ let formStatus=config.formConfig.crfEntry['FormStatus'];
|
|
|
|
+
|
|
|
|
+ let queryArray=new Array();
|
|
|
|
+ //site
|
|
|
|
+ queryArray.push(makeQuery('config','site','siteData',[]));
|
|
|
|
+ //users
|
|
|
|
+ queryArray.push(makeQuery('CRF','users','userData',[]));
|
|
|
|
+ queryArray[queryArray.length-1].schemaName='core';
|
|
|
|
+ //crfEditors
|
|
|
|
+ queryArray.push(makeQuery('config','crfEditors','crfEditorsData',[]));
|
|
|
|
+ //crfMonitors
|
|
|
|
+ queryArray.push(makeQuery('config','crfMonitors','crfMonitorsData',[]));
|
|
|
|
+ //crfSponsors
|
|
|
|
+ queryArray.push(makeQuery('config','crfSponsors','crfSponsorsData',[]));
|
|
|
|
+ //study
|
|
|
|
+ queryArray.push(makeQuery('data','Study','studyDataAll',[]));
|
|
|
|
+ let e=queryArray[queryArray.length-1];
|
|
|
|
+ e.schemaName='study';
|
|
|
|
+ e.columns="SubjectColumnName,EudraCTNumber,StudySponsor";
|
|
|
|
+ e.columns+=",StudyCoordinator,RegulatoryNumber";
|
|
|
|
+
|
|
|
|
+ //formStatus
|
|
|
|
+ let formFilter=LABKEY.Filter.create('Key',formStatus);
|
|
|
|
+ queryArray.push(makeQuery('config','FormStatus','formStatusData',[formFilter]));
|
|
|
|
+ //crfButtons
|
|
|
|
+ let statusFilter=LABKEY.Filter.create(varLabel,formStatus);
|
|
|
|
+ queryArray.push(makeQuery('config','crfButtons','crfButtons',[statusFilter]));
|
|
|
|
+ //Forms
|
|
|
|
+ queryArray.push(makeQuery('config','Forms','formData',[]));
|
|
|
|
+ //FormSetup
|
|
|
|
+ queryArray.push(makeQuery('config','FormSetup','formSetup',[]));
|
|
|
|
+ //generateConfig
|
|
|
|
+ queryArray.push(makeQuery('config','generateConfig','generateConfigData',[]));
|
|
|
|
+ //parentCrf
|
|
|
|
+ let parentCrf=config.formConfig.crfEntry['parentCrf'];
|
|
|
|
+ if (parentCrf!=undefined){
|
|
|
|
+ let crfFilter=LABKEY.Filter.create('entryId',parentCrf);
|
|
|
|
+ queryArray.push(makeQuery('data','crfEntry','parentCrfData',[crfFilter]));
|
|
|
|
+ }
|
|
|
|
+ queryArray.push(makeQuery('data','help','help'));
|
|
|
|
+
|
|
|
|
+ print('running getDataFromQueries');
|
|
|
|
+ getDataFromQueries(queryArray,fcontinue);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function selectFormSetupRows(formId){
|
|
|
|
+ let formSetupRows=new Array();
|
|
|
|
+ let allRows=config.formConfig.formSetup.rows;
|
|
|
|
+ for (let i=0;i<allRows.length;i++){
|
|
|
|
+ let formEntry=allRows[i];
|
|
|
|
+ if (formEntry.formName==formId)
|
|
|
|
+ formSetupRows.push(formEntry);
|
|
|
|
+ }
|
|
|
|
+ return formSetupRows;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function fcontinue(){
|
|
|
|
+ //parse site
|
|
|
|
+ config.formConfig.siteRows=config.formConfig.siteData.rows;
|
|
|
|
+ let sRows=config.formConfig.siteRows;
|
|
|
|
+ for (let i=0;i<sRows.length;i++){
|
|
|
|
+ let siteId=sRows[i].siteNumber;
|
|
|
|
+ print('site '+siteId);
|
|
|
|
+ if (siteId==config.formConfig.crfEntry.Site){
|
|
|
|
+ config.formConfig.currentSite=sRows[i];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //config.formConfig.site=data.rows[0];
|
|
|
|
+ print("Setting site name to "+config.formConfig.currentSite.siteName);
|
|
|
|
+ //study
|
|
|
|
+ config.formConfig.studyData=config.formConfig.studyDataAll.rows[0];
|
|
|
|
+ print("XSetting participantField to "+
|
|
|
|
+ config.formConfig.studyData["SubjectColumnName"]);
|
|
|
|
+
|
|
|
|
+ config.formConfig.crfEditors=config.formConfig.crfEditorsData.rows;
|
|
|
|
+ config.formConfig.crfMonitors=config.formConfig.crfMonitorsData.rows;
|
|
|
|
+ config.formConfig.crfSponsors=config.formConfig.crfSponsorsData.rows;
|
|
|
|
+
|
|
|
|
+ config.formConfig.userRows=config.formConfig.userData.rows;
|
|
|
|
+ let uRows=config.formConfig.userRows;
|
|
|
|
+ for (let i=0;i<uRows.length;i++){
|
|
|
|
+ let userId=uRows[i].UserId;
|
|
|
|
+ if (userId==config.formConfig.crfEntry.UserId){
|
|
|
|
+ config.formConfig.user=uRows[i];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //config.formConfig.user=data.rows[0];
|
|
|
|
+ print("Setting user to "+config.formConfig.user["DisplayName"]);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let fsRows=config.formConfig.formStatusData.rows;
|
|
|
|
+ config.formConfig.formStatus=fsRows[0].formStatus;
|
|
|
|
+ config.formConfig.operator=config.role;
|
|
|
|
+ //config.formConfig.operator=fsRows[0].operator;
|
|
|
|
+
|
|
|
|
+ print('Setting operator to: '+config.formConfig.operator);
|
|
|
|
+
|
|
|
|
+ config.formConfig.formRows=config.formConfig.formData.rows;
|
|
|
|
+
|
|
|
|
+ let formRows=config.formConfig.formRows;
|
|
|
|
+ //filter out the current form
|
|
|
|
+ for (let i=0;i<formRows.length;i++){
|
|
|
|
+ if (formRows[i].Key==config.formId){
|
|
|
|
+ config.formConfig.form=formRows[i];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ config.formConfig.formSetupRows=selectFormSetupRows(config.formId);
|
|
|
|
+
|
|
|
|
+ print("Number of datasets for form ["+config.formId+"]: "+
|
|
|
|
+ config.formConfig.formSetupRows.length);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ let fields=config.formConfig.formSetup.metaData.fields;
|
|
|
|
+
|
|
|
|
+ //get the lookup for queryName column
|
|
|
|
+ let formQueryName='queryName';
|
|
|
|
+ let field="NONE";
|
|
|
|
+ for (f in fields){
|
|
|
|
+ if (fields[f]['name']!=formQueryName) continue;
|
|
|
|
+ field=fields[f];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ let lookup=field.lookup;
|
|
|
|
+
|
|
|
|
+ print("Getting dataset names from "+lookup.queryName);
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ //inputLists should be in configuration container
|
|
|
|
+ selectRows.containerPath=getContainer('config');
|
|
|
|
+ selectRows.schemaName=lookup.schemaName;
|
|
|
|
+ selectRows.queryName=lookup.queryName;
|
|
|
|
+ selectRows.success=afterFormDatasets;
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterFormDatasets(data){
|
|
|
|
+ print('afterFormDatasets: '+data.rows.length);
|
|
|
|
+ config.formConfig.formDatasets=data;//inputLists
|
|
|
|
+ config.formConfig.fields=new Object();
|
|
|
|
+ config.formConfig.queryMap=new Object();
|
|
|
|
+ config.formConfig.additionalData=new Object();
|
|
|
|
+
|
|
|
|
+ let rows=config.formConfig.formSetupRows;
|
|
|
|
+
|
|
|
|
+ //should skip report only rows
|
|
|
|
+ for (let i=0;i<rows.length;i++){
|
|
|
|
+ let entry=rows[i];
|
|
|
|
+ let reviewField=(entry['showFlag']=='REVIEW');
|
|
|
|
+ //is the operator set yet?
|
|
|
|
+ let accessMode=config.formConfig.operator+'Mode';
|
|
|
|
+ let skipField=(entry[accessMode]=="NONE");
|
|
|
|
+ let queryId=entry['queryName'];
|
|
|
|
+ let lookupRows=config.formConfig.formDatasets.rows;
|
|
|
|
+ print('QueryID['+i+']='+queryId);
|
|
|
|
+ let dentry;
|
|
|
|
+
|
|
|
|
+ for (let j=0;j<lookupRows.length;j++){
|
|
|
|
+
|
|
|
|
+ if (queryId!=lookupRows[j]['Key']) continue;
|
|
|
|
+ dentry=lookupRows[j];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ let qName=dentry['queryName'];
|
|
|
|
+
|
|
|
|
+ //update list of dataset formConfig is observing (fields/queryMap)
|
|
|
|
+ while (1){
|
|
|
|
+ //review contains no data
|
|
|
|
+ if (reviewField) break;
|
|
|
|
+ if (skipField) break;
|
|
|
|
+ //already in fields
|
|
|
|
+ if (qName in config.formConfig.fields) break;
|
|
|
|
+ config.formConfig.fields[qName]=new Object();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ while(1){
|
|
|
|
+ //already done
|
|
|
|
+ if (queryId in config.formConfig.queryMap) break;
|
|
|
|
+ config.formConfig.queryMap[queryId]=qName;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (reviewField) continue;
|
|
|
|
+ if (skipField) continue;
|
|
|
|
+ //only do this for real lists
|
|
|
|
+ let field=config.formConfig.fields[qName];
|
|
|
|
+ field.title=entry['title'];
|
|
|
|
+ field.queryId=queryId;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ print("List of datasets in form : ");
|
|
|
|
+ for (f in config.formConfig.fields){
|
|
|
|
+ let field=config.formConfig.fields[f];
|
|
|
|
+ print("\t"+f+" ID: "+field.queryId+' title '+field.title);
|
|
|
|
+ }
|
|
|
|
+ afterConfig();
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//>>>>>>>>>>>>>>>>>new>>>>>>>>>>>>
|
|
|
|
+
|
|
|
|
+function setDataLayout(cb){
|
|
|
|
+ let rowsSetup=config.formConfig.formSetupRows;
|
|
|
|
+ config.formConfig.dataQueries=new Object();
|
|
|
|
+ let dS=config.formConfig.dataQueries;//reference only
|
|
|
|
+ let qMap=config.formConfig.queryMap;
|
|
|
|
+ config.formConfig.lookup=new Object();
|
|
|
|
+ for (let i=0;i<rowsSetup.length;i++){
|
|
|
|
+ let entry=rowsSetup[i];
|
|
|
|
+ //skip review rows
|
|
|
|
+ if (entry['showFlag']=='REVIEW')
|
|
|
|
+ continue;
|
|
|
|
+ let queryId=entry['queryName'];
|
|
|
|
+ let queryName=qMap[entry['queryName']];
|
|
|
|
+ dS[queryName]=new Object();
|
|
|
|
+ dS[queryName].title=entry['title'];
|
|
|
|
+ if (entry['showQuery']!="NONE"){
|
|
|
|
+ let sqName=entry['showQuery'];
|
|
|
|
+ dS[sqName]=new Object();
|
|
|
|
+ dS[sqName].title=findTitle(sqName);
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ //always add reviews
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ config.formConfig.dataQueries['reviewComments']=new Object();
|
|
|
|
+
|
|
|
|
+ //perhaps we will need queryId, but this is stuff for later
|
|
|
|
+ for (q in config.formConfig.dataQueries){
|
|
|
|
+ //callback will be a watchdog and will complete only
|
|
|
|
+ //when all data will be gathered
|
|
|
|
+ let dq=config.formConfig.dataQueries[q];
|
|
|
|
+ dq.collectingLayout="INITIALIZED";
|
|
|
|
+
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ selectRows.queryName=q;
|
|
|
|
+ selectRows.schemaName='lists';
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+ //we are only interested in metadata
|
|
|
|
+ selectRows.success=function(data){afterDatasets(data,cb);}
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function findTitle(queryName){
|
|
|
|
+//find by name from formDatasets
|
|
|
|
+//and set associated title as title
|
|
|
|
+ let rows=config.formConfig.formDatasets.rows;
|
|
|
|
+ for (let i=0;i<rows.length;i++){
|
|
|
|
+ let entry=rows[i];
|
|
|
|
+ if (entry['queryName']!=queryName) continue;
|
|
|
|
+ return entry['title'];
|
|
|
|
+ }
|
|
|
|
+ return "NONE";
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//this happens after the for loop, so all dataQueries objects are set
|
|
|
|
+function afterDatasets(data,cb){
|
|
|
|
+ let qobject=config.formConfig.dataQueries[data.queryName];
|
|
|
|
+ print("Inspecting layout for "+data.queryName+" "+qobject);
|
|
|
|
+ qobject.fields=data.metaData.fields;
|
|
|
|
+ qobject.collectingLayout="STARTED";
|
|
|
|
+ //qobject.started="TRUE";
|
|
|
|
+ qobject.lookup=new Object();//keep track of objects
|
|
|
|
+
|
|
|
|
+ let i=0;
|
|
|
|
+ for (let f in qobject.fields){
|
|
|
|
+ //anything else is simple but lookup
|
|
|
|
+ let field=qobject.fields[f];
|
|
|
|
+ if (!("lookup" in field)) continue;
|
|
|
|
+ qobject.lookup[f]="PENDING";
|
|
|
|
+ print("Adding pending lookup for field "+f);
|
|
|
|
+ if (field.lookup.queryName in config.formConfig.lookup){
|
|
|
|
+ qobject.lookup[f]="DONE";
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ print("Setting up query for field "+f);
|
|
|
|
+ config.formConfig.lookup[field.lookup.queryName]=new Object();
|
|
|
|
+ let lObject=config.formConfig.lookup[field.lookup.queryName];
|
|
|
|
+ lObject.keyColumn=field.lookup.keyColumn;
|
|
|
|
+ lObject.displayColumn=field.lookup.displayColumn;
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ selectRows.schemaName=field.lookup.schemaName;
|
|
|
|
+ selectRows.queryName=field.lookup.queryName;
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+ if ("containerPath" in field.lookup){
|
|
|
|
+ selectRows.containerPath=field.lookup.containerPath;
|
|
|
|
+ }
|
|
|
|
+ //selectRows.columns=field.lookup.keyColumn+","+field.lookup.displayColumn;
|
|
|
|
+ //get all, descriptions may be hidden in further variables
|
|
|
|
+ //wait for all lookups to return
|
|
|
|
+ selectRows.success=function(data){addLookup(data,qobject,f,cb);};
|
|
|
|
+ print("Sending query: ["+
|
|
|
|
+ field.lookup.queryName+"] "+
|
|
|
|
+ field.lookup.keyColumn+'/'+
|
|
|
|
+ field.lookup.displayColumn);
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+ i+=1;
|
|
|
|
+ }
|
|
|
|
+ if (i==0){
|
|
|
|
+ print("No lookups for "+data.queryName);
|
|
|
|
+ qobject.collectingLayout="FINISHED";
|
|
|
|
+ }
|
|
|
|
+ //check if done (both here and in lookup
|
|
|
|
+ //this only passes if no lookups are anywhere in the dataset assembly
|
|
|
|
+ if (!dataLayoutSet()) return;
|
|
|
|
+ cb();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function addLookup(data,qobject,f,cb){
|
|
|
|
+ print("Adding lookup "+data.queryName+' '+qobject+' '+f);
|
|
|
|
+ let lObject=config.formConfig.lookup[data.queryName];
|
|
|
|
+ lObject.LUT=new Array();//key to value
|
|
|
|
+ lObject.ValToKey=new Array();//value to key
|
|
|
|
+ let key=lObject.keyColumn;
|
|
|
|
+ let val=lObject.displayColumn;
|
|
|
|
+
|
|
|
|
+ for (let i=0;i<data.rows.length;i++){
|
|
|
|
+ lObject.LUT[data.rows[i][key]]=data.rows[i][val];
|
|
|
|
+ lObject.ValToKey[data.rows[i][val]]=data.rows[i][key];
|
|
|
|
+ }
|
|
|
|
+ lObject.rows=data.rows;
|
|
|
|
+ qobject.lookup[f]="DONE";
|
|
|
|
+ if (!dataLayoutSet()) return;
|
|
|
|
+ cb();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function dataLayoutSet(){
|
|
|
|
+ print("Checking layout completeness");
|
|
|
|
+ let dq=config.formConfig.dataQueries;
|
|
|
|
+ for (f in dq){
|
|
|
|
+ print("["+f+"]: "+dq[f].collectingLayout);
|
|
|
|
+ if (dq[f].collectingLayout=="INITIALIZED")
|
|
|
|
+ return 0;
|
|
|
|
+ if (dq[f].collectingLayout=="FINISHED")
|
|
|
|
+ continue; //OK
|
|
|
|
+ let qobject=dq[f];
|
|
|
|
+ for (q in qobject.lookup){
|
|
|
|
+ if (qobject.lookup[q]=="DONE") {
|
|
|
|
+ print("["+f+"/"+q+"]: DONE");
|
|
|
|
+ continue;//OK
|
|
|
|
+ }
|
|
|
|
+ print("["+f+"/"+q+"]: "+qobject.lookup[q]);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ dq[f].collectingLayout="FINISHED";
|
|
|
|
+ }
|
|
|
|
+ print("Success");
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function setData(cb){
|
|
|
|
+ fName='[setData]';
|
|
|
|
+ print(fName+': cb '+cb);
|
|
|
|
+ let crfMatch=getCRFref();
|
|
|
|
+ let parentCrf=config.formConfig.crfEntry['parentCrf'];
|
|
|
|
+ if (parentCrf!=undefined) crfMatch=parentCrf;
|
|
|
|
+
|
|
|
|
+ print(fName+' form crf ['+getCRFref()+'] matching for crfRef='+crfMatch);
|
|
|
|
+ //collect data and execute callback cb for queries in cb.queryList
|
|
|
|
+ for (q in config.formConfig.dataQueries){
|
|
|
|
+ let fQuery=config.formConfig.dataQueries[q];
|
|
|
|
+ fQuery.collectingData="STARTED";
|
|
|
|
+ let selectRows=new Object();
|
|
|
|
+ selectRows.containerPath=getContainer('data');
|
|
|
|
+ selectRows.queryName=q;
|
|
|
|
+ selectRows.schemaName='lists';
|
|
|
|
+ selectRows.filterArray=[
|
|
|
|
+ LABKEY.Filter.create("crfRef",crfMatch)
|
|
|
|
+ ];
|
|
|
|
+ selectRows.success=function(data){assembleData(data,cb);};
|
|
|
|
+ LABKEY.Query.selectRows(selectRows);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function assembleData(data,cb){
|
|
|
|
+ let fName='[assembleData/'+data.queryName+']';
|
|
|
|
+ let fQuery=config.formConfig.dataQueries[data.queryName];
|
|
|
|
+ fQuery.rows=data.rows;
|
|
|
|
+ fQuery.collectingData="FINISHED";
|
|
|
|
+ print(fName+': adding data');
|
|
|
|
+ for (q in config.formConfig.dataQueries){
|
|
|
|
+ let dq=config.formConfig.dataQueries[q];
|
|
|
|
+ //print("assembleData ["+q+"]: "+dq.collectingData);
|
|
|
|
+ if (dq.collectingData=="STARTED") return;
|
|
|
|
+ }
|
|
|
|
+ print(fName+': completing');
|
|
|
|
+ cb();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function uploadFile(inputElement,context){
|
|
|
|
+ //context should have ID and dirName attributes;
|
|
|
|
+ //path will be dirName/ID/fieldName_ID.suf
|
|
|
|
+ //where suf is identical to localPath content picked from
|
|
|
|
+ //inputElement
|
|
|
|
+ print('uploadFile: '+inputElement.value+'/');
|
|
|
|
+ if (inputElement.type=="text") return;
|
|
|
|
+ print('uploadFile: '+inputElement.files+'/');
|
|
|
|
+ print('uploadFile: '+inputElement.files.length+'/');
|
|
|
|
+ if (inputElement.files.length>0){
|
|
|
|
+ let file=inputElement.files[0];
|
|
|
|
+ print('uploadFile: '+inputElement.value+'/'+file.size);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let url=LABKEY.ActionURL.getBaseURL();
|
|
|
|
+ url+='_webdav';
|
|
|
|
+ url+=LABKEY.ActionURL.getContainer();
|
|
|
|
+ url+='/@files';
|
|
|
|
+ url+='/'+context['dirName'];
|
|
|
|
+
|
|
|
|
+ print('uploadFile url: '+url);
|
|
|
|
+ let uploadConfig=new Object();
|
|
|
|
+ uploadConfig.inputElement=inputElement;
|
|
|
|
+ uploadConfig.context=context;
|
|
|
|
+ uploadConfig.url=url;
|
|
|
|
+ uploadConfig.success=afterBaseDir;
|
|
|
|
+ uploadConfig.failure=tryMakeDir;
|
|
|
|
+ webdavCheck(uploadConfig);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterBaseDir(cfg){
|
|
|
|
+ print('afterBaseDir');
|
|
|
|
+ cfg.url+='/'+cfg.context['ID'];
|
|
|
|
+ cfg.success=afterIDDir;
|
|
|
|
+ cfg.failure=tryMakeDir;
|
|
|
|
+ webdavCheck(cfg);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterIDDir(cfg){
|
|
|
|
+ print('afterIDDir');
|
|
|
|
+ if (cfg.inputElement.files.length==0){
|
|
|
|
+ print('No files found');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ let file=cfg.inputElement.files[0];
|
|
|
|
+ print('Uploading '+file.name);
|
|
|
|
+ let suf=file.name.split('.').pop();
|
|
|
|
+ cfg.url+='/'+cfg.context['ID']+'.'+suf;
|
|
|
|
+ cfg.success=afterUpload;
|
|
|
|
+ cfg.failure=onFailure;
|
|
|
|
+ cfg.data=file;
|
|
|
|
+ webdavPut(cfg);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function afterUpload(cfg){
|
|
|
|
+ print('afterUpload');
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function tryMakeDir(cfg){
|
|
|
|
+ print('tryMakeDir '+cfg.url);
|
|
|
|
+ cfg.failure=onFailure;
|
|
|
|
+ webdavMakeDir(cfg);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function request(cfg,verb,data){
|
|
|
|
+ print('request['+verb+'] '+cfg.url);
|
|
|
|
+ let connRequest=new XMLHttpRequest();
|
|
|
|
+ connRequest.addEventListener("loadend",
|
|
|
|
+ function(){checkResponse(connRequest,cfg);});
|
|
|
|
+ connRequest.open(verb, cfg.url);
|
|
|
|
+ connRequest.send(data);
|
|
|
|
+ //print('request['+verb+'] sent');
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function checkResponse(xrq,cfg){
|
|
|
|
+ //print('checkResponse: readyState '+xrq.readyState);
|
|
|
|
+ //print('checkResponse: status '+xrq.status);
|
|
|
|
+ if (xrq.status<400) {
|
|
|
|
+ //client errors 400-499
|
|
|
|
+ //server errors 500-599
|
|
|
|
+ cfg.success(cfg);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ cfg.status=xrq.status;
|
|
|
|
+ cfg.failure(cfg);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function webdavMakeDir(cfg){ request(cfg,'MKCOL',null);}
|
|
|
|
+function webdavCheck(cfg) { request(cfg,'GET',null);}
|
|
|
|
+function webdavPut(cfg) { request(cfg,'PUT',cfg.data);}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+function onFailure(cfg){
|
|
|
|
+ print('request failed with status='+cfg.status);
|
|
|
|
+}
|
|
|
|
+
|