Преглед изворни кода

Removing cross-branch copy of crfVisit

Andrej Studen пре 2 година
родитељ
комит
14954472b8
1 измењених фајлова са 0 додато и 3230 уклоњено
  1. 0 3230
      web/crfTecant/crfVisit.js

+ 0 - 3230
web/crfTecant/crfVisit.js

@@ -1,3230 +0,0 @@
-var crfVisit={};
-
-crfVisit.config=new Object();
-
-crfVisit.setDebug=
-function(debug=null){
-   if (debug){
-      this.print=function(msg){debug.this.print(msg);};
-      this.clear=function(){debug.clear();}
-      return;
-   }
-   //provide default functions if not debug object is available
-   this.print=function(msg){console.log(msg);}
-   this.clear=function(){;}
-}
-
-crfVisit.setDebug();
-
-//harmonize signature
-//(schema,query,row,action=cvDoNothing,container=null
-
-crfVisit.insertRows=
-function(schema,query,rows,action=null,container=null,failure=null){
-   this.modifyRows('insert',schema,query,rows,action,container);
-}
-
-crfVisit.deleteRows=
-function(schema,query,rows,action=null,container=null,failure=null){
-   this.modifyRows('delete',schema,query,rows,action,container);
-}
-
-crfVisit.modifyRows=
-function(mode,schema,query,rows,action=null,container=null,failure=null){
-	//insert rows to container/schema/query and return with action
-	let fName="[cvModifyRows/"+mode+"]";
-	this.print(fName+' '+schema+'/'+query);
-	let qconfig=new Object();
-	qconfig.schemaName=schema;
-	qconfig.queryName=query;
-   if (container) qconfig.containerPath=container;
-   if (!rows) {
-      this.print(fName+' rows '+rows);
-      return;
-   }
-	qconfig.rows=rows;
-   qconfig.success=function(data){;};
-	if (action) qconfig.success=action;
-   if (mode=='insert') LABKEY.Query.insertRows(qconfig);
-   if (mode=='update') LABKEY.Query.updateRows(qconfig);
-   if (mode=='delete') LABKEY.Query.deleteRows(qconfig);
-	this.print(fName+" done");
-}
-
-crfVisit.selectRows=
-function(schema,query,filters=[],action=null, container=null, failure=null, columns=null){
-	let fName="[cvSelectRows]";
-	this.print(fName+' '+schema+' '+query+' '+container);
-	let qconfig=new Object();
-	qconfig.schemaName=schema;
-	qconfig.queryName=query;
-   if (container) qconfig.containerPath=container;
-   qconfig.filterArray=filters;
-   qconfig.success=function(data){;};
-	if (action) qconfig.success=action;
-   if (failure) qconfig.failure=failure;
-   if (columns) qconfig.columns=columns;
-	LABKEY.Query.selectRows(qconfig);
-	this.print(fName+" done");
-
-}
-
-crfVisit.createCrfStatus=
-function(crfEntry){
-   let crfStatus=new Object();
-   crfStatus.entryId=crfEntry.entryId;
-   crfStatus.submissionDate=new Date();
-   crfStatus.FormStatus=crfEntry.FormStatus;
-   crfStatus.User=crfEntry.UserId;
-   crfStatus.Form=crfEntry.Form;
-   return crfStatus;
-}
-
-crfVisit.init=
-function(cb=null){
-   let that=this;
-   let action=function(){that.scriptsLoaded(cb);};
-   LABKEY.Utils.requiresScript(["crfTecant/runQuery.js","crfTecant/crfReviewSection.js","crfTecant/participantIdManager.js","crfTecant/variableList.js","crfTecant/webdav.js","crfTecant/crfPrint.js"],action);
-}
-
-crfVisit.scriptsLoaded=
-function(cb=null){
-   participantIdManager.set(this);
-   webdav.set(this);
-   crfReviewSection.set(this);
-   crfPrint.set(this);
-   if (cb) cb();
-}
-
-
-crfVisit.getElement=
-function(id){
-   return this.config.document.getElementById(id);
-}
-
-crfVisit.setContainer=
-function(label,container){
-   let config=this.config;
-	if (!(config.formConfig.hasOwnProperty('container'))){
-		config.formConfig.container=new Array();
-	}
-	config.formConfig.container[label]=container;
-}
-
-crfVisit.getContainer=
-function(label){
-	return this.config.formConfig.container[label];
-}
-
-
-crfVisit.getCRFrefFirst=
-function(){
-	//crfRef is part of html call and gets stored in the page
-	return this.getElement(this.config.crfRefId).innerHTML;
-}
-
-crfVisit.getCRFref=
-function (){
-	//'crfRefId'
-	return this.config.formConfig.crfEntry['entryId'];
-}
-
-crfVisit.getCRFrefData=
-function(){
-	let parentCrf=this.config.formConfig.crfEntry['parentCrf'];
-	if (parentCrf!=undefined) return parentCrf;
-	return this.getCRFref();
-}
-
-crfVisit.onFailure=
-function(errorInfo, options, responseObj){
-	
-	if (errorInfo && errorInfo.exception)
-		alert("Failure: " + errorInfo.exception);
-	else
-		alert("Failure: " + responseObj.statusText);
-}
-
-crfVisit.doNothing=
-function (){
-	this.print('doNothing called');
-}
-
-crfVisit.getSnapshotObject=
-function(){
-   if (!("dataQueriesSnapshot" in this.config.formConfig))
-      this.config.formConfig.dataQueriesSnapshot=new Object();
-   return this.config.formConfig.dataQueriesSnapshot;
-}
-
-crfVisit.getQuerySnapshot=
-function(queryName){
-   //check whether queryName is in snapshotObject?
-   return this.getSnapshotObject()[queryName];
-}
-
-crfVisit.getLayoutObject=
-function(){
-   if (!("dataQueriesLayout" in this.config.formConfig))
-      this.config.formConfig.dataQueriesLayout=new Object();
-   return this.config.formConfig.dataQueriesLayout;
-}
-
-crfVisit.getQueryLayout=
-function(queryName){
-   //check whether queryName is in snapshotObject?
-   return this.getLayoutObject()[queryName];
-}
-
-crfVisit.getLookupObject=
-function(){
-   if (!("lookup" in this.config.formConfig))
-      this.config.formConfig.lookup=new Object();
-   return this.config.formConfig.lookup;
-}
-
-crfVisit.getLookup=
-function(queryName){
-   let x=this.getLookupObject();
-   if (queryName in x) return x[queryName];
-   return null;
-}
-
-crfVisit.getQueryList=
-function(){
-   if (!("queryList" in this.config.formConfig))
-      this.config.formConfig.queryList=new Object();
-   return this.config.formConfig.queryList;
-}
-
-crfVisit.getIdManager=
-function(){
-   if (!("idManager" in this.config.formConfig))
-      this.config.formConfig.idManager=participantIdManager.getObject();
-   return this.config.formConfig.idManager;
-}
-
-crfVisit.getAdditionalData=
-function(formSetupEntry){
-   //return information on additional data associated with the form
-   //additionalData is a sub-list with multiple entries per patient/visit
-   
-   let config=this.config;
-   //argument is the row of the formSetup setup list
-	let queryName=config.formConfig.queryMap[formSetupEntry['queryName']];
-	let fName='[getAdditionalData/'+queryName+']';
-	this.print(fName);
-
-   //additionalData holds a reference to all queries already parsed
-   //this helps in reducing number of calls to the database (I assume)
-	if (queryName in config.formConfig.additionalData){
-		this.print(fName+': Returning preset value');
-		return config.formConfig.additionalData[queryName];
-	}
-
-   //first time we see this query, so we have to do the setup
-	this.print(fName+': generating');
-	config.formConfig.additionalData[queryName]=new Object();
-	
-   //takes address, so further changes will be to the newly created object
-   //in fact, ad is just a short alias of the long variable name on the right
-	let ad=config.formConfig.additionalData[queryName];
-
-   //no additional data
-	if (formSetupEntry["showFlag"]==="NONE") {
-		this.print(fName+": empty");
-		return ad;
-	}
-
-   //use showFlag to setup report section of the CRF list
-	if (formSetupEntry["showFlag"]==="REVIEW") {
-		//abuse additionalData to signal different segment
-		this.print(fName+": generateReport");
-		ad.isReview=true;
-		return ad;
-	}
-
-   //setup the additionalData memory object
-	this.print(fName+': setting values');
-	ad.showFlag=formSetupEntry["showFlag"];
-	ad.showFlagValue=formSetupEntry["showFlagValue"];
-	ad.queryName=formSetupEntry["showQuery"];
-
-   //for data queries, limit to present CRF only
-	ad.filters=new Object();
-	ad.filters['crfRef']=this.getCRFref();
-
-   //compose a long debug message
-	let msg=fName+": flag "+ad.showFlag;
-	msg+=" value "+ad.showFlagValue;
-	msg+=" query "+ad.queryName;
-	this.print(msg);
-
-	return ad;	
-}
-
-crfVisit.selectFormSetupRows=
-function(formId){
-	let formSetupRows=new Array();
-   let config=this.config;
-	let allRows=config.formConfig.formSetup.rows;
-	for (let i=0;i<allRows.length;i++){
-		let formEntry=allRows[i];
-		if (formEntry.formName==formId)
-			formSetupRows.push(formEntry);
-	}
-	return formSetupRows;
-}
-
-crfVisit.findTitle=
-function(queryName){
-//find by name from formDatasets 
-//and set associated title as title
-   let config=this.config;
-	let rows=config.formConfig.formDatasets.rows;
-	for (let i=0;i<rows.length;i++){
-		let entry=rows[i];
-		if (entry['queryName']!=queryName) continue;
-		return entry['title'];
-	}
-	return "NONE";
-}
-
-
-crfVisit.makeSetup=
-function(listName){
-	//generate setup object whcih should contain fields:
-	//readonlyFlag - whether the dataset is writeable
-	//filters - selection fields that allow creation of LABKEY.Filter.create()
-	//getInputId - formating of unique ids for html elements
-   let fName='[Setup]';
-	this.print(fName+' '+listName);
-
-	let setup=new Object();
-	setup.queryName=listName;
-	setup.readonlyFlag=function(vName){return false};
-	setup.filters=new Object();
-	setup.filters['crfRef']=this.getCRFref();
-	setup.getInputId=function(vName){return listName+"_"+vName;}
-	setup.isReview=false;
-   return setup;
-	
-}
-
-crfVisit.getFullAccessSetup=
-function(listName){
-	//addApply - whether a submit/Save button is generated
-	let setup=this.makeSetup(listName);
-	setup.addApply="Save";
-	return setup;
-
-}
-
-crfVisit.getReadonlySetup=
-function(listName){
-   let setup=this.makeSetup(listName);
-	//see definition of setup object above, change readonly flag
-	setup.readonlyFlag=function(vName){return true};
-	return setup;
-}
-
-crfVisit.getSetup=
-function(listName,writeAccess=true){
-	//change to section granulated permission of type EDIT, COMMENT, READ
-	//let formStatus=config.formConfig.formStatus;
-	//equivalent to READ
-
-	if (!writeAccess)
-	//if (formStatus=="Submitted")
-		return this.getReadonlySetup(listName);
-	//if (formStatus=="Approved")
-	//	return readonlySetup(listName);
-	return this.getFullAccessSetup(listName);
-}
-
-crfVisit.generateSection=
-function(formSetupEntry){
-   let config=this.config;
-   let that=this;
-	let listName=config.formConfig.queryMap[formSetupEntry['queryName']];
-   //if (!listName) is for debugSection
-   if (!listName){
-      listName="debugSection";
-   }
-	let fName='[generateSection/'+listName+']';
-	let sectionTitle=formSetupEntry['title'];	
-	let accessModeColumn=config.formConfig.operator+'Mode';
-	let accessMode=formSetupEntry[accessModeColumn];
-	//this will fix it for later use as well
-	let additionalData=this.getAdditionalData(formSetupEntry);
-	this.print(fName);
-
-	let formName=config.masterForm;//this is HTML designator of area on page
-	let debug=true;
-	let tb=config.document.createElement('table');
-	tb.className='t2';
-	let row=tb.insertRow();
-	let cell=config.document.createElement('th');
-	row.appendChild(cell);	
-	cell.setAttribute("colspan","4");
-	cell.style.fontSize="20px";
-	cell.style.textAlign="center";
-	let cellData=config.document.createTextNode(sectionTitle);
-	cell.appendChild(cellData);
-	cell=row.insertCell();
-	let input=config.document.createElement("input");	
-	input.type="button";
-	input.value="Show";
-	input.id="toggle"+listName+"VisbilityButton";
-	input.onclick=function(){that.toggleVisibility(listName,input.id)};
-	cell.appendChild(input);
-	this.getElement(formName).appendChild(tb);
-
-	let div=config.document.createElement('div');
-	div.id=listName;
-	div.style.display="none";
-	this.getElement(formName).appendChild(div);
-
-   //here divert for debugArea
-   if (listName=="debugSection"){
-      let debugArea=config.document.createElement('textarea');
-      debugArea.rows=10;
-      debugArea.cols=95;
-      debugArea.id=config.debugId;
-      div.appendChild(debugArea);
-      return;
-   }
-
-
-
-	let divTable=config.document.createElement('div');
-	divTable.id=listName+"Table";
-	div.appendChild(divTable);
-	
-	if ("showFlag" in additionalData) {
-		additionalData.divName=listName+"SubDiv";
-		additionalData.divQueryName=listName+"SubDivList";
-
-		let div1=config.document.createElement('div');
-		div1.id=additionalData.divName;
-		div1.style.display="none";
-		div.appendChild(div1);
-	
-		let div2=config.document.createElement('div');
-		div2.id=additionalData.divQueryName;
-		div1.appendChild(div2);
-
-	}
-	this.print(fName+" generate master table");
-
-	let writeMode=accessMode=="EDIT";	
-	let setup=this.getSetup(listName,writeMode);
-	
-
-   if	("isReview" in additionalData){
-      crfReviewSection.set(this);
-      let action=function(){crfReviewSection.CB();};
-		crfReviewSection.generateSection(listName,div.id,action);
-		return;	
-	}
-	//master table is unique per visit
-
-	
-	setup.unique=true;
-	this.generateTable(listName,divTable.id,additionalData,setup);
-	
-	if (debug) this.print("generate master table: done");
-
-	let generateSubTable=true;
-	//generateSubTable equivalent to read/write access to section
-	if (accessMode != "EDIT")
-		generateSubTable=false;
-	
-	if (! ("showFlag" in additionalData) ) generateSubTable=false;
-	
-	if (generateSubTable){
-		let qName=additionalData.queryName;
-		let dName=additionalData.divName;
-		
-
-		let xsetup=this.getFullAccessSetup(qName);
-		//only set master query for additionalData
-		xsetup.masterQuery=listName;
-		//if (readonly) setup=readonlySetup(config);
-      xsetup.subTable=true;
-		this.generateTable(qName,dName,additionalData,xsetup);
-		//generateTable(formSetupEntry,qName,dName,additionalData,setup);
-	}
-
-	this.print("generate review");
-
-	let divReviewList=config.document.createElement('div');
-	divReviewList.id=listName+"ReviewList";
-	div.appendChild(divReviewList);
-	
-	let divReview=config.document.createElement('div');
-	divReview.id=listName+"Review";
-	div.appendChild(divReview);
-
-
-	//assume we already have listId (content of config.setupQueryName is listId)
-	//we need listName also
-	//qconfig.queryName=config.setupQueryName;
-	this.generateReview(divReview.id,divReviewList.id,listName,accessMode);
-
-	if (accessMode!='GENERATE') return;
-	this.print('Adding generate button');	
-	//add generateButton
-	let divGenerateButton=config.document.createElement('div');
-	divGenerateButton.id=listName+'GenerateButton';
-	div.appendChild(divGenerateButton);
-	this.print('Adding generate button completed to here');	
-   let cb=function(){that.onGenerateQuery(listName);};
-	this.generateButton(divGenerateButton.id,'Generate','Generate '+listName,'onGenerateQuery',cb);
-	this.print('Adding generate button completed');	
-}
-
-crfVisit.generateReview=
-function(divReviewId,divReviewListId, listName, accessMode){
-   let config=this.config;
-	let listId=config.formConfig.fields[listName].queryId;
-
-	//listId is a number->should it be queryName?
-	
-   let fName='[generateReview]';
-   this.print(fName+" list "+listId+'/'+listName);
-	
-	let reviewSetup=new Object();
-	reviewSetup.readonlyFlag=function(vName){
-		if (vName=="queryName") return true; 
-		if (vName=="queryname") return true; 
-		if (vName=="ModifiedBy") return true;
-		return false;};
-	reviewSetup.addApply="Add Review";
-   reviewSetup.reviewTable=true;
-
-	let generateTableFlag=true;
-	let formStatus=config.formConfig.formStatus;
-	//COMMENTS allowed or not
-	//three levels of access: EDIT, COMMENT, READ
-	if (accessMode == "READ"){
-	//if (formStatus == "Approved" ){
-		delete reviewSetup.addApply;
-		reviewSetup.readonlyFlag=function(vName){return false;}
-		generateTableFlag=false;
-	}
-	
-	reviewSetup.filters=new Object();
-	reviewSetup.filters["crfRef"]=this.getCRFref();
-   if (config.formConfig.crfEntry.parentCrf){
-      reviewSetup.filters["crfRef"]=this.getCRFref()+";"+config.formConfig.crfEntry.parentCrf;
-   }
- 	reviewSetup.filters["queryName"]=listId;//entry in reviewComments list is queryname, all in small caps
-	//needs listName, in argument
-	
-	reviewSetup.getInputId=function(vName){return listName+"_add"+vName};
-	reviewSetup.divReviewListId=divReviewListId;
-	reviewSetup.isReview=true;	
-
-   let msg="Review: divId: "+divReviewId;
-   msg+=" inputId: "+reviewSetup.getInputId;
-   this.print(msg);
-	
-	this.updateListDisplay(divReviewListId,"reviewComments",reviewSetup.filters,true);
-
-	if (! generateTableFlag) return;
-
-	
-   this.generateTable("reviewComments",divReviewId,new Object(),reviewSetup);
-}	
-
-//>>>>>>>>>>trigger visibility of additional lists
-
-crfVisit.setListVisibility=
-function(input,setup,readonlyFlag){
-   let config=this.config;
-	let fName="[setListVisibility/"+setup.queryName+"]";
-	this.print(fName);
-	let additionalData=config.formConfig.additionalData[setup.queryName];
-	
-	let x = this.getElement(additionalData.divName);
-	this.print(fName+": Div: "+x);
-	x.style.display="none";
-
-	let sText;
-	if (readonlyFlag) sText=input.innerText;
-	else sText=input.options[input.selectedIndex].text;
-			
-	this.print(fName+": Selected option text: "+sText);
-
-	if (sText == additionalData.showFlagValue){
-		let filters=new Object();
-		if ("filters" in additionalData) filters=additionalData.filters;
-		x.style.display = "block";
-		this.updateListDisplay(additionalData.divQueryName,
-			additionalData.queryName,filters,readonlyFlag);
-	}
-}
-
-//>>have list refresh when data is added (not optimal yet)
-//
-
-crfVisit.updateListDisplay=
-function(divName,queryName,filters,readonlyFlag){
-	//use Labkey.QueryWebPart to show list
-
-	let fName="[updateListDisplay]";
-
-   this.print(fName+": UpdateListDisplay: Query - "+queryName
-      +" div - "+divName);
-
-	if (divName=="NONE") return;
-
-	let crfRef=this.getCRFref();
-	let div=this.getElement(divName);
-
-   this.print(fName+": generating WebPart: "+queryName);
-	
-	var qconfig=new Object();
-	qconfig.renderTo=divName;
-	//point to data container
-	qconfig.containerPath=this.getContainer('data');
-	qconfig.schemaName='lists'; 
-	qconfig.queryName=queryName;
-	qconfig.buttonBarPosition='top';
-	qconfig.filters=[];
-	for (f in filters){
-      let fType=LABKEY.Filter.Types.EQUAL;
-      this.print(fName+' filter ['+f+'] '+filters[f]+'/'+typeof(filters[f])+' ['+fType+']');
-     
-      if (variableList.isFilterList(filters[f])){
-         fType=LABKEY.Filter.Types.IN;
-      }
-		qconfig.filters.push(LABKEY.Filter.create(f, filters[f],fType));
-	}
-   let that=this;
-	qconfig.success=function(data){that.updateSuccess(data);};
-	qconfig.failure=function(errorInfo,options,responseObj){that.onFailure(errorInfo,options,responseObj);};
-	//show only print button
-	if (readonlyFlag){
-		qconfig.buttonBar=new Object();
-		qconfig.buttonBar.items=["print"];
-	}
-
-	LABKEY.QueryWebPart(qconfig);
-	
-}
-
-crfVisit.updateSuccess=
-function(data){
-	this.print("Update success");
-}
-
-//TODO: this should trigger a data refresh on section, ie populateData(field)
-crfVisit.toggleVisibility=
-function(divName,buttonName){
-	let fName='[toggleVisibility/'+divName+']';
-	this.print(fName);
-   let config=this.config;
-	let x = this.getElement(divName);
-	if (x.style.display === "none") {
-		//exclude non data sections (like debug)...
-		this.print(fName+': issuing setData(populateSection)');
-    		x.style.display = "block";
-		this.getElement(buttonName).value="Hide";
-      let that=this;
-		let cb=function(){that.populateSection(divName);};
-		this.setData(cb);
-
-  	} else {
-    		x.style.display = "none";
-		this.getElement(buttonName).value="Show";
-
-  	}
-}
-
-crfVisit.generateButton=
-function(divName,caption,label,callbackLabel,callback=null){
-	this.print("generateButtonX");
-   let config=this.config;
-	
-	let tb=config.document.createElement('table');
-	tb.className="t2";
-	
-	let r1=tb.insertRow();
-	th=config.document.createElement('th');
-	r1.appendChild(th);
-	th.innerHTML=caption;
-	//*!*
-	let c2=r1.insertCell();
-	let i1=config.document.createElement("input");	
-	i1.type="button";
-	i1.value=label;
-	i1.style.fontSize="20px";
-   let that=this;
-   if (callback)
-      i1.onclick=callback;
-   else
-	   i1.onclick=function(){that[callbackLabel]();};
-	i1.id='button_'+callbackLabel;
-	c2.appendChild(i1);	
-
-	let c1=r1.insertCell();
-	c1.setAttribute("colspan","1");
-	//this is only for saveReview?
-	c1.id=divName+'_reportField';
-	//c1.id=config.submitReportId;
-
-	let el=this.getElement(divName);
-	this.print("generateButton: element["+divName+"]: "+el);
-	
-	
-	el.appendChild(tb);
-	
-	
-}
-crfVisit.generateSubQuery=
-function(input, setup, readonlyFlag){
-	let fName="[generateSubQuery]";
-   let config=this.config;
-	if (setup.isReview) return;
-
-	if (!(setup.queryName in config.formConfig.additionalData)){
-		this.print(fName+': no additionalData entry (probably a subquery)');
-		return;
-	}
-
-	let additionalData=config.formConfig.additionalData[setup.queryName];
-	if (!("showFlag" in additionalData))
-		return;
-
-	this.print(fName);
-		
-	let expId=setup.getInputId(additionalData.showFlag);
-	if (expId!=input.id) {
-		this.print(fName+": ignoring field "+input.id+"/"+expId);
-		return;
-	}
-
-	this.print(fName+": Setting onChange to "+input.id);
-	if (readonlyFlag)
-      return;
-
-   let that=this;
-	input.onchange=function(){that.setListVisibility(input,setup,readonlyFlag)};
-}
-
-
-//>>populate fields
-//
-//
-//split to field generation and field population
-//
-crfVisit.addFieldRow=
-function(tb,field,setup,additionalData){
-
-	let fName="[addFieldRow/"+setup.queryName+':'+field.name+']';
-   let config=this.config;
-
-	let vName=field.name;
-	let vType=field.type;
-	let isLookup=("lookup" in field);
-	this.print(fName+": ["+vName+"/"+vType+'/'+isLookup+"]");
-
-	let row=tb.insertRow();
-	let cell=config.document.createElement('th');
-   cell.style.width='300px';
-	row.appendChild(cell);
-	
-	let text = config.document.createTextNode(field.shortCaption);
-	cell.appendChild(text);
-		
-	
-	let input=null;
-   let colSpan="3";
-	let cell1=row.insertCell();
-	cell1.colSpan=colSpan;
-	let readonlyFlag=setup.readonlyFlag(vName);
-
-
-	//set the html input object
-	while (1){
-
-		if (readonlyFlag){
-			input=config.document.createElement('label');
-			input.innerText='Loading';
-			break;
-		}
-	
-
-		//lookup
-		if (isLookup){
-			input = config.document.createElement("select");
-			break;
-		}
-
-		//date
-		if (vType=="date"){ 
-			input = config.document.createElement("input");
-			input.type="date";
-			break;
-		}
-
-		//string
-		if (vType=="string"){
-			//we have to make sure UNDEF is carried to below
-			//since we are adapting file to either show
-			//current file or allow user to select a file
-			//
-			//TODO change this so one can always select file
-			//but also show the selected file
-
-			if(vName.search("reviewComment")>-1){
-				input = config.document.createElement("textarea");
-				input.cols="65";
-				input.rows="5";
-				break;
-			}
-
-			input=config.document.createElement('input');
-			input.type="text";
-			
-			if (vName.search('_file_')<0) break;
-			cell1.setAttribute('colspan',"1");
-			let cell2=row.insertCell();
-			cell2.setAttribute('colspan',"2");
-			let input1=config.document.createElement('input');
-			input1.type="file";
-			input1.id=setup.getInputId(vName)+'_file_';
-			cell2.appendChild(input1);
-			break;
-				
-		}
-
-
-		if (vType=="float"){
-			input = config.document.createElement("input");
-			input.type="text";
-			break;
-		}	
-		
-		
-		if (vType=="boolean"){
-			input = config.document.createElement("input");
-			input.type="checkbox";
-			this.print("Creating checkbox");
-			break;
-		}
-		break;
-	}
-	
-	input.id=setup.getInputId(vName);
-	cell1.appendChild(input);
-	this.print(fName+': adding element '+input.id);
-	this.print(fName+': listing element '+this.getElement(input.id));
-	
-
-	//connect associated list
-	this.generateSubQuery(input,setup,readonlyFlag);	
-
-	if (readonlyFlag) {
-		this.print(fName+': exiting(readonlyFlag)');
-		return;
-	}
-	
-	if (!isLookup) 	{
-		this.print(fName+': exiting (not lookup)');
-		return;
-	}
-
-	let lookup=field["lookup"];
-
-	//get all values from config.formConfig.lookup[X]
-	let lObject=config.formConfig.lookup[lookup.queryName];
-	
-	//debug
-	this.print(fName+": query: "+lookup.queryName);
-	this.print(fName+": ElementId: "+input.id);
-	this.print(fName+": No of options: " +lObject.LUT.length);
-	this.print(fName+": Element: "+input);
-
-	//set the lut value (input is text label) for readonly
-
-   	//clear existing fields from input	
-	for(let i = input.options.length; i >= 0; i--) {
-		input.remove(i);
-   	}
-	
-	//create option -1
-	let opt = config.document.createElement("option");
-	opt.text = "<Select>";
-	opt.value = -1;
-	input.options[0] = opt;
-	this.print(fName+": Adding <Select>");
-	
-
-	//add other, label them with LUT
-	for (let v in lObject.LUT) {
-		this.print(fName+': populating '+v+': '+lObject.LUT[v]);
-
-		let opt = config.document.createElement("option");
-		opt.text = lObject.LUT[v];
-		opt.value = v;
-		input.options[input.options.length] = opt;
-		
-	}
-	input.selectedIndex=0;	
-
-}
-
-crfVisit.addSpecialFieldRows=
-function(tb,specFieldSetup,setup){
-   //tb is the table, specFieldSetup is a row from the table where special fields are being setup
-   //the first column is fieldUID, which is a colon joined amalgation of queryName:fieldName
-   let fieldUID=specFieldSetup["fieldUID"];
-   let x=fieldUID.split(':');
-   let fieldName=x[1];
-   let fName="[addSpecialFieldRow/"+fieldUID+"]";
-   let q=variableList.parseVariables(specFieldSetup['actionParameters']);
-   let config=this.config;//for add data
-   this.print(fName);
-   if (specFieldSetup['actionType']=='textArea'){
-      let row=tb.insertRow();
-      let cell1=row.insertCell();
-      cell1.colSpan="4";
-      cell1.style.textAlign="justify";
-      cell1.style.padding="10px";
-      cell1.style.backgroundColor="#e0e0e0";
-      cell1.innerText=q['description'];
-      return;
-   }
-   if (specFieldSetup['actionType']=='generationObject'){
-      //only in EDIT mode!!
-      let ro=setup.readonlyFlag(fieldName);
-      if (ro) return;
-      generateRegistration.set(this);
-      let gc=generateRegistration.getObject(q,setup.getInputId(fieldName));
-      let that=this;
-      let action=function(){that.doNothing();};
-      if ('mailRecipient' in q){
-         gc.callback=function(data){that.sendEmail(data,q['mailRecipient'],action,q['subject']);};
-      }
-      else 
-         gc.callback=function(data){that.doNothing();};
-      if ("addData" in q){
-         vars=q["addData"].split(',');
-         gc.addData=new Array();
-         for (let v in vars){
-            let s=vars[v]
-            //variable name can be written as A/B where A is the name in addData and B is the variable name in crfEntry
-            //useful for mocking up crfId from daughter crf-s such as registration
-            let sArray=s.split('/');
-            let sTarget=sArray[0];
-            let sSource=sArray[sArray.length-1];
-            gc.addData[sTarget]=config.formConfig.crfEntry[sSource];
-            this.print(fName+" addData ["+sTarget+"]: "+gc.addData[sTarget]);
-         }
-      }
-      let row=tb.insertRow();
-      let cell=config.document.createElement('th');
-      row.appendChild(cell);
-      let text = config.document.createTextNode("Automatic ID generator");
-      cell.appendChild(text);
-      let cell1=row.insertCell();
-      cell1.colSpan="3";
-      let b=config.document.createElement("input");
-      b.type="button";
-      b.id="generateIdButton";
-      b.onclick=function(){generateRegistration.execute(gc);};
-      b.value="Generate ID";
-      cell1.appendChild(b);
-
-   }
-}
-
-crfVisit.populateFieldRow=		
-function(entry,field,setup){
-	this.populateField(entry,field,setup);
-	this.populateSubQuery(entry,field,setup);
-}
-
-crfVisit.populateSubQuery=
-function(entry,field,setup){
-	let fName='[populateSubQuery/'+setup.queryName+':'+field.name+']';
-   let config=this.config;
-	if (setup.isReview) return;
-	
-	if (!(setup.queryName in config.formConfig.additionalData)){
-		let msg=fName+': no additionalData entry for '+setup.queryName;
-		msg+=' (probably a subquery)';
-		this.print(msg);
-		return;
-	}
-	//find if field is connected to a sub array
-	//find queryName
-	//
-	let additionalData=config.formConfig.additionalData[setup.queryName];	
-	this.print(fName);
-	//let flag=additionalData.showFlag;
-	
-	if (!("showFlag" in additionalData)) return;
-	let eId=setup.getInputId(additionalData.showFlag);
-	let id=setup.getInputId(field.name);
-	
-	if (eId!=id) {
-		this.print(fName+": ignoring field "+id+"/"+eId);
-		return;
-	}
-	
-	this.print(fName+': id '+id);
-	//hard to estimate readonlyFlag
-	//
-	let input=this.getElement(id);
-	let eType=input.nodeName.toLowerCase();
-	let readonlyFlag=eType!="select";
-	this.setListVisibility(input,setup,readonlyFlag);
-
-}
-
-crfVisit.clearField=
-function(field,setup){
-   let foo=new Object();
-   this.populateField(foo,field,setup);
-}
-
-crfVisit.populateField=
-function(entry,field,setup){
-
-	let vName=field.name;
-	let fName='[populateFieldName/'+vName+']';
-   let config=this.config;
-
-	let varValue="UNDEF";
-
-	//if (vName in setup.filters) varValue=setup.filters[vName];
-	if (vName in entry) varValue=entry[vName];
-	//if part of the filter, set it to value
-	if (vName in setup.filters) varValue=setup.filters[vName];
-	
-	let isLookup=("lookup" in field);
-	
-	this.print(fName+' v='+varValue+'/'+isLookup+' ['+
-		setup.getInputId(field.name)+']');
-	
-	let vType=field.type;
-	let id=setup.getInputId(vName);
-	let input=this.getElement(id);
-
-		
-	//date
-	if (vType=="date"){
-		if (varValue=="UNDEF") varValue=new Date();
-		else varValue=new Date(varValue);
-	}
-	
-	//lookup for readonly
-	if (isLookup && varValue!="UNDEF"){
-		let lookup=field["lookup"];
-		//get all values from config.formConfig.lookup[X]
-		let lObject=config.formConfig.lookup[lookup.queryName];
-		varValue=lObject.LUT[varValue];
-	}
-
-	this.print('Element: '+input);
-	//figure out the element type
-	let eType=input.nodeName.toLowerCase();
-	this.print('Element type: '+eType);
-
-	//change varValue for printing
-	if (varValue=="UNDEF") varValue="";
-	//HTMLTextArea, createElement(textArea)
-	if (eType==="textarea"){
-		input.value=varValue;
-		return;
-	}
-	//Text, createTextNode
-	if (eType==="#text"){
-		input.nodeValue=varValue;
-		return;
-	}
-	//HTMLLabelElement, createElement('label')
-	if (eType==="label"){
-		input.innerText=varValue;
-		return;
-	}
-
-	//HTMLSelectElement, createElement('select')
-	if (eType==="select"){
-		input.selectedIndex=0;
-		for (let i=0;i<input.options.length;i++){
-			let v=input.options[i].text;
-			if (v!=varValue) continue;
-			input.selectedIndex=i;
-			break;
-		}
-		return;
-	}
-
-	if (eType!="input"){
-		this.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;
-	}
-	this.print('Unknown input type: '+type+'. Ignoring.');
-}
-
-crfVisit.populateTable=
-function(listName,writeMode){
-//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+']';
-   
-
-	let setup=this.getSetup(listName,writeMode);
-	let entry=new Object();
-	
-	//data snapshot
-	let fQuery=this.getQuerySnapshot(listName);
-   let queryLayout=this.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 "+fQuery.rows.length);
-	
-	if (fQuery.rows.length>0)
-		entry=fQuery.rows[0];
-	
-	let fields=queryLayout.fields;
-		
-	for (f in fields){	
-		let field=fields[f];
-		//each field is a new row
-		this.print(fName+": Adding field: "+f+'/'+field.name+' hidden: '+field.hidden+' type:'+field.type);
-		if (field.hidden) continue;
-		if (field.name=="crfRef") continue;
-		this.populateFieldRow(entry,field,setup);
-		
-	}
-
-}
-
-crfVisit.generateTable=
-function(listName,divName,additionalData,setup){
-	let fName="[generateTable/"+listName+"]";	
-   let config=this.config;
-	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;
-   let populateData=true;
-   if ("subTable" in setup){
-      this.print(fName+" is subTable");
-      populateData=false;
-   }
-
-	let entry=new Object();
-
-
-
-	//data snapshot
-	let fQuerySnapshot=this.getQuerySnapshot(listName);
-   let queryLayout=this.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];
-
-   
-   if ("reviewTable" in setup){
-      entry['reviewComment']='';
-      delete entry["ModifiedBy"];
-   }
-	
-	let tb=config.document.createElement('table');
-	tb.className="t2";
-	this.getElement(divName).appendChild(tb);
-
-	//this are the fields (probably constant)
-	let fields=queryLayout.fields;
-		
-	for (f in fields){
-		let field=fields[f];
-      let fieldUID=listName+":"+field.name;
-		//each field is a new row
-		this.print(fName+": Adding field: "+f+'/'+field.name+' ('+fieldUID+').');
-      //unique name
-		if (field.hidden) continue;
-		if (field.name=="crfRef") continue;
-		this.addFieldRow(tb,field,setup,additionalData);
-		if (populateData) this.populateFieldRow(entry,field,setup);
-      if (fieldUID in config.formConfig["specialFields"]){
-         let specFieldSetup=config.formConfig["specialFields"][fieldUID];
-         this.addSpecialFieldRows(tb,specFieldSetup,setup);
-      }
-
-		
-	}
-   //finish of if apply button is not required
-	if (!("addApply" in setup)) {
-		this.print(fName+"populateTable: done");
-		return;
-	}
-	
-	let row=tb.insertRow();
-
-	let th=config.document.createElement('th');
-	row.appendChild(th);
-	th.innerHTML=setup.addApply; 
-	let cell=row.insertCell();
-	//cell.setAttribute("colspan","2");
-	let input=config.document.createElement("input");	
-	input.type="button";
-	input.value=setup.addApply;
-	cell.appendChild(input);	
-	let cell1=row.insertCell();
-	cell1.setAttribute("colspan","2");
-	cell1.id=setup.getInputId("rerviewLastSave");
-	cell1.innerHTML="No recent update";
-	//saveReview is a generic name for saving content of the html page to a list entry
-   let that=this;
-	input.onclick=function(){that.saveReview(listName,cell1.id,setup)};
-}	
-
-crfVisit.setEntryFromElement=
-function(entry,elementId, field){
-   //set value to entry from element using representation (field) from labkey
-   //
-   //
-   
-   let fName='setEntryFromElement';
-   let config=this.config;
-
-   let el=this.getElement(elementId);
-				
-   if (!el) {
-      this.print(fName+" element: "+elementId+" not found");
-      return;
-   }
-   this.print(fName+" element: "+elementId);
-      
-
-   let vName=field.name;
-   let vType=field.type;
-
-   let eType=el.nodeName.toLowerCase();
-
-   if (eType==="select"){
-      entry[vName]=el.options[el.selectedIndex].value;
-      return;
-   }
-
-   if (eType==="td"){
-      entry[vName]=el.innerText;
-      return;
-   }
-   
-   if (vType=="date"){
-      let date=el.valueAsDate;
-      if (!date) return;
-
-      date.setUTCHours(12);
-      entry[vName]=date.toString();
-      this.print(fName+" setting date to "+entry[vName]);
-      return;
-   }
-
-   if (vType=="string"){
-      entry[vName]=el.value;
-      
-      if (vName.search('_file_')<0) 
-         return;
-      
-      //upload file
-      let id1=elementId+'_file_';
-      let input1=this.getElement(id1);
-      this.print(fName+' attachment field: '+input1.value);
-      //entry[vName]=el.files[0].stream();
-      let ctx=new Object();
-      ctx['dirName']='consent';
-      ctx['ID']=entry['crfRef'];
-      //should point to data container
-      ctx['project']=getContainer('data');
-      //need ID->crf!
-      //assume crfRef will get set before this
-      //element is encountered
-      this.uploadFile(input1,ctx);
-      let fv=el.value;
-      let suf=fv.split('.').pop();
-      entry[vName]=entry['crfRef']+'.'+suf;
-      return;
-      
-   }	
-   if (vType=="float" || vType=="int"){
-      entry[vName]=el.value;
-      
-      if (vName=="queryName") {
-         this.print(fName+' parsing queryName: '+el.innerText);
-         entry[vName]=config.formConfig.fields[el.innerText].queryId;
-         //use queryMap lookup
-      }
-      return;
-   }	
-   if (vType=="boolean"){
-      entry[vName]=el.checked;
-      return;
-	}
-   return;
-}
-
-crfVisit.saveReview=
-function(queryName,elementId,setup){
-	//loads any queryName
-
-	let debug=true;
-   let fName='[saveReview/'+queryName+']';
-	this.print(fName+" elementId "+elementId);
-
-
-   let unique=("unique" in setup);
-	
-   //data snapshot
-	let fQuerySnapshot=this.getQuerySnapshot(queryName);
-   let nRows=fQuerySnapshot.rows.length;
-   
-   let mode='insert';
-   
-   //data layout 
-	let queryLayout=this.getQueryLayout(queryName);
-
-
-	let entry=new Object();
-	
-   //determine mode based on entry uniqueness and presence of data
-   if (unique && nRows>0){
-		entry=fQuerySnapshot.rows[0];
-      mode='update';
- 	}
-
-   this.print(fName+' unique '+unique+' mode '+mode+' nRows '+nRows);
-
-	entry.crfRef=this.getCRFrefData();
-
-	this.print(fName+" set crfRef="+entry.crfRef);
-
-
-	let fields=queryLayout.fields;
-	for (f in fields){
-
-		let field=fields[f];
-		this.print(fName+" saveReview field: "+field.name);
-		if (field.hidden) continue;
-		
-		let vName=field.name;
-		let vType=field.type;
-
-		this.print(fName+" vType: "+vType);
-		
-		if (vName=="crfRef") continue;
-		//need to save queryName for reviewComments
-		
-		let eId=setup.getInputId(vName);
-      //copy values from form to entry
-      this.setEntryFromElement(entry,eId,field);
-
-      //clear field value
-      if (!unique) this.clearField(field,setup);
-
-	}
-   let that=this;
-	let action=function(data){that.updateLastSavedFlag(data,setup,elementId)};
-
-   this.modifyRows(mode,'lists',queryName,[entry],action,this.getContainer('data'));
-
-}
-
-crfVisit.updateLastSavedFlag=
-function(data,setup,elementId){
-   let fName='[updateLastSavedFlag]';
-	let config=this.config;
-   this.print(fName+" update last saved flag to "+elementId);
-	let el=this.getElement(elementId);
-	let dt=new Date();
-	el.innerHTML="Last saved "+dt.toString();
-	if (data.queryName=="reviewComments"){
-		this.updateListDisplay(setup.divReviewListId,"reviewComments",setup.filters,true);
-	}	
-	//refresh stored data!
-	let writeMode=!setup.readonlyFlag();
-   let that=this;
-	if ("unique" in setup)
-		this.setData(function (){that.populateTable(data.queryName,writeMode);});
-	if ("masterQuery" in setup){
-		let ad=config.formConfig.additionalData[setup.masterQuery];
-		this.print('Updating list display: '+setup.queryName+'/'+ad.queryName);
-		this.updateListDisplay(ad.divQueryName,ad.queryName,ad.filters,false);
-	}
-}
-
-//******************************************upload to database *********************
-
-crfVisit.onDatabaseUpload=
-function(){
-	let fName='[onDatabaseUpload]';
-	this.print(fName);
-   let config=this.config;
-	config.upload=new Object();
-   let fc=new Object();
-   let pM=this.getIdManager();
-   fc.participantId=participantIdManager.getParticipantIdFromCrfEntry(pM);
-	this.print(fName+' id '+fc.participantId);
-   this.afterParticipantId(fc);
-}
-
-crfVisit.afterParticipantId=
-function(fc){
-	this.print("Setting participantId to "+fc.participantId);
-   let config=this.config;
-	config.upload.participantId=fc.participantId;
-	//another select rows to update all queries from setup
-	//just use registration for test
-	let formSetupRows=config.formConfig.formSetupRows;
-	config.upload.queries=new Array();
-	this.print("Form rows: "+formSetupRows.length);
-	for (let i=0;i<formSetupRows.length;i++){
-		let entry=formSetupRows[i];
-		//skip reviews
-		if (entry.showFlag=="REVIEW") continue;
-		//use lookup table to convert from id to name
-		let queryName=config.formConfig.queryMap[entry.queryName];
-		config.upload.queries.push({queryName:queryName,queryStatus:"QUEUED"});
-		this.print('form ['+i+']='+queryName+' '+entry.showFlag+'/'+entry.showQuery);
-		if (entry.showQuery=="NONE")
-			continue;
-		config.upload.queries.push({queryName:entry.showQuery,queryStatus:"QUEUED"});
-	}
-	//add reviews
-	config.upload.queries.push({queryName:"reviewComments",queryStatus:"QUEUED"});
-	config.upload.queryId=0;
-	this.copyToDataset();
-
-}
-
-
-crfVisit.copyToDataset=
-function(){
-	let fName='[copyToDataset]: ';
-   let config=this.config;
-	this.print(fName+'['+config.upload.queryId+'/'+config.upload.queries.length+']');
-	//watch dog + scheduler
-	//
-   
-   let that=this;
-
-	//watchdog part
-	if (config.upload.queryId==config.upload.queries.length) {
-		this.print(fName+'completing');
-		let targetStatus=config.formConfig.targetStatus['onDatabaseUpload'];
-		let targetRecipient=config.formConfig.targetRecipient['onDatabaseUpload'];
-		let action=new Object();
-		action.name='onDatabaseUpload';
-      let redirect=function(){that.redirect();};
-		action.cb=function(data){that.sendEmail(data,targetRecipient,redirect,'Form uploaded');}
-		this.updateFlag(targetStatus,action);//Approved
-		return;
-	}
-
-	//scheduler
-	let queryName=config.upload.queries[config.upload.queryId].queryName;
-	this.print("copyToDataset["+config.upload.queryId+"/"+
-			config.upload.queries.length+"]: "+queryName);
-
-	let filters=[LABKEY.Filter.create('crfRef',this.getCRFref())];
-   let action=function(data){that.afterListData(data);};
-   this.selectRows('lists',queryName,filters,action,this.getContainer('data'));
-}
-
-crfVisit.afterListData=
-function(data){
-	let fName='[afterListData]: ';
-   let config=this.config;
-
-	let queryName=config.upload.queries[config.upload.queryId].queryName;
-	this.print(fName+" ["+queryName+"/list]: "+data.rows.length+" entries");
-	config.upload.queries[config.upload.queryId].listData=data;
-	let id=config.upload.participantId;
-
-	let filters=[LABKEY.Filter.create('crfRef',this.getCRFref()),LABKEY.Filter.create('ParticipantId',id)];
-   let that=this;
-   let action=function(data){that.afterStudyData(data);};
-   this.selectRows('study',queryName,filters,action,this.getContainer('data'));
-}
-
-crfVisit.afterStudyData=
-function(data){
-
-	let fName='[afterStudyData]: ';
-   let config=this.config;
-	let queryObj=config.upload.queries[config.upload.queryId];
-	queryObj.studyData=data;
-
-	let msg=fName+"["+queryObj.queryName+"/study]: "+data.rows.length+" entries";
-	this.print(msg);
-	
-
-	let listRows=queryObj.listData.rows;
-	//skip uploading an empty set
-	if (listRows.length==0){
-		this.printErr("List "+queryObj.queryName+" empty.");
-		queryObj.queryStatus="DONE";
-		config.upload.queryId+=1;
-		//back to watchdog
-		this.copyToDataset();
-		return;
-	}
-	
-
-	let studyRows=queryObj.studyData.rows;
-
-	for (let i=0;i<studyRows.length;i++){
-		let entry=studyRows[i];
-		//
-		if (! (i<listRows.length) ) continue;
-		let entryList=listRows[i];
-		//keeps study only variables (ParticipantId, SequenceNum)
-		for (let f in entryList) {
-			entry[f]=entryList[f];
-			this.print(fName+"Copying ["+f+"]: "+entry[f]+"/"+entryList[f]);
-		}
-	}
-	this.print(fName+' copying completed');
-
-	if (studyRows.length>0) {
-      let that=this;
-      let action=function(data){that.afterStudyUpload(data);};
-      this.modifyRows('update','study',queryObj.queryName,studyRows,action,this.getContainer('data'));
-		this.print(fName+'updateRows sent');
-
-	}
-	else{
-		let data=new Object();
-		data.rows=new Array();
-		this.afterStudyUpload(data);
-	}
-}
-
-crfVisit.afterStudyUpload=
-function(data){
-	let fName='[afterStudyUpload] ';
-   let config=this.config;
-   let that=this;
-	this.print(fName);
-	//let participantField=config.participantField;
-	let participantField=config.formConfig.studyData["SubjectColumnName"];
-	this.print(fName+' participantField: '+participantField);
-
-	let queryObj=config.upload.queries[config.upload.queryId];
-	let queryName=queryObj.queryName;
-	this.printErr("Updated "+data.rows.length+" rows to "+queryName);
-	
-	let studyRows=queryObj.studyData.rows;
-	let listRows=queryObj.listData.rows;
-	
-	let rows=new Array();
-	//also updating existing rows, if they exist
-	for (let i=studyRows.length;i<listRows.length;i++){
-		let entry=listRows[i];
-		//make sure you have the participantField right
-		//
-		entry[participantField]=config.upload.participantId;
-		entry.crfRef=this.getCRFref();
-		entry.SequenceNum=this.getCRFref();
-		entry.SequenceNum=entry.SequenceNum % 1000000000;
-		
-		if (listRows.length>1){
-			entry.SequenceNum+=i/100;
-		}
-		this.print( "Adding sequence number "+entry.SequenceNum);
-		rows.push(entry);
-	}
-	if (rows.length>0){
-      let action=function(data){that.afterListUpload(data);};
-      this.insertRows('study',queryName,rows,action,this.getContainer('data'));
-	}
-	else{
-		let data=new Object();
-		data.rows=rows;
-		this.afterListUpload(data);
-	}
-			
-}
-
-crfVisit.afterListUpload=
-function(data){
-	let config=this.config;
-	let queryObj=config.upload.queries[config.upload.queryId];
-	let queryName=queryObj.queryName;
-	this.printErr("Inserted "+data.rows.length+" rows to "+queryName);
-	queryObj.queryStatus="DONE";
-	config.upload.queryId+=1;
-	this.copyToDataset();
-
-}
-
-
-
-
-//*************************update for further review *************************
-crfVisit.onUpdateForReview=
-function(){
-   let config=this.config;
-	let targetStatus=config.formConfig.targetStatus['onUpdateForReview'];
-	let targetRecipient=config.formConfig.targetRecipient['onUpdateForReview'];
-	let action=new Object();
-	action.name='onUpdateForReview';
-   let that=this;
-   let redirect=function(){that.redirect();};
-	action.cb=function(data){that.sendEmail(data,targetRecipient,redirect,'Form updated for review');};
-
-	this.updateFlag(targetStatus,action);
-}
-
-crfVisit.updateFlag=
-function(flag,action){
-	let fName='[updateFlag 1]';
-   let config=this.config;
-
-	let entry=config.formConfig.crfEntry;
-	entry.FormStatus=flag;
-	let uId=config.formConfig.currentUser.UserId;
-	entry[config.formConfig.operator]=uId;
-
-	this.print(fName+': Form: '+entry.Form);
-	this.print(fName+": set form status to "+entry.FormStatus);
-   let that=this;	
-	let cb=function(data){that.completeWithFlag(data,action);};
-   this.modifyRows('update','lists','crfEntry',[entry],cb,this.getContainer('data'));
-		
-}
-
-
-crfVisit.completeWithFlag=
-function(data,action){
-	let fName='[completeWithFlag]';
-	this.print(fName+': nrows '+data.rows.length);
-
-	let fentry=data.rows[0];
-	this.print(fName+': form status '+fentry.FormStatus);
-	this.print(fName+': form '+fentry.Form);
-
-	let crfStatus=this.createCrfStatus(fentry);
-   let config=this.config;
-	crfStatus.operator=config.formConfig.operator;
-	crfStatus.action=action.name;
-   let that=this;
-   let cb=function(){that.doNothing();};
-   if (action.cb) cb=action.cb;
-
-   this.insertRows('lists','crfStatus',[crfStatus],cb,this.getContainer('data'));
-
-}
-
-//************************************************ submit *******************************************
-
-crfVisit.onSubmit=
-function(){
-	//update list storage and change status
-
-	this.hideErr();
-	this.clearErr();
-	this.printErr("onSubmit");
-   let that=this;
-   let action=function(){that.verifyData();};
-	this.setData(action);
-	
-
-
-}
-
-crfVisit.verifyData=
-function(){
-	let fName='[verifyData]';
-   let config=this.config;
-   let qList=this.getQueryList();
-   let that=this;
-   let doNothing=function(data){that.doNothing();};
-	for (q in qList){
-		let qData=this.getQuerySnapshot(q);
-		if (q=="reviewComments") continue;
-		//copy snapshot to history
-      if (qData.rows.length==0){
-         this.print(fName+' no rows for '+q);
-      }
-      else
-		   this.insertRows('lists',q+'History',qData.rows,doNothing,this.getContainer('data'));
-		//if it doesn't have additionalData, it is a sub query
-		if (!(q in config.formConfig.additionalData)){
-			continue;
-		}
-		if (qData.rows.length<1){
-			this.printErr('Missing entry for query '+q);
-			return false;
-		}
-	}
-	//this is necessary only for Generated to Generation completed step
-	let actionSettings=config.formConfig.actionSettings['onSubmit'];	
-	if (variableList.hasVariable(actionSettings,"updateRegistration")){
-		this.updateRegistration();
-	}
-	let targetStatus=config.formConfig.targetStatus['onSubmit'];	
-	let targetRecipient=config.formConfig.targetRecipient['onSubmit'];
-	this.print(fName+' targetStatus: '+targetStatus);
-	
-	let finalStep=function(){that.redirect();};
-	if (variableList.hasVariable(actionSettings,"finalStep")){
-		//set to doNothing to remain on submit window
-		if (actionSettings.finalStep=="doNothing"){
-			finalStep=doNothing;
-		}
-	}
-	
-	let action=new Object();
-	action.name='onSubmit';
-	action.cb=function(data){that.sendEmail(data,targetRecipient,finalStep,'Form sumbitted');};
-	this.updateFlag(targetStatus,action);
-}
-
-crfVisit.getEmail=
-function(recipientCode){
-
-	this.print('getEmail w/'+recipientCode);
-   let config=this.config;
-	let recipients=new Array();
-	let typeTo=LABKEY.Message.recipientType.to;
-	let create=LABKEY.Message.createRecipient;
-	let currentUser=config.formConfig.currentUser;
-	let formCreator=config.formConfig.formCreator;
-	let currentSite=config.formConfig.currentSite;
-	let userRows=config.formConfig.userRows;
-	let parentUser=undefined;
-	if ("parentCrfData" in config.formConfig){
-		let parentCrf=config.formConfig.parentCrfData;
-		parentUser=this.getUser(parentCrf.rows[0].UserId,'parentUser');
-	}
-	
-
-	let recipientCategories=recipientCode.split(',');
-	for (let i=0;i<recipientCategories.length;i++){
-
-		let recipient=recipientCategories[i];
-		this.print('Checking '+recipient);
-		if (recipient=='crfEditor'){
-			this.print('Adding :'+formCreator.Email);
-			recipients.push(create(typeTo,formCreator.Email));
-			if (parentUser==undefined) continue;
-			this.print('Adding :'+parentUser.Email);
-			recipients.push(create(typeTo,parentUser.Email));
-			continue;
-		}
-		//Monitor or Sponsor
-		let fList=recipient+'s';
-		let fRows=config.formConfig[fList];
-		for (let i=0;i<fRows.length;i++){
-			this.print('Checking '+fRows[i].User+'/'+fRows[i].Site);
-			if (fRows[i].Site!=currentSite.siteNumber) continue;
-			for (let j=0;j<userRows.length;j++){
-				if (userRows[j].UserId!=fRows[i].User) continue;
-				this.print('Adding :'+userRows[j].Email);
-				recipients.push(create(typeTo,userRows[j].Email));
-				break;
-			}
-		}
-	}
-
-	return recipients;
-}
-
-crfVisit.sendEmail=
-function(data,recipient='crfEditor',cb=null,subj='Form submitted'){
-
-	this.print('sendEmail; recipient: '+recipient);
-   let config=this.config;
-   let that=this;
-
-   if (!cb)
-      cb=function(){that.redirect();};
-
-	let st=config.formConfig.settings;
-	let cvar='sendEmail';
-	if (cvar in st){
-		this.print(cvar+' set to '+st[cvar]);
-		if (st[cvar]=='FALSE'){
-			this.print('Skipping sending emails');
-			cb();
-			return;
-		}
-	}
-	if (recipient==null){
-      this.print('Skipping sending emails w/ no recipients');
-      cb();
-      return;
-   }
-
-
-	this.print('send email '+data.rows.length);
-	let crf=data.rows[0]['entryId'];
-	let formId=data.rows[0]['Form'];
-	let link=LABKEY.ActionURL.getBaseURL();
-	link+=LABKEY.ActionURL.getContainer();
-	link+='/crf_tecant-visit.view?';
-	link+='entryId='+crf;
-	link+='&formId='+formId;
-	link+='&role='+recipient;
-
-	//debug
-	let recipients=this.getEmail(recipient);
-	//from crfManagers list
-	
-	let typeHtml=LABKEY.Message.msgType.html;
-	let typePlain=LABKEY.Message.msgType.plain;
-	let msg1=LABKEY.Message.createMsgContent(typePlain,link);
-
-	//let cb=doNothing;
-	//let cb=redirect;
-	LABKEY.Message.sendMessage({
-		msgFrom:'labkey@fmf.uni-lj.si',
-		msgSubject:subj,
-		msgRecipients:recipients,
-		msgContent:[msg1],
-		success: cb
-	});
-
-}
-
-crfVisit.hideErr=
-function(){
-	let el=this.getElement("errorDiv");
-	el.style.display="none";
-}
-
-crfVisit.clearErr=
-function(){
-	let el=this.getElement("errorTxt");
-	el.value="";
-}
-
-crfVisit.showErr=
-function(){
-	let el=this.getElement("errorDiv");
-	el.style.display="block";
-}
-
-crfVisit.printErr=
-function(msg){
-	this.showErr();
-	el=this.getElement("errorTxt");
-	el.style.color="red";
-	el.value+="\n"+msg;
-}
-
-
-//**************************************************
-//
-crfVisit.onRemoveCRF=
-function(){
-   let fName='[onRemoveCRF]';
-   let config=this.config;
-	config.inputListsIterator=0;
-   this.print(fName+' starting loop');
-
-   //let rd=function(data){redirect();};
-   //let cb=function(){cvInsertRows('lists','crfStatus',[crfStatus],rd,getContainer('data'));};
-   let that=this;
-   let action=function(){that.redirect();}; 
-   let cb=function(){that.removeCrfEntries(action);};
-	this.removeCRFLoop(cb);
-}
-
-crfVisit.removeCRFLoop=
-function(cb){
-   let fName='[removeCRFLoop()]';
-   let config=this.config;
-   let that=this;
-
-	let i=config.inputListsIterator;
-	let iMax=config.formConfig.inputLists.rows.length;
-	//in fact, we are adding two additional passages of the loop, one for 
-	//crfEntry, the second for the same query, but using parentCrf as the 
-	//selection variable
-	//let iTotal=iMax+1;
-	//let iTotal=iMax+1;
-   //
-   let actionSettings=config.formConfig.actionSettings['onRemoveCRF'];
-   let queryNameDeleteWithParentCrf='NONE';
-   if (variableList.hasVariable(actionSettings,'removeWithParentCrf')){
-      queryNameDeleteWithParentCrf=actionSettings['removeWithParentCrf'];
-   }
-	
-	this.print(fName+" ["+i+"/"+iMax+"]");
-
-	if (!(i<iMax)){
-      cb();
-      return;
-	}
-	//in all but crfEntry, variable is called crfRef
-	let queryName=config.formConfig.inputLists.rows[i].queryName;
-   let idVar="crfRef";
-   let idValue=config.formConfig.crfEntry['entryId'];
-
-	//delete also crfEntries where parentCrf is set to crf that we are deleting
-
-   if (queryNameDeleteWithParentCrf==queryName){
-      idValue=config.formConfig.crfEntry['parentCrf'];
-   }
-	
-	this.print(fName+" ["+i+"/"+iMax+"] "+queryName+":"+idVar+'/'+idValue);
-
-   let filters=[LABKEY.Filter.create(idVar,idValue)];
-   let action=function(data){that.removeListCRF(data,cb);};
-   let failure=function(errorInfo){that.skipListCRF(errorInfo,cb);};
-   this.selectRows('lists',queryName,filters,action,this.getContainer('data'),failure);
-	//selectRows.failure=skipListCRF;
-}
-
-crfVisit.removeListCRF=
-function(data,cb){
-   let fName="[removeListCRF]";
-   let config=this.config;
-   let that=this;
-	this.print(fName+" "+data.queryName+": "+data.rows.length);
-
-	config.inputListsIterator+=1;
-	
-	if (data.rows.length==0){
-		this.removeCRFLoop(cb);
-		return;
-	}
-
-   let action=function(data){that.removeCRFLoop(cb)};
-   this.deleteRows(data.schemaName,data.queryName,data.rows,action,this.getContainer('data'));
-	
-}
-
-crfVisit.skipListCRF=
-function(errorInfo,cb){
-   let fName='[skipListCRF]';
-	this.print(fName+" error in removeCRF: "+errorInfo.exception);
-   let config=this.config;
-
-	config.inputListsIterator+=1;
-	
-	this.removeCRFLoop(cb);
-	
-}
-
-crfVisit.removeCrfEntries=
-function(cb){
-	let queryName="crfEntry";
-	let idVar="entryId";
-	let crfRef=this.getCRFref();
-   let that=this;
-
-   let filters=[LABKEY.Filter.create('entryId',crfRef)];
-   let action=function(data){that.deleteAndUpdateCrfStatus(data,null);}
-   this.selectRows('lists',queryName,filters,action,this.getContainer('CRF'));
-   let action1=function(data){that.deleteAndUpdateCrfStatus(data,cb);}
-   let filters1=[LABKEY.Filter.create('parentCrf',crfRef)];
-   this.selectRows('lists',queryName,filters1,action1,this.getContainer('CRF'));
-}
-
-crfVisit.deleteAndUpdateCrfStatus=
-function(data,cb){
-   let fName='[deleteAndUpdateCrfStatus]';
-   let config=this.config;
-   let that=this;
-   let rows=data.rows;
-   let stack=new Array();
-   stack.push(cb);
-   for (let i=0;i<rows.length;i++){
-      //generate crfStatus entry out of crfEntry
-      let crfStatus=this.createCrfStatus(rows[i]);
-      crfStatus.action='onRemoveCRF';
-      crfStatus.FormStatus=config.formConfig.targetStatus[crfStatus.action];
-      this.print(fName+' status '+crfStatus.FormStatus);
-      crfStatus.operator=config.formConfig.operator;
-      let k=stack.length-1;
-      let containerPath=this.getContainer('CRF');
-      stack.push(function(){that.insertRows('lists','crfStatus',[crfStatus],stack[k],containerPath);});
-      let k1=k+1;
-      stack.push(function(){that.deleteRows('lists','crfEntry',[rows[i]],stack[k1],containerPath);});
-   }
-   //execute the whole stack
-   let m=stack.length-1;
-   stack[m]();
-}
-
-crfVisit.redirect=
-function(){
-	let debug=false;
-	let formUrl="begin";
-	let params=new Object();
-	params.name=formUrl;
-	params.pageId="CRF";
-
-	//points to crf container
-	let containerPath=this.getContainer('CRF');
-        
-	// This changes the page after building the URL. 
-	//Note that the wiki page destination name is set in params.
-        
-	var homeURL = LABKEY.ActionURL.buildURL(
-			"project", formUrl , containerPath, params);
-        this.print("Redirecting to "+homeURL);
-	if (debug) return;	 
-	window.location = homeURL;
-
-	
-
-}
-
-//master section, entry point from html files
-crfVisit.generateMasterForm=
-function(){
-   let that=this;
-   let action=function(){that.setFormConfig();}
-   this.init(action);
-}
-
-
-//helper function to set basic parameters on web page 
-//(fields defined in html file)
-crfVisit.populateBasicData=
-function(){
-
-   let staticData=new Object();
-   let titles=new Object();
-   let config=this.config;
-   staticData['version']=config.formConfig.softwareVersion;	
-   titles['version']='Software version';
-   let varRows=config.formConfig['crfStaticVariables'].rows;
-   for (let i=0;i<varRows.length;i++){
-      let vName=varRows[i].staticVariable;
-      let val=config.formConfig.crfEntry[vName];
-      if (val==undefined) continue;
-      staticData[vName]=val;
-      titles[vName]=varRows[i].Title;
-   }
-	staticData['investigatorName']=config.formConfig.user['DisplayName'];
-   titles['investigatorName']='Investigator';
-   staticData['email']=config.formConfig.user['Email'];
-   titles['email']='Email';
-   staticData['siteName']=config.formConfig.currentSite['siteName'];
-   titles['siteName']='Site';
-   staticData['sitePhone']=config.formConfig.currentSite['sitePhone'];
-   titles['sitePhone']='Telephone(site)';
-
-   for (f in staticData){
-      this.addStaticData(f,titles[f],staticData[f]);
-   }
-}
-
-crfVisit.addStaticData=
-function(f,title,value){
-   let el=this.getElement(f);
-
-   //populate only
-   if (el!=undefined){
-      el.innerText=value;
-      return;
-   }
-   
-   //add row to table if element cannot be found
-   let table=this.getElement('staticTable');
-   let row=table.insertRow();
-   let cell=row.insertCell();
-   cell.innerText=title;
-   let cell1=row.insertCell();
-   cell1.id=f;
-   cell1.style.fontWeight='bold';
-
-   //populate
-   cell1.innerText=value;
-}
-
-//come here after the layout is read from labkey page
-//
-crfVisit.generateErrorMsg=
-function(msg){
-   let config=this.config;
-	let txt=config.document.createElement('p');
-	txt.innerText=msg;
-	this.getElement(config.masterForm).appendChild(txt);
-	this.generateButton("submitDiv",'Exit','Exit','redirect');
-}
-
-crfVisit.getUser=
-function(id,field){
-   let config=this.config;
-	if (field in config.formConfig) return config.formConfig[field];
-	let uRows=config.formConfig.userRows;
-	for (let i=0;i<uRows.length;i++){
-		let userId=uRows[i].UserId;
-		if (userId!=id) continue;
-		config.formConfig[field]=uRows[i];
-		return config.formConfig[field];
-	}
-	return null;
-}	
-
-crfVisit.afterConfig=
-function(){
-   let fName='[afterConfig]';
-   let config=this.config;
-	this.print(fName);	
-   
-	this.populateBasicData();
-	
-	//check if user has permission on the form
-	let currentUser=this.getUser(LABKEY.Security.currentUser.id,'currentUser');
-	let currentSite=config.formConfig.currentSite;
-	let formCreator=this.getUser(config.formConfig.crfEntry.UserId,'formCreator');
-	let formCreatorId=formCreator.UserId;
-
-
-
-	//let formSite=config.formConfig.crfEntry.Site;
-	let fList=config.formConfig.operator+'s';
-	let fRows=config.formConfig[fList];
-	//let currentSiteId=-1;
-	
-	//depending on operator mode, we should decide what is right
-	let operator=config.formConfig.operator;
-	if (operator=='crfEditor'){
-		//editor can only edit its own forms
-		if (currentUser.UserId!=formCreatorId){
-			let msg='User '+currentUser.DisplayName;
-			msg+=' has no permission on this form';
-			this.generateErrorMsg(msg);
-			return;
-		}
-	}
-	if (operator=='crfMonitor' || operator=='crfSponsor'){
-		//monitor can look at forms based on his site
-		//find monitor line
-		let operatorSites=new Array();
-		for (let i=0;i<fRows.length;i++){
-			if (fRows[i].User!=currentUser.UserId) continue;
-			operatorSites.push(fRows[i].Site);
-		}
-		this.print('operator Site: '+operatorSites.length);
-		if (operatorSites.length==0){
-			let msg='User '+currentUser.DisplayName;
-			msg+=' is not a '+operator;
-			this.generateErrorMsg(msg);
-			return;
-		}
-
-		let selectedSite=-1;
-		let siteCandidates="[";
-		for (let i=0;i<operatorSites.length;i++){
-			if (i>0) siteCandidates+=", ";
-			siteCandidates+=operatorSites[i];
-			if (operatorSites[i]!=currentSite.siteNumber) continue;
-			selectedSite=currentSite.siteNumber;
-			break;
-		}
-		siteCandidates+="]";
-		if (selectedSite==-1){
-			let msg='User '+currentUser.DisplayName;
-			msg+=' is not a '+operator+' for site ';
-			msg+=currentSite.siteName+'('+currentSite.siteNumber+')';
-			msg+='/'+siteCandidates;
-			this.generateErrorMsg(msg);
-			return;
-		}
-	}
-
-
-	this.print('User '+currentUser.DisplayName+'/'+
-		config.formConfig.currentSite['siteName']+
-		' acting as '+config.formConfig.operator);	
-
-
-	let rows=config.formConfig.crfButtons.rows;
-	config.formConfig.targetStatus=new Array();
-	config.formConfig.targetRecipient=new Array();
-	config.formConfig.actionSettings=new Array();
-
-	for (let i=0; i<rows.length; i++){
-		let action=rows[i].action;//String
-		let tstatus=rows[i].targetFormStatus;
-		let trecip=rows[i].targetRecipient;
-		config.formConfig.targetStatus[action]=tstatus;
-		config.formConfig.targetRecipient[action]=trecip;
-		//allow for settings to be promoted with each action (and potentially parsed and acted upon)
-		config.formConfig.actionSettings[action]=undefined;
-		let aSet=rows[i].actionSettings;
-		if (aSet){
-			config.formConfig.actionSettings[action]=variableList.parseVariables(aSet);
-			variableList.printVariables(this,config.formConfig.actionSettings[action]);
-		}
-
-	}
-	let formStatus=config.formConfig.formStatus;
-
-	//let functionArray=new Array();
-
-	this.print("Generating buttons for formStatus \""+ formStatus+"\"");
-
-   let allButtonRows=config.formConfig.crfButtons.rows;
-	let buttonRows=new Array();
-   
-   //specifying role=X in actionSettings will limit button to that role
-   for (let i=0;i<allButtonRows.length;i++){
-      let action=allButtonRows[i]['action'];
-      //filter on actionSettings
-      let as=config.formConfig.actionSettings[action];
-      if (variableList.hasVariable(as,'role')){
-         this.print('Role['+config.formConfig.operator+'/'+as['role']+'] limited for action '+action);
-         //mismatch skips addition of button to buttonRows
-         if (config.formConfig.operator!=as['role']) continue;
-      }
-      buttonRows.push(allButtonRows[i]);
-   }
-
-
-
-	for (let i=0;i<buttonRows.length;i++){
-		let bt=buttonRows[i];
-		//if (typeof window[bt.action]==="function"){
-		this.generateButton("submitDiv",bt.caption,bt.label,bt.action,null);
-		//}
-		//else{
-		//	this.print('No match for function :'+bt.action+
-		//		' obj: '+window[bt.action]);
-		//}
-	}
-
-	this.print('Here');
-
-
-	//here we should get data. For now, just initialize objects that will hold data
-   let that=this;
-   let action=function(){that.afterDataLayout();};
-	this.setDataLayout(action);//callback is afterDataLayout
-}
-
-crfVisit.afterDataLayout=
-function(){
-
-   let that=this;
-   let action=function(){that.afterData();};
-   //let action=function(){that.doNothing();};
-	this.setData(action);//callback is afterData
-}
-
-crfVisit.updateRegistration=
-function(){
-	let fName="[updateRegistration]";
-   let config=this.config;
-	this.print(fName);
-   let pM=this.getIdManager();
-	let idFieldName=participantIdManager.getCrfEntryFieldName(pM,"STUDY");
-	//have to reload query data
-	let regQueryPars=variableList.parseVariables(config.formConfig.settings['registrationQuery']);
-   let regQuery=regQueryPars['query'];
-	let fQuery=this.getQuerySnapshot(regQuery);
-
-	if (fQuery.rows.length==0) {
-		this.print(fName+" registration is empty");
-		return; //registration is empty
-	}
-	let regEntry=fQuery.rows[0];
-
-	for (x in regEntry){
-		this.print(fName+" ["+x+"] "+regEntry[x]);
-	}
-
-
-	let studyId=fQuery.rows[0][idFieldName];
-	if (!studyId) {
-		this.print(fName+" study id not set ("+idFieldName+'/'+studyId+")");
-		return; //study id not set
-	}
-	
-	//set 
-	participantIdManager.setParticipantIdToCrfEntry(pM,studyId,"STUDY");
-	//this will only update crfEntry in memory, but not on LabKey, 
-	//we are counting on updateFlag to follow updateRegistration
-
-	//update parentCRF as well, here we schedule update of data entry as well
-	if ("parentCrfData" in config.formConfig){
-		let parentCrfEntry=config.formConfig.parentCrfData.rows[0];
-		parentCrfEntry[idFieldName]=studyId;
-      let that=this;
-      let action={name:"updateRegistration",cb:function(){that.doNothing();}};
-		let cb=function(data){that.completeWithFlag(data,action);};
-      this.modifyRows('update','lists','crfEntry',[parentCrfEntry],cb,this.getContainer('CRF'));
-	}
-}
-
-crfVisit.afterData=
-function(){
-	let fName='afterData';
-   let config=this.config;
-	//operatorBasedAccessMode	
-	let accessMode=config.formConfig.operator+'Mode';
-	let rowsSetup=config.formConfig.formSetupRows;
-
-   let idMode=config.formConfig.form['idMode'];
-   //set default value if no value is in the list (read value is null)
-   if (!idMode) idMode="STUDY:EDIT";
-
-   this.print(fName+': idMode '+idMode);
-   //add print to config so participantManager can use it
-   let pM=this.getIdManager();
-   //extend object
-   let that=this;
-   let action=new Object();
-   action.name='updateCrfEntry';
-   action.cb=function(){that.doNothing();};
-   pM.updateCrfEntry=function(){that.updateFlag(config.formConfig.crfEntry['FormStatus'],action);};   
-
-   let idModeArray=idMode.split(':');
-   pM.mode="STUDY";
-   if (idModeArray.includes("LOCAL")) {
-      pM.mode="LOCAL";
-      //OK, but check if CRF or registration indicate that study id is already set
-      participantIdManager.verifyCrfStudyId(pM);
-	  //study id should already be set by updateRegistration
-      //verifyRegistration(pM);
-   }
-   if (idModeArray.includes("READONLY")){
-      pM.readOnly="TRUE";
-   }
-   
-   let pId=participantIdManager.getParticipantIdFromCrfEntry(pM);
-   if (!pId){
-      participantIdManager.setEditMode(pM);
-   }
-   else{
-      let label=pId;
-      if (pM.mode=="STUDY"){
-         let loc=participantIdManager.getParticipantIdFromCrfEntry(pM,'LOCAL');
-         label=pId+':'+loc;
-         pM.readOnly="true";
-      }
-      participantIdManager.setLabelMode(pM,label);
-      //in STUDY mode also change LOCAL ID from crfEntry
-      
-   }
-
-	for (let i=0;i<rowsSetup.length;i++){
-		let entry=rowsSetup[i];
-		let queryName=config.formConfig.queryMap[entry['queryName']];
-		
-		this.print(fName+" ["+queryName+"]: showFlag: "+entry["showFlag"]);
-		this.print(fName+" ["+queryName+"]: accessMode: "+entry[accessMode]);
-
-		const nData=this.getQuerySnapshot(queryName).rows.length;
-		
-		this.print(fName+" ["+queryName+"]: nData: "+nData);
-
-
-		//skip sections
-		//also from fields
-		if (entry[accessMode]=="NONE") continue;
-		//skip readonly empty records
-		//if (entry[accessMode]=="READ" && nData==0) continue;
-			
-		//let additionalData=new Object();
-		//setAdditionalData(additionalData,entry);
-		//section fits one dataset/list
-      
-		this.generateSection(entry);
-		//generateSection(queryName,entry["title"],entry[accessMode], 
-		//		additionalData);
-	}
-
-}
-
-crfVisit.findSetupRow=
-function(queryName,formId){
-   let config=this.config;
-	let rowsSetup=config.formConfig.formSetupRows;
-	for (let i=0;i<rowsSetup.length;i++){
-		let e=rowsSetup[i];
-		let queryName1=config.formConfig.queryMap[e['queryName']];
-		if (e.formName!=formId) continue;
-		if (queryName1!=queryName) continue;
-		return e;
-	}
-	return null;
-}
-
-crfVisit.populateSection=
-function(queryName){
-	let fName='[populateSection/'+queryName+']';
-   let config=this.config;
-	this.print(fName);
-
-   //old setting
-   let formId=config.formId;
-   //new setting
-   formId=config.formConfig.formId;
-
-	let entry=this.findSetupRow(queryName,formId);
-	//ignore names without associated entry in formSetup
-	if (entry==undefined){
-		this.print(fName+': no matching FormSetup entry found');
-		return;
-	}
-	//populate comes after generate, we should be pretty safe in taking
-	//already generated additionalData
-	
-	if (!(queryName in config.formConfig.additionalData)){
-		this.print(fName+': no additionalData generated for '+queryName);
-		return;
-	}
-	
-	let additionalData=config.formConfig.additionalData[queryName];
-	this.print(fName+': using additionalData '+additionalData);
-	if ("isReview" in additionalData){
-      let action=function(){crfReviewSection.CB();};
-		crfReviewSection.generateSection(queryName,queryName,action);
-		return;	
-	}
-
-	let accessMode=config.formConfig.operator+'Mode';
-	let aM=entry[accessMode];
-	this.print(fName+': accessMode '+aM);
-
-	if (aM!='GENERATE'){
-		let writeMode=entry[accessMode]=='EDIT';
-		this.print(fName+': mode='+writeMode);
-	   this.populateTable(queryName,writeMode);
-		return;
-	}
-
-	//deal with generate
-	//
-	//already available -> shift to READ mode
-	let divTable=queryName+'Table';
-	let divObj=this.getElement(divTable);
-	let divRev=this.getElement(queryName+'Review');
-	let divRLi=this.getElement(queryName+'ReviewList');
-	let divGBu=this.getElement(queryName+'GenerateButton');
-
-	this.print('div GBU: '+divGBu);
-	divObj.style.display="block";
-	divRev.style.display="block";
-	divRLi.style.display="block";
-	if (divGBu!=undefined) divGBu.style.display="none";
-
-	let nData=this.getQuerySnapshot(queryName).rows.length;
-	this.print('['+queryName+']: nrows '+nData);
-	if (nData>0){
-		this.populateTable(queryName,0);
-		return;
-	}
-	//hide table
-	divObj.style.display="none";
-	divRev.style.display="none";
-	divRLi.style.display="none";
-	if (divGBu!=undefined) divGBu.style.display="block";
-	//add buttons?
-	//is button already generated?
-	
-	//populateTable(entry);
-	
-}		
-
-//*******    generateQuery infrastructure *********************
-
-crfVisit.onGenerateQuery=
-function(queryName){
-
-   let fName='[onGenerateQuery]';
-	this.print(fName+' '+queryName);
-//
-   let config=this.config;
-	let cfgRows=config.formConfig.generateConfigData.rows;
-//	//queryName to queryId?
-	let queryId=config.formConfig.fields[queryName].queryId;
-	let cfgRow=undefined;
-
-	for (let i=0;i<cfgRows.length;i++){
-		if (cfgRows[i].queryId!=queryId) continue;
-		cfgRow=cfgRows[i];
-		break;
-	}
-	if (cfgRow==undefined){
-		this.print('generateConfig for queryName['+queryId+']='+queryName+' not found');
-		return;
-	}
-	//add config to the list
-	if (!("generateConfig" in config.formConfig)){
-		config.formConfig.generateConfig=new Object();
-	}
-	config.formConfig.generateConfig[queryName]=cfgRow;
-
-	if (!("generateForm" in config.formConfig)){
-		config.formConfig.generateForm=new Object();
-	}
-	
-//
-	let formRows=config.formConfig.formRows;	
-	let formId=cfgRow.formId;
-	for (let i=0;i<formRows.length;i++){
-		if (formRows[i].Key==formId) {
-			config.formConfig.generateForm[queryName]=formRows[i];
-			break;
-		}
-	}
-	//this.print('XcfgRow '+config.formConfig.generateForm[queryName]);
-//
-//	//check if all required datasets were at least saved
-	this.checkGenerationFields(queryName);
-}
-
-crfVisit.checkGenerationFields=
-function(queryName){
-   let fName='[checkGenerationFields]';
-   let config=this.config;
-	let genForm=config.formConfig.generateForm[queryName];
-	let genCfg=config.formConfig.generateConfig[queryName];
-	let mailRecipient=genCfg.emailRecipient;
-	
-	//list of queries that are part of Registration form
-	this.print(fName);	
-	this.print(fName+' setRecipient: '+mailRecipient);
-	let formId=genForm.Key;
-	this.print(fName+" Checking form w/id "+formId);
-	let selectGenerationRows=this.selectFormSetupRows(formId);
-	//registration rows
-	for (let i=0;i<selectGenerationRows.length;i++){
-		let row=selectGenerationRows[i];
-		let queryId=row.queryName;
-		let fQueryName=config.formConfig.queryMap[queryId];
-		if (fQueryName==queryName) continue;
-		let fQuery=this.getQuerySnapshot(fQueryName);
-		this.print('Checking '+fQueryName+' nrows: '+fQuery.rows.length);
-		if (fQuery.rows.length==0){ 
-			this.generateError(queryName,fQueryName);
-			return;
-		}
-	}
-	this.generateMessage(queryName,'Vailidation OK');
-	this.print('callback: set recipient: '+mailRecipient);
-   let that=this;
-	let cb=function(){that.prepareForm(queryName,formId,mailRecipient);};
-	this.generateListEntry(formId,queryName,cb);
-}
-
-
-crfVisit.prepareForm=
-function(queryName,formId,mailRecipient){
-   let fName="[prepareForm]";
-
-	this.print(fName+' recipient '+mailRecipient);
-
-	//look for existing registration entry
-   let that=this;
-	let action=function(data){that.generateForm(data,queryName,mailRecipient);};
-	let formFilter=LABKEY.Filter.create('Form',formId);
-	let parentCrfFilter=LABKEY.Filter.create('parentCrf',this.getCRFref());
-   let filters=[formFilter,parentCrfFilter];
-   this.selectRows('lists','crfEntry',filters,action,this.getContainer('data'));
-
-}
-
-crfVisit.generateError=
-function(queryName,fQueryName){
-	let elName=queryName+'GenerateButton'+'_reportField';
-	let el=this.getElement(elName);
-	el.innerText='Error: '+fQueryName+' was not set';
-	el.style.color='red';
-}
-
-crfVisit.generateMessage=
-function(queryName,msg){
-	let elName=queryName+'GenerateButton'+'_reportField';
-	let el=this.getElement(elName);
-	el.innerText=msg;
-	el.style.color='green';
-}
-
-crfVisit.generateForm=
-function(data,queryName,mailRecipient){
-
-   let fName='[generateForm]';
-
-	this.print(fName+' recipient: '+mailRecipient);
-//	
-	const nData=data.rows.length;
-	this.print(fName+' Registration: '+nData+' rows');
-
-   let config=this.config;
-	let formRow=config.formConfig.generateForm[queryName];
-	let formCfg=config.formConfig.generateConfig[queryName];
-
-	//we have to generate masterQuery with parentCrf and crfRef 
-	//and crfEntry with new entryId and parentCrf equal to crfRef
-	if (nData>0) {
-		this.generateMessage(queryName,'Registration already generated.');
-		return;
-	}
-	let formId=formRow.Key;
-	let formName=formRow.formName;
-	let crfBase=config.formConfig.crfEntry;
-	let crfEntry=new Object();
-	//add new reference
-	crfEntry.entryId=Date.now();
-	crfEntry.parentCrf=this.getCRFref();
-	crfEntry["Date"]=new Date();
-	crfEntry["View"]="[VIEW]";
-
-	crfEntry.formStatus=1;//In progress
-   //checks for both field presence (if not in query, undefined) and field value (if not set, null)
-   this.print(fName+' setup status: '+formCfg.formStatus);
-   if (formCfg.formStatus){
-      crfEntry.formStatus=formCfg.formStatus;
-   }
-
-   //get local Id
-   let pM=this.getIdManager();
-   
-   crfEntry[participantIdManager.getCrfEntryFieldName(pM)]=participantIdManager.getParticipantIdFromCrfEntry(pM);
-//	//set other variables
-	//requires studyData as part of formConfig
-//	let studyData=config.formConfig.studyData;
-	this.print('Adding study: '+crfBase.EudraCTNumber);
-	crfEntry.EudraCTNumber=crfBase.EudraCTNumber;
-	crfEntry.StudyCoordinator=crfBase.StudyCoordinator;
-	crfEntry.StudySponsor=crfBase.StudySponsor;
-	crfEntry.RegulatoryNumber=crfBase.RegulatoryNumber;
-//
-//	//find sponsor for site
-	let site=crfBase.Site;
-	let crfSponsors=config.formConfig.crfSponsors;
-	let users=config.formConfig.userRows;
-	for (let i=0;i<crfSponsors.length;i++){
-		//this.print('Checking for site '+crfSponsors[i].Site);
-		if (crfSponsors[i].Site!=site) continue;
-		config.formConfig.sponsorId=crfSponsors[i].User;
-		//this.print('Setting id '+config.formConfig.sponsorId);
-		//finds first
-		break;
-	}
-	for (let j=0;j<users.length;j++){
-		if (config.formConfig.sponsorId!=users[j].UserId) continue;
-		config.formConfig.sponsor=users[j];
-		//finds first (should be unique)
-		break;
-	}
-	this.print('Selecting '+config.formConfig.sponsor.DisplayName+' as sponsor');
-	//different user than the original form...
-	//should be set to the study sponsor
-	crfEntry.UserId=config.formConfig.sponsor.UserId;
-	crfEntry.Site=site;
-//	//set formId to one found through registration search
-	crfEntry.Form=formId;
-////
-
-   let crfStatus=this.createCrfStatus(crfEntry);
-   crfStatus.operator=config.formConfig.operator;
-   crfStatus.action='generateForm';
-
-   let that=this;
-   let action=function(){that.doNothing();};
-	let cb=function(data){that.sendEmail(data,mailRecipient,action,formName+' generated');}
-   let containerPath=this.getContainer('data');
-   let pass=function(data){that.insertRows('lists','crfStatus',[crfStatus],cb,containerPath);};
-   this.insertRows('lists','crfEntry',[crfEntry],pass,this.getContainer('data'));
-
-}
-
-crfVisit.generateListEntry=
-function(formId,queryName,cb){
-
-	//check if registration was already generated
-   let config=this.config;
-
-	let formRows=config.formConfig.formRows;
-	let qForm=undefined;
-	for (let i=0;i<formRows.length;i++){
-		if (formRows[i].Key!=formId) continue;
-		qForm=formRows[i];
-	}
-	let nData=this.getQuerySnapshot(queryName).rows.length;
-
-   if (nData>0) return;
-
-
-   //create new list entry
-   let pM=this.getIdManager();
-   
-
-	let e2=new Object();
-	e2.crfRef=this.getCRFref();
-	e2.registrationStatus=0;
-	e2.submissionDate=new Date();
-   e2[participantIdManager.getCrfEntryFieldName(pM)]=participantIdManager.getParticipantIdFromCrfEntry(pM);
-	this.print('set values');
-
-   this.insertRows('lists',queryName,[e2],cb,this.getContainer('data'));
-
-}
-		
-// ******************** end form generator (Registration) ********************
-
-//jump to populate table/generate review, etc defined at the begining of the file
-
-//entry point from generateMasterForm
-crfVisit.setFormConfig=
-function(){
-   let fName="[setFormConfig]";
-   let config=this.config;
-
-	//add object to store form related data
-	config.formConfig=new Object();
-
-	config.formConfig.softwareVersion='T.15.68';
-
-	this.print(fName+" generateMasterForm");	
-	
-	//set containers for data and configuration
-
-	//TODO: set this from a query
-	//
-	
-	this.setContainer('data',LABKEY.ActionURL.getContainer());
-	this.setContainer('config',LABKEY.ActionURL.getContainer());
-	this.setContainer('CRF',LABKEY.ActionURL.getContainer());
-
-	//this is local data
-   let that=this;
-   let action=function(data){that.afterSettings(data);};
-   this.selectRows('lists','crfSettings',[],action,this.getContainer('CRF'));
-	//store form related data to this object
-
-}
-
-
-crfVisit.afterSettings=
-function(data){
-   let fName='[afterSettings]';
-   let config=this.config;
-   
-	config.formConfig.settings=variableList.convertToDictionary(data.rows);
-
-	let st=config.formConfig.settings;
-	this.print('afterSettings');
-	for (let k in st){
-		this.print(fName+'\t'+k+'='+st[k]);
-	}
-
-	//if ('dataContainer' in st){
-	//	setContainer('data',st['dataContainer']);
-	//}
-	let vname='configContainer';
-	if (vname in st){
-		this.setContainer('config',st[vname]);
-	}
-	this.print('Config: '+this.getContainer('config'));
-	this.print('Data: '+this.getContainer('data'));
-
-	//use first-> we must first establish link to the rigth crf entry
-	let filters=[LABKEY.Filter.create('entryId',this.getCRFrefFirst())];
-   let that=this;
-   let action=function(data){that.afterCRFEntry(data);};
-   this.selectRows('lists','crfEntry',filters,action,this.getContainer('data'));
-}
-
-crfVisit.afterCRFEntry=
-function(data){
-   let config=this.config;
-   let fName='[afterCRFEntry]';
-	config.formConfig.crfEntry=data.rows[0];
-	this.print("Setting crfEntry (x) to "+config.formConfig.crfEntry["entryId"]);
-	//for empty records or those with parentCrf not set, parentCrf comes up as null
-	//nevertheless, with two equal signs, check against undefined also works
-	this.print('parentCrf set to '+config.formConfig.crfEntry.parentCrf);
-	
-	this.collectData();
-}
-
-crfVisit.collectData=
-function(){
-   let config=this.config;	
-   let targetObject=config.formConfig;
-	let queryArray=new Array();
-   //k
-	//site
-	queryArray.push(runQuery.makeQuery(targetObject,'config','site','siteData',[]));
-	//users
-	queryArray.push(runQuery.makeQuery(targetObject,'CRF','users','userData',[]));
-	queryArray[queryArray.length-1].schemaName='core';
-	//crfEditors
-	queryArray.push(runQuery.makeQuery(targetObject,'config','crfEditors','crfEditorsData',[]));
-	//crfMonitors
-	queryArray.push(runQuery.makeQuery(targetObject,'config','crfMonitors','crfMonitorsData',[]));
-	//crfSponsors
-	queryArray.push(runQuery.makeQuery(targetObject,'config','crfSponsors','crfSponsorsData',[]));
-
-   //study static data
-   queryArray.push(
-      runQuery.makeQuery(targetObject,'data','crfStaticVariables','crfStaticVariables',[]));
-
-   queryArray.push(runQuery.makeQuery(targetObject,'data','specialFields','specialFieldsQuery',[]));
-	//study
-	queryArray.push(runQuery.makeQuery(targetObject,'data','Study','studyDataAll1',[]));
-	let e=queryArray[queryArray.length-1];
-	//overload schema name
-	e.schemaName='study';
-	//make sure variables not part of default view are loaded
-	//here we should already have read crfStaticVariables table
-	e.columns="SubjectColumnName,EudraCTNumber,StudySponsor";
-	e.columns+=",StudyCoordinator,RegulatoryNumber";
-	
-	//formStatus
-	let varLabel='sourceFormStatus';
-	let formStatus=config.formConfig.crfEntry['FormStatus'];
-	let formFilter=LABKEY.Filter.create('Key',formStatus);
-	queryArray.push(
-		runQuery.makeQuery(targetObject,'config','FormStatus','formStatusData',[formFilter]));
-	//crfButtons
-	let statusFilter=LABKEY.Filter.create(varLabel,formStatus);
-	queryArray.push(
-		runQuery.makeQuery(targetObject,'config','crfButtons','crfButtons',[statusFilter]));
-	//Forms	
-	queryArray.push(runQuery.makeQuery(targetObject,'config','Forms','formData',[]));
-	//FormSetup	
-	queryArray.push(runQuery.makeQuery(targetObject,'config','FormSetup','formSetup',[]));
-	//generateConfig
-	queryArray.push(
-		runQuery.makeQuery(targetObject,'config','generateConfig','generateConfigData',[]));	
-	
-   //inputLists 
-	queryArray.push(
-		runQuery.makeQuery(targetObject,'config','inputLists','inputLists',[]));	
-   //parentCrf
-	let parentCrf=config.formConfig.crfEntry['parentCrf'];
-	if (parentCrf!=undefined){
-		let crfFilter=LABKEY.Filter.create('entryId',parentCrf);
-		queryArray.push(runQuery.makeQuery(targetObject,'data','crfEntry','parentCrfData',[crfFilter]));	
-	}	
-
-	this.print('running getDataFromQueries');
-   let that=this;
-   //let action=function(data){that.doNothing();};
-   let action=function(){that.addStudyData();};
-	runQuery.getDataFromQueries(this,queryArray,action);
-}
-
-crfVisit.addStudyData=
-function(){
-   let fName='addStudyData';
-   let config=this.config;
-
-   //convert specialFields to array
-   let q=config.formConfig["specialFieldsQuery"].rows;
-   config.formConfig.specialFields=variableList.convertToAssociatedArray(q,"fieldUID");
-   this.print(fName);
-	let queryArray=new Array();
-	
-   let targetObject=config.formConfig;
-	//study
-	queryArray.push(runQuery.makeQuery(targetObject,'data','Study','studyDataAll',[]));
-	//queryArray.push(runQuery.makeQuery('data','Study','studyDataAll',[]));
-	let e=queryArray[queryArray.length-1];
-	//overload schema name
-	e.schemaName='study';
-	//make sure variables not part of default view are loaded
-	//here we should already have read crfStaticVariables table
-   let staticVarRows=config.formConfig['crfStaticVariables'].rows;
-   let columnModel=""
-   for (let i=0;i<staticVarRows.length;i++){
-      if (i>0) columnModel+=',';
-      columnModel+=staticVarRows[i]['staticVariable'];
-   }
-	e.columns=columnModel;
-
-   //also collect ids already in study
-   //registrationQuery should be a dataset
-   //since monitors can review late, it might be profitable to use lists
-   //rather than study
-   let regQueryPars=variableList.parseVariables(config.formConfig.settings['registrationQuery']);
-   let regQuery=regQueryPars['query'];
-   let regSchema='study';
-   if ('schema' in regQueryPars){
-      regSchema=regQueryPars['schema'];
-   }
-   queryArray.push(runQuery.makeQuery(targetObject,'data',regQuery,'registrationData',[]));
-   queryArray[queryArray.length-1].schemaName=regSchema;
-      
-	let that=this;
-   let action=function(){that.fcontinue();};
-	runQuery.getDataFromQueries(this,queryArray,action);
-
-}
-
-crfVisit.fcontinue=
-function(){
-
-   //debug
-   let fName='[fcontinue]';
-   let config=this.config;
-   let varRows=config.formConfig['crfStaticVariables'].rows;
-   let studyVars=config.formConfig['studyDataAll'].rows[0];
-   for (let i=0;i<varRows.length;i++){
-      let vName=varRows[i].staticVariable;
-      this.print(fName+' '+vName+': '+studyVars[vName]);
-   }
-
-	//parse site
-	config.formConfig.siteRows=config.formConfig.siteData.rows;
-	let sRows=config.formConfig.siteRows;
-	for (let i=0;i<sRows.length;i++){
-		let siteId=sRows[i].siteNumber;
-		this.print('site '+siteId);
-		if (siteId==config.formConfig.crfEntry.Site){
-			config.formConfig.currentSite=sRows[i];
-			break;
-		}
-	}
-	//config.formConfig.site=data.rows[0];
-	this.print("Setting site name to "+config.formConfig.currentSite.siteName);
-	//study
-	config.formConfig.studyData=config.formConfig.studyDataAll.rows[0];
-	this.print("XSetting participantField to "+
-			config.formConfig.studyData["SubjectColumnName"]);
-	
-	config.formConfig.crfEditors=config.formConfig.crfEditorsData.rows;
-	config.formConfig.crfMonitors=config.formConfig.crfMonitorsData.rows;
-	config.formConfig.crfSponsors=config.formConfig.crfSponsorsData.rows;
-
-	config.formConfig.userRows=config.formConfig.userData.rows;
-	let uRows=config.formConfig.userRows;
-	for (let i=0;i<uRows.length;i++){
-		let userId=uRows[i].UserId;
-		if (userId==config.formConfig.crfEntry.UserId){
-			config.formConfig.user=uRows[i];
-			break;
-		}
-	}
-	//config.formConfig.user=data.rows[0];
-	this.print("Setting user to "+config.formConfig.user["DisplayName"]);
-
-
-
-	let fsRows=config.formConfig.formStatusData.rows;
-	config.formConfig.formStatus=fsRows[0].formStatus;
-	config.formConfig.operator=config.role;
-	//config.formConfig.operator=fsRows[0].operator;
-
-	this.print('Setting operator to: '+config.formConfig.operator);
-	
-	config.formConfig.formRows=config.formConfig.formData.rows;
-
-   //point formId to point to form set in crfEntry
-   config.formConfig.formId=config.formConfig.crfEntry['Form'];
-
-   //old setting, set from URL in visit.html
-   let formId=config.formId;
-   //new setting, set from crfEntry
-   formId=config.formConfig.formId;
-
-	let formRows=config.formConfig.formRows;
-	//filter out the current form
-	for (let i=0;i<formRows.length;i++){
-		if (formRows[i].Key==formId){
-			config.formConfig.form=formRows[i];
-			break;
-		}
-	}
-	
-	config.formConfig.formSetupRows=this.selectFormSetupRows(formId);
-
-	this.print("Number of datasets for form ["+formId+"]: "+
-			config.formConfig.formSetupRows.length);
-
-
-
-	let fields=config.formConfig.formSetup.metaData.fields;
-
-	//get the lookup for queryName column
-	let formQueryName='queryName';
-	let field="NONE";
-	for (f in fields){
-		if (fields[f]['name']!=formQueryName) continue;
-		field=fields[f];
-		break;
-	}
-	let lookup=field.lookup;
-
-	this.print("Getting dataset names from "+lookup.queryName);
-
-	//inputLists should be in configuration container
-   let that=this;
-   let action=function(data){that.afterFormDatasets(data);};
-   //let action=function(data){that.doNothing();};
-
-   this.selectRows(lookup.schemaName,lookup.queryName,[],action,this.getContainer('config'));
-
-}
-
-crfVisit.afterFormDatasets=
-function(data){
-   let fName='[afterFormDatasets]';
-	this.print(fName+' nrows '+data.rows.length);
-   let config=this.config;
-	config.formConfig.formDatasets=data;//inputLists
-	config.formConfig.fields=new Object();
-	config.formConfig.queryMap=new Object();
-	config.formConfig.additionalData=new Object();
-
-	let rows=config.formConfig.formSetupRows;
-
-	//should skip report only rows
-	for (let i=0;i<rows.length;i++){
-		let entry=rows[i];
-		let reviewField=(entry['showFlag']=='REVIEW');
-		//is the operator set yet?
-		let accessMode=config.formConfig.operator+'Mode';
-		let skipField=(entry[accessMode]=="NONE");
-		let queryId=entry['queryName'];
-		let lookupRows=config.formConfig.formDatasets.rows;
-		this.print('QueryID['+i+']='+queryId);
-		let dentry;
-
-		for (let j=0;j<lookupRows.length;j++){
-	
-			if (queryId!=lookupRows[j]['Key']) continue;
-			dentry=lookupRows[j];
-			break;
-		}
-		let qName=dentry['queryName'];
-
-		//update list of dataset formConfig is observing (fields/queryMap)
-		while (1){
-			//review contains no data
-			if (reviewField) break;
-			if (skipField) break;
-			//already in fields
-			if (qName in config.formConfig.fields) break;
-			config.formConfig.fields[qName]=new Object();
-			break;
-		}
-
-		while(1){
-			//already done
-			if (queryId in config.formConfig.queryMap) break;
-			config.formConfig.queryMap[queryId]=qName;
-			break;
-		}
-		if (reviewField) continue;
-		if (skipField) continue;
-		//only do this for real lists
-		let field=config.formConfig.fields[qName];
-		field.title=entry['title'];
-		field.queryId=queryId;
-
-	}
-	this.print("List of datasets in form : ");
-	for (f in config.formConfig.fields){
-		let field=config.formConfig.fields[f];
-		this.print("\t"+f+" ID: "+field.queryId+' title '+field.title);
-	}
-	this.afterConfig();
-
-}
-
-//>>>>>>>>>>>>>>>>>new>>>>>>>>>>>>
-crfVisit.setDataLayout=
-function(cb){
-   let fName='[setDataLayout]';
-   let config=this.config;
-   this.print(fName);
-	let rowsSetup=config.formConfig.formSetupRows;
-   let queryArray=new Array();
-	let dS=this.getLayoutObject();//reference only
-   let qList=this.getQueryList();
-	let qMap=config.formConfig.queryMap;
-	//config.formConfig.lookup=new Object();
-	for (let i=0;i<rowsSetup.length;i++){
-		let entry=rowsSetup[i];
-		//skip review rows
-		if (entry['showFlag']=='REVIEW')
-			continue;
-		let queryId=entry['queryName'];
-		let q=qMap[queryId];
-		queryArray.push(runQuery.makeQuery(dS,'data',q,q,[]));
-      qList[q]=0;
-      this.print(fName+' adding '+q);
-		if (entry['showQuery']!="NONE"){
-			let sq=entry['showQuery'];
-		   queryArray.push(runQuery.makeQuery(dS,'data',sq,sq,[]));
-         qList[sq]=0;
-         this.print(fName+' adding '+sq);
-			
-		}
-	}
-
-	//always add reviews
-   let q='reviewComments';
-   queryArray.push(runQuery.makeQuery(dS,'data',q,q,[]));
-   qList[q]=0;
-   let that=this;
-   let action=function(){that.processLayout(cb);};
-   runQuery.getDataFromQueries(this,queryArray,action);
-}
-
-//this happens after the for loop, so all dataQueries objects are set
-crfVisit.processLayout=
-function(cb){
-   let fName='[processLayout]';
-   let qList=this.getQueryList();
-   //for layouts
-   let queryArray=new Array();
-   let targetObject=this.getLookupObject();
-   let lookupSet=new Object();
-   for (let q in qList){
-      let qobject=this.getQueryLayout(q);
-	   this.print(fName+" inspecting layout for "+q+" "+qobject);
-	   qobject.fields=qobject.metaData.fields;
-	   qobject.title=this.findTitle(q);
-
-      //check for lookups
-	   for (let f in qobject.fields){
-		   //anything else is simple but lookup
-		   let field=qobject.fields[f];
-		   if (!("lookup" in field)) continue;
-         let lookup=field.lookup;
-         let qObject=this.getLookup(lookup.queryName);
-         if (qObject) continue;
-         //add to list
-         let qName=lookup.queryName;
-         let qCode=qName+':'+lookup.keyColumn+':'+lookup.displayColumn;
-         let e=runQuery.makeQuery(targetObject,'data',qName,qCode,[]);
-         //adjust minor settings
-         if (lookup.containerPath) e.containerPath=lookup.containerPath;
-         e.schemaName=lookup.schemaName;
-         e.columns=lookup.keyColumn+','+lookup.displayColumn;
-         lookupSet[qCode]=e;
-         this.print(fName+' inserting '+qCode);
-      }
-   }
-   for (let x in lookupSet){
-      queryArray.push(lookupSet[x]);
-      this.print(fName+' adding '+x);
-      for (let v in lookupSet[x]){
-         this.print(fName+' value ['+v+'] '+lookupSet[x][v]);
-      }
-   }
-   //this.print(fName+' print '+targetObject.print);
-   let that=this;
-   let action=function(){that.processLookup(cb);};
-   this.print(fName+' getDataFromQueries');
-   runQuery.getDataFromQueries(this,queryArray,action);
-   this.print(fName+' getDataFromQueries done');
-}
-
-crfVisit.processLookup=
-function(cb){
-   let fName="[processLookup]";
-
-   let obj=this.getLookupObject();
-   for (let q in obj){
-	   this.print(fName+" "+q);
-      let a=q.split(':');
-      if (a.length<3) continue;
-      let lookupName=a[0];
-      let key=a[1];
-      let val=a[2];
-      obj[lookupName]=new Object();
-      this.print(fName+' adding ['+lookupName+'] '+key+'/'+val);
-      let lObject=obj[lookupName];
-
-	   lObject.LUT=new Array();//key to value
-	   lObject.ValToKey=new Array();//value to key
-	   lObject.keyColumn=key
-	   lObject.displayColumn=val;
-      
-      let qRows=obj[q].rows;
-	   for (let i=0;i<qRows.length;i++){
-         let r=qRows[i];
-         this.print(fName+' LUT ['+r[key]+'] '+r[val]);
-		   lObject.LUT[r[key]]=r[val];
-		   lObject.ValToKey[r[val]]=r[key];
-	   }
-   }
-	cb();
-}
-
-crfVisit.setData=
-function(cb){
-	fName='[setData]';
-	let crfMatch=this.getCRFref();
-   let config=this.config;
-	let parentCrf=config.formConfig.crfEntry['parentCrf'];
-	if (parentCrf!=undefined) crfMatch=parentCrf;
-
-	this.print(fName+' form crf ['+this.getCRFref()+'] matching for crfRef='+crfMatch);
-
-   let queryArray=new Array();
-   let targetObject=this.getSnapshotObject();
-	//collect data and execute callback cb for queries in cb.queryList
-   let qList=this.getQueryList();
-	for (q in qList){
-
-		let filters=[LABKEY.Filter.create("crfRef",crfMatch)];
-      queryArray.push(runQuery.makeQuery(targetObject,'data',q,q,filters));
-
-	}
-   runQuery.getDataFromQueries(this,queryArray,cb);
-}
-
-crfVisit.uploadFile=
-function(inputElement,context){
-	//context should have ID and dirName attributes; 
-	//path will be dirName/ID/fieldName_ID.suf
-	//where suf is identical to localPath content picked from
-	//inputElement
-	this.print('uploadFile: '+inputElement.value+'/');
-	if (inputElement.type=="text") return;
-	this.print('uploadFile: '+inputElement.files+'/');
-	this.print('uploadFile: '+inputElement.files.length+'/');
-	if (inputElement.files.length>0){
-		let file=inputElement.files[0];
-		this.print('uploadFile: '+inputElement.value+'/'+file.size);
-      webdav.uploadFile(file,context);
-   }
-}
-
-crfVisit.printForm=
-function(){
-   crfPrint.printForm();
-}