|
@@ -66,7 +66,6 @@ function(){
|
|
|
|
|
|
crfVisit.getCrfRef=
|
|
|
function (){
|
|
|
- //'crfRefId'
|
|
|
return crfData.getCrfEntry()['entryId'];
|
|
|
}
|
|
|
|
|
@@ -137,6 +136,7 @@ function(sectionId,listName){
|
|
|
setup.filters=new Object();
|
|
|
setup.filters['crfRef']=this.getCrfRef();
|
|
|
setup.getInputId=function(vName){return sectionId+"_"+vName;}
|
|
|
+ setup.getLabelId=function(vName){return sectionId+"_"+vName+"_label";}
|
|
|
setup.sectionId=sectionId;
|
|
|
setup.isReview=false;
|
|
|
this.addSetup(sectionId,setup);
|
|
@@ -181,34 +181,54 @@ function(sectionId,listName,writeAccess=true){
|
|
|
|
|
|
crfVisit.generateSection=
|
|
|
function(formSetupEntry){
|
|
|
+
|
|
|
+ //generate section, ie. part that corresponds to a single row from FormSetup
|
|
|
+ //<div> hierarchy
|
|
|
+ //this.masterForm -> X -> [ XTable, XSubDiv -> XSubDivList, XReviewList, XReview ]
|
|
|
+ //visibility is toggled on X
|
|
|
+ //X is a shorthand for sectionId
|
|
|
+
|
|
|
let that=this;
|
|
|
let listName=crfSetup.getMap('inputLists')[formSetupEntry['queryName']];
|
|
|
let sectionId="section"+formSetupEntry['Key'];
|
|
|
- //if (!listName) is for debugSection
|
|
|
+
|
|
|
+//section is also generated for debug
|
|
|
if (!listName){
|
|
|
listName="debugSection";
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
let fName='[generateSection/'+listName+']';
|
|
|
let sectionTitle=formSetupEntry['title'];
|
|
|
+
|
|
|
+ //role dictates how the section is displayed (EDIT, COMMENT, READ)
|
|
|
let accessModeColumn=this.role+'Mode';
|
|
|
- let accessMode=formSetupEntry[accessModeColumn];
|
|
|
+ let accessMode=formSetupEntry[accessModeColumn];
|
|
|
+
|
|
|
//this will fix it for later use as well
|
|
|
this.print(fName+' title '+sectionTitle);
|
|
|
|
|
|
+ //js <table> commands
|
|
|
let tb=crfHTML.createTable(this.masterForm);
|
|
|
tb.className='t2';
|
|
|
+
|
|
|
+ //generate header
|
|
|
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);
|
|
|
+
|
|
|
+ //toggle visibility button (Show/Hide)
|
|
|
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)};
|
|
|
|
|
|
+
|
|
|
+ //js <div> under this.masterForm
|
|
|
let div=crfHTML.createDiv(sectionId,this.masterForm);
|
|
|
div.style.display="none";
|
|
|
|
|
@@ -221,47 +241,47 @@ function(formSetupEntry){
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- let additionalData=crfSetup.getAdditionalData(listName);
|
|
|
+ //js <div> for table
|
|
|
let divTable=crfHTML.createDiv(sectionId+"Table",null,div);
|
|
|
|
|
|
+ //check for sub-queries
|
|
|
+ let additionalData=crfSetup.getAdditionalData(listName);
|
|
|
if ("showFlag" in additionalData) {
|
|
|
additionalData.divName=sectionId+"SubDiv";
|
|
|
additionalData.divQueryName=sectionId+"SubDivList";
|
|
|
-
|
|
|
+//[XSubDiv]
|
|
|
let div1=crfHTML.createDiv(additionalData.divName,null,div);
|
|
|
div1.style.display="none";
|
|
|
+//[XSubDiv->XSubDivList]
|
|
|
let div2=crfHTML.createDiv(additionalData.divQueryName,null,div1);
|
|
|
|
|
|
}
|
|
|
this.print(fName+" generate master table");
|
|
|
|
|
|
+ //convert from accessMode to setup
|
|
|
let writeMode=accessMode=="EDIT";
|
|
|
let setup=this.getSetup(sectionId,listName,writeMode);
|
|
|
setup.setVariables=variableList.parseVariables(formSetupEntry['variableDefinition']);
|
|
|
|
|
|
-
|
|
|
+//special case for providing review sections (not used in hypoAfrica)
|
|
|
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
|
|
|
|
|
|
|
|
|
+ //main table is unique per visit
|
|
|
setup.unique=true;
|
|
|
this.generateTable(listName,divTable.id,additionalData,setup);
|
|
|
|
|
|
- this.print("generate master table: done");
|
|
|
+ this.print("generate main 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){
|
|
|
+ //subTable is the editable interface to data,
|
|
|
+ //only generate for write/EDIT access to section
|
|
|
+
|
|
|
+ if (accessMode == "EDIT" && ("showFlag" in additionalData)){
|
|
|
let qName=additionalData.queryName;
|
|
|
let dName=additionalData.divName;
|
|
|
|
|
@@ -269,24 +289,20 @@ function(formSetupEntry){
|
|
|
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");
|
|
|
|
|
|
+ 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;
|
|
|
+
|
|
|
+//special provisions for GENERATE (typically associated with Registration section/table)
|
|
|
this.print('Adding generate button');
|
|
|
//add generateButton
|
|
|
let divGenerateButton=crfHTML.createDiv(listName+"GenerateButton",null,div);
|
|
@@ -336,6 +352,7 @@ function(divReviewId,divReviewListId, listName, accessMode){
|
|
|
//needs listName, in argument
|
|
|
|
|
|
reviewSetup.getInputId=function(vName){return listName+"_add"+vName};
|
|
|
+ reviewSetup.getLabelId=function(vName){return listName+"_add"+vName+"_label";};
|
|
|
reviewSetup.divReviewListId=divReviewListId;
|
|
|
reviewSetup.isReview=true;
|
|
|
this.addSetup(divReviewId,reviewSetup);
|
|
@@ -534,8 +551,9 @@ function(tb,field,setup,additionalData){
|
|
|
let row=tb.insertRow();
|
|
|
let cell=crfHTML.createTblHeader(null,row);
|
|
|
cell.style.width='300px';
|
|
|
-
|
|
|
+ cell.id=setup.getLabelId(vName);
|
|
|
let text = crfHTML.createTextNode(field.shortCaption,null,cell);
|
|
|
+
|
|
|
|
|
|
|
|
|
let input=null;
|
|
@@ -789,6 +807,21 @@ function(entry,field,setup){
|
|
|
let vName=field.name;
|
|
|
let fName='[populateFieldName/'+vName+']';
|
|
|
|
|
|
+ //this.print(fName+" label element: "+labelElement);
|
|
|
+ //this.print(fName+" label element: "+labelElement.childNodes.length);
|
|
|
+ if ("_mergeData" in entry){
|
|
|
+ let dataArray=entry["_mergeData"][vName];
|
|
|
+ this.print(fName+" vals "+dataArray);
|
|
|
+ let label=field.shortCaption+" [";
|
|
|
+ for (let i=0;i<dataArray.length;i++){
|
|
|
+ if (i) label+="/";
|
|
|
+ label+=dataArray[i].toString();
|
|
|
+ }
|
|
|
+ label+="]";
|
|
|
+ crfHTML.setTextNode(crfHTML.getElement(setup.getLabelId(vName)).childNodes[0],label);
|
|
|
+ }
|
|
|
+ //this.print(fName+" label "+label);
|
|
|
+
|
|
|
let varValue="UNDEF";
|
|
|
|
|
|
//if (vName in setup.filters) varValue=setup.filters[vName];
|
|
@@ -803,6 +836,7 @@ function(entry,field,setup){
|
|
|
|
|
|
let vType=field.type;
|
|
|
let id=setup.getInputId(vName);
|
|
|
+ //here I would also need the label to update in case of multiple matches
|
|
|
let input=crfHTML.getElement(id);
|
|
|
|
|
|
|
|
@@ -907,29 +941,21 @@ function(entry,field,setup){
|
|
|
|
|
|
crfVisit.populateTable=
|
|
|
function(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+']';
|
|
|
|
|
|
- //should contain formSetup key
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
//data snapshot
|
|
|
let fQuery=crfData.getQuerySnapshot(listName);
|
|
|
let queryLayout=crfData.getQueryLayout(listName);
|
|
|
+ let fields=queryLayout.fields;
|
|
|
|
|
|
//here I assume that listName was parsed during setDataLayout and setData
|
|
|
//so that rows was set (even if they are empty)
|
|
|
this.print(fName+"]: nrows "+fQuery.rows.length);
|
|
|
|
|
|
- let entry=this.selectEntry(fQuery.rows,setup);
|
|
|
+ let entry=this.selectEntry(fQuery.rows,setup,fields);
|
|
|
|
|
|
if (!entry) entry=new Object();
|
|
|
- let fields=queryLayout.fields;
|
|
|
|
|
|
for (f in fields){
|
|
|
let field=fields[f];
|
|
@@ -946,31 +972,33 @@ function(listName,writeMode,setup){
|
|
|
|
|
|
crfVisit.generateTable=
|
|
|
function(listName,divName,additionalData,setup){
|
|
|
+ //generate table for query(listName)
|
|
|
let fName="[generateTable/"+listName+"]";
|
|
|
this.print(fName);
|
|
|
|
|
|
- //is listName and setup.queryName a duplicate of the same value
|
|
|
this.print(fName+': setup.queryName '+setup.queryName);
|
|
|
+
|
|
|
//assume data is set in config.formConfig.dataQueries[data.queryName].rows;
|
|
|
+ //populate old data for main query, but not subqueries (since one assumess distinct data in each row)
|
|
|
let populateData=true;
|
|
|
if ("subTable" in setup){
|
|
|
this.print(fName+" is subTable");
|
|
|
populateData=false;
|
|
|
}
|
|
|
|
|
|
- let entry=new Object();
|
|
|
-
|
|
|
-
|
|
|
+ //this are the fields (probably constant)
|
|
|
+ let queryLayout=crfData.getQueryLayout(listName);
|
|
|
+ let fields=queryLayout.fields;
|
|
|
|
|
|
//data snapshot
|
|
|
let fQuerySnapshot=crfData.getQuerySnapshot(listName);
|
|
|
- let queryLayout=crfData.getQueryLayout(listName);
|
|
|
//here I assume that listName was parsed during setDataLayout and setData
|
|
|
//so that rows was set (even if they are empty)
|
|
|
this.print(fName+": Nrows "+fQuerySnapshot.rows.length);
|
|
|
-
|
|
|
- if (fQuerySnapshot.rows.length>0)
|
|
|
- entry=fQuerySnapshot.rows[0];
|
|
|
+
|
|
|
+ entry=this.selectEntry(fQuerySnapshot.rows,setup,fields);
|
|
|
+ if (!entry) entry=new Object();
|
|
|
+ //fQuerySnapshot.rows[0];
|
|
|
|
|
|
|
|
|
if ("reviewTable" in setup){
|
|
@@ -981,8 +1009,6 @@ function(listName,divName,additionalData,setup){
|
|
|
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];
|
|
@@ -1113,30 +1139,75 @@ function(entry,elementId, field){
|
|
|
}
|
|
|
|
|
|
crfVisit.selectEntry=
|
|
|
-function(fRows,setup){
|
|
|
+function(fRows,setup,fields){
|
|
|
+ //out of potentially many entries, prepare a combined entry and
|
|
|
+ //fill the _mergeData field with observations during merge
|
|
|
+ //where each field gets a comment that will be displayed
|
|
|
+ //with instructions of the field
|
|
|
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];
|
|
|
+ return this.mergeEntries(fRows,setup,fields);
|
|
|
+
|
|
|
|
|
|
+ candidates=new Array();
|
|
|
for (let i=0;i<fRows.length;i++){
|
|
|
+ let entryOK=true;
|
|
|
for (let v in setup.setVariables){
|
|
|
this.print(fName+' row '+i+' ['+v+'] '+fRows[i][v]+'/'+setup.setVariables[v]);
|
|
|
- if (fRows[i][v]==setup.setVariables[v]){
|
|
|
- this.print(fName+' using '+i);
|
|
|
- return fRows[i];
|
|
|
+ if (fRows[i][v]!=setup.setVariables[v]){
|
|
|
+ entryOK=false;
|
|
|
+ break;
|
|
|
}
|
|
|
+
|
|
|
+ }
|
|
|
+ if (!entryOK){
|
|
|
+ this.print(fName+' skipping '+i);
|
|
|
+ continue;
|
|
|
}
|
|
|
+ this.print(fName+' adding '+i);
|
|
|
+ candidates.push(fRows[i])
|
|
|
}
|
|
|
- return null;
|
|
|
+ return this.mergeEntries(candidates,setup,fields);
|
|
|
|
|
|
}
|
|
|
|
|
|
+crfVisit.mergeEntries=
|
|
|
+function(fRows,setup,fields){
|
|
|
+ let fName="[mergeEntries]";
|
|
|
+ this.print(fName+" entries["+fRows.length+"]");
|
|
|
+ let entry=fRows[0];
|
|
|
+ if (fRows.length==1){
|
|
|
+ return entry
|
|
|
+ }
|
|
|
+ let mergeData=new Object();
|
|
|
+
|
|
|
+ for (let k=0;k<fields.length;k++){
|
|
|
+ let field=fields[k];
|
|
|
+ let LUT=null;
|
|
|
+ if ("lookup" in field)
|
|
|
+ LUT=crfData.getLookup(field.lookup.queryName).LUT;
|
|
|
+ let v=new Array();
|
|
|
+ for (let i=0;i<fRows.length;i++){
|
|
|
+ let varValue=fRows[i][field.name];
|
|
|
+ if (LUT!=null) varValue=LUT[varValue];
|
|
|
+ v.push(varValue)
|
|
|
+ }
|
|
|
+
|
|
|
+ this.print(fName+" "+field.name+" "+v);
|
|
|
+ mergeData[field.name]=v;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ entry["_mergeData"]=mergeData;
|
|
|
+ return entry;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
crfVisit.saveReview=
|
|
|
function(queryName,elementId,setup){
|
|
|
//loads any queryName
|
|
@@ -1153,9 +1224,10 @@ function(queryName,elementId,setup){
|
|
|
|
|
|
//data layout
|
|
|
let queryLayout=crfData.getQueryLayout(queryName);
|
|
|
+ let fields=queryLayout.fields;
|
|
|
|
|
|
//determine mode based on entry uniqueness and presence of data
|
|
|
- let entry=this.selectEntry(fQuerySnapshot.rows,setup);
|
|
|
+ let entry=this.selectEntry(fQuerySnapshot.rows,setup,fields);
|
|
|
let mode='update';
|
|
|
|
|
|
if (!entry){
|
|
@@ -1169,7 +1241,6 @@ function(queryName,elementId,setup){
|
|
|
this.print(fName+" set crfRef="+entry.crfRef);
|
|
|
|
|
|
|
|
|
- let fields=queryLayout.fields;
|
|
|
for (f in fields){
|
|
|
|
|
|
let field=fields[f];
|
|
@@ -1912,7 +1983,9 @@ function(){
|
|
|
let accessMode=this.role+'Mode';
|
|
|
let formId=crfData.getCrfEntry()['Form'];
|
|
|
let rowsSetup=crfSetup.selectFormSetupRows(formId);
|
|
|
+//go through formSetup and generate section for each entry
|
|
|
for (let i=0;i<rowsSetup.length;i++){
|
|
|
+//row in FormSetup
|
|
|
let entry=rowsSetup[i];
|
|
|
|
|
|
//debug
|
|
@@ -1924,6 +1997,7 @@ function(){
|
|
|
|
|
|
//skip sections
|
|
|
//also from fields
|
|
|
+ //this can be crfEditorMode, crfMonitorMode or crfSponsorMode
|
|
|
if (entry[accessMode]=="NONE") continue;
|
|
|
|
|
|
//section fits one dataset/list
|
|
@@ -2001,10 +2075,6 @@ function(sectionId){
|
|
|
divRev.style.display="none";
|
|
|
divRLi.style.display="none";
|
|
|
if (divGBu!=undefined) divGBu.style.display="block";
|
|
|
- //add buttons?
|
|
|
- //is button already generated?
|
|
|
-
|
|
|
- //populateTable(entry);
|
|
|
|
|
|
}
|
|
|
|
|
@@ -2266,7 +2336,6 @@ function(){
|
|
|
let vName=varRows[i].staticVariable;
|
|
|
this.print(fName+' '+vName+': '+studyVars[vName]);
|
|
|
}
|
|
|
-
|
|
|
//parse site
|
|
|
this.siteEntry=crfSetup.getEntryMap('siteData')[crfData.getCrfEntry()['Site']];
|
|
|
this.print("Setting site name to "+this.siteEntry['siteName']);
|
|
@@ -2340,3 +2409,13 @@ crfVisit.printForm=
|
|
|
function(){
|
|
|
crfPrint.printForm();
|
|
|
}
|
|
|
+
|
|
|
+crfVisit.getFieldNames=
|
|
|
+function(fields){
|
|
|
+ //fields is an array of items with attribute name
|
|
|
+ let fieldNames=new Array();
|
|
|
+ for (let i=0;i<fields.length;i++){
|
|
|
+ fieldNames.push(fields[i].name);
|
|
|
+ }
|
|
|
+ return fieldNames;
|
|
|
+}
|