소스 검색

(1) Adding crfStaticVariables that are displayed at the top of the form as labkey list, (2) adding variableDetails list to provide long descriptions of variables and (3) adding first approximation of a form generalized participantId entry, which is not used in upload of the data

Andrej Studen 2 년 전
부모
커밋
953b80f3ee
3개의 변경된 파일430개의 추가작업 그리고 113개의 파일을 삭제
  1. 1 0
      views/visit.view.xml
  2. 182 113
      web/crf/crfVisit.js
  3. 247 0
      web/crf/participantIdManager.js

+ 1 - 0
views/visit.view.xml

@@ -1,6 +1,7 @@
 <view xmlns="http://labkey.org/data/xml/view" title="CRF Form">
 	<dependencies>
       <dependency path="crf/runQuery.js"/>
+      <dependency path="crf/participantIdManager.js"/>
       <dependency path="crf/crfVisit.js"/>
 		<dependency path="crf/crfReview.js"/>
 		<!--local copy of pdfkit, version 0.10.0-->

+ 182 - 113
web/crf/crfVisit.js

@@ -18,78 +18,6 @@ function print(msg){
 	el.value+="\n"+msg;
 }
 
-function makeQuery(containerName,queryName,fieldName,filterArray){
-	let e=new Object();
-	e.containerName=containerName;
-	e.queryName=queryName;
-	e.fieldName=fieldName;
-	e.filterArray=filterArray;
-	return e;
-}
-
-function getDataFromQueries(queryArray,cb){
-	//queryArray should contain elements with
-	//- fieldName to set the data variable
-	//- containerName to select container (data,config,CRF)
-	//- queryName to select query
-	//- filterArray to perform filtering, empty array works
-	//- callback cb to be called with no arguments
-	//
-	afterQuery(new Object(),-1,queryArray,cb);
-}
-
-function afterQuery(data,id,queryArray,cb){
-	//queryArray should contain elements with
-	//- fieldName to set the data variable
-	//- containerName to select container (data,config,CRF)
-	//- queryName to select query
-	//- filterArray to perform filtering, empty array works
-	//- callback cb to be called with no arguments
-	//
-	//it should be called with id -1.
-	//
-	print('afterQuery['+id+']: ');
-
-	if (id>-1){
-		let fieldName=queryArray[id].fieldName;
-		print('afterQuery['+fieldName+']: '+data.rows.length);
-		config.formConfig[fieldName]=data;
-	}
-	id+=1;
-	if (id==queryArray.length) {
-		cb();
-		return;
-	}
-
-
-	let e=queryArray[id];
-	let qconfig=new Object();
-	qconfig.containerPath=getContainer(e.containerName);
-	qconfig.schemaName="lists";
-	if ("schemaName" in e){
-		print('afterQuery: schemaName='+e.schemaName);
-		qconfig.schemaName=e.schemaName;
-	}
-
-	if ("columns" in e){
-		print('afterQuery: columns='+e.columns);
-		qconfig.columns=e.columns;
-	}
-	qconfig.queryName=e.queryName;
-	//this should point to configuration container
-	//don't filter -> so we can pick up other forms (say registration) later on
-	//qconfig.filterArray=[LABKEY.Filter.create('Key',config.formId)];
-	if ("filterArray" in e)
-		qconfig.filterArray=e.filterArray;
-	
-	//qconfig.filterArray=[LABKEY.Filter.create('formStatus',1)]
-	qconfig.success=function(data){afterQuery(data,id,queryArray,cb);};
-	qconfig.failure=doNothing;
-	LABKEY.Query.selectRows(qconfig);
-
-}
-
-
 function getCRFrefFirst(){
 	//crfRef is part of html call and gets stored in the page
 	return config.document.getElementById(config.crfRefId).innerHTML;
@@ -173,40 +101,60 @@ function generateDebugSection(){
 
 
 function getAdditionalData(formSetupEntry){
+   //return information on additional data associated with the form
+   //additionalData is a sub-list with multiple entries per patient/visit
+   
 
+   //argument is the row of the formSetup setup list
 	let queryName=config.formConfig.queryMap[formSetupEntry['queryName']];
 	let fName='[getAdditionalData/'+queryName+']';
 	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){
 		print(fName+': Returning preset value');
 		return config.formConfig.additionalData[queryName];
 	}
+
+   //first time we see this query, so we have to do the setup
 	print(fName+': generating');
 	config.formConfig.additionalData[queryName]=new Object();
-	//takes address, so further changes will be to the newly created 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") {
 		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
 		print(fName+": generateReport");
 		ad.isReview=true;
 		return ad;
 	}
+
+   //setup the additionalData memory object
 	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']=getCRFref();
+
+   //compose a long debug message
 	let msg=fName+": flag "+ad.showFlag;
 	msg+=" value "+ad.showFlagValue;
 	msg+=" query "+ad.queryName;
 	print(msg);
+
 	return ad;	
 }
 
