Bläddra i källkod

Adding crfReview

Andrej Studen 4 år sedan
förälder
incheckning
6302091049

+ 1 - 1
config/module.xml

@@ -4,7 +4,7 @@
        xmlns:util="http://www.springframework.org/schema/util"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
     <bean id="moduleBean" class="org.labkey.api.module.SimpleModule">
-        <property name="name" value="TECANT"/>
+        <property name="name" value="CRF"/>
         <property name="version" value="0.1"/>
         <property name="requiredServerVersion" value="0.0"/>
         <property name="moduleDependencies" value=""/>

+ 4 - 4
views/crfPortal.html

@@ -56,8 +56,8 @@ window.onload = init();
 // entering data associated with the current user.
 function init() {
 
-    var config=new Object();
-    config.document=document;
+	var config=new Object();
+	config.document=document;
 	config.debugId='formStatus';
 
 	generateHead(config,"debugAreaHead","debugAreaDiv","Debug info");
@@ -159,7 +159,7 @@ function init() {
 	parForm.selectId="FormSelect";
 	parForm.selectAll=true;
 	parForm.inputType="select";
-	parForm.urlName="formUrl";
+	parForm.urlName="viewURL";
 
 	//FormStatus;
 	par.vars["FormStatus"]=new Object();
@@ -188,4 +188,4 @@ function init() {
 }
 	
 	
-</script>
+</script>

+ 5 - 2
views/crfPortal.view.xml

@@ -1,5 +1,8 @@
-<view xmlns="http://labkey.org/data/xml/view" title="CRF Portal">
+<view xmlns="http://labkey.org/data/xml/view" title="CRF Portal" frame="portal">
 	<dependencies>
-			<dependency path="tecant/crfPortal.js"/>
+		<dependency path="crf/crfPortal.js"/>
 	</dependencies>
+	<permissions>
+		<permission name="login"/>
+	</permissions>
 </view>

+ 3 - 0
views/crfPortal.webpart.xml

@@ -0,0 +1,3 @@
+<webpart xmlns="http:/labkey.org/data/xml/webpart" title="CRF Portal">
+	<view name="crfPortal"/>
+</webpart>

+ 159 - 0
views/reviewPortal.html

@@ -0,0 +1,159 @@
+<style>
+p.hidden{
+	display:none;
+}
+table {margin-bottom:20px;table-layout:fixed; border-collapse:collapse; border-spacing:10px}
+table.t1 {width:400px; border:1px solid black}
+table.t1 th {border:1px solid black;padding:4px;background-color:#e0e0e0}
+table.t1 td {text-align:center}
+table.t2 {width:800px; border:1px solid black;}
+table.t2 th {border:1px solid black;padding:4px;background-color:#e0e0e0}
+table.t2 td {border:1px solid black; text-align:center}
+
+table.headTable {width:800px}
+table.headTable th {font-size:20px,text-align:center,background-color:#e0e0e0}
+table.headTable td {font-size:20px,text-align:center}
+
+div.d1 {text-align:center; width=400px; background-color:#e0e0e0;
+        font-size:      20px; margin-bottom:20px}
+
+</style>
+
+<div class="d1">CRF Review Portal</div>
+
+<div id="generalDataHead"></div>
+<div id="generalDataDiv" style="display:none">
+<table id="generalDataTable" cellspacing="2" cellpadding="5" border="0">
+<tr><td>Eudra CT Number: </td><td><strong id="eudraCTNumber">Loading</strong></td></tr>
+<tr><td>Study Sponsor: </td><td><strong id="studySponsor">Loading</strong></td></tr>
+<tr><td>Study Coordinator: </td><td><strong id="studyCoordinator">Loading</strong></td></tr>
+<tr><td>Regulatory authority Entry Number:</td><td><strong id="regulatoryNumber">Loading</strong></td></tr>
+</table>
+</div>
+
+<div id="pickFormHead"></div>
+<div id="pickFormDiv" style="display:none">
+	<div id="formDiv"></div>
+	<div id="selectFormDiv" style="display:block"></div>
+	<div id="listDiv"></div>
+</div>
+
+<div id="startDiv"></div>
+
+<div id="debugAreaHead"></div>
+<div id="debugAreaDiv" style="display:block">
+<textarea cols="95" rows="5" name="formStatus" id="formStatus">Entering data</textarea>
+</div>
+
+<script type="text/javascript">
+
+document.getElementById("formStatus").value+="\nStarting";
+window.onload = init();
+
+
+
+// Initialize the form by populating the Reagent drop-down list and
+// entering data associated with the current user.
+function init() {
+
+	var config=new Object();
+	config.document=document;
+	config.debugId='formStatus';
+
+	print(config,"Testing");
+	generateHead(config,"debugAreaHead","debugAreaDiv","Debug info");
+	generateHead(config,"generalDataHead","generalDataDiv","General data");
+	generateHead(config,"pickFormHead","pickFormDiv","Select CRF");
+						
+	let par=new Object();
+	par.masterQuery="crfEntry";
+	par.dataDiv="listDiv";
+	par.masterUserVarName="UserId";
+	par.formStatusName="FormStatus";
+											//Select PendingReview only
+	//*****CHANGE*****
+	par.formStatus=2;//Submitted
+	par.addDiv="selectFormDiv";
+	
+	par.config=config;	
+
+	par.source=new Object();
+	par.source.queryName="StudyProperties";
+	par.source.schemaName="study";
+	par.source.vars=["eudraCTNumber","studyCoordinator","regulatoryNumber","studySponsor"];
+	par.vars=new Object();
+
+	//User
+	let parUser=new Object();
+	parUser.masterSelectVarName="UserId";
+	parUser.callback=function(){};
+	parUser.selectId="UserSelect";
+	parUser.inputType="select";
+	//only display users in crfReviewers list
+	parUser.filter=new Object();
+	parUser.filter.queryName="crfReviewers";
+	parUser.filter.filterVarName="User";
+	parUser.filter.filters=new Object();
+	parUser.filter.filters["User"]=LABKEY.Security.currentUser.id;
+	par.vars["User"]=parUser;
+	//Crf		
+	let parCrf=new Object();
+	parCrf.masterSelectVarName="entryId";
+	parCrf.callback=generateList;
+	parCrf.selectId="crfSelect";
+	parCrf.addSelect=true;
+	//*****CHANGE****
+	//parCrf.addNewFlag=-1;
+	parCrf.inputType="select";
+	par.vars["Crf"]=parCrf;
+	//Site
+	let parSite=new Object();
+	parSite.masterSelectVarName="Site";
+	parSite.callback=generateListAndPopulateDaughterSelect;
+	parSite.selectId="SiteSelect";
+	parSite.daughterSelect="Crf";
+	parSite.inputType="select";
+
+	parSite.filter=new Object();
+	parSite.filter.queryName="crfReviewers";
+	parSite.filter.filterVarName="Site";
+	parSite.filter.filters=new Object();
+	parSite.filter.filters["User"]=LABKEY.Security.currentUser.id;
+	par.vars["Site"]=parSite;
+	
+	//Form
+	par.vars["Form"]=new Object();
+	let parForm=par.vars["Form"];
+	parForm.masterSelectVarName="Form";
+	parForm.callback=function(){};
+	parForm.selectId="FormSelect";
+	parForm.selectAll=true;
+	parForm.inputType="select";
+	//****CHANGE***** 
+	parForm.urlName="reviewFormUrl";
+				
+	//FormStatus;
+	par.vars["FormStatus"]=new Object();
+	let parFormStatus=par.vars["FormStatus"];
+	parFormStatus.masterSelectVarName="FormStatus";
+	parFormStatus.callback=generateListAndPopulateDaughterSelect;
+	parFormStatus.selectId="FormStatusSelect";
+	parFormStatus.daughterSelect="Crf";
+	parFormStatus.inputType="select";
+												
+	parFormStatus.filter=new Object();
+	parFormStatus.filter.queryName="formStatusVisibility";	
+	parFormStatus.filter.filterVarName="formStatus";
+	parFormStatus.filter.filters=new Object();
+	parFormStatus.filter.filters["visibilityLevel"]="crfReviewer"; 
+																				
+	par.vars["eudraCTNumber"]=sourceVar("EudraCTNumber","eudraCTNumber","EudraCTNumber");
+	par.vars["studyCoordinator"]=sourceVar("StudyCoordinator","studyCoordinator","StudyCoordinator");
+	par.vars["studySponsor"]=sourceVar("StudySponsor","studySponsor","StudySponsor");
+	par.vars["regulatoryNumber"]=sourceVar("RegulatoryNumber","regulatoryNumber","RegulatoryNumber");	
+
+	par.filters=["Site","FormStatus"];
+
+	drawForm(par);
+}
+</script>

+ 9 - 0
views/reviewPortal.view.xml

@@ -0,0 +1,9 @@
+<view xmlns="http://labkey.org/data/xml/view" title="Review Portal">
+	<dependencies>
+			<dependency path="crf/crfPortal.js"/>
+		</dependencies>
+	<permissions>
+		<permission name="login"/>
+	</permissions>
+
+</view>

+ 1 - 1
views/test.view.xml

@@ -1,5 +1,5 @@
 <view xmlns="http://labkey.org/data/xml/view" title="Test">
 	<dependencies>
-			<dependency path="tecant/test.js"/>
+			<dependency path="crf/test.js"/>
 	</dependencies>
 </view>

+ 97 - 0
views/visit0.html

@@ -0,0 +1,97 @@
+<style>
+table {margin-bottom:20px;table-layout:fixed; border-collapse:collapse; border-spacing:10px}
+table.t1 {width:400px; border:1px solid black}
+table.t1 th {border:1px solid black;padding:4px;background-color:#e0e0e0}
+table.t1 td {text-align:center}
+table.t2 {width:800px; border:1px solid black;}
+table.t2 th {border:1px solid black;padding:4px;background-color:#e0e0e0}
+table.t2 td {border:1px solid black; text-align:center}
+
+div.d1 {text-align:center; width=400px; background-color:#e0e0e0;
+        font-size:      20px; margin-bottom:20px}
+</style>
+
+<table cellspacing="2" cellpadding="5" border="0">
+<tr><td>CRF ID: </td><td><strong id="crfRefId">1583163135258</strong></td></tr>
+<tr><td>Eudra CT Number: </td><td><strong id="eudraCTNumber">Loading</strong></td></tr>
+<tr><td>Study Sponsor: </td><td><strong id="studySponsor">Loading</strong></td></tr>
+<tr><td>Study Coordinator: </td><td><strong id="studyCoordinator">Loading</strong></td></tr>
+<tr><td>Site: </td><td><strong id="siteName">Loading</strong></td></tr>
+<tr><td>Investigator: </td><td><strong id="investigatorName">Loading</strong></td></tr>
+</table>
+
+<form name="visitForm" id="visitForm">
+
+</form>
+
+<div id="submitDiv"/>
+
+
+<div id="errorDiv" style="display:none">
+<textarea id="errorTxt" cols="95" rows="10"></textarea>
+</div>
+
+<div id="debug" style="display:block">
+<textarea cols="95" rows="10" name="formStatus" id="formStatus">
+Loading
+</textarea>
+</div>
+
+
+
+<script type="text/javascript">
+
+window.onload = init();
+
+function init(){
+		
+	var searchParams = new URLSearchParams(window.location.search);
+	
+	//update this to pick crfRef from url
+	let crfRef=searchParams.get('entryId');
+	document.getElementById("crfRefId").innerHTML=crfRef;
+	//let crfRef=document.getElementById("crfRefId").innerHTML;
+	
+
+
+	let config=new Object();
+	//will this change if we are in views?
+	config.masterForm="visitForm";
+	
+	config.document=document;
+	config.debugId="formStatus";
+	config.crfRefId="crfRefId";
+	config.containerPath="TECANT/Data";
+	
+	
+	clear(config);
+	print(config,"Container path"+config.containerPath);
+
+
+	let selectRows=new Object();
+	selectRows.containerPath=config.containerPath;
+	selectRows.schemaName='lists';
+	selectRows.queryName='crfEntry';
+	selectRows.filterArray=[LABKEY.Filter.create('entryId',crfRef)];
+	selectRows.success=function(data){populateBasicData(config,data)};
+	//requires populateBasicData
+	LABKEY.Query.selectRows(selectRows);
+
+	config.fields=new Object();	
+
+	let configSelectRows=new Object();
+	configSelectRows.containerPath=config.containerPath;
+	configSelectRows.schemaName='lists';
+	configSelectRows.queryName='visitZeroSetup';
+	configSelectRows.success=function(data){generateForm(config,data);};
+	configSelectRows.failure=function(errorTxt){print(config,"generateForm fail")};
+	LABKEY.Query.selectRows(configSelectRows);
+
+	config.submitReportId="submitReport";
+	//requires onSubmit
+	generateButton(config,"submitDiv","Submit",onSubmit,config);
+
+	
+
+}
+</script>

+ 6 - 0
views/visit0.view.xml

@@ -0,0 +1,6 @@
+<view xmlns="http://labkey.org/data/xml/view" title="Visit #0">
+	<dependencies>
+			<dependency path="crf/crfVisit.js"/>
+	</dependencies>
+</view>
+<!-- need to restart labkey to add new files -->

+ 2 - 2
web/tecant/crfPortal.js → web/crf/crfPortal.js

@@ -698,10 +698,10 @@ function finalRedirect(data,entry,par){
 		"entryId": entry[par.vars["Crf"].masterSelectVarName]
 	};
 
-	let containerPath="TECANT/Data";//part of data?
+	let containerPath="TECANT";//part of data?
         // This changes the page after building the URL. 
 	//Note that the wiki page destination name is set in params.
-        var wikiURL = LABKEY.ActionURL.buildURL("wiki", "page", containerPath, params);
+        var wikiURL = LABKEY.ActionURL.buildURL("crf", formUrl , containerPath, params);
         print(par.config,"Redirecting to "+wikiURL);
 		 
 	window.location = wikiURL;

+ 872 - 0
web/crf/crfVisit.js

@@ -0,0 +1,872 @@
+function clear(config){
+	config.document.getElementById(config.debugId).value="";
+}
+
+function print(config,msg){
+	config.document.getElementById(config.debugId).value+="\n"+msg;
+}
+
+function getCRFref(config){
+	//'crfRefId'
+	return config.document.getElementById(config.crfRefId).innerHTML;
+}
+
+function populateBasicData(config,data){
+	let debug=false;
+	if (debug)
+		print(config,"crfRef matched entries: "+data.rows.length);
+	if (data.rows.length!=1) { return;}
+	config.document.getElementById('eudraCTNumber').innerHTML=data.rows[0].EudraCTNumber;
+	config.document.getElementById('studyCoordinator').innerHTML=data.rows[0].StudyCoordinator;
+	config.document.getElementById('studySponsor').innerHTML=data.rows[0].StudySponsor;
+	let qconfig=new Object();
+	qconfig.containerPath=config.containerPath;
+	qconfig.schemaName='lists';
+	qconfig.queryName='site';
+	qconfig.filterArray=[LABKEY.Filter.create('siteNumber', data.rows[0].Site)];
+	qconfig.success=function(data){setHTML(config,data,'siteName','siteName')};
+	LABKEY.Query.selectRows(qconfig);
+
+	let qconfig1=new Object();
+	qconfig1.containerPath=config.containerPath;
+	qconfig1.schemaName='core';
+	qconfig1.queryName='Users';
+	qconfig1.filterArray= [LABKEY.Filter.create('UserId',data.rows[0].UserId)];
+	qconfig1.success= function(data){setHTML(config,data,'investigatorName','DisplayName')};
+	LABKEY.Query.selectRows(qconfig1);
+}
+
+function setHTML(config,data,elementId,varName){
+	print(config,"setHTML "+data.rows.length+" elementId: "+elementId+" varName:"+varName);
+	if (data.rows.length>0){
+		let entry=data.rows[0];
+		let el=config.document.getElementById(elementId);
+		
+		print(config,"setHTML: Entry[" + varName + "]: " + entry[varName]);
+		print(config,"setHTML: Element[" + elementId + "]: " + el);
+		el.innerHTML=entry[varName];
+	}
+
+}
+
+function setAdditionalData(config,additionalData,entry){
+	let debug=true;
+	if (debug) print(config,"setAdditionalData");
+	if (entry["showFlag"]==="NONE") {
+		if (debug) print(config,"Returning empty additionalData");
+		return additionalData;
+	}
+	additionalData.showFlag=entry["showFlag"];
+	additionalData.showFlagValue=entry["showFlagValue"];
+	additionalData.queryName=entry["showQuery"];
+	additionalData.filters=new Object();
+	additionalData.filters['crfRef']=getCRFref(config);
+	return additionalData;
+}
+
+function fullAccessSetup(config,listName){
+	let debug=true;
+	if (debug) print(config,"fullAccessSetup");
+
+	let setup=new Object();
+	setup.readonlyFlag=function(vName){return false};
+	setup.filters=new Object();
+	setup.filters['crfRef']=getCRFref(config);
+	setup.getInputId=function(vName){return listName+"_"+vName;}
+	setup.addApply="Save";
+	setup.unique=true;
+	//no addApply
+	return setup;
+}
+
+function generateForm(config,data){
+
+	let debug=true;
+	if (debug) print(config,"generateForm ["+data.rows.length+"]");
+	for (let i=0;i<data.rows.length;i++){
+
+		if (debug) print(config,"generateForm ["+i+"/"+data.rows.length+"]");
+
+		let entry=data.rows[i];
+		let queryName=entry["queryName"];
+		
+		if (debug) print(config,"entry[queryName]: "+entry["queryName"]);
+		
+		if (!(queryName in config.fields))
+			 config.fields[queryName]=new Object();
+		
+		let field=config.fields[queryName];
+		field.title=entry["title"];
+
+		if (debug) print(config,"entry[showFlag]: "+entry["showFlag"]);
+
+		let additionalData=new Object();
+		setAdditionalData(config,additionalData,entry);
+		generateSection(config,entry["queryName"],entry["title"],
+				entry["queryName"], additionalData);
+
+	}
+}
+
+function generateSection(config, sectionName, sectionTitle, listName, additionalData){
+
+	let formName=config.masterForm;
+	let debug=true;
+	if (debug) print(config,"generateSection "+sectionName);
+	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"+sectionName+"VisbilityButton";
+	input.onclick=function(){toggleVisibility(config,sectionName,input.id)};
+	cell.appendChild(input);
+	config.document.getElementById(formName).appendChild(tb);
+
+	let div=config.document.createElement('div');
+	div.id=sectionName;
+	div.style.display="none";
+	config.document.getElementById(formName).appendChild(div);	
+
+	let divTable=config.document.createElement('div');
+	divTable.id=sectionName+"Table";
+	div.appendChild(divTable);
+	
+	if ("showFlag" in additionalData) {
+
+		additionalData.divName=sectionName+"SubDiv";
+		additionalData.divQueryName=sectionName+"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(config,"generate master table");
+	
+	generateTable(config,listName,divTable.id,true,additionalData,fullAccessSetup(config,listName));
+	
+	if (debug) print(config,"generate master table: done");
+	
+	if ("showFlag" in additionalData){
+		let qName=additionalData.queryName;
+		let dName=additionalData.divName;
+		generateTable(config,qName,dName,false,additionalData,fullAccessSetup(config,qName));
+	}
+
+	let divReviewList=config.document.createElement('div');
+	divReviewList.id=sectionName+"ReviewList";
+	div.appendChild(divReviewList);
+	
+	let divReview=config.document.createElement('div');
+	divReview.id=sectionName+"Review";
+	div.appendChild(divReview);
+
+	let qconfig=new Object();	
+	qconfig.containerPath=config.containerPath;
+	qconfig.schemaName='lists';
+	qconfig.queryName='visitZeroSetup';
+	qconfig.success=function(data){generateReview(config,data,divReview.id,divReviewList.id,listName)};
+	LABKEY.Query.selectRows(qconfig);
+}
+
+function generateReview(config,data,divReviewId,divReviewListId, listName){
+	let debug=true;
+	if (debug) print(config,"Generate review for: "+listName);
+	let listId=-1;
+	for (let i=0;i<data.rows.length;i++){
+		let entry=data.rows[i];
+		if (entry["queryName"]!=listName) continue;
+		listId=entry["Key"];
+		break;
+	}
+	if (debug) print(config,"Review: setting listId: "+listId);	
+
+	let reviewSetup=new Object();
+	reviewSetup.readonlyFlag=function(vName){
+		if (vName=="queryName") return true; 
+		if (vName=="ModifiedBy") return true;
+		return false;};
+	reviewSetup.addApply="Add Review";
+	reviewSetup.filters=new Object();
+	reviewSetup.filters["crfRef"]=getCRFref(config);
+	reviewSetup.filters["queryName"]=listId;
+	reviewSetup.filters["ModifiedBy"]=LABKEY.Security.currentUser.id;
+	reviewSetup.getInputId=function(vName){return listName+"_add"+vName};
+	reviewSetup.divReviewListId=divReviewListId;
+		
+
+	if (debug) print(config,"Review: divId: "+divReviewId+" inputId: "+reviewSetup.getInputId);
+	
+	updateListDisplay(config,divReviewListId,"reviewComments",reviewSetup.filters,true);
+	generateTable(config,"reviewComments",divReviewId,false,new Object(),reviewSetup);
+}	
+
+function setListVisibility(config,setup,additionalData,readonlyFlag){
+	let debug=true;
+	if (debug){
+		print(config,"Set list visibility ");
+		for (f in additionalData){
+			print(config,"AdditionalData["+f+"]: "+additionalData[f]);
+		}
+	}
+	let x = config.document.getElementById(additionalData.divName);
+	if (debug) print(config,"\n Div: "+x);
+	x.style.display="none";
+	let eId=setup.getInputId(additionalData.showFlag);
+	let e = config.document.getElementById(eId);
+	
+	let sText;
+	if (readonlyFlag) sText=e.innerHTML;
+	else sText=e.options[e.selectedIndex].text;
+	
+	if (debug) print(config,"\n Selected option text: "+sText);
+
+	if (sText == additionalData.showFlagValue){
+		let filters=new Object();
+		if ("filters" in additionalData) filters=additionalData.filters;
+		x.style.display = "block";
+		updateListDisplay(config,additionalData.divQueryName,additionalData.queryName,filters,readonlyFlag);
+	}
+}
+
+function updateListDisplay(config,divName,queryName,filters,readonlyFlag){
+	let debug=true;
+
+	if (debug) print(config,"UpdateListDisplay: Query - "+queryName+" div - "+divName);
+
+	if (divName=="NONE") return;
+	let crfRef=getCRFref(config);
+	let div=config.document.getElementById(divName);
+
+	if (debug)
+		print(config,"Enabling display to queryName: "+queryName);
+	
+	var qconfig=new Object();
+	qconfig.renderTo=divName;
+	qconfig.containerPath=config.containerPath;
+	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=function(data){updateSuccess(config,data)};
+	qconfig.failure=function(data){updateFailure(config,data)};
+	//show only print button
+	if (readonlyFlag){
+		qconfig.buttonBar=new Object();
+		qconfig.buttonBar.items=["print"];
+	}
+
+	LABKEY.QueryWebPart(qconfig);
+	
+}
+
+function updateSuccess(config,data){
+	print(config,"Update success");
+}
+
+function updateFailure(config,data){
+	print(config,"Update failed");
+}
+
+function toggleVisibility(config, divName,buttonName){
+
+	let x = config.document.getElementById(divName);
+	if (x.style.display === "none") {
+    		x.style.display = "block";
+		config.document.getElementById(buttonName).value="Hide";
+
+  	} else {
+    		x.style.display = "none";
+		config.document.getElementById(buttonName).value="Show";
+
+  	}
+}
+
+function generateButton(config,divName,buttonName,callback,callbackParameters){
+	let debug=true;
+	if (debug) print(config,"generateButton");
+	
+	let tb=config.document.createElement('table');
+	tb.className="t2";
+	
+	let r1=tb.insertRow();
+	th=config.document.createElement('th');
+	r1.appendChild(th);
+	th.innerHTML="Complete submission";
+	//*!*
+	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(config,"generateButton: element["+divName+"]: "+el);
+	
+	
+	el.appendChild(tb);
+	
+	
+}
+
+function generateTable(config,listName,divName,unique,additionalData,setup){
+	let debug=true;
+	
+	if (debug) print(config,"generateTable: "+listName);
+
+	//add temp variables
+	let qconfig=new Object();
+	qconfig.containerPath=config.containerPath;
+	qconfig.schemaName='lists';
+	qconfig.queryName=listName;
+	//apply filters on data to get right entries
+	qconfig.filterArray=[];
+	for (f in setup.filters){
+		qconfig.filterArray.push(LABKEY.Filter.create(f,setup.filters[f]));
+	}
+	qconfig.success=function(data){populateTable(config,data,divName,unique,additionalData,setup)};
+	LABKEY.Query.selectRows(qconfig);
+}
+
+function populateTable(config,data,divName,unique,additionalData,setup){
+	//generate and populate table with the first suitable entry
+	let debug=true;
+
+	if (debug){
+		print(config,"populateTable Query: "+data.queryName+" divName: "+divName+" setup: "+setup);
+
+
+		if (0){
+			let obj=data.metaData.fields;
+			for (f in obj){	
+				print(config,"Data["+f+"]: "+obj[f]);
+				for (g in obj[f]){
+					print(config,"Data.metaData.fields["+f+"]["+g+"]: "+obj[f][g]);
+				}
+				if ("lookup" in obj[f]){
+					for (h in obj[f]["lookup"]){
+						print(config,"Lookup["+h+"]: "+obj[f]["lookup"][h]);
+	
+					}
+				}
+
+			}
+		}
+	}
+	let crfRef=getCRFref(config);
+	let entry=new Object();
+
+	if (debug)
+		print(config,"Data: nrows "+data.rows.length);
+
+	if (data.rows.length > 0) entry=data.rows[0];
+	
+	let tb=config.document.createElement('table');
+	tb.className="t2";
+	config.document.getElementById(divName).appendChild(tb);
+
+	let fields=data.metaData.fields;
+	for (f in fields){
+		let field=fields[f];
+		if (field.hidden) continue;
+		
+		let vName=field.name;
+		
+		if (debug) print(config,"Field ["+vName+"]");
+		if (vName=="crfRef") continue;		
+
+		let vType=field.type;
+		if (debug) print(config,"Field ["+vName+"/"+vType+"]");
+		let row=tb.insertRow();
+		let cell=config.document.createElement('th');
+		row.appendChild(cell);
+		let text = config.document.createTextNode(fields[f].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];
+		if (vType=="date"){
+			if (varValue==="UNDEF") varValue=new Date();
+			else varValue=new Date(varValue);
+		}
+		if (debug) print(config,"value: "+varValue);		
+		let input;
+		if (setup.readonlyFlag(vName)){
+			input=config.document.createTextNode(varValue);
+			cell.id=setup.getInputId(vName);
+		}
+		else{
+			cell.colSpan="3";
+
+			let cellClass="input";
+			let cellType="text";
+			if ("lookup" in field){
+				input = config.document.createElement("select");
+			}
+			if (vType=="date"){ 
+				input = config.document.createElement("input");
+				input.type="date";
+			}
+			if (vType=="string"){
+				if(vName.search("reviewComment")>-1){
+					input = config.document.createElement("textarea");
+					input.cols="65";
+					input.rows="5";
+				}
+				else{
+					input = config.document.createElement("input");
+					input.type="text";
+				}
+			}
+			if (vType=="float"){
+				input = config.document.createElement("input");
+				input.type="text";
+			}	
+		
+			input.id=setup.getInputId(vName);
+			if (vName in entry){
+				if (vType=="string") input.value=varValue;
+				if (vType=="float")  input.value=varValue;
+				if (vType=="date") input.valueAsDate=varValue;
+			}
+		}
+
+	
+		cell.appendChild(input);
+		
+		if ("lookup" in field){
+			let lookup=field["lookup"];
+			let qconfig=new Object();
+			if (debug) print(config,"populateTable lookup: Query: "+lookup.queryName);
+			qconfig.containerPath=config.containerPath;
+			qconfig.schemaName=lookup.schemaName;
+			qconfig.queryName=lookup.queryName;
+			let parameters= new Object();
+			parameters.elementId=setup.getInputId(vName);
+			parameters.keyColumn=lookup.keyColumn;
+			parameters.displayColumn=lookup.displayColumn;
+			
+			if (vName in setup.filters) parameters.selectedKey=setup.filters[vName];
+			if (vName in entry) parameters.selectedKey=entry[vName];
+			
+			if ("showFlag" in additionalData) parameters.additionalData=additionalData;
+			if (debug) print(config,"Populate select for "+parameters.elementId);
+			qconfig.success=function(data){
+				populateSelect(config,data,parameters,setup,setup.readonlyFlag(vName))
+			};
+			LABKEY.Query.selectRows(qconfig);
+		}
+		
+	}
+	//add comment field	
+	if (!("addApply" in setup)) {
+		print(config,"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";
+	input.onclick=function(){saveReview(config,data.queryName,cell1.id,setup)};
+}	
+	
+function populateSelect(config,data,parameters,setup,readonlyFlag){
+	let debug=true;
+	if (debug)
+		print(config,"populateSelect on "+data.queryName);
+	let elementId=parameters.elementId;
+	let keyColumn=parameters.keyColumn;
+	let displayColumn=parameters.displayColumn;
+	if (debug){
+		print(config,"Query: "+data.queryName);
+		print(config,"ElementId: "+elementId);
+		print(config,"keyColumn: "+keyColumn);
+		print(config,"displayColumn: "+displayColumn);
+	
+		if ("selectedKey" in parameters){
+			print(config,"SelectedKey: "+parameters["selectedKey"]);
+		}
+	}
+	let el = config.document.getElementById(elementId);
+	
+	if (debug)
+		print(config,"Element: "+el);
+   	
+	if (!readonlyFlag){
+		//clear options
+		for(i = el.options.length; i >= 0; i--) {
+			el.remove(i);
+   		}
+	
+		let opt = config.document.createElement("option");
+		opt.text = "<Select>";
+		opt.value = -1;
+		el.options[0] = opt;
+
+	}
+
+	for (let i = 0; i < data.rows.length; i++) {
+		let displayText = data.rows[i][displayColumn];
+		let keyValue = data.rows[i][keyColumn];
+
+		if (!readonlyFlag){
+			let opt = config.document.createElement("option");
+
+			opt.text = displayText;
+			opt.value = keyValue;
+			el.options[el.options.length] = opt;
+		
+		}
+		if (debug) print(config,"Adding: "+keyValue+" : "+displayText);
+		
+		let t1=checkVariable(config,el,keyValue,displayText,parameters,"selectedKey",readonlyFlag);
+		if (t1) setup.keyValue=keyValue;
+
+		
+	}
+	
+	if (!("additionalData" in parameters)) return;
+
+	if (debug) print(config,"\n Parsing additional data ");
+
+	let additionalData=parameters["additionalData"];	
+
+	let expId=setup.getInputId(additionalData.showFlag);
+	if (expId!=elementId) {
+		print(config,"Element mismatch: got :"+expId+"/"+elementId);
+		return;
+	}
+
+	if (debug)
+		print(config,"Setting onChange to "+el.id);
+	
+	el.onchange=function(){setListVisibility(config,setup,additionalData,readonlyFlag)};
+	setListVisibility(config,setup,additionalData,readonlyFlag);
+
+}	
+
+function checkVariable(config,el,varValue,displayText, parameters,varName,readonlyFlag){
+	let debug=true;
+	if (!varName in parameters) return false;
+	if (debug) print(config,"Comparing: " + varValue  + "/" + parameters[varName]);
+			
+        if (varValue==parameters[varName]){
+		if (readonlyFlag) el.innerHTML=displayText;
+		else {
+			el.selectedIndex=el.options.length-1;
+			if (debug) print(config,"Equal; "+el.selectedIndex);
+		}
+		return true;
+	}
+	return false;
+	
+}
+
+function failureSelect(config,errorInfo,resp,opt){
+	print(config,"Error: ");
+
+}
+
+function saveReview(config,queryName,elementId,setup){
+	let debug=true;
+	if (debug) print(config,"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(config))];
+
+	}
+	qconfig.success=function(data){saveReviewToList(config,data,elementId,setup);}
+	//to guess the fields, one must do selectRows first?
+	LABKEY.Query.selectRows(qconfig);
+}
+
+function saveReviewToList(config,data,elementId,setup){
+	let debug=true;
+	if (debug) print(config,"saveReviewToList: "+" elementId "+elementId+ " nrows "+data.rows.length);
+	
+	let useInsert=false;
+	if (!("unique" in setup)) useInsert=true;
+	if (data.rows.length==0) useInsert=true;
+	let entry=new Object();
+	
+	if (!useInsert){
+		entry=data.rows[0];
+ 	}
+	entry.crfRef=getCRFref(config);
+
+	if (debug) print(config,"Set crfRef="+entry.crfRef);
+
+	if ("queryName" in setup.filters) entry.queryName=setup.filters["queryName"];
+	
+	let fields=data.metaData.fields;
+	for (f in fields){
+
+		let field=fields[f];
+		if (debug) print(config,"saveReview field: "+field.name);
+		if (field.hidden) continue;
+		
+		let vName=fields[f].name;
+
+		if (vName=="crfRef") continue;
+		if (vName=="queryName") continue;
+		
+		let eId=setup.getInputId(vName);
+		
+		let el=config.document.getElementById(eId);
+				
+		if (!el) {
+			if (debug) print(config,"saveReview element: "+eId+" not found");
+			continue;
+		}
+		if (debug) print(config,"saveReview element: "+eId);
+		
+		let vType=fields[f].type;
+
+		if ("lookup" in fields[f]){
+			if (el.nodeName==="SELECT"){
+				entry[vName]=el.options[el.selectedIndex].value;
+			}
+			if (el.nodeName==="TD"){
+				entry[vName]=el.innerHTML;	
+			}
+
+			print(config,"Setting lookup to "+entry[vName]);
+			continue;
+		}
+		if (vType=="date"){
+			var date=el.valueAsDate;
+			if (date==="null") continue;
+			date.setUTCHours(12);
+			entry[vName]=date.toString();
+			print(config,"Setting date to "+entry[vName]);
+		}	
+		if (vType=="string"){
+			entry[vName]=el.value;
+		}	
+		if (vType=="float"){
+			entry[vName]=el.value;
+		}	
+
+
+	}
+	
+	let qconfig=new Object();
+	qconfig.rows=[entry];
+	qconfig.containerPath=config.containerPath;
+	qconfig.schemaName=data.schemaName;
+	qconfig.queryName=data.queryName;
+
+	//only update comments
+
+	qconfig.success=function(data){updateLastSavedFlag(config,data,setup,elementId)};
+	if (!useInsert){
+		LABKEY.Query.updateRows(qconfig);
+	}
+	else{
+		LABKEY.Query.insertRows(qconfig);
+	}
+}
+
+function updateLastSavedFlag(config,data,setup,elementId){
+	let debug=true;
+	if (debug) print(config,"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(config,setup.divReviewListId,"reviewComments",setup.filters,true);
+	}	
+}
+
+function onSubmit(config){
+	let debug=true;
+	hideErr(config);
+	clearErr(config);
+	printErr(config,"onSubmit");
+	checkForm(config);
+	let cb=new Object();
+	cb.success=finalValidation;
+	cb.failure=function(config){printErr(config,"waitForCheckForm failed")};
+	waitForCheckForm(config,cb);
+}
+
+function finalValidation(config){
+	let debug=true;
+	if (debug) print(config,"validate");
+	
+	let completed=true;
+	for (f in config.fields){
+		let field=config.fields[f];
+		if (field.status!="DONE") {
+			printErr(config,"Missing entry for "+field.title);
+			completed=false;
+		}
+	}
+	if (debug) print(config,"valid: "+completed);
+
+	if (completed){
+		finalRedirect(config);
+	}
+	else{
+		updateSubmitStatus(config,"Form invalid");
+	}
+}
+
+function finalRedirect(config){
+	printErr(config,"Form valid");
+	let c1=new Object();
+	c1.schemaName='lists';
+	c1.queryName='crfEntry';
+	c1.filterArray=[LABKEY.Filter.create('crfRef',getCRFref(config))];
+	c1.success=function(data){setSubmitStatus(config,data)};
+	LABKEY.Query.selectRows(c1);
+}
+
+function setSubmitStatus(config,data){
+	let entry=data.rows[0];
+	entry.formStatus=2;//Submitted
+	let c1=new Object();
+	c1.schemaName=data.schemaName;
+	c1.queryName=data.queryName;
+	c1.containerPath=config.containerPath;
+	c1.rows=[entry];
+	c1.success=function(data){updateSubmitStatus(config,"Form submitted")};
+	LABKEY.Query.updateRows(c1);
+}
+
+function updateSubmitStatus(config,msg){
+	let el=document.getElementById(config.submitReportId);
+	el.innerHTML=msg;
+}
+
+function hideErr(config){
+	let el=config.document.getElementById("errorDiv");
+	el.style.display="none";
+}
+
+function clearErr(config){
+	let el=config.document.getElementById("errorTxt");
+	el.value="";
+}
+
+function showErr(config){
+	let el=config.document.getElementById("errorDiv");
+	el.style.display="block";
+}
+
+function printErr(config,msg){
+	showErr(config);
+	el=config.document.getElementById("errorTxt");
+	el.style.color="red";
+	el.value+="\n"+msg;
+}
+
+function checkForm(config){
+	let debug=false;
+	let crfRef=getCRFref(config)
+	
+	
+	config.status="UNKNOWN";
+	for (f in config.fields){
+		let field=config.fields[f];
+		field.status="UNKNOWN";
+
+		if (debug) 
+			print(config,"Setting status for "+f+" to "+ field.status);
+
+		let selectRows=new Object();
+		selectRows.containerPath=config.containerPath;
+		selectRows.schemaName="lists";
+		selectRows.queryName=f;
+		selectRows.filterArray=[LABKEY.Filter.create('crfRef',crfRef)];
+		selectRows.success=function(data){checkData(data,config)};
+		selectRows.failure=function(errorObj){print(config,"checkData failed.")};
+		LABKEY.Query.selectRows(selectRows);
+	}
+}
+
+function waitForCheckForm(config,cb){
+	let debug=true;
+	if (!("i" in config)) config.i=0;
+	if (debug) print(config,"["+config.i+"] checkForm status "+config.status);
+	if (config.i>100) {
+		if (debug) print(config,"executing failure");	
+		cb.failure(config);
+		return;
+	}
+	if (config.status=="DONE") {
+		if (debug) print(config,"executing success");	
+		cb.success(config);
+		if (debug) print(config,"success executed");	
+		return;
+	}
+	config.i+=1;
+	setTimeout(function(){waitForCheckForm(config,cb);},1000);
+}
+
+function checkData(data,config){
+	let debug=false;
+	if (debug) print(config,"checkData ");
+	let field=config.fields[data.queryName];
+	field.status="NONE";
+	if (debug) print(config,"Setting status for "+data.queryName+" to "+field.status);
+	if (data.rows.length>0)
+		field.status="DONE";
+	
+	if (debug)
+		print(config,"checkData set status for "+data.queryName+" to "+field.status);
+	
+	for (f in config.fields){
+		let subField=config.fields[f];
+		if (debug) 
+			print(config,"checkData status["+f+"]: "+subField.status);	
+		if (subField.status=="UNKNOWN") {
+			if (debug) print(config,"\t Status for "+f+" not set ["+ subField.status+"]");
+			return;
+		}
+		
+	}
+	config.status="DONE";
+}
+

+ 831 - 0
web/crf/crfVisitAll.js

@@ -0,0 +1,831 @@
+function myprint(config, msg){
+	config.document.getElementById(config.debugId).value+="\n"+msg;
+}
+
+function print(config,msg){myprint(config,msg);}
+
+function getCRFref(config){
+	//'crfRefId'
+	return config.document.getElementById(config.crfRefId).innerHTML;
+}
+
+function populateBasicData(config,data){
+	let debug=false;
+	if (debug)
+		print(config,"crfRef matched entries: "+data.rows.length);
+	if (data.rows.length!=1) { return;}
+	config.document.getElementById('eudraCTNumber').innerHTML=data.rows[0].EudraCTNumber;
+	config.document.getElementById('studyCoordinator').innerHTML=data.rows[0].StudyCoordinator;
+	config.document.getElementById('studySponsor').innerHTML=data.rows[0].StudySponsor;
+	LABKEY.Query.selectRows({schemaName: 'lists',queryName: 'site', 
+		filterArray: [LABKEY.Filter.create('siteNumber', data.rows[0].Site)],
+		success: function(data){setHTML(config,data,'siteName','siteName')};
+	});	
+	LABKEY.Query.selectRows({schemaName: 'core',queryName: 'Users',
+		filterArray: [LABKEY.Filter.create('UserId',data.rows[0].UserId)],
+		success: function(data){setHTML(config,data,'investigatorName','DisplayName')}
+	});
+}
+
+function setHTML(config,data,elementId,varName){
+	print(config,"\nsetHTML "+data.rows.length+" elementId: "+elementId+" varName:"+varName);
+	if (data.rows.length>0){
+		let entry=data.rows[0];
+		let el=config.document.getElementById(elementId);
+		
+		print(config,"\nsetHTML: Entry[" + varName + "]: " + entry[varName]);
+		print(config,"\nsetHTML: Element[" + elementId + "]: " + el;
+		el.innerHTML=entry[varName];
+	}
+
+}
+
+function setAdditionalData(config,additionalData,entry){
+	let debug=true;
+	if (debug) print(config,"setAdditionalData");
+	if (entry["showFlag"]==="NONE") {
+		if (debug) print(config,"Returning empty additionalData");
+		return additionalData;
+	}
+	additionalData.showFlag=entry["showFlag"];
+	additionalData.showFlagValue=entry["showFlagValue"];
+	additionalData.queryName=entry["showQuery"];
+	additionalData.filters=new Object();
+	additionalData.filters['crfRef']=getCRFref();
+	return additionalData;
+}
+
+function fullAccessSetup(listName){
+	let setup=new Object();
+	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.unique=true;
+	//no addApply
+	return setup;
+}
+
+function generateForm(config,data){
+
+	let debug=true;
+	if (debug) print(config,"generateForm ["+data.rows.length+"]");
+	for (let i=0;i<data.rows.length;i++){
+		let entry=data.rows[i];
+		let queryName=entry["queryName"];
+
+		if (!(queryName in config.fields))
+			 config.fields[queryName]=new Object();
+		let field=config.fields[queryName];
+		field.title=entry["title"];
+
+		if (debug) print(config,"generateForm ["+i+"/"+data.rows.length+"]");
+		if (debug) print(config,"entry[queryName]: "+entry["queryName"]);
+		if (debug) print(config,"entry[showFlag]: "+entry["showFlag"]);
+		let additionalData=new Object();
+		setAdditionalData(config,additionalData,entry);
+		generateSection(config,entry["queryName"],entry["title"],
+				entry["queryName"], additionalData);
+
+	}
+}
+
+function generateSection(config, sectionName, sectionTitle, listName, additionalData){
+	let formName=config.masterForm;
+	let debug=true;
+	if (debug) print(config,"generateSection");
+	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"+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;
+	div.style.display="none";
+	config.document.getElementById(formName).appendChild(div);	
+
+	let divTable=config.document.createElement('div');
+	divTable.id=sectionName+"Table";
+	div.appendChild(divTable);
+	
+	if ("showFlag" in additionalData) {
+
+		additionalData.divName=sectionName+"SubDiv";
+		additionalData.divQueryName=sectionName+"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(config,"generate master table");
+	generateTable(config,listName,divTable.id,true,additionalData,fullAccessSetup(listName));
+	if (debug) print(config,"generate master table: done");
+	if ("showFlag" in additionalData){
+		let qName=additionalData.queryName;
+		let dName=additionalData.divName;
+		generateTable(config,qName,dName,false,additionalData,fullAccessSetup(qName));
+	}
+
+	let divReviewList=config.document.createElement('div');
+	divReviewList.id=sectionName+"ReviewList";
+	div.appendChild(divReviewList);
+	
+	let divReview=config.document.createElement('div');
+	divReview.id=sectionName+"Review";
+	div.appendChild(divReview);
+
+	let config=new Object();	
+	config.schemaName='lists';
+	config.queryName='visitZeroSetup';
+	config.success=function(data){generateReview(config,data,divReview.id,divReviewList.id,listName)};
+	LABKEY.Query.selectRows(config);
+}
+
+function generateReview(config,data,divReviewId,divReviewListId, listName){
+	let debug=true;
+	let listId=-1;
+	for (let i=0;i<data.rows.length;i++){
+		let entry=data.rows[i];
+		if (entry["queryName"]!=listName) continue;
+		listId=entry["Key"];
+		break;
+	}
+	
+	let reviewSetup=new Object();
+	reviewSetup.readonlyFlag=function(vName){if (vName=="queryName") return true; return false;};
+	reviewSetup.addApply="Add Review";
+	reviewSetup.filters=new Object();
+	reviewSetup.filters["crfRef"]=getCRFref(config);
+	reviewSetup.filters["queryName"]=listId;
+	reviewSetup.getInputId=function(vName){return listName+"_"+vName;}	
+	reviewSetup.divReviewListId=divReviewListId;	
+
+	if (debug) print(config,"update list display");
+	updateListDisplay(config,divReviewListId,"reviewComments",reviewSetup.filters,true);
+	generateTable(config,"reviewComments",divReviewId,false,new Object(),reviewSetup);
+}	
+
+function setListVisibility(config,setup,additionalData,readonlyFlag){
+	let debug=true;
+	if (debug){
+		print(config,"Set list visibility ");
+		for (f in additionalData){
+			print(config,"AdditionalData["+f+"]: "+additionalData[f]);
+		}
+	}
+	let x = config.document.getElementById(additionalData.divName);
+	if (debug) print("\n Div: "+x);
+	x.style.display="none";
+	let eId=setup.getInputId(additionalData.showFlag);
+	let e = config.document.getElementById(eId);
+	
+	let sText;
+	if (readonlyFlag) sText=e.innerHTML;
+	else sText=e.options[e.selectedIndex].text;
+	
+	if (debug) print(config,"\n Selected option text: "+sText);
+
+	if (sText == additionalData.showFlagValue){
+		let filters=new Object();
+		if ("filters" in additionalData) filters=additionalData.filters;
+		x.style.display = "block";
+		updateListDisplay(config,additionalData.divQueryName,additionalData.queryName,filters,readonlyFlag);
+	}
+}
+
+function updateListDisplay(config,divName,queryName,filters,readonlyFlag){
+	let debug=true;
+
+	if (debug) print(config,"UpdateListDisplay: Query - "+queryName+" div - "+divName);
+
+	if (divName=="NONE") return;
+	let crfRef=getCRFref(config);
+	let div=config.document.getElementById(divName);
+
+	if (debug)
+		print(config,"Enabling display to queryName: "+queryName);
+	
+	var qconfig=new Object();
+	qconfig.renderTo=divName;
+	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=function(data){updateSuccess(config,data)};
+	qconfig.failure=function(data){updateFailure(config,data)};
+	//show only print button
+	if (readonlyFlag){
+		qconfig.buttonBar=new Object();
+		qconfig.buttonBar.items=["print"];
+	}
+
+	LABKEY.QueryWebPart(qconfig);
+	
+}
+
+function updateSuccess(config,data){
+	print(config,"Update success");
+}
+
+function updateFailure(config,data){
+	print(config,"Update failed");
+}
+
+function toggleVisibility(config, divName,buttonName){
+
+	let x = config.document.getElementById(divName);
+	if (x.style.display === "none") {
+    		x.style.display = "block";
+		config.document.getElementById(buttonName).value="Hide";
+
+  	} else {
+    		x.style.display = "none";
+		config.document.getElementById(buttonName).value="Show";
+
+  	}
+}
+
+function generateButton(config,divName,buttonName,callback,callbackParameters){
+	let debug=true;
+	if (debug) print(config,"generateButton");
+	
+	let tb=config.document.createElement('table');
+	tb.className="t2";
+	
+	let r1=tb.insertRow();
+	th=config.document.createElement('th');
+	r1.appendChild(th);
+	th.innerHTML="Complete submission";
+	//*!*
+	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 generateTable(config,listName,divName,unique,additionalData,setup){
+	let debug=true;
+	
+	//add temp variables
+	let qconfig=new Object();
+	qconfig.schemaName='lists';
+	qconfig.queryName=listName;
+	//apply filters on data to get right entries
+	qconfig.filterArray=[];
+	for (f in setup.filters){
+		qconfig.filterArray.push(LABKEY.Filter.create(f,setup.filters[f]));
+	}
+	qconfig.success=function(data){populateTable(config,data,divName,unique,additionalData,setup)};
+	LABKEY.Query.selectRows(qconfig);
+}
+
+function populateTable(config,data,divName,unique,additionalData,setup){
+	//generate and populate table with the first suitable entry
+	let debug=true;
+
+	if (debug){
+		print(config,"populateTable Query: "+data.queryName+" divName: "+divName+" setup: "+setup);
+
+
+		if (0){
+			let obj=data.metaData.fields;
+			for (f in obj){	
+				print(config,"Data["+f+"]: "+obj[f]);
+				for (g in obj[f]){
+					print(config,"Data.metaData.fields["+f+"]["+g+"]: "+obj[f][g]);
+				}
+				if ("lookup" in obj[f]){
+					for (h in obj[f]["lookup"]){
+						print(config,"Lookup["+h+"]: "+obj[f]["lookup"][h]);
+	
+					}
+				}
+
+			}
+		}
+	}
+	let crfRef=getCRFref(config);
+	let entry=new Object();
+
+	if (debug)
+		print(config,"Data: nrows "+data.rows.length);
+
+	if (data.rows.length > 0) entry=data.rows[0];
+	
+	let tb=config.document.createElement('table');
+	tb.className="t2";
+	config.document.getElementById(divName).appendChild(tb);
+
+	let fields=data.metaData.fields;
+	for (f in fields){
+		let field=fields[f];
+		if (field.hidden) continue;
+		
+		let vName=field.name;
+		
+		if (debug) print(config,"Field ["+vName+"]");
+		if (vName=="crfRef") continue;		
+
+		let vType=field.type;
+		if (debug) print(config,"Field ["+vName+"/"+vType+"]");
+		let row=tb.insertRow();
+		let cell=config.document.createElement('th');
+		row.appendChild(cell);
+		let text = config.document.createTextNode(fields[f].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];
+		if (vType=="date"){
+			if (varValue==="UNDEF") varValue=new Date();
+			else varValue=new Date(varValue);
+		}
+		if (debug) print("value: "+varValue);		
+		let input;
+		if (setup.readonlyFlag(vName)){
+			input=config.document.createTextNode(varValue);
+			cell.id=setup.getInputId(vName);
+		}
+		else{
+			cell.colSpan="3";
+
+			let cellClass="input";
+			let cellType="text";
+			if ("lookup" in field){
+				input = config.document.createElement("select");
+			}
+			if (vType=="date"){ 
+				input = config.document.createElement("input");
+				input.type="date";
+			}
+			if (vType=="string"){
+				if(vName.search("reviewComment")>-1){
+					input = config.document.createElement("textarea");
+					input.cols="65";
+					input.rows="5";
+				}
+				else{
+					input = config.document.createElement("input");
+					input.type="text";
+				}
+			}
+			if (vType=="float"){
+				input = config.document.createElement("input");
+				input.type="text";
+			}	
+		
+			input.id=setup.getInputId(vName);
+			if (vName in entry){
+				if (vType=="string") input.value=varValue;
+				if (vType=="float")  input.value=varValue;
+				if (vType=="date") input.valueAsDate=varValue;
+			}
+		}
+
+	
+		cell.appendChild(input);
+		
+		if ("lookup" in field){
+			let lookup=field["lookup"];
+			let qconfig=new Object();
+			if (debug) print(config,"Query: "+lookup.queryName);
+			qconfig.schemaName=lookup.schemaName;
+			qconfig.queryName=lookup.queryName;
+			let parameters= new Object();
+			parameters.elementId=setup.getInputId(vName);
+			parameters.keyColumn=lookup.keyColumn;
+			parameters.displayColumn=lookup.displayColumn;
+			
+			if (vName in setup.filters) parameters.selectedKey=setup.filters[vName];
+			if (vName in entry) parameters.selectedKey=entry[vName];
+			
+			if ("showFlag" in additionalData) parameters.additionalData=additionalData;
+			if (debug) print("Populate select for "+parameters.elementId);
+			qconfig.success=function(data){populateSelect(config,data,parameters,setup,setup.readonlyFlag(vName))};
+			LABKEY.Query.selectRows(qconfig);
+		}
+		
+	}
+	//add comment field	
+	if (!("addApply" in setup)) {
+		print(config,"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("rewievLastSave");
+	cell1.innerHTML="No recent update";
+	input.onclick=function(){saveReview(config,data.queryName,cell1.id,setup)};
+}	
+	
+
+function populateSelect(config,data,parameters,setup,readonlyFlag){
+	let debug=true;
+	if (debug)
+		print(config,"populateSelect on "+data.queryName);
+	let elementId=parameters.elementId;
+	let keyColumn=parameters.keyColumn;
+	let displayColumn=parameters.displayColumn;
+	if (debug){
+		print(config,"Query: "+data.queryName);
+		print(config,"ElementId: "+elementId);
+		print(config,"keyColumn: "+keyColumn);
+		print(config,"displayColumn: "+displayColumn);
+	
+		if ("selectedKey" in parameters){
+			print(config,"SelectedKey: "+parameters["selectedKey"]);
+		}
+	}
+	let el = config.document.getElementById(elementId);
+	
+	if (debug)
+		print(config,"Element: "+el);
+   	
+	if (!readonlyFlag){
+		//clear options
+		for(i = el.options.length; i >= 0; i--) {
+			el.remove(i);
+   		}
+	
+		let opt = config.document.createElement("option");
+		opt.text = "<Select>";
+		opt.value = -1;
+		el.options[0] = opt;
+
+	}
+
+	for (let i = 0; i < data.rows.length; i++) {
+		let displayText = data.rows[i][displayColumn];
+		let keyValue = data.rows[i][keyColumn];
+
+		if (!readonlyFlag){
+			let opt = config.document.createElement("option");
+
+			opt.text = displayText;
+			opt.value = keyValue;
+			el.options[el.options.length] = opt;
+		
+		}
+		if (debug) print("Adding: "+keyValue+" : "+displayText);
+		
+		let t1=checkVariable(config,el,keyValue,displayText,parameters,"selectedKey",readonlyFlag);
+		if (t1) setup.keyValue=keyValue;
+
+		
+	}
+	
+	if (!("additionalData" in parameters)) return;
+
+	if (debug) print(config,"\n Parsing additional data ");
+
+	let additionalData=parameters["additionalData"];	
+
+	let expId=setup.getInputId(additionalData.showFlag);
+	if (expId!=elementId) {
+		print(config,"Element mismatch: got :"+expId+"/"+elementId);
+		return;
+	}
+
+	if (debug)
+		print(config,"Setting onChange to "+el.id);
+	
+	el.onchange=function(){setListVisibility(config,setup,additionalData,readonlyFlag)};
+	setListVisibility(config,setup,additionalData,readonlyFlag);
+
+}	
+
+function checkVariable(config,el,varValue,displayText, parameters,varName,readonlyFlag){
+	let debug=true;
+	if (!varName in parameters) return false;
+	if (debug) print(config,"Comparing: " + varValue  + "/" + parameters[varName]);
+			
+        if (varValue==parameters[varName]){
+		if (readonlyFlag) el.innerHTML=displayText;
+		else {
+			el.selectedIndex=el.options.length-1;
+			if (debug) print(" Equal; "+el.selectedIndex);
+		}
+		return true;
+	}
+	return false;
+	
+}
+
+
+function failureSelect(config,errorInfo,resp,opt){
+	document.getElementById('formStatus').value+="\n Error: ";
+
+}
+
+function saveReview(config,queryName,elementId,setup){
+	let debug=true;
+	if (debug) print(config,"saveReview: elementId "+elementId);
+	let qconfig=new Object();
+	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(config,data,elementId,setup);}
+	//to guess the fields, one must do selectRows first?
+	LABKEY.Query.selectRows(qconfig);
+}
+
+function saveReviewToList(config,data,elementId,setup){
+	let debug=true;
+	if (debug) print(config,"saveReviewToList: "+" elementId "+elementId+ " nrows "+data.rows.length);
+	
+	let useInsert=false;
+	if (!("unique" in setup)) useInsert=true;
+	if (data.rows.length==0) useInsert=true;
+	let entry=new Object();
+	
+	if (!useInsert){
+		entry=data.rows[0];
+ 	}
+	entry.crfRef=getCRFref();
+	
+	if ("keyValue" in setup) entry.queryName=setup.keyValue;
+	
+	let fields=data.metaData.fields;
+	for (f in fields){
+
+		let field=fields[f];
+		if (debug) print(config,"saveReview field: "+field.name);
+		if (field.hidden) continue;
+		
+		let vName=fields[f].name;
+
+		if (vName=="crfRef") continue;
+		if (vName=="queryName") continue;
+		
+		let eId=setup.getInputId(vName);
+		
+		let el=config.document.getElementById(eId);
+				
+		if (!el) {
+			if (debug) print(config,"saveReview element: "+eId+" not found");
+			continue;
+		}
+		if (debug) print(config,"saveReview element: "+eId);
+		
+		let vType=fields[f].type;
+
+		if ("lookup" in fields[f]){
+			if (el.nodeName==="SELECT"){
+				entry[vName]=el.options[el.selectedIndex].value;
+			}
+			if (el.nodeName==="TD"){
+				entry[vName]=el.innerHTML;	
+			}
+
+			print(config,"Setting lookup to "+entry[vName]);
+			continue;
+		}
+		if (vType=="date"){
+			var date=el.valueAsDate;
+			if (date==="null") continue;
+			date.setUTCHours(12);
+			entry[vName]=date.toString();
+			print(config,"Setting date to "+entry[vName]);
+		}	
+		if (vType=="string"){
+			entry[vName]=el.value;
+		}	
+		if (vType=="float"){
+			entry[vName]=el.value;
+		}	
+
+
+	}
+	
+	let qconfig=new Object();
+	qconfig.rows=[entry];
+	qconfig.schemaName=data.schemaName;
+	qconfig.queryName=data.queryName;
+
+	//only update comments
+
+	qconfig.success=function(data){updateLastSavedFlag(config,data,setup,elementId)};
+	if (!useInsert){
+		LABKEY.Query.updateRows(qconfig);
+	}
+	else{
+		LABKEY.Query.insertRows(qconfig);
+	}
+}
+
+function updateLastSavedFlag(config,data,setup,elementId){
+	let debug=true;
+	if (debug) print(config,"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(config,setup.divReviewListId,"reviewComments",setup.filters,true);
+	}	
+}
+
+function onSubmit(config){
+	let debug=true;
+	hideErr(config);
+	clearErr(config);
+	printErr(config,"onSubmit");
+	checkForm(config);
+	let cb=new Object();
+	cb.success=finalValidation;
+	cb.failure=function(config){printErr("waitForCheckForm failed")};
+	waitForCheckForm(config,cb);
+}
+
+function finalValidation(config){
+	let debug=true;
+	if (debug) print(config,"validate");
+	
+	let completed=true;
+	for (f in config.fields){
+		let field=config.fields[f];
+		if (field.status!="DONE") {
+			printErr(config,"Missing entry for "+field.title);
+			completed=false;
+		}
+	}
+	if (debug) print(config,"valid: "+completed);
+
+	if (completed){
+		finalRedirect(config);
+	}
+	else{
+		updateSubmitStatus(config,"Form invalid");
+	}
+}
+
+function finalRedirect(config){
+	printErr(config,"Form valid");
+	let c1=new Object();
+	c1.schemaName='lists';
+	c1.queryName='crfEntry';
+	c1.filterArray=[LABKEY.Filter.create('crfRef',getCRFref(config))];
+	c1.success=function(data){setSubmitStatus(config,data)};
+	LABKEY.Query.selectRows(c1);
+}
+
+function setSubmitStatus(config,data){
+	let entry=data.rows[0];
+	entry.formStatus=2;//Submitted
+	let c1=new Object();
+	c1.schemaName=data.schemaName;
+	c1.queryName=data.queryName;
+	c1.rows=[entry];
+	c1.success=function(data){updateSubmitStatus(config,"Form submitted")};
+	LABKEY.Query.updateRows(c1);
+}
+
+function updateSubmitStatus(config,msg){
+	let el=document.getElementById(config.submitReportId);
+	el.innerHTML=msg;
+}
+
+function hideErr(config){
+	let el=config.document.getElementById("errorDiv");
+	el.style.display="none";
+}
+
+function clearErr(config){
+	let el=config.document.getElementById("errorTxt");
+	el.value="";
+}
+
+function showErr(config){
+	let el=config.document.getElementById("errorDiv");
+	el.style.display="block";
+}
+
+
+function printErr(config,msg){
+	showErr(config);
+	el=config.document.getElementById("errorTxt");
+	el.style.color="red";
+	el.value+="\n"+msg;
+}
+
+function checkForm(config){
+	let debug=false;
+	let crfRef=getCRFref(config)
+	
+	
+	config.status="UNKNOWN";
+	for (f in config.fields){
+		let field=config.fields[f];
+		field.status="UNKNOWN";
+
+		if (debug) 
+			print(config,"Setting status for "+f+" to "+ field.status);
+
+		let selectRows=new Object();
+		selectRows.schemaName="lists";
+		selectRows.queryName=f;
+		selectRows.filterArray=[LABKEY.Filter.create('crfRef',crfRef)];
+		selectRows.success=function(data){checkData(data,config)};
+		selectRows.failure=function(errorObj){print(config,"checkData failed.")};
+		LABKEY.Query.selectRows(selectRows);
+	}
+}
+
+function waitForCheckForm(config,cb){
+	let debug=true;
+	if (!("i" in config)) config.i=0;
+	if (debug) print(config,"["+config.i+"] checkForm status "+config.status);
+	if (config.i>100) {
+		if (debug) print(config,"executing failure");	
+		cb.failure(config);
+		return;
+	}
+	if (config.status=="DONE") {
+		if (debug) print(config,"executing success");	
+		cb.success(config);
+		if (debug) print(config,"success executed");	
+		return;
+	}
+	config.i+=1;
+	setTimeout(function(){waitForCheckForm(config,cb);},1000);
+}
+
+function checkData(data,config){
+	let debug=false;
+	if (debug) print(config,"checkData ");
+	let field=config.fields[data.queryName];
+	field.status="NONE";
+	if (debug) print(config,"Setting status for "+data.queryName+" to "+field.status);
+	if (data.rows.length>0)
+		field.status="DONE";
+	
+	if (debug)
+		print(config,"checkData set status for "+data.queryName+" to "+field.status);
+	
+	for (f in config.fields){
+		let subField=config.fields[f];
+		if (debug) 
+			print(config,"checkData status["+f+"]: "+subField.status);	
+		if (subField.status=="UNKNOWN") {
+			if (debug) print(config,"\t Status for "+f+" not set ["+ subField.status+"]");
+			return;
+		}
+		
+	}
+	config.status="DONE";
+}
+

+ 0 - 0
web/tecant/generateTable.js → web/crf/generateTable.js


+ 0 - 0
web/tecant/test.js → web/crf/test.js