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 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){ //return information on additional data associated with the form //additionalData is a sub-list with multiple entries per patient/visit //argument is the row of the formSetup setup list let queryName=config.formConfig.queryMap[formSetupEntry['queryName']]; let fName='[getAdditionalData/'+queryName+']'; print(fName); //additionalData holds a reference to all queries already parsed //this helps in reducing number of calls to the database (I assume) if (queryName in config.formConfig.additionalData){ print(fName+': Returning preset value'); return config.formConfig.additionalData[queryName]; } //first time we see this query, so we have to do the setup print(fName+': generating'); config.formConfig.additionalData[queryName]=new Object(); //takes address, so further changes will be to the newly created object //in fact, ad is just a short alias of the long variable name on the right let ad=config.formConfig.additionalData[queryName]; //no additional data if (formSetupEntry["showFlag"]==="NONE") { print(fName+": empty"); return ad; } //use showFlag to setup report section of the CRF list if (formSetupEntry["showFlag"]==="REVIEW") { //abuse additionalData to signal different segment print(fName+": generateReport"); ad.isReview=true; return ad; } //setup the additionalData memory object print(fName+': setting values'); ad.showFlag=formSetupEntry["showFlag"]; ad.showFlagValue=formSetupEntry["showFlagValue"]; ad.queryName=formSetupEntry["showQuery"]; //for data queries, limit to present CRF only ad.filters=new Object(); ad.filters['crfRef']=getCRFref(); //compose a long debug message let msg=fName+": flag "+ad.showFlag; msg+=" value "+ad.showFlagValue; msg+=" query "+ad.queryName; print(msg); return ad; } function fullAccessSetup(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=new Object(); setup.queryName=listName; setup.readonlyFlag=function(vName){return false}; setup.filters=new Object(); setup.filters['crfRef']=getCRFref(); setup.getInputId=function(vName){return listName+"_"+vName;} setup.addApply="Save"; setup.isReview=false; return setup; } function readonlySetup(listName){ //see definition of setup object above let debug=true; if (debug) print("readonlySetup"); let setup=new Object(); setup.queryName=listName; setup.readonlyFlag=function(vName){return true}; setup.filters=new Object(); setup.filters['crfRef']=getCRFref(); setup.getInputId=function(vName){return listName+'_'+vName;} setup.isReview=false; return setup; } function getSetup(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(listName); //if (formStatus=="Approved") // return readonlySetup(listName); return fullAccessSetup(listName); } function generateSection(formSetupEntry){ let listName=config.formConfig.queryMap[formSetupEntry['queryName']]; let fName='[generateSection/'+listName+']'; 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"+listName+"VisbilityButton"; input.onclick=function(){toggleVisibility(listName,input.id)}; cell.appendChild(input); config.document.getElementById(formName).appendChild(tb); let div=config.document.createElement('div'); div.id=listName; div.style.display="none"; config.document.getElementById(formName).appendChild(div); let divTable=config.document.createElement('div'); divTable.id=listName+"Table"; div.appendChild(divTable); if ("showFlag" in additionalData) { additionalData.divName=listName+"SubDiv"; additionalData.divQueryName=listName+"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("generate master table"); let writeMode=accessMode=="EDIT"; let setup=getSetup(listName,writeMode); if ("isReview" in additionalData){ generateReviewSection(listName,div.id,generateReviewSectionCB); return; } //master table is unique per visit setup.unique=true; generateTable(listName,divTable.id,additionalData,setup); if (debug) print("generate 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 setup=fullAccessSetup(qName); //only set master query for additionalData setup.masterQuery=listName; //if (readonly) setup=readonlySetup(config); generateTable(qName,dName,additionalData,setup); //generateTable(formSetupEntry,qName,dName,additionalData,setup); } print("generate review"); let divReviewList=config.document.createElement('div'); divReviewList.id=listName+"ReviewList"; div.appendChild(divReviewList); let divReview=config.document.createElement('div'); divReview.id=listName+"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); if (accessMode!='GENERATE') return; print('Adding generate button'); //add generateButton let divGenerateButton=config.document.createElement('div'); divGenerateButton.id=listName+'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;ifx[i]) continue; i0=i-1; break; } let fval=1; if (i0obj.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>>>>>>>>>>>>>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=new Object(); 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 listName+"_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 (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+": UpdateListDisplay: Query - "+queryName +" div - "+divName); if (divName=="NONE") return; let crfRef=getCRFref(); let div=config.document.getElementById(divName); 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"); } //TODO: this should trigger a data refresh on section, ie populateData(field) function toggleVisibility(divName,buttonName){ let fName='[toggleVisibility/'+divName+']'; print(fName); let x = config.document.getElementById(divName); 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(divName);}; 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'); cell.style.width='300px'; row.appendChild(cell); let text = config.document.createTextNode(field.shortCaption); cell.appendChild(text); let input=null; let colSpan="3"; let cell1=row.insertCell(); cell1.colSpan=colSpan; let readonlyFlag=setup.readonlyFlag(vName); //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; } 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 //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 = ""); //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 parseVariables(pars){ let pA=pars.split(";"); let q=new Object(); for (let i=0;i0) entry=fQuery.rows[0]; let fields=fQuery.fields; 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); } } 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; let entry=new Object(); //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); if (fQuery.rows.length>0) entry=fQuery.rows[0]; 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; for (f in fields){ let field=fields[f]; let fieldUID=listName+":"+field.name; //each field is a new row print(fName+": Adding field: "+f+'/'+field.name+' ('+fieldUID+').'); //unique name if (field.hidden) continue; if (field.name=="crfRef") continue; addFieldRow(tb,field,setup,additionalData); populateFieldRow(entry,field,setup); if (fieldUID in config.formConfig["specialFields"]){ let specFieldSetup=config.formConfig["specialFields"][fieldUID]; addSpecialFieldRow(tb,specFieldSetup,setup); } } //finish of if apply button is not required if (!("addApply" in setup)) { print(fName+"populateTable: 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]; if (fQuery.rows.length==0) useInsert=true; let entry=new Object(); if (!useInsert){ entry=fQuery.rows[0]; } 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; } } 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);}); 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(); let fc=new Object(); let pM=getParticipantManagerObject(config); fc.participantId=pM.getParticipantIdFromCrfEntry(); print(fName+' id '+fc.participantId); afterParticipantId(fc); } function onDatabaseUpload1(){ 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;i0) { 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;i1){ 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 fName='[updateFlag 1]'; let debug=true; let entry=config.formConfig.crfEntry; 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;iiTotal){ if (0) return; redirect(); } let queryName="crfEntry"; let idVar="entryId"; let idValue=getCRFref(); if (i100){ 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;i0) 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; i0){ populateTable(queryName,0); 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){ let fName='[onGenerateQuery]'; print(fName+' '+queryName); // let cfgRows=config.formConfig.generateConfigData.rows; // //queryName to queryId? let queryId=config.formConfig.fields[queryName].queryId; let cfgRow=undefined; for (let i=0;i0) { 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 //get local Id let pM=getParticipantManagerObject(config); crfEntry[pM.getCrfEntryFieldName()]=pM.getParticipantIdFromCrfEntry(); // //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;i0) return; let pM=getParticipantManagerObject(config); let e2=new Object(); e2.crfRef=getCRFref(); e2.registrationStatus=0; e2.submissionDate=new Date(); e2[pM.getCrfEntryFieldName()]=pM.getParticipantIdFromCrfEntry(); 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='T.15.18'; 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 convertToDictionary(rows){ let x=new Array(); for (let i=0;i 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 targetObject=config.formConfig; targetObject.print=print; targetObject.getContainer=getContainer; let queryArray=new Array(); //k //site queryArray.push(makeQuery(targetObject,'config','site','siteData',[])); //users queryArray.push(makeQuery(targetObject,'CRF','users','userData',[])); queryArray[queryArray.length-1].schemaName='core'; //crfEditors queryArray.push(makeQuery(targetObject,'config','crfEditors','crfEditorsData',[])); //crfMonitors queryArray.push(makeQuery(targetObject,'config','crfMonitors','crfMonitorsData',[])); //crfSponsors queryArray.push(makeQuery(targetObject,'config','crfSponsors','crfSponsorsData',[])); //study static data queryArray.push( makeQuery(targetObject,'data','crfStaticVariables','crfStaticVariables',[])); queryArray.push(makeQuery(targetObject,'data','specialFields','specialFieldsQuery',[])); //study queryArray.push(makeQuery(targetObject,'data','Study','studyDataAll1',[])); let e=queryArray[queryArray.length-1]; //overload schema name e.schemaName='study'; //make sure variables not part of default view are loaded //here we should already have read crfStaticVariables table e.columns="SubjectColumnName,EudraCTNumber,StudySponsor"; e.columns+=",StudyCoordinator,RegulatoryNumber"; //formStatus let varLabel='sourceFormStatus'; let formStatus=config.formConfig.crfEntry['FormStatus']; let formFilter=LABKEY.Filter.create('Key',formStatus); queryArray.push( makeQuery(targetObject,'config','FormStatus','formStatusData',[formFilter])); //crfButtons let statusFilter=LABKEY.Filter.create(varLabel,formStatus); queryArray.push( makeQuery(targetObject,'config','crfButtons','crfButtons',[statusFilter])); //Forms queryArray.push(makeQuery(targetObject,'config','Forms','formData',[])); //FormSetup queryArray.push(makeQuery(targetObject,'config','FormSetup','formSetup',[])); //generateConfig queryArray.push( makeQuery(targetObject,'config','generateConfig','generateConfigData',[])); //parentCrf let parentCrf=config.formConfig.crfEntry['parentCrf']; if (parentCrf!=undefined){ let crfFilter=LABKEY.Filter.create('entryId',parentCrf); queryArray.push(makeQuery(targetObject,'data','crfEntry','parentCrfData',[crfFilter])); } print('running getDataFromQueries'); getDataFromQueries(queryArray,addStudyData); } function addStudyData(){ let fName='addStudyData'; //convert specialFields to array let q=config.formConfig["specialFieldsQuery"].rows; config.formConfig.specialFields=convertToAssociatedArray(q,"fieldUID"); print(fName); let queryArray=new Array(); let targetObject=config.formConfig; targetObject.print=print; targetObject.getContainer=getContainer; //study queryArray.push(makeQuery(targetObject,'data','Study','studyDataAll',[])); //queryArray.push(makeQuery('data','Study','studyDataAll',[])); let e=queryArray[queryArray.length-1]; //overload schema name e.schemaName='study'; //make sure variables not part of default view are loaded //here we should already have read crfStaticVariables table let staticVarRows=config.formConfig['crfStaticVariables'].rows; let columnModel="" for (let i=0;i0) columnModel+=','; columnModel+=staticVarRows[i]['staticVariable']; } e.columns=columnModel; //also collect ids already in study //registrationQuery should be a dataset let demoQuery=config.formConfig.settings['registrationQuery']; queryArray.push(makeQuery(targetObject,'data',demoQuery,'registrationData',[])); queryArray[queryArray.length-1].schemaName='study'; getDataFromQueries(queryArray,fcontinue); } function selectFormSetupRows(formId){ let formSetupRows=new Array(); let allRows=config.formConfig.formSetup.rows; for (let i=0;i>>>>>>>>>>>>>>>>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;i0){ 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); }