var crfVisit={}; //crfVisit.config=new Object(); crfVisit.setDebug= function(debug=null){ if (debug){ this.print=function(msg){debug.this.print(msg);}; this.clear=function(){debug.clear();} return; } //provide default functions if not debug object is available this.print=function(msg){console.log(msg);} this.clear=function(){;} } crfVisit.setDebug(); crfVisit.init= function(cb=null){ let that=this; let action=function(){that.scriptsLoaded(cb);}; let dependencies=new Array(); dependencies.push('crfDORA/runQuery.js'); dependencies.push("crfDORA/crfReviewSection.js"); dependencies.push("crfDORA/participantIdManager.js"); dependencies.push("crfDORA/variableList.js"); dependencies.push("crfDORA/webdav.js"); dependencies.push("crfDORA/crfPrint.js"); dependencies.push("crfDORA/crfSetup.js"); dependencies.push("crfDORA/crfData.js"); dependencies.push("crfDORA/crfHTML.js"); dependencies.push("crfDORA/generateRegistration.js"); dependencies.push("crfDORA/formPortalNew.js"); LABKEY.Utils.requiresScript(dependencies,action); } crfVisit.scriptsLoaded= function(cb=null){ participantIdManager.set(crfSetup,crfData); webdav.set(this); crfReviewSection.set(this); crfPrint.set(this); crfData.setSetup(crfSetup); crfHTML.init(); //generateRegistration.init(); let initRegistration=function(){generateRegistration.init(cb);}; let initIdManager=function(){participantIdManager.init(initRegistration);}; let initCrfData=function(){crfData.init(initIdManager)}; let initFormPortal=function(){formPortal.init(initCrfData);}; crfSetup.init(initFormPortal); } crfVisit.getContainer= function(label){ return crfSetup.getContainer(label); } crfVisit.getCrfRefFirst= function(){ //crfRef is part of html call and gets stored in the page return this.crfRef; } crfVisit.getCrfRef= function (){ //'crfRefId' return crfData.getCrfEntry()['entryId']; } crfVisit.getCrfRefData= function(){ let parentCrf=crfData.getCrfEntry()['parentCrf']; if (parentCrf!=undefined) return parentCrf; return this.getCrfRef(); } crfVisit.onFailure= function(errorInfo, options, responseObj){ if (errorInfo && errorInfo.exception) alert("Failure: " + errorInfo.exception); else alert("Failure: " + responseObj.statusText); } crfVisit.doNothing= function (){ this.print('doNothing called'); } crfVisit.getIdManager= function(){ if (!("masterForm" in participantIdManager)){ participantIdManager.siteNumber=crfData.getCrfEntry()['Site']; participantIdManager.masterForm=this.masterForm; participantIdManager.generateTable(); } return participantIdManager; } crfVisit.getSetupObject= function(){ if (!("setups" in this)) this.setups=new Object(); return this.setups; } crfVisit.getStoredSetup= function(sectionId){ let sObj=this.getSetupObject(); if (sectionId in sObj) return sObj[sectionId]; return null; } crfVisit.addSetup= function(sectionId,setup){ let sObj=this.getSetupObject(); sObj[sectionId]=setup; } crfVisit.makeSetup= function(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 // let fName='[Setup]'; this.print(fName+' '+sectionId+'/'+listName); let setup=new Object(); setup.queryName=listName; setup.readonlyFlag=function(vName){return false}; setup.filters=new Object(); setup.filters['crfRef']=this.getCrfRef(); setup.getInputId=function(vName){return sectionId+"_"+vName;} setup.sectionId=sectionId; setup.isReview=false; this.addSetup(sectionId,setup); setup.setVariables=new Object(); return setup; } crfVisit.makeFullAccessSetup= function(sectionId,listName){ //addApply - whether a submit/Save button is generated let setup=this.makeSetup(sectionId,listName); setup.addApply="Save"; return setup; } crfVisit.makeReadonlySetup= function(sectionId,listName){ let setup=this.makeSetup(sectionId,listName); //see definition of setup object above, change readonly flag setup.readonlyFlag=function(vName){return true}; return setup; } crfVisit.getSetup= function(sectionId,listName,writeAccess=true){ //change to section granulated permission of type EDIT, COMMENT, READ //let formStatus=config.formConfig.formStatus; //equivalent to READ let setup=this.getStoredSetup(sectionId); if (setup) return setup; if (!writeAccess) //if (formStatus=="Submitted") return this.makeReadonlySetup(sectionId,listName); //if (formStatus=="Approved") // return readonlySetup(listName); return this.makeFullAccessSetup(sectionId,listName); } crfVisit.generateSection= function(formSetupEntry){ let that=this; let listName=crfSetup.getMap('inputLists')[formSetupEntry['queryName']]; let sectionId="section"+formSetupEntry['Key']; //if (!listName) is for debugSection if (!listName){ listName="debugSection"; } let fName='[generateSection/'+listName+']'; let sectionTitle=formSetupEntry['title']; let accessModeColumn=this.role+'Mode'; let accessMode=formSetupEntry[accessModeColumn]; //this will fix it for later use as well this.print(fName+' title '+sectionTitle); let tb=crfHTML.createTable(this.masterForm); tb.className='t2'; let row=tb.insertRow(); let cell=crfHTML.createTblHeader(null,row); cell.setAttribute("colspan","4"); cell.style.fontSize="20px"; cell.style.textAlign="center"; crfHTML.createTextNode(sectionTitle,null,cell); cell=row.insertCell(); let input=crfHTML.createButton(null,cell); input.value="Show"; input.id="toggle"+sectionId+"VisbilityButton"; input.onclick=function(){that.toggleVisibility(sectionId,input.id)}; let div=crfHTML.createDiv(sectionId,this.masterForm); div.style.display="none"; //here divert for debugArea if (listName=="debugSection"){ let debugArea=crfHTML.createTextArea(null,div); debugArea.rows=10; debugArea.cols=95; debugArea.id=this.debugId; return; } let additionalData=crfSetup.getAdditionalData(listName); let divTable=crfHTML.createDiv(sectionId+"Table",null,div); if ("showFlag" in additionalData) { additionalData.divName=sectionId+"SubDiv"; additionalData.divQueryName=sectionId+"SubDivList"; let div1=crfHTML.createDiv(additionalData.divName,null,div); div1.style.display="none"; let div2=crfHTML.createDiv(additionalData.divQueryName,null,div1); } this.print(fName+" generate master table"); let writeMode=accessMode=="EDIT"; let setup=this.getSetup(sectionId,listName,writeMode); setup.setVariables=variableList.parseVariables(formSetupEntry['variableDefinition']); if ("isReview" in additionalData){ crfReviewSection.set(this); let action=function(){crfReviewSection.CB();}; crfReviewSection.generateSection(listName,div.id,action); return; } //master table is unique per visit setup.unique=true; this.generateTable(listName,divTable.id,additionalData,setup); this.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 subsectionId='sub'+sectionId; let xsetup=this.makeFullAccessSetup(subsectionId,qName); //only set master query for additionalData xsetup.masterQuery=listName; //if (readonly) setup=readonlySetup(config); xsetup.subTable=true; this.generateTable(qName,dName,additionalData,xsetup); //generateTable(formSetupEntry,qName,dName,additionalData,setup); } this.print("generate review"); let divReviewList=crfHTML.createDiv(sectionId+"ReviewList",null,div); let divReview=crfHTML.createDiv(sectionId+"Review",null,div); //assume we already have listId (content of config.setupQueryName is listId) //we need listName also //qconfig.queryName=config.setupQueryName; this.generateReview(divReview.id,divReviewList.id,listName,accessMode); if (accessMode!='GENERATE') return; this.print('Adding generate button'); //add generateButton let divGenerateButton=crfHTML.createDiv(listName+"GenerateButton",null,div); this.print('Adding generate button completed to here'); let cb=function(){that.onGenerateQuery(listName);}; this.generateButton(divGenerateButton.id,'Generate','Generate '+listName,'onGenerateQuery',cb); this.print(fName+' adding generate button completed'); } crfVisit.generateReview= function(divReviewId,divReviewListId, listName, accessMode){ let qMapInvert=crfSetup.invertMap(crfSetup.getMap('inputLists')); let listId=qMapInvert[listName] //listId is a number->should it be queryName? let fName='[generateReview]'; this.print(fName+" list "+listId+'/'+listName); let reviewSetup=new Object(); reviewSetup.setVariables=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"; reviewSetup.reviewTable=true; let generateTableFlag=true; let formStatus=crfData.getCrfEntry()['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"]=this.crfRef; if (crfData.getCrfEntry()['parentCrf']){ let parentCrf=crfData.getCrfEntry()['parentCrf']; reviewSetup.filters["crfRef"]=this.crfRef+";"+parentCrf; } 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; this.addSetup(divReviewId,reviewSetup); let msg="Review: divId: "+divReviewId; msg+=" inputId: "+reviewSetup.getInputId; this.print(msg); this.updateListDisplay(divReviewListId,"reviewComments",reviewSetup.filters,true); if (! generateTableFlag) return; this.generateTable("reviewComments",divReviewId,new Object(),reviewSetup); } //>>>>>>>>>>trigger visibility of additional lists crfVisit.setListVisibility= function(input,setup,readonlyFlag){ let fName="[setListVisibility/"+setup.queryName+"]"; this.print(fName); let additionalData=crfSetup.getAdditionalData(setup.queryName); let x = crfHTML.getElement(additionalData.divName); this.print(fName+": Div: "+x); x.style.display="none"; let sText; if (readonlyFlag) sText=input.innerText; else sText=input.options[input.selectedIndex].text; this.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"; this.updateListDisplay(additionalData.divQueryName, additionalData.queryName,filters,readonlyFlag); } } //>>have list refresh when data is added (not optimal yet) // crfVisit.updateListDisplay= function(divName,queryName,filters,readonlyFlag){ //use Labkey.QueryWebPart to show list let fName="[updateListDisplay]"; this.print(fName+": UpdateListDisplay: Query - "+queryName +" div - "+divName); if (divName=="NONE") return; let crfRef=this.getCrfRef(); let div=crfHTML.getElement(divName); this.print(fName+": generating WebPart: "+queryName); var qconfig=new Object(); qconfig.renderTo=divName; //point to data container qconfig.containerPath=this.getContainer('data'); qconfig.schemaName='lists'; qconfig.queryName=queryName; qconfig.buttonBarPosition='top'; qconfig.filters=[]; for (f in filters){ let fType=LABKEY.Filter.Types.EQUAL; this.print(fName+' filter ['+f+'] '+filters[f]+'/'+typeof(filters[f])+' ['+fType+']'); if (variableList.isFilterList(filters[f])){ fType=LABKEY.Filter.Types.IN; } qconfig.filters.push(LABKEY.Filter.create(f, filters[f],fType)); } let that=this; qconfig.success=function(data){that.updateSuccess(data);}; qconfig.failure=function(errorInfo,options,responseObj){that.onFailure(errorInfo,options,responseObj);}; //show only print button if (readonlyFlag){ qconfig.buttonBar=new Object(); qconfig.buttonBar.items=["print"]; } LABKEY.QueryWebPart(qconfig); } crfVisit.updateSuccess= function(data){ this.print("Update success"); } //TODO: this should trigger a data refresh on section, ie populateData(field) crfVisit.toggleVisibility= function(sectionId,buttonName){ let fName='[toggleVisibility/'+sectionId+']'; this.print(fName); let x = crfHTML.getElement(sectionId); if (x.style.display === "none") { //exclude non data sections (like debug)... this.print(fName+': issuing setData(populateSection)'); x.style.display = "block"; crfHTML.getElement(buttonName).value="Hide"; let that=this; let cb=function(){that.populateSection(sectionId);}; crfData.setData(crfData.getCrfRefForData(),cb); } else { x.style.display = "none"; crfHTML.getElement(buttonName).value="Show"; } } crfVisit.generateButton= function(divName,caption,label,callbackLabel,callback=null){ this.print("generateButtonX"); let tb=crfHTML.createTable(divName); tb.className="t2"; let r1=tb.insertRow(); let th=crfHTML.createTblHeader(null,r1); th.innerHTML=caption; //*!* let c2=r1.insertCell(); let i1=crfHTML.createButton(null,c2); i1.value=label; i1.style.fontSize="20px"; let that=this; if (callback) i1.onclick=callback; else i1.onclick=function(){that[callbackLabel]();}; i1.id='button_'+callbackLabel; let c1=r1.insertCell(); c1.setAttribute("colspan","1"); //this is only for saveReview? c1.id=divName+'_reportField'; //c1.id=config.submitReportId; } crfVisit.generateSubQuery= function(input, setup, readonlyFlag){ let fName="[generateSubQuery]"; if (setup.isReview) return; if (!(setup.queryName in crfSetup.getAdditionalDataObject())){ this.print(fName+': no additionalData entry (probably a subquery)'); return; } let additionalData=crfSetup.getAdditionalData(setup.queryName); if (!("showFlag" in additionalData)) return; this.print(fName); let expId=setup.getInputId(additionalData.showFlag); if (expId!=input.id) { this.print(fName+": ignoring field "+input.id+"/"+expId); return; } this.print(fName+": Setting onChange to "+input.id); if (readonlyFlag) return; let that=this; input.onchange=function(){that.setListVisibility(input,setup,readonlyFlag)}; } //>>populate fields // // //split to field generation and field population // crfVisit.addFieldRow= function(tb,field,setup,additionalData){ let fName="[addFieldRow/"+setup.queryName+':'+field.name+']'; let vName=field.name; let vType=field.type; let isLookup=("lookup" in field); this.print(fName+": ["+vName+"/"+vType+'/'+isLookup+"]"); let row=tb.insertRow(); let cell=crfHTML.createTblHeader(null,row); cell.style.width='300px'; let text = crfHTML.createTextNode(field.shortCaption,null,cell); 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=crfHTML.createLabel('Loading',null,cell1); break; } //lookup if (isLookup){ let lookup=field["lookup"]; //get all values from config.formConfig.lookup[X] let lObject=crfData.getLookup(lookup.queryName); input = crfHTML.createSelect(lObject.LUT,null,cell1); break; } //date if (vType=="date"){ input = crfHTML.createDate(null,cell1); 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 = crfHTML.createTextArea(null,cell1); input.cols="65"; input.rows="5"; break; } input=crfHTML.createTextInput(null,cell1); if (vName.search('_file_')<0) break; cell1.setAttribute('colspan',"1"); let cell2=row.insertCell(); cell2.setAttribute('colspan',"2"); let input1=crfHTML.createFileInput(null,cell2); input1.id=setup.getInputId(vName)+'_file_'; break; } if (vType=="float"){ input = crfHTML.createTextInput(null,cell1); break; } if (vType=="boolean"){ input = crfHTML.createCheckbox(null,cell1); this.print("Creating checkbox"); break; } break; } input.id=setup.getInputId(vName); this.print(fName+': adding element '+input.id); this.print(fName+': listing element '+crfHTML.getElement(input.id)); //connect associated list this.generateSubQuery(input,setup,readonlyFlag); if (readonlyFlag) { this.print(fName+': exiting(readonlyFlag)'); return; } } crfVisit.addSpecialFieldRows= function(tb,field,specFieldSetup,setup){ //tb is the table, specFieldSetup is a row from the table where special fields are being setup //the first column is fieldUID, which is a colon joined amalgation of queryName:fieldName let fieldUID=specFieldSetup["fieldUID"]; let x=fieldUID.split(':'); let fieldName=x[1]; let fName="[addSpecialFieldRow/"+fieldUID+"]"; let q=variableList.parseVariables(specFieldSetup['actionParameters']); this.print(fName); let type=specFieldSetup['actionType']; this.print(fName+' type '+type); if (type=='textArea' || type=="textAreaFromVariableDefinition"){ let row=tb.insertRow(); let cell1=row.insertCell(); cell1.colSpan="4"; cell1.style.textAlign="justify"; cell1.style.padding="10px"; cell1.style.backgroundColor="#e0e0e0"; cell1.innerText=q['description']; if (type!='textAreaFromVariableDefinition') return; let varName=q['varName']; //get the value. But sometimes and particularly in this case, there are two rows for the same query //one should rely on formSetup variable definition let value=setup.setVariables[varName]; let code=q['pattern']; code=code.replace(varName,value); this.print(fName+' using ['+varName+'] '+value+' pattern '+q['pattern']+' code '+code); cell1.innerText=q[code]; } //copyCrfEntry in populateSpecialField if (specFieldSetup['actionType']=='generationObject'){ //only in EDIT mode!! let ro=setup.readonlyFlag(fieldName); if (ro) return; generateRegistration.set(this); q['setup']=setup; let gc=generateRegistration.getObject(q,setup.getInputId(fieldName)); let that=this; let action=function(){that.doNothing();}; if ('mailRecipient' in q){ gc.callback=function(data){that.sendEmail(data,q['mailRecipient'],action,q['subject']);}; } else gc.callback=function(data){that.doNothing();}; if ("addData" in q){ vars=q["addData"].split(','); gc.addData=new Array(); for (let v in vars){ let s=vars[v] //variable name can be written as A/B where A is the name in addData and B is the variable name in crfEntry //useful for mocking up crfId from daughter crf-s such as registration let sArray=s.split('/'); let sTarget=sArray[0]; let sSource=sArray[sArray.length-1]; gc.addData[sTarget]=crfData.getCrfEntry()[sSource]; this.print(fName+" addData ["+sTarget+"]: "+gc.addData[sTarget]); } } let row=tb.insertRow(); let cell=crfHTML.createTblHeader(null,row); crfHTML.createTextNode("Automatic ID generator",null,cell); let cell1=row.insertCell(); cell1.colSpan="3"; let b=crfHTML.createButton(null,cell1); b.id="generateIdButton"; b.onclick=function(){generateRegistration.execute(gc);}; b.value="Generate ID"; } if (specFieldSetup['actionType']=='multiChoiceButtonRow'){ //need all options for the field if (!("lookup" in field)) { this.print(fieldUID+" only enabled for lookup fields"); return; } let lookup=field["lookup"]; let lObject=crfData.getLookup(lookup.queryName); let row=tb.insertRow(); let cell=crfHTML.createTblHeader(null,row); let header="All variables"; if ('header' in q){ header=q['header']; header=header.replace(/_fieldCaption_/,field.shortCaption); header=header.replace(/_t_/,"\t"); } crfHTML.createTextNode(header,null,cell); crfHTML.addStyle(cell,'center'); crfHTML.addStyle(cell,'topLess'); let cell1=row.insertCell(); cell1.colSpan="3"; for (let x in lObject.LUT){ let b=crfHTML.createButton(null,cell1); b.id=fieldUID+':'+x; b.value=lObject.LUT[x]; input=crfHTML.getElement(setup.getInputId(field.name)); b.onclick=function(){crfHTML.updateSelect(input,cell1,x,b.value);} } } } crfVisit.populateFieldRow= function(entry,field,setup){ this.populateField(entry,field,setup); this.populateSubQuery(entry,field,setup); this.populateSpecialFields(entry,field,setup); } crfVisit.populateSubQuery= function(entry,field,setup){ let fName='[populateSubQuery/'+setup.queryName+':'+field.name+']'; if (setup.isReview) return; if (!(setup.queryName in crfSetup.getAdditionalDataObject())){ let msg=fName+': no additionalData entry for '+setup.queryName; msg+=' (probably a subquery)'; this.print(msg); return; } //find if field is connected to a sub array //find queryName // let additionalData=crfSetup.getAdditionalData(setup.queryName); this.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) { this.print(fName+": ignoring field "+id+"/"+eId); return; } this.print(fName+': id '+id); //hard to estimate readonlyFlag // let input=crfHTML.getElement(id); let eType=input.nodeName.toLowerCase(); let readonlyFlag=eType!="select"; this.setListVisibility(input,setup,readonlyFlag); } crfVisit.clearField= function(field,setup){ let foo=new Object(); this.populateField(foo,field,setup); } crfVisit.populateField= function(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); this.print(fName+' v='+varValue+'/'+isLookup+' ['+ setup.getInputId(field.name)+']'); let vType=field.type; let id=setup.getInputId(vName); let input=crfHTML.getElement(id); //date if (vType=="date"){ if (varValue=="UNDEF") varValue=new Date(); else varValue=new Date(varValue); } //lookup for readonly if (isLookup && varValue!="UNDEF"){ let lookup=field["lookup"]; //get all values from config.formConfig.lookup[X] let lObject=crfData.getLookup(lookup.queryName); varValue=lObject.LUT[varValue]; } this.print('Element: '+id+'/'+input); //figure out the element type let eType=input.nodeName.toLowerCase(); this.print('Element type: '+eType); //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;i0) entry=fQuerySnapshot.rows[0]; if ("reviewTable" in setup){ entry['reviewComment']=''; delete entry["ModifiedBy"]; } let tb=crfHTML.createTable(divName); tb.className="t2"; //this are the fields (probably constant) let fields=queryLayout.fields; for (f in fields){ let field=fields[f]; let fieldUID=listName+":"+field.name; //each field is a new row this.print(fName+": Adding field: "+f+'/'+field.name+' ('+fieldUID+').'); //unique name if (field.hidden) continue; if (field.name=="crfRef") continue; if (field.name in setup.setVariables) continue; this.addFieldRow(tb,field,setup,additionalData); if (populateData) this.populateFieldRow(entry,field,setup); let specialFields=crfSetup.getEntryMap('specialFields:fieldUID'); if (fieldUID in specialFields){ let specFieldSetup=specialFields[fieldUID]; this.addSpecialFieldRows(tb,field,specFieldSetup,setup); } } //finish of if apply button is not required if (!("addApply" in setup)) { this.print(fName+"populateTable: done"); return; } let row=tb.insertRow(); let th=crfHTML.createTblHeader(null,row); th.innerHTML=setup.addApply; let cell=row.insertCell(); //cell.setAttribute("colspan","2"); let input=crfHTML.createButton(null,cell); input.value=setup.addApply; 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 let that=this; input.onclick=function(){that.saveReview(listName,cell1.id,setup)}; } crfVisit.setEntryFromElement= function(entry,elementId, field){ //set value to entry from element using representation (field) from labkey // // let fName='setEntryFromElement'; let el=crfHTML.getElement(elementId); if (!el) { this.print(fName+" element: "+elementId+" not found"); return; } this.print(fName+" element: "+elementId); let vName=field.name; let vType=field.type; let eType=el.nodeName.toLowerCase(); if (eType==="select"){ entry[vName]=el.options[el.selectedIndex].value; return; } if (eType==="td"){ entry[vName]=el.innerText; return; } if (vType=="date"){ let date=el.valueAsDate; if (!date) return; date.setUTCHours(12); entry[vName]=date.toString(); this.print(fName+" setting date to "+entry[vName]); return; } if (vType=="string"){ entry[vName]=el.value; if (vName.search('_file_')<0) return; //upload file let id1=elementId+'_file_'; let input1=crfHTML.getElement(id1); this.print(fName+' 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 this.uploadFile(input1,ctx); let fv=el.value; let suf=fv.split('.').pop(); entry[vName]=entry['crfRef']+'.'+suf; return; } if (vType=="float" || vType=="int"){ entry[vName]=el.value; if (vName=="queryName") { this.print(fName+' parsing queryName: '+el.innerText); let qMapInverse=crfSetup.invertMap(crfSetup.getMap('inputLists')); entry[vName]=qMapInverse[el.innerText]; //use queryMap lookup } return; } if (vType=="boolean"){ entry[vName]=el.checked; return; } return; } crfVisit.selectEntry= function(fRows,setup){ let fName='[selectEntry]'; if (!("unique" in setup)) return null; if (fRows.length==0) return null; keys=Object.keys(setup.setVariables); if (keys.length==0) return fRows[0]; for (let i=0;i>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //generic form status switch statementes crfVisit.changeFormStatusAndNotify= function(actionName){ let fName='[changeStatusAndNotify]'; this.print(fName); let targetStatus=crfSetup.getTargetStatus(actionName); let targetRecipient=crfSetup.getTargetRecipient(actionName); let actionSettings=crfSetup.getActionSettings(actionName); let action=new Object(); action.name=actionName; let finalStep=function(){that.redirect();}; if (variableList.hasVariable(actionSettings,"finalStep")){ this.print(fName+' adjusting finalStep'); //set to doNothing to remain on submit window if (actionSettings.finalStep=="doNothing"){ finalStep=function(){that.doNothing();}; } } this.print(fName+' action '+actionName+' targetStatus '+targetStatus); let that=this; action.cb=function(data){that.sendEmail(data,targetRecipient,finalStep,actionName);} this.updateFlag(targetStatus,action);//Approved } crfVisit.updateFlag= function(flag,action){ let fName='[updateFlag]'; let entry=crfData.getCrfEntry(); entry.FormStatus=flag; let uId=LABKEY.Security.currentUser.id; entry[this.role]=uId; this.print(fName+': Form: '+entry.Form); this.print(fName+": set form status to "+entry.FormStatus); let that=this; let cb=function(data){that.completeWithFlag(data,action);}; runQuery.modifyRows('update','lists','crfEntry',[entry],cb,crfSetup.getContainer('data')); } crfVisit.completeWithFlag= function(data,action){ let fName='[completeWithFlag]'; this.print(fName+': nrows '+data.rows.length); let fentry=data.rows[0]; this.print(fName+': form status '+fentry.FormStatus); this.print(fName+': form '+fentry.Form); let crfStatus=crfData.createCrfStatus(fentry); crfStatus.operator=this.role; crfStatus.action=action.name; let that=this; let cb=function(){that.doNothing();}; if (action.cb) cb=action.cb; runQuery.insertRows('lists','crfStatus',[crfStatus],cb,crfSetup.getContainer('data')); } //******************************************upload to database ********************* crfVisit.onDatabaseUpload= function(){ let actionName='onDatabaseUpload'; let fName='['+actionName+']'; this.print(fName); let pM=this.getIdManager(); let participantId=participantIdManager.getParticipantIdFromCrfEntry('STUDY'); let that=this; let crfRefForData=crfData.getCrfRefForData(); //load lists and study data //check what needs to be updated and upload //a (reverse) sequence of functions let completeUpload=function(){that.changeFormStatusAndNotify(actionName);}; let uploadData=function(){crfData.uploadData(participantId,crfRefForData,completeUpload);}; let loadStudy=function(){crfData.setData(crfRefForData,uploadData,'study');} crfData.setData(crfRefForData,loadStudy,'lists'); } //*************************update for further review ************************* crfVisit.onUpdateForReview= function(){ let actionName='onUpdateForReview'; this.changeFormStatusAndNotify(actionName); } //************************************************ submit ******************************************* crfVisit.onSubmit= function(){ //update list storage and change status this.hideErr(); this.clearErr(); this.printErr("onSubmit"); let that=this; let actionName='onSubmit'; let action=function(){that.verifyData(actionName);}; crfData.setData(crfData.getCrfRefForData(),action); } crfVisit.verifyData= function(actionName){ let fName='[verifyData/'+actionName+']'; let qList=crfData.getActiveQueries(); let that=this; let doNothing=function(data){that.doNothing();}; let pM=this.getIdManager(); let fieldName=pM.getCrfEntryFieldName(pM.getMode()); let setId=crfData.getCrfEntry()[fieldName]; this.print(fName+' crfEntry ['+fieldName+'] '+crfData.getCrfEntry()[fieldName]); if (!setId){ this.printErr('Missing ID !'); return false; } for (let qId in qList){ let entry=qList[qId]; let q=entry['queryName']; let qData=crfData.getQuerySnapshot(q); if (q=="reviewComments") continue; //copy snapshot to history if (qData.rows.length==0){ this.print(fName+' no rows for '+q); } else runQuery.insertRows('lists',q+'History',qData.rows,doNothing,this.getContainer('data')); //if it doesn't have additionalData, it is a sub query if (!(q in crfSetup.getAdditionalDataObject())){ continue; } if (qData.rows.length<1){ this.printErr('Missing entry for query '+q); return false; } } //this is necessary only for Generated to Generation completed step //let actionSettings=crfSetup.getActionSettings(actionName); //if (variableList.hasVariable(actionSettings,"updateRegistration")){ //if updateRegistrationFormId is set, only update when submit is used on that form // if (variableList.hasVariable(actionSettings,"updateRegistrationFormId")){ // let formId=crfData.getCrfEntry()['Form']; //if (actionSettings['updateRegistrationFormId']==formId) // this.updateRegistration(); //} //else // this.updateRegistration(); //} this.changeFormStatusAndNotify(actionName); } crfVisit.getEmail= function(recipientCode){ this.print('getEmail w/'+recipientCode); let recipients=new Array(); let typeTo=LABKEY.Message.recipientType.to; let create=LABKEY.Message.createRecipient; let userMap=crfSetup.getEntryMap('users'); let currentUser=userMap[LABKEY.Security.currentUser.id]; let currentSite=this.siteEntry; let formCreator=userMap[crfData.getCrfEntry()['UserId']]; let userRows=crfSetup.getRows('users'); let parentUser=null; if ("parentCrfData" in crfSetup){ let parentCrf=crfSetup.getRows('parentCrfData'); parentUser=userMap[parentCrf[0].UserId]; } let recipientCategories=recipientCode.split(','); for (let i=0;i0){ this.populateTable(queryName,0,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 ********************* crfVisit.onGenerateQuery= function(queryName){ let fName='[onGenerateQuery]'; this.print(fName+' '+queryName); // let cfgRows=crfSetup.getRows('generateConfigData'); // //queryName to queryId? let qMapInverse=crfSetup.invertMap(crfSetup.getMap('inputLists')); let queryId=qMapInverse[queryName]; let cfgRow=crfSetup.getEntryMap('generateConfigData:queryId')[queryId]; if (!cfgRow){ this.print('generateConfig for queryName['+queryId+']='+queryName+' not found'); return; } //let formRows=crfSetup.selectFormSetupRows(cfgRow.formId); // // //check if all required datasets were at least saved this.checkGenerationFields(cfgRow); } crfVisit.checkGenerationFields= function(entry){ //entry is generateConfig row let fName='[checkGenerationFields]'; let mailRecipient=entry.emailRecipient; let qMap=crfSetup.getMap('inputLists'); let qName=qMap[entry['queryId']]; //list of queries that are part of Registration form this.print(fName); this.print(fName+' setRecipient: '+mailRecipient); let formId=entry['formId']; this.print(fName+" Checking form w/id "+formId); let formRows=crfSetup.selectFormSetupRows(formId); //registration rows for (let i=0;i0) { this.generateMessage(queryName,formName+' already generated.'); return; } //use current crfEntry as base let crfBase=crfData.getCrfEntry(); let idLabel=crfSetup.getParticipantLabel(crfBase); //role will appear in crfStatus and will be validated agains crfCreator entry of the form let roleAndSite='generate:'+crfBase.Site; //have to overload crfEntry // - parentCrf // - formStatus // - UserId (set to sponsor UserId) // // should provide mail recipient and/or modified cb // // let crfEntryOverload=new Object(); //parentCrf crfEntryOverload.parentCrf=crfBase.entryId; //formStatus crfEntryOverload.formStatus=1;//In progress //checks for both field presence (if not in query, undefined) and field value (if not set, null) this.print(fName+' setup status: '+entry.formStatus); if (entry.formStatus){ crfEntryOverload.formStatus=entry.formStatus; } // UserId //find sponsor for site let site=crfBase.Site; let crfSponsors=crfSetup.getRows('crfSponsors'); let userMap=crfSetup.getEntryMap('users'); let sponsorId=null; for (let i=0;i0) return; //create new list entry let pM=this.getIdManager(); let e2=new Object(); e2.crfRef=this.getCrfRef(); e2.registrationStatus=0; e2.submissionDate=new Date(); let idLabel=crfSetup.getParticipantLabel(crfData.getCrfEntry()); e2[crfSetup.getLocalIdLabel()]=crfSetup.getLocalId(idLabel); e2[crfSetup.getStudyIdLabel()]=crfSetup.getStudyId(idLabel); this.print('set values'); e2.site=crfData.getCrfEntry()['Site']; runQuery.insertRows('lists',queryName,[e2],cb,crfSetup.getContainer('data')); } // ******************** end form generator (Registration) ******************** //jump to populate table/generate review, etc defined at the begining of the file //entry point from generateMasterForm crfVisit.setFormConfig= function(){ let fName="[setFormConfig]"; let crfRef=this.crfRef; let that=this; let afterCrfEntry=function(){that.afterCrfEntry();}; let action=function(){crfData.setCrfEntry(crfRef,afterCrfEntry);};//afterCrfEntry crfSetup.setContainers(action); } crfVisit.afterCrfEntry= function(){ let fName='[afterCRFEntry]'; this.print(fName+" setting crfEntry (x) to "+crfData.getCrfEntry()["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 crfSetup.formStatus=crfData.getCrfEntry()['FormStatus']; let parentCrf=crfData.getCrfEntry()['parentCrf']; this.print(fName+' parentCrf set to '+parentCrf); if (parentCrf) crfSetup.parentCrf=parentCrf; let that=this; let action=function(){that.parseSetup();}; crfSetup.parseSetup(action); } crfVisit.parseSetup= function(){ //debug let fName='[parseSetup]'; let varRows=crfSetup.getRows('crfStaticVariables'); let studyVars=crfSetup.getRows('studyData')[0]; for (let i=0;i0){ let file=inputElement.files[0]; this.print('uploadFile: '+inputElement.value+'/'+file.size); webdav.uploadFile(file,context); } } crfVisit.printForm= function(){ crfPrint.printForm(); }