Browse Source

Version that reloads data on show/hide, useful for prompt generation of reports

tomcat8 @ merlin 2 years ago
parent
commit
4a97afd27d
1 changed files with 346 additions and 257 deletions
  1. 346 257
      web/crf/crfVisit.js

+ 346 - 257
web/crf/crfVisit.js

@@ -37,6 +37,10 @@ function onFailure(errorInfo, options, responseObj){
 		alert("Failure: " + responseObj.statusText);
 }
 
+function doNothing(){
+	print('doNothing called');
+}
+
 function generateDebugSection(){
 	//let debug=true;
 	//if (debug) print("generateDebugSection "+sectionName);
@@ -125,7 +129,7 @@ function fullAccessSetup(listName){
 
 }
 
-function readonlySetup(){
+function readonlySetup(listName){
 	//see definition of setup object above
 	let debug=true;
 	if (debug) print("readonlySetup");
@@ -134,10 +138,19 @@ function readonlySetup(){
 	setup.readonlyFlag=function(vName){return true};
 	setup.filters=new Object();
 	setup.filters['crfRef']=getCRFref();
-	setup.getInputId=function(vName){return vName;}
+	setup.getInputId=function(vName){return listName+'_'+vName;}
 	return setup;
 }
 
+function getSetup(listName){
+	let formStatus=config.formConfig.formStatus;
+	if (formStatus=="Submitted")
+		return readonlySetup(listName);
+	if (formStatus=="Approved")
+		return readonlySetup(listName);
+	return fullAccessSetup(listName);
+}
+	
 //afterFormConfig replaced by afterFormSetup
 
 //afterFormSetupLookup replaced by afterFormDatasets
@@ -194,12 +207,7 @@ function generateSection(sectionName, sectionTitle, listName, additionalData){
 	if (debug) print("generate master table");
 
 		
-	let setup=fullAccessSetup(listName);
-	let formStatus=config.formConfig.formStatus;
-	if (formStatus=="Submitted")
-		setup=readonlySetup();
-	if (formStatus=="Approved")
-		setup=readonlySetup();
+	let setup=getSetup(listName);
 	
 	if ("isReview" in additionalData){
 		generateReviewSection(listName,div.id,generateReviewSectionCB);
@@ -209,7 +217,7 @@ function generateSection(sectionName, sectionTitle, listName, additionalData){
 
 	
 	setup.unique=true;
-	generateTable(listName,divTable.id,true,additionalData,setup);
+	generateTable(listName,divTable.id,additionalData,setup);
 	
 	if (debug) print("generate master table: done");
 
@@ -228,7 +236,7 @@ function generateSection(sectionName, sectionTitle, listName, additionalData){
 
 		let setup=fullAccessSetup(qName);
 		//if (readonly) setup=readonlySetup(config);
-		generateTable(qName,dName,false,additionalData,setup);
+		generateTable(qName,dName,additionalData,setup);
 	}
 
 	print("generate review");
@@ -389,84 +397,79 @@ function patternReplace(src,replacements,values){
 
 }
 
-function plotImage(row,rowVariable,obj,pid){
-	let nim=obj.values.length;
+function plotImage(cell,k,row,rowVariable,obj,pid){
 	let baseDir=patternReplace(obj.imageDir,obj.replacements,pid);
 	print('Base dir: '+pid.basePath);
-	for (let im=0;im<nim;im++){
-		pid[obj.variable]=obj.values[im];
-		let img=config.document.createElement('img');
-
-		let imgSrc=patternReplace(obj.file,obj.replacements,pid);
-		print('Image: '+imgSrc);
-		let imagePath=pid.basePath+'/'+baseDir+'/'+imgSrc;
-			
-		img.src=imagePath;
-		img.width="300";
-
-		let cell=row.insertCell();
-		cell.id=pid[obj.variable]+"_"+rowVariable+pid[rowVariable];
+	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(row,rowVariable,obj,pid){
-	let nr=obj.values.length;
-	for (let ir=0;ir<nr;ir++){
-
-		let cell=row.insertCell();
-		cell.id=obj.values[ir]+"_"+rowVariable+pid[rowVariable];
-		cell.width="300px";
-		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[ir];
-		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 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(row,rowSetup,j,obj,pid){
+function showProbability(cell,k,row,rowSetup,j,obj,pid){
 	print('showProbability: '+rowSetup);
-	let np=obj.values.length;
+	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);
-	for (let ip=0;ip<np;ip++){
-
 
-		let cell=row.insertCell();
-		probDensity.func=obj.values[ip];
-		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=[];
-		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);
 
+	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=[];
+	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){
@@ -503,6 +506,19 @@ function erf(x){
 }
 
 
+function setLine(fbox,name,value,fontSize){
+	let fpId=fbox.id+name;
+	let fp=config.document.getElementById(fpId);
+	if (fp===null){
+		fp=config.document.createElement("p");
+		fp.id=fpId;
+		fbox.appendChild(fp);
+	}
+	fp.classList.add("center");
+	fp.style.textAlign="center";
+	fp.style.fontSize=fontSize;
+	fp.innerText=value;
+}	
 
 function drawProbability(data,cell,obj,pid,probDensity){
 	print('drawProbability');
@@ -529,8 +545,14 @@ function drawProbability(data,cell,obj,pid,probDensity){
 		color=obj.intervals.colors[i-1];
 		break;
 	}
-
-	let fbox=config.document.createElement("div");
+	
+	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";
@@ -546,40 +568,13 @@ function drawProbability(data,cell,obj,pid,probDensity){
 		organName="Bowel";
 	}
 
-	let fp4=document.createElement("p");
-	fp4.classList.add("center");
-	fp4.style.textAlign="center";
-	fp4.innerHTML=organName;
-	fbox.appendChild(fp4);
-	
-	let fp=document.createElement("p");
-	//fp.innerHTML=prob.toPrecision(3);
-	fp.innerHTML=val.toPrecision(3);
-	fp.style.fontSize="25px";
-	fp.style.textAlign="center";
-	fbox.appendChild(fp);
-
-	let fp1=document.createElement("p");
-	fp1.classList.add("center");
-	fp1.style.textAlign="center";
-	//fp1.innerHTML="IRAEMM-probability";
-	fp1.innerHTML="SUV("+probDensity.percentile+"%)";
-	fbox.appendChild(fp1);
-
-	let fp2=document.createElement("p");
-	fp2.innerHTML=fzx.toPrecision(3);
-	fp2.style.fontSize="25px";
-	fp2.style.textAlign="center";
-	fbox.appendChild(fp2);
+	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");
 
-	let fp3=document.createElement("p");
-	fp3.classList.add("center");
-	fp3.style.textAlign="center";
-	fp3.innerHTML="z-value";
-	fbox.appendChild(fp3);
 
-
-	cell.appendChild(fbox);
 }
 
 function generateReviewSection2(pid){ 
@@ -606,24 +601,43 @@ function generateReviewSection2(pid){
 	
 	
 	let el=config.document.getElementById(id);
-	let table=config.document.createElement('table');
+	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";
-	el.appendChild(table);
 	
 	for (let i=0;i<nrows;i++){
 		pid[json.rows.variable]=json.rows.values[i];
 		//let organ=organs[i];
-		let row=table.insertRow();
+		let row=null;
+		if (i<table.rows.length)
+			row=table.rows[i];
+		else
+			row=table.insertRow();
 
+		let ic=0;
 		for (let j=0;j<ncol;j++){
 			let obj=json.columns[j];
-			if (obj.display=="image") 
-				plotImage(row,json.rows.variable,obj,pid);
-			if (obj.display=="report") 
-				showReport(row,json.rows.variable,obj,pid);
-			if (obj.display=="probability"){ 
-				showProbability(row,json.rows,i,obj,pid);
+			let nv=obj.values.length;
+			for (let k=0;k<nv;k++){
+				let cell=null;
+				if (ic<row.cells.length)
+					cell=row.cells[ic];
+				else
+					cell=row.insertCell();
+				if (obj.display=="image") 
+					plotImage(cell,k,row,json.rows.variable,obj,pid);
+				if (obj.display=="report") 
+					showReport(cell,k,row,json.rows.variable,obj,pid);
+				if (obj.display=="probability"){ 
+					showProbability(cell,k,row,json.rows,i,obj,pid);
+				}	
+				ic++;
 			}
 
 
@@ -677,7 +691,7 @@ function generateReview(divReviewId,divReviewListId, listName){
 	if (! generateTableFlag) return;
 
 	
-	generateTable("reviewComments",divReviewId,false,new Object(),reviewSetup);
+	generateTable("reviewComments",divReviewId,new Object(),reviewSetup);
 }	
 
 //>>>>>>>>>>trigger visibility of additional lists
@@ -764,6 +778,8 @@ function toggleVisibility(divName,buttonName){
 
 	let x = config.document.getElementById(divName);
 	if (x.style.display === "none") {
+		//exclude non data sections (like debug)...
+		populateSection(divName);
     		x.style.display = "block";
 		config.document.getElementById(buttonName).value="Hide";
 
@@ -844,8 +860,10 @@ function generateButton(divName,title,buttonName,callback){
 
 //>>populate fields
 //
-
-function addFieldRow(tb,entry,field,setup,additionalData){
+//
+//split to field generation and field population
+//
+function addFieldRow(tb,field,setup,additionalData){
 
 	let vName=field.name;
 	let vType=field.type;
@@ -858,40 +876,21 @@ function addFieldRow(tb,entry,field,setup,additionalData){
 	
 	let text = config.document.createTextNode(field.shortCaption);
 	cell.appendChild(text);
-	cell=row.insertCell();
-		
-	let varValue="UNDEF";
-	if (vName in setup.filters) varValue=setup.filters[vName];
-	if (vName in entry) varValue=entry[vName];
-
+	let cell1=row.insertCell();
 		
-	//date
-	if (vType=="date"){
-		if (varValue==="UNDEF") varValue=new Date();
-		else varValue=new Date(varValue);
-	}
 	
 	let input=null;
-	cell.colSpan="3";
-
-	let cellClass="input";
-	let cellType="text";
+	cell1.colSpan="3";
 
 	let readonlyFlag=setup.readonlyFlag(vName);
 
-	if (isLookup){
-		let lookup=field["lookup"];
-
-		//get all values from config.formConfig.lookup[X]
-		let lObject=config.formConfig.lookup[lookup.queryName];
-		varValue=lObject.LUT[varValue];
-	}
 
 	//set the html input object
 	while (1){
 
 		if (readonlyFlag){
-			input=config.document.createTextNode(varValue);
+			input=config.document.createElement('label');
+			input.innerText='Loading';
 			break;
 		}
 	
@@ -917,10 +916,6 @@ function addFieldRow(tb,entry,field,setup,additionalData){
 			//
 			//TODO change this so one can always select file
 			//but also show the selected file
-			if (varValue==null) varValue="UNDEF";
-			else{
-				if (varValue.length==0) varValue="UNDEF";
-			}
 
 			if(vName.search("reviewComment")>-1){
 				input = config.document.createElement("textarea");
@@ -933,12 +928,13 @@ function addFieldRow(tb,entry,field,setup,additionalData){
 			input.type="text";
 			
 			if (vName.search('_file_')<0) break;
-			
-			print('varValue: '+varValue);
-
-			if (varValue!="UNDEF") break;
-
-			input.type="file";
+			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;
 				
 		}
@@ -961,20 +957,11 @@ function addFieldRow(tb,entry,field,setup,additionalData){
 	}
 	
 	input.id=setup.getInputId(vName);
-	cell.appendChild(input);
+	cell1.appendChild(input);
+	print('Adding element '+input.id);
+	print('Listing element '+config.document.getElementById(input.id));
 	
 	
-	if (varValue != "UNDEF"){
-		if (vType=="string") 
-			input.value=varValue;
-		if (vType=="float")  
-			input.value=varValue;
-		if (vType=="date") 
-			input.valueAsDate=varValue;
-		if (vType=="boolean") 
-			input.checked=varValue;
-	}
-		
 	if (readonlyFlag) return;
 	
 	if (!isLookup) 	return;
@@ -1004,11 +991,7 @@ function addFieldRow(tb,entry,field,setup,additionalData){
 	opt.value = -1;
 	input.options[0] = opt;
 	print( "Adding <Select>");
-
-	//set value
-	let fv=entry[vName];//can be undefined
-	if (vName in setup.filters) fv=setup.filters[vName];
-	input.selectedIndex=0;
+	
 
 	//add other, label them with LUT
 	for (let v in lObject.LUT) {
@@ -1018,11 +1001,9 @@ function addFieldRow(tb,entry,field,setup,additionalData){
 		opt.text = lObject.LUT[v];
 		opt.value = v;
 		input.options[input.options.length] = opt;
-		if (fv==undefined) continue;
-		if (fv==v) input.selectedIndex=input.options.length-1;
 		
 	}
-		
+	input.selectedIndex=0;	
 
 	//add watcher for showFlag field of additionalData
 	if (!("showFlag" in additionalData))
@@ -1043,14 +1024,124 @@ function addFieldRow(tb,entry,field,setup,additionalData){
 
 }
 		
+function populateFieldRow(entry,field,setup){
 
+	print('populateFieldRow ['+field.name+']: '+entry[field.Name]+' ['+
+		setup.getInputId(field.name)+']');
 	
+	let vName=field.name;
+	let vType=field.type;
+	let id=setup.getInputId(vName);
+	let input=config.document.getElementById(id);
+	let isLookup=("lookup" in field);
 
+	let varValue="UNDEF";
+	//if (vName in setup.filters) varValue=setup.filters[vName];
+	if (vName in entry) varValue=entry[vName];
+		
+	//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=config.formConfig.lookup[lookup.queryName];
+		varValue=lObject.LUT[varValue];
+	}
+
+	print('Element: '+input);
+	//figure out the element type
+	let eType=input.nodeName.toLowerCase();
+	print('Element type: '+eType);
 
+	//HTMLTextArea, createElement(textArea)
+	if (eType==="textarea"){
+		input.value=varValue;
+		return;
+	}
+	//Text, createTextNode
+	if (eType==="#text"){
+		input.nodeValue=varValue;
+		return;
+	}
+	//HTMLLabelElement, createElement('label')
+	if (eType==="label"){
+		input.innerText=varValue;
+		return;
+	}
 
+	//HTMLSelectElement, createElement('select')
+	if (eType==="select"){
+		input.selectedIndex=0;
+		for (let i=0;i<input.options.length;i++){
+			let v=input.options[i].text;
+			if (v!=varValue) continue;
+			input.selectedIndex=i;
+			break;
+		}
+		return;
+	}
 
-function generateTable(listName,divName,unique,additionalData,setup){
+	if (eType!="input"){
+		print('Unknown type: '+eType+' encountered, igonring');
+		return;
+	}
+	
+	//HTMLInputElement
+	let type=input.type;
 
+	if (type=="date"){
+		input.valueAsDate=varValue;
+		return;
+	}
+	//string,float
+	if (type=="text"){
+		input.value=varValue;
+		return;
+	}
+	//boolean
+	if (type=="checkbox"){
+		input.checked=varValue;
+		return;
+	}
+	print('Unknown input type: '+type+'. Ignoring.');
+}
+
+
+function populateTable(listName){
+	
+	let setup=getSetup(listName);
+	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("Nrows "+fQuery.rows.length);
+	
+	if (fQuery.rows.length>0)
+		entry=fQuery.rows[0];
+	
+	let fields=fQuery.fields;
+		
+	for (f in fields){	
+		let field=fields[f];
+		//each field is a new row
+		print("Adding field: "+f+'/'+field.name);
+		if (field.hidden) continue;
+		if (field.name=="crfRef") continue;
+		populateFieldRow(entry,field,setup);
+		
+	}
+
+}
+
+function generateTable(listName,divName,additionalData,setup){
 	let debug=true;
 	
 	if (debug) print("generateTable: "+listName);
@@ -1083,7 +1174,8 @@ function generateTable(listName,divName,unique,additionalData,setup){
 		print("Adding field: "+f+'/'+field.name);
 		if (field.hidden) continue;
 		if (field.name=="crfRef") continue;
-		addFieldRow(tb,entry,field,setup,additionalData);
+		addFieldRow(tb,field,setup,additionalData);
+		populateFieldRow(entry,field,setup);
 		
 	}
 	//add comment field	
@@ -1108,86 +1200,48 @@ function generateTable(listName,divName,unique,additionalData,setup){
 	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(data.queryName,cell1.id,setup)};
+	input.onclick=function(){saveReview(listName,cell1.id,setup)};
 }	
 	
-function checkVariable(el,varValue,displayText, parameters,varName,readonlyFlag){
-	//set value with a little bit of QA
-	//parameters should contain varName or this will return false
-	//compares current varValue to value in parameters[varName], if they are equal,
-	//sets the selectedIndex to last one
-	let debug=true;
-	if (!varName in parameters) return false;
-	print("Comparing: " + varValue  + "/" + parameters[varName]);
-			
-        if (varValue==parameters[varName]){
-		if (readonlyFlag) el.innerHTML=displayText;
-		else {
-			//last one added?
-			el.selectedIndex=el.options.length-1;
-			print("Equal; "+el.selectedIndex);
-		}
-		return true;
-	}
-	return false;
-	
-}
-
 function saveReview(queryName,elementId,setup){
-	let debug=true;
-	if (debug) print("saveReview: elementId "+elementId+" queryName "+queryName);
-	let qconfig=new Object();
-	qconfig.containerPath=config.containerPath;
-	qconfig.schemaName='lists';//could be made more generic
-	qconfig.queryName=queryName;
-	if ("unique" in setup){
-		qconfig.filterArray=[LABKEY.Filter.create("crfRef",getCRFref())];
-
-	}
-	qconfig.success=function(data){saveReviewToList(data,elementId,setup);}
-	//to guess the fields, one must do selectRows first?
-	LABKEY.Query.selectRows(qconfig);
-}
 
-function saveReviewToList(data,elementId,setup){
 	let debug=true;
-	if (debug) {
-		let msg="saveReviewToList: "+" elementId "+elementId;
-		msg+=" nrows "+data.rows.length;
-		print(msg);
-	}
+	if (debug) print("saveReview: elementId "+elementId+" queryName "+queryName);
 	let useInsert=false;
+	
 	if (!("unique" in setup)) useInsert=true;
-	if (data.rows.length==0) useInsert=true;
+
+	let fQuery=config.formConfig.dataQueries[queryName];
+
+	if (fQuery.rows.length==0) useInsert=true;
 	let entry=new Object();
 	
 	if (!useInsert){
-		entry=data.rows[0];
+		entry=fQuery.rows[0];
  	}
 	entry.crfRef=getCRFref();
 
 	if (debug) print("Set crfRef="+entry.crfRef);
 
-	if ("queryName" in setup.filters) {
-		entry.queryName=setup.filters["queryName"];
-		if (debug) print("Setting queryName: "+entry.queryName);
-	}
-	if ("queryname" in setup.filters) {
-		entry.queryname=setup.filters["queryname"];
-		if (debug) print("Setting queryname: "+entry.queryname);
-	}
-	let fields=data.metaData.fields;
+	//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=fields[f].name;
+		let vName=field.name;
+		let vType=field.type;
 
+		if (debug) print("vType: "+vType);
+		
 		if (vName=="crfRef") continue;
 		if (vName=="queryName") continue;
-		if (vName=="queryname") continue;
 		
 		let eId=setup.getInputId(vName);
 		
@@ -1199,52 +1253,58 @@ function saveReviewToList(data,elementId,setup){
 		}
 		if (debug) print("saveReview element: "+eId);
 		
-		let vType=fields[f].type;
-
-		if (debug) print("vType: "+vType);
-
-		if ("lookup" in fields[f]){
-			if (el.nodeName==="SELECT"){
-				entry[vName]=el.options[el.selectedIndex].value;
-			}
-			if (el.nodeName==="TD"){
-				entry[vName]=el.innerHTML;	
-			}
+		let eType=el.nodeName.toLowerCase();
 
-			print("Setting lookup to "+entry[vName]);
+		if (eType==="select"){
+			entry[vName]=el.options[el.selectedIndex].value;
+			continue;
+		}
+	
+		if (eType==="td"){
+			entry[vName]=el.innerText;
 			continue;
 		}
+		
 		if (vType=="date"){
-			var date=el.valueAsDate;
+			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;
-			let idx=field.name.search('_file_');
-			let lg=el.value.length;
-			if (idx>-1 && lg>0){
-				print('Attachment field: '+el.value);
-				//entry[vName]=el.files[0].stream();
-				let ctx=new Object();
-				ctx['dirName']='consent';
-				ctx['ID']=entry['crfRef'];
-				ctx['project']=config.containerPath;
-				//need ID->crf!
-				//assume crfRef will get set before this
-				//element is encountered
-				uploadFile(el,ctx);
-				let suf=entry[vName].split('.').pop();
-				entry[vName]=entry['crfRef']+'.'+suf;
-			}
+			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'];
+			ctx['project']=config.containerPath;
+			//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"){
 			entry[vName]=el.value;
+			continue;
 		}	
 		if (vType=="boolean"){
 			entry[vName]=el.checked;
+			continue;
 		}
 
 
@@ -1253,8 +1313,8 @@ function saveReviewToList(data,elementId,setup){
 	let qconfig=new Object();
 	qconfig.rows=[entry];
 	qconfig.containerPath=config.containerPath;
-	qconfig.schemaName=data.schemaName;
-	qconfig.queryName=data.queryName;
+	qconfig.schemaName='lists';
+	qconfig.queryName=queryName;
 
 	//only update comments
 	print("modifyRows: useInsert "+useInsert);
@@ -1276,6 +1336,9 @@ function updateLastSavedFlag(data,setup,elementId){
 	if (data.queryName=="reviewComments"){
 		updateListDisplay(setup.divReviewListId,"reviewComments",setup.filters,true);
 	}	
+	//refresh stored data!
+	if ("unique" in setup)
+		setData(function (){populateTable(data.queryName);});
 }
 
 //******************************************upload to database *********************
@@ -2209,6 +2272,32 @@ function afterData(){
 
 }
 
+function populateSection(queryName){
+	let rowsSetup=config.formConfig.formSetup.rows;
+	let entry=null;
+	for (let i=0;i<rowsSetup.length;i++){
+		let e=rowsSetup[i];
+		let queryName1=config.formConfig.queryMap[e['queryName']];
+		if (queryName1!=queryName) continue;
+		entry=e;
+		break;
+	}
+	//ignore names without associated entry in formSetup
+	if (entry===null) return;
+	let additionalData=new Object();
+	setAdditionalData(additionalData,entry);
+	if ("isReview" in additionalData){
+		generateReviewSection(queryName,queryName,generateReviewSectionCB);
+		return;	
+	}
+	let setup=getSetup(queryName);
+	setup.unique=true;
+	populateTable(queryName,additionalData,setup);
+	
+
+
+}		
+
 //entry point from generateMasterForm
 
 function setFormConfig(){