@@ -260,12 +208,7 @@ function getSetup(listName,writeAccess=true){
 	//	return readonlySetup(listName);
 	return fullAccessSetup(listName);
 }
-	
-//afterFormConfig replaced by afterFormSetup
-
-//afterFormSetupLookup replaced by afterFormDatasets
 
-//function generateSection(listName, sectionTitle, accessMode, additionalData){
 function generateSection(formSetupEntry){
 
 	let listName=config.formConfig.queryMap[formSetupEntry['queryName']];
@@ -1055,19 +998,36 @@ function addFieldRow(tb,field,setup,additionalData){
 	let vType=field.type;
 	let isLookup=("lookup" in field);
 	print(fName+": ["+vName+"/"+vType+'/'+isLookup+"]");
+
+   let detailsRow=config.formConfig['variableDetails'].rows;
+   let details=undefined;
+   for (let i=0;i<detailsRow.length;i++){
+      if (detailsRow[i]['variableName']==field.name){
+         print(fName+": ["+vName+"]: details "+detailsRow[i].description);
+         details=detailsRow[i].description;
+         break;
+      }
+   }
 	
 	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 cell1=row.insertCell();
 		
 	
 	let input=null;
-	cell1.colSpan="3";
-
+   let colSpan="3";
+   if (details!=undefined){
+      let cell2=row.insertCell();
+      cell2.colSpan="2";
+      cell2.innerText=details;
+      colSpan="1";
+   }
+	let cell1=row.insertCell();
+	cell1.colSpan=colSpan;
 	let readonlyFlag=setup.readonlyFlag(vName);
 
 
@@ -2421,22 +2381,54 @@ function generateMasterForm(){
 //(fields defined in html file)
 function populateBasicData(){
 
-	config.document.getElementById('version').innerText=config.formConfig.softwareVersion;	
-	config.document.getElementById('eudraCTNumber').innerText=
-		config.formConfig.crfEntry.EudraCTNumber;
-	config.document.getElementById('studyCoordinator').innerText=
-		config.formConfig.crfEntry.StudyCoordinator;
-	config.document.getElementById('studySponsor').innerText=
-		config.formConfig.crfEntry.StudySponsor;
-	config.document.getElementById('siteName').innerText=
-		config.formConfig.currentSite['siteName'];
-	config.document.getElementById('sitePhone').innerText=
-		config.formConfig.currentSite['sitePhone'];
-	config.document.getElementById('investigatorName').innerText=
-		config.formConfig.user['DisplayName'];
+   let staticData=new Object();
+   let titles=new Object();
+   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){
+      addStaticData(f,titles[f],staticData[f]);
+   }
+}
+
+function addStaticData(f,title,value){
+   let el=config.document.getElementById(f);
+
+   //populate only
+   if (el!=undefined){
+      el.innerText=value;
+      return;
+   }
+   
+   //add row to table if element cannot be found
+   let table=config.document.getElementById('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
 //
 function generateErrorMsg(msg){
@@ -2581,6 +2573,24 @@ function afterData(){
 	//operatorBasedAccessMode	
 	let accessMode=config.formConfig.operator+'Mode';
 	let rowsSetup=config.formConfig.formSetupRows;
+
+   print(fName+': '+'generatePariticpantEntry');
+   //generateParticipantEntryField();
+   //add print to config so participantManager can use it
+   config.print=print;
+   let pM=getParticipantManagerObject(config);
+
+   print(fName+': pariticpantManager: '+pM);
+   //check if ParticipantId is set in crfEntry
+   let pId=config.formConfig.crfEntry['ParticipantId'];
+   print(fName+' pId '+pId);
+   if (!pId){ 
+      pM.setParticipantManagerToEditMode();
+   }
+   else{
+      pM.setParticipantManagerToLabelMode(pId,'Record');
+   }
+
 	for (let i=0;i<rowsSetup.length;i++){
 		let entry=rowsSetup[i];
 		let queryName=config.formConfig.queryMap[entry['queryName']];
@@ -2602,6 +2612,7 @@ function afterData(){
 		//let additionalData=new Object();
 		//setAdditionalData(additionalData,entry);
 		//section fits one dataset/list
+      
 		generateSection(entry);
 		//generateSection(queryName,entry["title"],entry[accessMode], 
 		//		additionalData);
@@ -2928,7 +2939,7 @@ function setFormConfig(){
 	//add object to store form related data
 	config.formConfig=new Object();
 
-	config.formConfig.softwareVersion='0.14.18';
+	config.formConfig.softwareVersion='0.15.08';
 	let debug=true;
 
 	if (debug)
@@ -3004,50 +3015,98 @@ function afterCRFEntry(data){
 }
 
 function collectData(){
-
-	let varLabel='sourceFormStatus';
-	let formStatus=config.formConfig.crfEntry['FormStatus'];
-
+	
+   let targetObject=config.formConfig;
+   targetObject.print=print;
+   targetObject.getContainer=getContainer;
 	let queryArray=new Array();
+   //k
 	//site
-	queryArray.push(makeQuery('config','site','siteData',[]));
+	queryArray.push(makeQuery(targetObject,'config','site','siteData',[]));
 	//users
-	queryArray.push(makeQuery('CRF','users','userData',[]));
+	queryArray.push(makeQuery(targetObject,'CRF','users','userData',[]));
 	queryArray[queryArray.length-1].schemaName='core';
 	//crfEditors
-	queryArray.push(makeQuery('config','crfEditors','crfEditorsData',[]));
+	queryArray.push(makeQuery(targetObject,'config','crfEditors','crfEditorsData',[]));
 	//crfMonitors
-	queryArray.push(makeQuery('config','crfMonitors','crfMonitorsData',[]));
+	queryArray.push(makeQuery(targetObject,'config','crfMonitors','crfMonitorsData',[]));
 	//crfSponsors
-	queryArray.push(makeQuery('config','crfSponsors','crfSponsorsData',[]));
+	queryArray.push(makeQuery(targetObject,'config','crfSponsors','crfSponsorsData',[]));
+
+   //study static data
+   queryArray.push(
+      makeQuery(targetObject,'data','crfStaticVariables','crfStaticVariables',[]));
+
+   queryArray.push(makeQuery(targetObject,'data','variableDetails','variableDetails',[]));
 	//study
-	queryArray.push(makeQuery('data','Study','studyDataAll',[]));
+	queryArray.push(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(makeQuery('config','FormStatus','formStatusData',[formFilter]));
+	queryArray.push(
+		makeQuery(targetObject,'config','FormStatus','formStatusData',[formFilter]));
 	//crfButtons
 	let statusFilter=LABKEY.Filter.create(varLabel,formStatus);
-	queryArray.push(makeQuery('config','crfButtons','crfButtons',[statusFilter]));
+	queryArray.push(
+		makeQuery(targetObject,'config','crfButtons','crfButtons',[statusFilter]));
 	//Forms	
-	queryArray.push(makeQuery('config','Forms','formData',[]));
+	queryArray.push(makeQuery(targetObject,'config','Forms','formData',[]));
 	//FormSetup	
-	queryArray.push(makeQuery('config','FormSetup','formSetup',[]));
+	queryArray.push(makeQuery(targetObject,'config','FormSetup','formSetup',[]));
 	//generateConfig
-	queryArray.push(makeQuery('config','generateConfig','generateConfigData',[]));	
+	queryArray.push(
+		makeQuery(targetObject,'config','generateConfig','generateConfigData',[]));	
 	//parentCrf
 	let parentCrf=config.formConfig.crfEntry['parentCrf'];
 	if (parentCrf!=undefined){
 		let crfFilter=LABKEY.Filter.create('entryId',parentCrf);
-		queryArray.push(makeQuery('data','crfEntry','parentCrfData',[crfFilter]));	
+		queryArray.push(makeQuery(targetObject,'data','crfEntry','parentCrfData',[crfFilter]));	
 	}	
 
 	print('running getDataFromQueries');
+	getDataFromQueries(queryArray,addStudyData);
+}
+
+function addStudyData(){
+	let queryArray=new Array();
+	
+   let targetObject=config.formConfig;
+   targetObject.print=print;
+   targetObject.getContainer=getContainer;
+	//study
+	queryArray.push(makeQuery(targetObject,'data','Study','studyDataAll',[]));
+	//queryArray.push(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
+   let demoQuery=config.formConfig.settings['demographicQuery'];
+
+   queryArray.push(makeQuery(targetObject,'data',demoQuery,'demographicData',[]));
+   queryArray[queryArray.length-1].schemaName='study';
+      
+	
 	getDataFromQueries(queryArray,fcontinue);
+
 }
 
 function selectFormSetupRows(formId){
@@ -3062,6 +3121,16 @@ function selectFormSetupRows(formId){
 }
 
 function fcontinue(){
+
+   //debug
+   let fName='[fcontinue]';
+   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;
+      print(fName+' '+vName+': '+studyVars[vName]);
+   }
+
 	//parse site
 	config.formConfig.siteRows=config.formConfig.siteData.rows;
 	let sRows=config.formConfig.siteRows;
@@ -3363,7 +3432,7 @@ function dataLayoutSet(){
 
 function setData(cb){
 	fName='[setData]';
-	print(fName+': cb '+cb);	
+	//print(fName+': cb '+cb);	
 	let crfMatch=getCRFref();
 	let parentCrf=config.formConfig.crfEntry['parentCrf'];
 	if (parentCrf!=undefined) crfMatch=parentCrf;

+ 247 - 0
web/crf/participantIdManager.js

@@ -0,0 +1,247 @@
+//all functions are based off of participantManager (print, config, etc.)
+
+function addSelectOptions(){
+   let pM=this;
+   let input=pM.inputSelector;
+   let config=pM.config;
+
+   let fName='addParticipantSelectOptions';
+   pM.print(fName);
+   let opt=config.document.createElement("option");
+   opt.value=-1;
+
+   opt.text="<Select>";
+   input.options[input.options.length]=opt;
+
+   let opt1=config.document.createElement("option");
+   opt1.value=0;
+   opt1.text="New";
+   input.options[input.options.length]=opt1;
+
+   let demoRows=config.formConfig['demographicData'].rows;
+   pM.print(fName+" demoRows: "+demoRows.length);
+   for (let i=0;i<demoRows.length;i++){
+      let opt2=config.document.createElement("option");
+      opt2.value=i+1;
+      opt2.text=demoRows[i][pM.participantField];
+      input.options[input.options.length]=opt2;
+      pM.print(fName+' '+pM.participantField+' '+demoRows[i][pM.participantField]);
+   }
+
+   input.selectedIndex=0;
+}
+
+function updateElements(){
+   let pM=this;
+   //reset all values (some might be different depending on the call timing)
+   pM.cellSelector=config.document.getElementById(pM.cellSelectorId);
+   pM.inputSelector=config.document.getElementById(pM.inputSelectorId);
+   pM.textSelector=config.document.getElementById(pM.textSelectorId);
+   pM.cellValue=config.document.getElementById(pM.cellValueId);
+   pM.inputValue=config.document.getElementById(pM.inputValueId);
+   pM.textValue=config.document.getElementById(pM.textValueId);
+   
+   pM.inputManage=config.document.getElementById(pM.inputManageId);
+}
+
+function generateEntryField(){
+   let pM=this;
+   let fName='[generateParticipantEntryField]:';
+   pM.print(fName);
+
+   //this is HTML designator of area on page
+   let config=pM.config;
+	let formName=config.masterForm;
+
+    
+   pM.tb=config.document.createElement('table');
+   let tb=pM.tb;
+	tb.className='t2';
+	let row=tb.insertRow();
+	
+   //header
+   let cell=config.document.createElement('th');
+	row.appendChild(cell);	
+	cell.setAttribute("colspan","1");
+	cell.style.fontSize="20px";
+	cell.style.textAlign="left";
+   //Use study coding for participant field
+	cell.innerText=pM.participantField;
+
+
+   //selector
+   let cellSelector=row.insertCell();
+   cellSelector.id=pM.cellSelectorId;
+
+
+   //value
+   let cellValue=row.insertCell();
+   cellValue.id=pM.cellValueId;
+
+   //manage
+   let cellManage=row.insertCell();
+   let inputManage=config.document.createElement("input");
+   inputManage.type="button";
+   //initially in set mode
+   inputManage.onclick=function(){pM.manageParticipantId();};
+   inputManage.id=pM.inputManageId;
+   cellManage.appendChild(inputManage);
+
+   config.document.getElementById(formName).appendChild(tb);
+
+}
+
+//callback
+function manageParticipantId(){
+   let pM=this;
+   let fName='[manageParticipantId]';
+   pM.print(fName);
+   //this can happen after object was created, so make sure current
+   //elements are used
+   pM.updateElements();
+   if (pM.inputManage.value=="Set"){
+      pM.setParticipantId();
+      return;
+   }
+   if (pM.inputManage.value=="Edit"){
+      pM.editParticipantId();
+      return;
+   }
+}
+
+//set mode
+function setParticipantId(){
+   let pM=this;
+   let fName='[setParticipantId]';
+   pM.print(fName);
+   //update to current elements
+   pM.print(fName+" select value: "+pM.inputSelector.value+" value: "+pM.inputValue.value);
+   if (pM.inputSelector.value<0) return;
+   let pId=pM.inputValue.value;
+   let opt=pM.inputSelector.options[pM.inputSelector.selectedIndex];
+   if (pM.inputSelector.value>0)
+      pId=opt.text;
+
+   pM.print(fName+" new value "+pId);
+   pM.setParticipantManagerToLabelMode(pId,opt.text);
+}
+
+function setParticipantManagerToLabelMode(pId,optText){
+   let pM=this;
+   let config=pM.config;
+   //set crfEntry and upload it to labkey
+   let textValue=config.document.createElement("p");
+   textValue.innerText=pId;
+   textValue.id=pM.textValueId;
+   if (pM.inputValue!=undefined)
+      pM.cellValue.replaceChild(textValue,pM.inputValue);
+   else
+      pM.cellValue.appendChild(textValue);
+
+   
+   let textSelector=config.document.createElement("p");
+   textSelector.innerText=optText;
+   textSelector.id=pM.textSelectorId;
+   if (pM.inputSelector!=undefined)
+      pM.cellSelector.replaceChild(textSelector,pM.inputSelector);
+   else
+      pM.cellSelector.appendChild(textSelector);
+
+   //addStaticData(participantField,participantField,pid);
+
+   pM.inputManage.value="Edit";
+}
+
+function editParticipantId(){
+   let pM=this;
+   pM.setParticipantManagerToEditMode();
+}
+
+function setParticipantManagerToEditMode(){
+   let pM=this;
+   let config=pM.config;
+
+   let fName='[setParticipantManagerToEditMode]';
+   pM.print(fName);
+   //input
+   let inputValue=config.document.createElement("input");
+   inputValue.id=pM.inputValueId;
+   pM.print(fName+" value old "+pM.textValue+" new "+inputValue);
+   if (pM.textValue!=undefined)
+      pM.cellValue.replaceChild(inputValue,pM.textValue);
+   else
+      pM.cellValue.appendChild(inputValue);
+
+   //select
+   let inputSelector = config.document.createElement("select");
+   inputSelector.id=pM.inputSelectorId;
+   pM.inputSelector=inputSelector;
+   pM.addSelectOptions();
+   pM.print(fName+" select old "+pM.textSelector+" new "+inputSelector);
+   if (pM.textSelector!=undefined)
+      pM.cellSelector.replaceChild(inputSelector,pM.textSelector);
+   else
+      pM.cellSelector.appendChild(inputSelector);
+
+   pM.inputManage.value="Set";
+
+}
+
+function getParticipantField(config){
+   return config.formConfig['studyDataAll'].rows[0]['SubjectColumnName'];
+}
+
+function getParticipantId(){
+   let pM=this;
+   //let participantField=config.formConfig['studyDataAll'].rows[0]['SubjectColumnName'];
+   return pM.textValue.innerText;
+}
+
+
+
+//main interface. Use this to generate object and to refer to it later on
+function getParticipantManagerObject(config){
+
+   let fName='[getParticipantManagerObject]';
+
+   if ("participantManager" in config) {
+      let pM=config.participantManager;
+      pM.updateElements();
+      return pM;
+   }
+
+   let pM=new Object();
+   //circular reference to traverse pM up and down
+   config.participantManager=pM;
+   pM.config=config;
+   //config should have a print routine
+   pM.print=config.print;
+
+   //this never change
+   pM.participantField=getParticipantField(config);
+
+
+   pM.cellSelectorId=pM.participantField+"_cellSelect";
+   pM.inputSelectorId=pM.participantField+"_Select";
+   pM.textSelectorId=pM.participantField+"_textSelect";
+
+   pM.cellValueId=pM.participantField+"_cellValue";
+   pM.inputValueId=pM.participantField+"_Value";
+   pM.textValueId=pM.participantField+"_textValue";
+
+   pM.inputManageId=pM.participantField+"_Manage";
+   //add methods
+   pM.updateElements=updateElements;
+   pM.addSelectOptions=addSelectOptions;
+   pM.generateEntryField=generateEntryField;
+   pM.manageParticipantId=manageParticipantId;
+   pM.setParticipantId=setParticipantId;
+   pM.editParticipantId=editParticipantId;
+   pM.setParticipantManagerToLabelMode=setParticipantManagerToLabelMode;
+   pM.setParticipantManagerToEditMode=setParticipantManagerToEditMode;
+   pM.getParticipantId=getParticipantId;
+
+   pM.generateEntryField();
+   pM.updateElements();
+   return pM;
+}