crfVisit.js 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312
  1. var crfVisit={};
  2. crfVisit.config=new Object();
  3. crfVisit.setDebug=
  4. function(debug=null){
  5. if (debug){
  6. this.print=function(msg){debug.this.print(msg);};
  7. this.clear=function(){debug.clear();}
  8. return;
  9. }
  10. //provide default functions if not debug object is available
  11. this.print=function(msg){console.log(msg);}
  12. this.clear=function(){;}
  13. }
  14. crfVisit.setDebug();
  15. //harmonize signature
  16. //(schema,query,row,action=cvDoNothing,container=null
  17. crfVisit.insertRows=
  18. function(schema,query,rows,action=null,container=null,failure=null){
  19. this.modifyRows('insert',schema,query,rows,action,container);
  20. }
  21. crfVisit.deleteRows=
  22. function(schema,query,rows,action=null,container=null,failure=null){
  23. this.modifyRows('delete',schema,query,rows,action,container);
  24. }
  25. crfVisit.modifyRows=
  26. function(mode,schema,query,rows,action=null,container=null,failure=null){
  27. //insert rows to container/schema/query and return with action
  28. let fName="[cvModifyRows/"+mode+"]";
  29. this.print(fName+' '+schema+'/'+query);
  30. let qconfig=new Object();
  31. qconfig.schemaName=schema;
  32. qconfig.queryName=query;
  33. if (container) qconfig.containerPath=container;
  34. if (!rows) {
  35. this.print(fName+' rows '+rows);
  36. return;
  37. }
  38. qconfig.rows=rows;
  39. qconfig.success=function(data){;};
  40. if (action) qconfig.success=action;
  41. if (mode=='insert') LABKEY.Query.insertRows(qconfig);
  42. if (mode=='update') LABKEY.Query.updateRows(qconfig);
  43. if (mode=='delete') LABKEY.Query.deleteRows(qconfig);
  44. this.print(fName+" done");
  45. }
  46. crfVisit.selectRows=
  47. function(schema,query,filters=[],action=null, container=null, failure=null, columns=null){
  48. let fName="[cvSelectRows]";
  49. this.print(fName+' '+schema+' '+query+' '+container);
  50. let qconfig=new Object();
  51. qconfig.schemaName=schema;
  52. qconfig.queryName=query;
  53. if (container) qconfig.containerPath=container;
  54. qconfig.filterArray=filters;
  55. qconfig.success=function(data){;};
  56. if (action) qconfig.success=action;
  57. if (failure) qconfig.failure=failure;
  58. if (columns) qconfig.columns=columns;
  59. LABKEY.Query.selectRows(qconfig);
  60. this.print(fName+" done");
  61. }
  62. crfVisit.createCrfStatus=
  63. function(crfEntry){
  64. let crfStatus=new Object();
  65. crfStatus.entryId=crfEntry.entryId;
  66. crfStatus.submissionDate=new Date();
  67. crfStatus.FormStatus=crfEntry.FormStatus;
  68. crfStatus.User=crfEntry.UserId;
  69. crfStatus.Form=crfEntry.Form;
  70. return crfStatus;
  71. }
  72. crfVisit.init=
  73. function(cb=null){
  74. let that=this;
  75. let action=function(){that.scriptsLoaded(cb);};
  76. LABKEY.Utils.requiresScript(["crfTecant/runQuery.js","crfTecant/crfReviewSection.js","crfTecant/participantIdManager.js","crfTecant/variableList.js","crfTecant/webdav.js","crfTecant/crfPrint.js"],action);
  77. }
  78. crfVisit.scriptsLoaded=
  79. function(cb=null){
  80. participantIdManager.set(this);
  81. webdav.set(this);
  82. crfReviewSection.set(this);
  83. crfPrint.set(this);
  84. if (cb) cb();
  85. }
  86. crfVisit.getElement=
  87. function(id){
  88. return this.config.document.getElementById(id);
  89. }
  90. crfVisit.setContainer=
  91. function(label,container){
  92. let config=this.config;
  93. if (!(config.formConfig.hasOwnProperty('container'))){
  94. config.formConfig.container=new Array();
  95. }
  96. config.formConfig.container[label]=container;
  97. }
  98. crfVisit.getContainer=
  99. function(label){
  100. return this.config.formConfig.container[label];
  101. }
  102. crfVisit.getCRFrefFirst=
  103. function(){
  104. //crfRef is part of html call and gets stored in the page
  105. return this.getElement(this.config.crfRefId).innerHTML;
  106. }
  107. crfVisit.getCRFref=
  108. function (){
  109. //'crfRefId'
  110. return this.config.formConfig.crfEntry['entryId'];
  111. }
  112. crfVisit.getCRFrefData=
  113. function(){
  114. let parentCrf=this.config.formConfig.crfEntry['parentCrf'];
  115. if (parentCrf!=undefined) return parentCrf;
  116. return this.getCRFref();
  117. }
  118. crfVisit.onFailure=
  119. function(errorInfo, options, responseObj){
  120. if (errorInfo && errorInfo.exception)
  121. alert("Failure: " + errorInfo.exception);
  122. else
  123. alert("Failure: " + responseObj.statusText);
  124. }
  125. crfVisit.doNothing=
  126. function (){
  127. this.print('doNothing called');
  128. }
  129. crfVisit.getSnapshotObject=
  130. function(){
  131. if (!("dataQueriesSnapshot" in this.config.formConfig))
  132. this.config.formConfig.dataQueriesSnapshot=new Object();
  133. return this.config.formConfig.dataQueriesSnapshot;
  134. }
  135. crfVisit.getQuerySnapshot=
  136. function(queryName){
  137. //check whether queryName is in snapshotObject?
  138. return this.getSnapshotObject()[queryName];
  139. }
  140. crfVisit.getLayoutObject=
  141. function(){
  142. if (!("dataQueriesLayout" in this.config.formConfig))
  143. this.config.formConfig.dataQueriesLayout=new Object();
  144. return this.config.formConfig.dataQueriesLayout;
  145. }
  146. crfVisit.getQueryLayout=
  147. function(queryName){
  148. //check whether queryName is in snapshotObject?
  149. return this.getLayoutObject()[queryName];
  150. }
  151. crfVisit.getLookupObject=
  152. function(){
  153. if (!("lookup" in this.config.formConfig))
  154. this.config.formConfig.lookup=new Object();
  155. return this.config.formConfig.lookup;
  156. }
  157. crfVisit.getLookup=
  158. function(queryName){
  159. let x=this.getLookupObject();
  160. if (queryName in x) return x[queryName];
  161. return null;
  162. }
  163. crfVisit.getQueryList=
  164. function(){
  165. if (!("queryList" in this.config.formConfig))
  166. this.config.formConfig.queryList=new Object();
  167. return this.config.formConfig.queryList;
  168. }
  169. crfVisit.getIdManager=
  170. function(){
  171. if (!("idManager" in this.config.formConfig))
  172. this.config.formConfig.idManager=participantIdManager.getObject();
  173. return this.config.formConfig.idManager;
  174. }
  175. crfVisit.getAdditionalData=
  176. function(formSetupEntry){
  177. //return information on additional data associated with the form
  178. //additionalData is a sub-list with multiple entries per patient/visit
  179. let config=this.config;
  180. //argument is the row of the formSetup setup list
  181. let queryName=config.formConfig.queryMap[formSetupEntry['queryName']];
  182. let fName='[getAdditionalData/'+queryName+']';
  183. this.print(fName);
  184. //additionalData holds a reference to all queries already parsed
  185. //this helps in reducing number of calls to the database (I assume)
  186. if (queryName in config.formConfig.additionalData){
  187. this.print(fName+': Returning preset value');
  188. return config.formConfig.additionalData[queryName];
  189. }
  190. //first time we see this query, so we have to do the setup
  191. this.print(fName+': generating');
  192. config.formConfig.additionalData[queryName]=new Object();
  193. //takes address, so further changes will be to the newly created object
  194. //in fact, ad is just a short alias of the long variable name on the right
  195. let ad=config.formConfig.additionalData[queryName];
  196. //no additional data
  197. if (formSetupEntry["showFlag"]==="NONE") {
  198. this.print(fName+": empty");
  199. return ad;
  200. }
  201. //use showFlag to setup report section of the CRF list
  202. if (formSetupEntry["showFlag"]==="REVIEW") {
  203. //abuse additionalData to signal different segment
  204. this.print(fName+": generateReport");
  205. ad.isReview=true;
  206. return ad;
  207. }
  208. //setup the additionalData memory object
  209. this.print(fName+': setting values');
  210. ad.showFlag=formSetupEntry["showFlag"];
  211. ad.showFlagValue=formSetupEntry["showFlagValue"];
  212. ad.queryName=formSetupEntry["showQuery"];
  213. //for data queries, limit to present CRF only
  214. ad.filters=new Object();
  215. let crfValues=this.getCRFref();
  216. let settings=this.config.formConfig.settings;
  217. let doMerge=false;
  218. if ("mergeListData" in settings){
  219. let ar=settings["mergeListData"].split(',');
  220. if (ar.includes(ad.queryName))
  221. doMerge=true;
  222. }
  223. let idField='participantStudyId';
  224. let id=this.config.formConfig.crfEntry[idField];
  225. this.print(fName+": studyId "+id+" doMerge "+doMerge);
  226. if (doMerge){
  227. let entries=config.formConfig.crfEntries.rows;
  228. for (let i=0;i<entries.length;i++){
  229. let e=entries[i];
  230. if (e[idField]==id){
  231. crfValues+=";"+e['entryId'];
  232. }
  233. }
  234. }
  235. this.print(fName+": crfValues "+crfValues);
  236. ad.filters['crfRef']=crfValues;
  237. //compose a long debug message
  238. let msg=fName+": flag "+ad.showFlag;
  239. msg+=" value "+ad.showFlagValue;
  240. msg+=" query "+ad.queryName;
  241. this.print(msg);
  242. return ad;
  243. }
  244. crfVisit.selectFormSetupRows=
  245. function(formId){
  246. let formSetupRows=new Array();
  247. let config=this.config;
  248. let allRows=config.formConfig.formSetup.rows;
  249. for (let i=0;i<allRows.length;i++){
  250. let formEntry=allRows[i];
  251. if (formEntry.formName==formId)
  252. formSetupRows.push(formEntry);
  253. }
  254. return formSetupRows;
  255. }
  256. crfVisit.findTitle=
  257. function(queryName){
  258. //find by name from formDatasets
  259. //and set associated title as title
  260. let config=this.config;
  261. let rows=config.formConfig.formDatasets.rows;
  262. for (let i=0;i<rows.length;i++){
  263. let entry=rows[i];
  264. if (entry['queryName']!=queryName) continue;
  265. return entry['title'];
  266. }
  267. return "NONE";
  268. }
  269. crfVisit.makeSetup=
  270. function(listName){
  271. //generate setup object whcih should contain fields:
  272. //readonlyFlag - whether the dataset is writeable
  273. //filters - selection fields that allow creation of LABKEY.Filter.create()
  274. //getInputId - formating of unique ids for html elements
  275. let fName='[Setup]';
  276. this.print(fName+' '+listName);
  277. let setup=new Object();
  278. setup.queryName=listName;
  279. setup.readonlyFlag=function(vName){return false};
  280. setup.filters=new Object();
  281. setup.filters['crfRef']=this.getCRFref();
  282. setup.getInputId=function(vName){return listName+"_"+vName;}
  283. setup.isReview=false;
  284. return setup;
  285. }
  286. crfVisit.getFullAccessSetup=
  287. function(listName){
  288. //addApply - whether a submit/Save button is generated
  289. let setup=this.makeSetup(listName);
  290. setup.addApply="Save";
  291. return setup;
  292. }
  293. crfVisit.getReadonlySetup=
  294. function(listName){
  295. let setup=this.makeSetup(listName);
  296. //see definition of setup object above, change readonly flag
  297. setup.readonlyFlag=function(vName){return true};
  298. return setup;
  299. }
  300. crfVisit.getSetup=
  301. function(listName,writeAccess=true){
  302. //change to section granulated permission of type EDIT, COMMENT, READ
  303. //let formStatus=config.formConfig.formStatus;
  304. //equivalent to READ
  305. if (!writeAccess)
  306. //if (formStatus=="Submitted")
  307. return this.getReadonlySetup(listName);
  308. //if (formStatus=="Approved")
  309. // return readonlySetup(listName);
  310. return this.getFullAccessSetup(listName);
  311. }
  312. crfVisit.generateSection=
  313. function(formSetupEntry){
  314. let config=this.config;
  315. let that=this;
  316. let listName=config.formConfig.queryMap[formSetupEntry['queryName']];
  317. //if (!listName) is for debugSection
  318. if (!listName){
  319. listName="debugSection";
  320. }
  321. let fName='[generateSection/'+listName+']';
  322. let sectionTitle=formSetupEntry['title'];
  323. let accessModeColumn=config.formConfig.operator+'Mode';
  324. let accessMode=formSetupEntry[accessModeColumn];
  325. //this will fix it for later use as well
  326. let additionalData=this.getAdditionalData(formSetupEntry);
  327. this.print(fName);
  328. let formName=config.masterForm;//this is HTML designator of area on page
  329. let debug=true;
  330. let tb=config.document.createElement('table');
  331. tb.className='t2';
  332. let row=tb.insertRow();
  333. let cell=config.document.createElement('th');
  334. row.appendChild(cell);
  335. cell.setAttribute("colspan","4");
  336. cell.style.fontSize="20px";
  337. cell.style.textAlign="center";
  338. let cellData=config.document.createTextNode(sectionTitle);
  339. cell.appendChild(cellData);
  340. cell=row.insertCell();
  341. let input=config.document.createElement("input");
  342. input.type="button";
  343. input.value="Show";
  344. input.id="toggle"+listName+"VisbilityButton";
  345. input.onclick=function(){that.toggleVisibility(listName,input.id)};
  346. cell.appendChild(input);
  347. this.getElement(formName).appendChild(tb);
  348. let div=config.document.createElement('div');
  349. div.id=listName;
  350. div.style.display="none";
  351. this.getElement(formName).appendChild(div);
  352. //here divert for debugArea
  353. if (listName=="debugSection"){
  354. let debugArea=config.document.createElement('textarea');
  355. debugArea.rows=10;
  356. debugArea.cols=95;
  357. debugArea.id=config.debugId;
  358. div.appendChild(debugArea);
  359. return;
  360. }
  361. let divTable=config.document.createElement('div');
  362. divTable.id=listName+"Table";
  363. div.appendChild(divTable);
  364. if ("showFlag" in additionalData) {
  365. additionalData.divName=listName+"SubDiv";
  366. additionalData.divQueryName=listName+"SubDivList";
  367. let div1=config.document.createElement('div');
  368. div1.id=additionalData.divName;
  369. div1.style.display="none";
  370. div.appendChild(div1);
  371. let div2=config.document.createElement('div');
  372. div2.id=additionalData.divQueryName;
  373. div1.appendChild(div2);
  374. }
  375. this.print(fName+" generate master table");
  376. let writeMode=accessMode=="EDIT";
  377. let setup=this.getSetup(listName,writeMode);
  378. if ("isReview" in additionalData){
  379. crfReviewSection.set(this);
  380. let action=function(){crfReviewSection.CB();};
  381. crfReviewSection.generateSection(listName,div.id,action);
  382. return;
  383. }
  384. //master table is unique per visit
  385. setup.unique=true;
  386. this.generateTable(listName,divTable.id,additionalData,setup);
  387. if (debug) this.print("generate master table: done");
  388. let generateSubTable=true;
  389. //generateSubTable equivalent to read/write access to section
  390. if (accessMode != "EDIT")
  391. generateSubTable=false;
  392. if (! ("showFlag" in additionalData) ) generateSubTable=false;
  393. if (generateSubTable){
  394. let qName=additionalData.queryName;
  395. let dName=additionalData.divName;
  396. let xsetup=this.getFullAccessSetup(qName);
  397. //only set master query for additionalData
  398. xsetup.masterQuery=listName;
  399. //if (readonly) setup=readonlySetup(config);
  400. xsetup.subTable=true;
  401. this.generateTable(qName,dName,additionalData,xsetup);
  402. //generateTable(formSetupEntry,qName,dName,additionalData,setup);
  403. }
  404. this.print("generate review");
  405. let divReviewList=config.document.createElement('div');
  406. divReviewList.id=listName+"ReviewList";
  407. div.appendChild(divReviewList);
  408. let divReview=config.document.createElement('div');
  409. divReview.id=listName+"Review";
  410. div.appendChild(divReview);
  411. //assume we already have listId (content of config.setupQueryName is listId)
  412. //we need listName also
  413. //qconfig.queryName=config.setupQueryName;
  414. this.generateReview(divReview.id,divReviewList.id,listName,accessMode);
  415. if (accessMode!='GENERATE') return;
  416. this.print('Adding generate button');
  417. //add generateButton
  418. let divGenerateButton=config.document.createElement('div');
  419. divGenerateButton.id=listName+'GenerateButton';
  420. div.appendChild(divGenerateButton);
  421. this.print('Adding generate button completed to here');
  422. let cb=function(){that.onGenerateQuery(listName);};
  423. this.generateButton(divGenerateButton.id,'Generate','Generate '+listName,'onGenerateQuery',cb);
  424. this.print('Adding generate button completed');
  425. }
  426. crfVisit.generateReview=
  427. function(divReviewId,divReviewListId, listName, accessMode){
  428. let config=this.config;
  429. let listId=config.formConfig.fields[listName].queryId;
  430. //listId is a number->should it be queryName?
  431. let fName='[generateReview]';
  432. this.print(fName+" list "+listId+'/'+listName);
  433. let reviewSetup=new Object();
  434. reviewSetup.readonlyFlag=function(vName){
  435. if (vName=="queryName") return true;
  436. if (vName=="queryname") return true;
  437. if (vName=="ModifiedBy") return true;
  438. return false;};
  439. reviewSetup.addApply="Add Review";
  440. reviewSetup.reviewTable=true;
  441. let generateTableFlag=true;
  442. let formStatus=config.formConfig.formStatus;
  443. //COMMENTS allowed or not
  444. //three levels of access: EDIT, COMMENT, READ
  445. if (accessMode == "READ"){
  446. //if (formStatus == "Approved" ){
  447. delete reviewSetup.addApply;
  448. reviewSetup.readonlyFlag=function(vName){return false;}
  449. generateTableFlag=false;
  450. }
  451. reviewSetup.filters=new Object();
  452. reviewSetup.filters["crfRef"]=this.getCRFref();
  453. if (config.formConfig.crfEntry.parentCrf){
  454. reviewSetup.filters["crfRef"]=this.getCRFref()+";"+config.formConfig.crfEntry.parentCrf;
  455. }
  456. reviewSetup.filters["queryName"]=listId;//entry in reviewComments list is queryname, all in small caps
  457. //needs listName, in argument
  458. reviewSetup.getInputId=function(vName){return listName+"_add"+vName};
  459. reviewSetup.divReviewListId=divReviewListId;
  460. reviewSetup.isReview=true;
  461. let msg="Review: divId: "+divReviewId;
  462. msg+=" inputId: "+reviewSetup.getInputId;
  463. this.print(msg);
  464. this.updateListDisplay(divReviewListId,"reviewComments",reviewSetup.filters,true);
  465. if (! generateTableFlag) return;
  466. this.generateTable("reviewComments",divReviewId,new Object(),reviewSetup);
  467. }
  468. //>>>>>>>>>>trigger visibility of additional lists
  469. crfVisit.setListVisibility=
  470. function(input,setup,readonlyFlag){
  471. let config=this.config;
  472. let fName="[setListVisibility/"+setup.queryName+"]";
  473. this.print(fName);
  474. let additionalData=config.formConfig.additionalData[setup.queryName];
  475. let x = this.getElement(additionalData.divName);
  476. this.print(fName+": Div: "+x);
  477. x.style.display="none";
  478. let sText;
  479. if (readonlyFlag) sText=input.innerText;
  480. else sText=input.options[input.selectedIndex].text;
  481. this.print(fName+": Selected option text: "+sText);
  482. if (sText == additionalData.showFlagValue){
  483. let filters=new Object();
  484. if ("filters" in additionalData) filters=additionalData.filters;
  485. x.style.display = "block";
  486. this.updateListDisplay(additionalData.divQueryName,
  487. additionalData.queryName,filters,readonlyFlag);
  488. }
  489. }
  490. //>>have list refresh when data is added (not optimal yet)
  491. //
  492. crfVisit.updateListDisplay=
  493. function(divName,queryName,filters,readonlyFlag){
  494. //use Labkey.QueryWebPart to show list
  495. let fName="[updateListDisplay]";
  496. this.print(fName+": UpdateListDisplay: Query - "+queryName
  497. +" div - "+divName);
  498. if (divName=="NONE") return;
  499. let crfRef=this.getCRFref();
  500. let div=this.getElement(divName);
  501. this.print(fName+": generating WebPart: "+queryName);
  502. var qconfig=new Object();
  503. qconfig.renderTo=divName;
  504. //point to data container
  505. qconfig.containerPath=this.getContainer('data');
  506. qconfig.schemaName='lists';
  507. qconfig.queryName=queryName;
  508. qconfig.buttonBarPosition='top';
  509. qconfig.filters=[];
  510. for (f in filters){
  511. let fType=LABKEY.Filter.Types.EQUAL;
  512. this.print(fName+' filter ['+f+'] '+filters[f]+'/'+typeof(filters[f])+' ['+fType+']');
  513. if (variableList.isFilterList(filters[f])){
  514. fType=LABKEY.Filter.Types.IN;
  515. }
  516. qconfig.filters.push(LABKEY.Filter.create(f, filters[f],fType));
  517. }
  518. let that=this;
  519. qconfig.success=function(data){that.updateSuccess(data);};
  520. qconfig.failure=function(errorInfo,options,responseObj){that.onFailure(errorInfo,options,responseObj);};
  521. //show only print button
  522. if (readonlyFlag){
  523. qconfig.buttonBar=new Object();
  524. qconfig.buttonBar.items=["print"];
  525. }
  526. qconfig.showUpdateColumn=false;
  527. qconfig.showDetailsColumn=false;
  528. LABKEY.QueryWebPart(qconfig);
  529. }
  530. crfVisit.updateSuccess=
  531. function(data){
  532. this.print("Update success");
  533. }
  534. //TODO: this should trigger a data refresh on section, ie populateData(field)
  535. crfVisit.toggleVisibility=
  536. function(divName,buttonName){
  537. let fName='[toggleVisibility/'+divName+']';
  538. this.print(fName);
  539. let config=this.config;
  540. let x = this.getElement(divName);
  541. if (x.style.display === "none") {
  542. //exclude non data sections (like debug)...
  543. this.print(fName+': issuing setData(populateSection)');
  544. x.style.display = "block";
  545. this.getElement(buttonName).value="Hide";
  546. let that=this;
  547. let cb=function(){that.populateSection(divName);};
  548. this.setData(cb);
  549. } else {
  550. x.style.display = "none";
  551. this.getElement(buttonName).value="Show";
  552. }
  553. }
  554. crfVisit.generateButton=
  555. function(divName,caption,label,callbackLabel,callback=null){
  556. this.print("generateButtonX");
  557. let config=this.config;
  558. let tb=config.document.createElement('table');
  559. tb.className="t2";
  560. let r1=tb.insertRow();
  561. th=config.document.createElement('th');
  562. r1.appendChild(th);
  563. th.innerHTML=caption;
  564. //*!*
  565. let c2=r1.insertCell();
  566. let i1=config.document.createElement("input");
  567. i1.type="button";
  568. i1.value=label;
  569. i1.style.fontSize="20px";
  570. let that=this;
  571. if (callback)
  572. i1.onclick=callback;
  573. else
  574. i1.onclick=function(){that[callbackLabel]();};
  575. i1.id='button_'+callbackLabel;
  576. c2.appendChild(i1);
  577. let c1=r1.insertCell();
  578. c1.setAttribute("colspan","1");
  579. //this is only for saveReview?
  580. c1.id=divName+'_reportField';
  581. //c1.id=config.submitReportId;
  582. let el=this.getElement(divName);
  583. this.print("generateButton: element["+divName+"]: "+el);
  584. el.appendChild(tb);
  585. }
  586. crfVisit.generateSubQuery=
  587. function(input, setup, readonlyFlag){
  588. let fName="[generateSubQuery]";
  589. let config=this.config;
  590. if (setup.isReview) return;
  591. if (!(setup.queryName in config.formConfig.additionalData)){
  592. this.print(fName+': no additionalData entry (probably a subquery)');
  593. return;
  594. }
  595. let additionalData=config.formConfig.additionalData[setup.queryName];
  596. if (!("showFlag" in additionalData))
  597. return;
  598. this.print(fName);
  599. let expId=setup.getInputId(additionalData.showFlag);
  600. if (expId!=input.id) {
  601. this.print(fName+": ignoring field "+input.id+"/"+expId);
  602. return;
  603. }
  604. this.print(fName+": Setting onChange to "+input.id);
  605. if (readonlyFlag)
  606. return;
  607. let that=this;
  608. input.onchange=function(){that.setListVisibility(input,setup,readonlyFlag)};
  609. }
  610. //>>populate fields
  611. //
  612. //
  613. //split to field generation and field population
  614. //
  615. crfVisit.addFieldRow=
  616. function(tb,field,setup,additionalData){
  617. let fName="[addFieldRow/"+setup.queryName+':'+field.name+']';
  618. let config=this.config;
  619. let vName=field.name;
  620. let vType=field.type;
  621. let isLookup=("lookup" in field);
  622. this.print(fName+": ["+vName+"/"+vType+'/'+isLookup+"]");
  623. let row=tb.insertRow();
  624. let cell=config.document.createElement('th');
  625. cell.style.width='300px';
  626. row.appendChild(cell);
  627. let text = config.document.createTextNode(field.shortCaption);
  628. cell.appendChild(text);
  629. let input=null;
  630. let colSpan="3";
  631. let cell1=row.insertCell();
  632. cell1.colSpan=colSpan;
  633. let readonlyFlag=setup.readonlyFlag(vName);
  634. //set the html input object
  635. while (1){
  636. if (readonlyFlag){
  637. input=config.document.createElement('label');
  638. input.innerText='Loading';
  639. break;
  640. }
  641. //lookup
  642. if (isLookup){
  643. input = config.document.createElement("select");
  644. break;
  645. }
  646. //date
  647. if (vType=="date"){
  648. input = config.document.createElement("input");
  649. input.type="date";
  650. break;
  651. }
  652. //string
  653. if (vType=="string"){
  654. //we have to make sure UNDEF is carried to below
  655. //since we are adapting file to either show
  656. //current file or allow user to select a file
  657. //
  658. //TODO change this so one can always select file
  659. //but also show the selected file
  660. if(vName.search("reviewComment")>-1){
  661. input = config.document.createElement("textarea");
  662. input.cols="65";
  663. input.rows="5";
  664. break;
  665. }
  666. input=config.document.createElement('input');
  667. input.type="text";
  668. if (vName.search('_file_')<0) break;
  669. cell1.setAttribute('colspan',"1");
  670. let cell2=row.insertCell();
  671. cell2.setAttribute('colspan',"2");
  672. let input1=config.document.createElement('input');
  673. input1.type="file";
  674. input1.id=setup.getInputId(vName)+'_file_';
  675. cell2.appendChild(input1);
  676. break;
  677. }
  678. if (vType=="float"){
  679. input = config.document.createElement("input");
  680. input.type="text";
  681. break;
  682. }
  683. if (vType=="boolean"){
  684. input = config.document.createElement("input");
  685. input.type="checkbox";
  686. this.print("Creating checkbox");
  687. break;
  688. }
  689. break;
  690. }
  691. input.id=setup.getInputId(vName);
  692. cell1.appendChild(input);
  693. this.print(fName+': adding element '+input.id);
  694. this.print(fName+': listing element '+this.getElement(input.id));
  695. //connect associated list
  696. this.generateSubQuery(input,setup,readonlyFlag);
  697. if (readonlyFlag) {
  698. this.print(fName+': exiting(readonlyFlag)');
  699. return;
  700. }
  701. if (!isLookup) {
  702. this.print(fName+': exiting (not lookup)');
  703. return;
  704. }
  705. let lookup=field["lookup"];
  706. //get all values from config.formConfig.lookup[X]
  707. let lObject=config.formConfig.lookup[lookup.queryName];
  708. //debug
  709. this.print(fName+": query: "+lookup.queryName);
  710. this.print(fName+": ElementId: "+input.id);
  711. this.print(fName+": No of options: " +lObject.LUT.length);
  712. this.print(fName+": Element: "+input);
  713. //set the lut value (input is text label) for readonly
  714. //clear existing fields from input
  715. for(let i = input.options.length; i >= 0; i--) {
  716. input.remove(i);
  717. }
  718. //create option -1
  719. let opt = config.document.createElement("option");
  720. opt.text = "<Select>";
  721. opt.value = -1;
  722. input.options[0] = opt;
  723. this.print(fName+": Adding <Select>");
  724. //add other, label them with LUT
  725. for (let v in lObject.LUT) {
  726. this.print(fName+': populating '+v+': '+lObject.LUT[v]);
  727. let opt = config.document.createElement("option");
  728. opt.text = lObject.LUT[v];
  729. opt.value = v;
  730. input.options[input.options.length] = opt;
  731. }
  732. input.selectedIndex=0;
  733. }
  734. crfVisit.addSpecialFieldRows=
  735. function(tb,specFieldSetup,setup){
  736. //tb is the table, specFieldSetup is a row from the table where special fields are being setup
  737. //the first column is fieldUID, which is a colon joined amalgation of queryName:fieldName
  738. let fieldUID=specFieldSetup["fieldUID"];
  739. let x=fieldUID.split(':');
  740. let fieldName=x[1];
  741. let fName="[addSpecialFieldRow/"+fieldUID+"]";
  742. let q=variableList.parseVariables(specFieldSetup['actionParameters']);
  743. let config=this.config;//for add data
  744. this.print(fName);
  745. if (specFieldSetup['actionType']=='textArea'){
  746. let row=tb.insertRow();
  747. let cell1=row.insertCell();
  748. cell1.colSpan="4";
  749. cell1.style.textAlign="justify";
  750. cell1.style.padding="10px";
  751. cell1.style.backgroundColor="#e0e0e0";
  752. cell1.innerText=q['description'];
  753. return;
  754. }
  755. if (specFieldSetup['actionType']=='generationObject'){
  756. //only in EDIT mode!!
  757. let ro=setup.readonlyFlag(fieldName);
  758. if (ro) return;
  759. generateRegistration.set(this);
  760. let gc=generateRegistration.getObject(q,setup.getInputId(fieldName));
  761. let that=this;
  762. let action=function(){that.doNothing();};
  763. if ('mailRecipient' in q){
  764. gc.callback=function(data){that.sendEmail(data,q['mailRecipient'],action,q['subject']);};
  765. }
  766. else
  767. gc.callback=function(data){that.doNothing();};
  768. if ("addData" in q){
  769. vars=q["addData"].split(',');
  770. gc.addData=new Array();
  771. for (let v in vars){
  772. let s=vars[v]
  773. //variable name can be written as A/B where A is the name in addData and B is the variable name in crfEntry
  774. //useful for mocking up crfId from daughter crf-s such as registration
  775. let sArray=s.split('/');
  776. let sTarget=sArray[0];
  777. let sSource=sArray[sArray.length-1];
  778. gc.addData[sTarget]=config.formConfig.crfEntry[sSource];
  779. this.print(fName+" addData ["+sTarget+"]: "+gc.addData[sTarget]);
  780. }
  781. }
  782. let row=tb.insertRow();
  783. let cell=config.document.createElement('th');
  784. row.appendChild(cell);
  785. let text = config.document.createTextNode("Automatic ID generator");
  786. cell.appendChild(text);
  787. let cell1=row.insertCell();
  788. cell1.colSpan="3";
  789. let b=config.document.createElement("input");
  790. b.type="button";
  791. b.id="generateIdButton";
  792. b.onclick=function(){generateRegistration.execute(gc);};
  793. b.value="Generate ID";
  794. cell1.appendChild(b);
  795. }
  796. }
  797. crfVisit.populateFieldRow=
  798. function(entry,field,setup){
  799. this.populateField(entry,field,setup);
  800. this.populateSubQuery(entry,field,setup);
  801. }
  802. crfVisit.populateSubQuery=
  803. function(entry,field,setup){
  804. let fName='[populateSubQuery/'+setup.queryName+':'+field.name+']';
  805. let config=this.config;
  806. if (setup.isReview) return;
  807. if (!(setup.queryName in config.formConfig.additionalData)){
  808. let msg=fName+': no additionalData entry for '+setup.queryName;
  809. msg+=' (probably a subquery)';
  810. this.print(msg);
  811. return;
  812. }
  813. //find if field is connected to a sub array
  814. //find queryName
  815. //
  816. let additionalData=config.formConfig.additionalData[setup.queryName];
  817. this.print(fName);
  818. //let flag=additionalData.showFlag;
  819. if (!("showFlag" in additionalData)) return;
  820. let eId=setup.getInputId(additionalData.showFlag);
  821. let id=setup.getInputId(field.name);
  822. if (eId!=id) {
  823. this.print(fName+": ignoring field "+id+"/"+eId);
  824. return;
  825. }
  826. this.print(fName+': id '+id);
  827. //hard to estimate readonlyFlag
  828. //
  829. let input=this.getElement(id);
  830. let eType=input.nodeName.toLowerCase();
  831. let readonlyFlag=eType!="select";
  832. this.setListVisibility(input,setup,readonlyFlag);
  833. }
  834. crfVisit.clearField=
  835. function(field,setup){
  836. let foo=new Object();
  837. this.populateField(foo,field,setup);
  838. }
  839. crfVisit.populateField=
  840. function(entry,field,setup){
  841. let vName=field.name;
  842. let fName='[populateFieldName/'+vName+']';
  843. let config=this.config;
  844. let varValue=null;
  845. //if (vName in setup.filters) varValue=setup.filters[vName];
  846. if (vName in entry) varValue=entry[vName];
  847. //if part of the filter, set it to value
  848. if (vName in setup.filters) varValue=setup.filters[vName];
  849. let isLookup=("lookup" in field);
  850. this.print(fName+' v='+varValue+'/'+isLookup+' ['+
  851. setup.getInputId(field.name)+']');
  852. let vType=field.type;
  853. let id=setup.getInputId(vName);
  854. let input=this.getElement(id);
  855. //date
  856. if (vType=="date"){
  857. if (varValue) varValue=new Date(varValue);
  858. }
  859. //lookup for readonly
  860. if (isLookup && varValue){
  861. let lookup=field["lookup"];
  862. //get all values from config.formConfig.lookup[X]
  863. let lObject=config.formConfig.lookup[lookup.queryName];
  864. varValue=lObject.LUT[varValue];
  865. }
  866. this.print('Element: '+input);
  867. //figure out the element type
  868. let eType=input.nodeName.toLowerCase();
  869. this.print('Element type: '+eType);
  870. //change varValue for printing
  871. //HTMLTextArea, createElement(textArea)
  872. if (eType==="textarea"){
  873. input.value=varValue;
  874. return;
  875. }
  876. //Text, createTextNode
  877. if (eType==="#text"){
  878. input.nodeValue=varValue;
  879. return;
  880. }
  881. //HTMLLabelElement, createElement('label')
  882. if (eType==="label"){
  883. input.innerText=varValue;
  884. return;
  885. }
  886. //HTMLSelectElement, createElement('select')
  887. if (eType==="select"){
  888. input.selectedIndex=0;
  889. for (let i=0;i<input.options.length;i++){
  890. let v=input.options[i].text;
  891. if (v!=varValue) continue;
  892. input.selectedIndex=i;
  893. break;
  894. }
  895. return;
  896. }
  897. if (eType!="input"){
  898. this.print('Unknown type: '+eType+' encountered, igonring');
  899. return;
  900. }
  901. //HTMLInputElement
  902. let type=input.type;
  903. if (type=="date"){
  904. input.valueAsDate=varValue;
  905. return;
  906. }
  907. //string,float
  908. if (type=="text"){
  909. input.value=varValue;
  910. return;
  911. }
  912. //boolean
  913. if (type=="checkbox"){
  914. input.checked=varValue;
  915. return;
  916. }
  917. this.print('Unknown input type: '+type+'. Ignoring.');
  918. }
  919. crfVisit.populateSpecialFieldRow=
  920. function(specFieldSetup,entry,field,setup){
  921. //tb is the table, specFieldSetup is a row from the table where special fields are being setup
  922. //the first column is fieldUID, which is a colon joined amalgation of queryName:fieldName
  923. let fieldUID=specFieldSetup["fieldUID"];
  924. let x=fieldUID.split(':');
  925. let fName="[addSpecialFieldRow/"+fieldUID+"]";
  926. let q=variableList.parseVariables(specFieldSetup['actionParameters']);
  927. let config=this.config;//for add data
  928. this.print(fName);
  929. if (specFieldSetup['actionType']=='maskDate'){
  930. let el=this.getElement(setup.getInputId(field.name));
  931. let operator=config.formConfig.operator;
  932. let applyMask=true;
  933. if ('role' in q && q['role']!=operator) applyMask=false;
  934. if (applyMask){
  935. let date=new Date(el.innerText);
  936. this.print(fName+' value '+el.innerText+" date "+date+' year '+date.getFullYear());
  937. el.innerText=date.getFullYear();
  938. }
  939. }
  940. }
  941. crfVisit.populateTable=
  942. function(listName,writeMode){
  943. //function populateTable(formSetupEntry){
  944. //let listName=config.formConfig.queryMap[formSetupEntry['queryName']];
  945. //let accessMode=config.formConfig.operator+'Mode';
  946. //let writeMode=formSetupEntry[accessMode]=='EDIT';
  947. let fName='[populateTable/'+listName+']';
  948. let setup=this.getSetup(listName,writeMode);
  949. let entry=new Object();
  950. //data snapshot
  951. let fQuery=this.getQuerySnapshot(listName);
  952. let queryLayout=this.getQueryLayout(listName);
  953. //here I assume that listName was parsed during setDataLayout and setData
  954. //so that rows was set (even if they are empty)
  955. this.print(fName+"]: nrows "+fQuery.rows.length);
  956. if (fQuery.rows.length>0)
  957. entry=fQuery.rows[0];
  958. let fields=queryLayout.fields;
  959. for (f in fields){
  960. let field=fields[f];
  961. //each field is a new row
  962. this.print(fName+": Adding field: "+f+'/'+field.name+' hidden: '+field.hidden+' type:'+field.type);
  963. if (field.hidden) continue;
  964. if (field.name=="crfRef") continue;
  965. this.populateFieldRow(entry,field,setup);
  966. let fieldUID=listName+":"+field.name;
  967. if (fieldUID in this.config.formConfig["specialFields"]){
  968. let specFieldSetup=this.config.formConfig["specialFields"][fieldUID];
  969. this.populateSpecialFieldRow(specFieldSetup,entry,field,setup);
  970. }
  971. }
  972. }
  973. crfVisit.generateTable=
  974. function(listName,divName,additionalData,setup){
  975. let fName="[generateTable/"+listName+"]";
  976. let config=this.config;
  977. this.print(fName);
  978. //is listName and setup.queryName a duplicate of the same value
  979. this.print(fName+': setup.queryName '+setup.queryName);
  980. //assume data is set in config.formConfig.dataQueries[data.queryName].rows;
  981. let populateData=true;
  982. if ("subTable" in setup){
  983. this.print(fName+" is subTable");
  984. populateData=false;
  985. }
  986. let entry=new Object();
  987. //data snapshot
  988. let fQuerySnapshot=this.getQuerySnapshot(listName);
  989. let queryLayout=this.getQueryLayout(listName);
  990. //here I assume that listName was parsed during setDataLayout and setData
  991. //so that rows was set (even if they are empty)
  992. this.print(fName+": Nrows "+fQuerySnapshot.rows.length);
  993. if (fQuerySnapshot.rows.length>0)
  994. entry=fQuerySnapshot.rows[0];
  995. if ("reviewTable" in setup){
  996. entry['reviewComment']='';
  997. delete entry["ModifiedBy"];
  998. }
  999. let tb=config.document.createElement('table');
  1000. tb.className="t2";
  1001. this.getElement(divName).appendChild(tb);
  1002. //this are the fields (probably constant)
  1003. let fields=queryLayout.fields;
  1004. for (f in fields){
  1005. let field=fields[f];
  1006. let fieldUID=listName+":"+field.name;
  1007. //each field is a new row
  1008. this.print(fName+": Adding field: "+f+'/'+field.name+' ('+fieldUID+').');
  1009. //unique name
  1010. if (field.hidden) continue;
  1011. if (field.name=="crfRef") continue;
  1012. this.addFieldRow(tb,field,setup,additionalData);
  1013. if (populateData) this.populateFieldRow(entry,field,setup);
  1014. if (fieldUID in config.formConfig["specialFields"]){
  1015. let specFieldSetup=config.formConfig["specialFields"][fieldUID];
  1016. this.addSpecialFieldRows(tb,specFieldSetup,setup);
  1017. this.populateSpecialFieldRow(specFieldSetup,entry,field,setup);
  1018. }
  1019. }
  1020. //finish of if apply button is not required
  1021. if (!("addApply" in setup)) {
  1022. this.print(fName+"populateTable: done");
  1023. return;
  1024. }
  1025. let row=tb.insertRow();
  1026. let th=config.document.createElement('th');
  1027. row.appendChild(th);
  1028. th.innerHTML=setup.addApply;
  1029. let cell=row.insertCell();
  1030. //cell.setAttribute("colspan","2");
  1031. let input=config.document.createElement("input");
  1032. input.type="button";
  1033. input.value=setup.addApply;
  1034. cell.appendChild(input);
  1035. let cell1=row.insertCell();
  1036. cell1.setAttribute("colspan","2");
  1037. cell1.id=setup.getInputId("rerviewLastSave");
  1038. cell1.innerHTML="No recent update";
  1039. //saveReview is a generic name for saving content of the html page to a list entry
  1040. let that=this;
  1041. input.onclick=function(){that.saveReview(listName,cell1.id,setup)};
  1042. }
  1043. crfVisit.setEntryFromElement=
  1044. function(entry,elementId, field){
  1045. //set value to entry from element using representation (field) from labkey
  1046. //
  1047. //
  1048. let fName='setEntryFromElement';
  1049. let config=this.config;
  1050. let el=this.getElement(elementId);
  1051. if (!el) {
  1052. this.print(fName+" element: "+elementId+" not found");
  1053. return;
  1054. }
  1055. this.print(fName+" element: "+elementId);
  1056. let vName=field.name;
  1057. let vType=field.type;
  1058. let eType=el.nodeName.toLowerCase();
  1059. if (eType==="select"){
  1060. entry[vName]=el.options[el.selectedIndex].value;
  1061. return;
  1062. }
  1063. if (eType==="td"){
  1064. entry[vName]=el.innerText;
  1065. return;
  1066. }
  1067. if (vType=="date"){
  1068. let date=el.valueAsDate;
  1069. if (!date) return;
  1070. date.setUTCHours(12);
  1071. entry[vName]=date.toString();
  1072. this.print(fName+" setting date to "+entry[vName]);
  1073. return;
  1074. }
  1075. if (vType=="string"){
  1076. entry[vName]=el.value;
  1077. if (vName.search('_file_')<0)
  1078. return;
  1079. //upload file
  1080. let id1=elementId+'_file_';
  1081. let input1=this.getElement(id1);
  1082. this.print(fName+' attachment field: '+input1.value);
  1083. //entry[vName]=el.files[0].stream();
  1084. let ctx=new Object();
  1085. ctx['dirName']='consent';
  1086. ctx['ID']=entry['crfRef'];
  1087. //should point to data container
  1088. ctx['project']=getContainer('data');
  1089. //need ID->crf!
  1090. //assume crfRef will get set before this
  1091. //element is encountered
  1092. this.uploadFile(input1,ctx);
  1093. let fv=el.value;
  1094. let suf=fv.split('.').pop();
  1095. entry[vName]=entry['crfRef']+'.'+suf;
  1096. return;
  1097. }
  1098. if (vType=="float" || vType=="int"){
  1099. entry[vName]=el.value;
  1100. if (vName=="queryName") {
  1101. this.print(fName+' parsing queryName: '+el.innerText);
  1102. entry[vName]=config.formConfig.fields[el.innerText].queryId;
  1103. //use queryMap lookup
  1104. }
  1105. return;
  1106. }
  1107. if (vType=="boolean"){
  1108. entry[vName]=el.checked;
  1109. return;
  1110. }
  1111. return;
  1112. }
  1113. crfVisit.saveReview=
  1114. function(queryName,elementId,setup){
  1115. //loads any queryName
  1116. let debug=true;
  1117. let fName='[saveReview/'+queryName+']';
  1118. this.print(fName+" elementId "+elementId);
  1119. let unique=("unique" in setup);
  1120. //data snapshot
  1121. let fQuerySnapshot=this.getQuerySnapshot(queryName);
  1122. let nRows=fQuerySnapshot.rows.length;
  1123. let mode='insert';
  1124. //data layout
  1125. let queryLayout=this.getQueryLayout(queryName);
  1126. let entry=new Object();
  1127. //determine mode based on entry uniqueness and presence of data
  1128. if (unique && nRows>0){
  1129. entry=fQuerySnapshot.rows[0];
  1130. mode='update';
  1131. }
  1132. this.print(fName+' unique '+unique+' mode '+mode+' nRows '+nRows);
  1133. entry.crfRef=this.getCRFrefData();
  1134. this.print(fName+" set crfRef="+entry.crfRef);
  1135. let fields=queryLayout.fields;
  1136. for (f in fields){
  1137. let field=fields[f];
  1138. this.print(fName+" saveReview field: "+field.name);
  1139. if (field.hidden) continue;
  1140. let vName=field.name;
  1141. let vType=field.type;
  1142. this.print(fName+" vType: "+vType);
  1143. if (vName=="crfRef") continue;
  1144. //need to save queryName for reviewComments
  1145. let eId=setup.getInputId(vName);
  1146. //copy values from form to entry
  1147. this.setEntryFromElement(entry,eId,field);
  1148. //clear field value
  1149. if (!unique) this.clearField(field,setup);
  1150. }
  1151. let that=this;
  1152. let action=function(data){that.updateLastSavedFlag(data,setup,elementId)};
  1153. this.modifyRows(mode,'lists',queryName,[entry],action,this.getContainer('data'));
  1154. }
  1155. crfVisit.updateLastSavedFlag=
  1156. function(data,setup,elementId){
  1157. let fName='[updateLastSavedFlag]';
  1158. let config=this.config;
  1159. this.print(fName+" update last saved flag to "+elementId);
  1160. let el=this.getElement(elementId);
  1161. let dt=new Date();
  1162. el.innerHTML="Last saved "+dt.toString();
  1163. if (data.queryName=="reviewComments"){
  1164. this.updateListDisplay(setup.divReviewListId,"reviewComments",setup.filters,true);
  1165. }
  1166. //refresh stored data!
  1167. let writeMode=!setup.readonlyFlag();
  1168. let that=this;
  1169. if ("unique" in setup)
  1170. this.setData(function (){that.populateTable(data.queryName,writeMode);});
  1171. if ("masterQuery" in setup){
  1172. let ad=config.formConfig.additionalData[setup.masterQuery];
  1173. this.print('Updating list display: '+setup.queryName+'/'+ad.queryName);
  1174. this.updateListDisplay(ad.divQueryName,ad.queryName,ad.filters,false);
  1175. }
  1176. }
  1177. //******************************************upload to database *********************
  1178. crfVisit.onDatabaseUpload=
  1179. function(){
  1180. let fName='[onDatabaseUpload]';
  1181. this.print(fName);
  1182. let config=this.config;
  1183. config.upload=new Object();
  1184. let fc=new Object();
  1185. let pM=this.getIdManager();
  1186. fc.participantId=participantIdManager.getParticipantIdFromCrfEntry(pM);
  1187. this.print(fName+' id '+fc.participantId);
  1188. this.afterParticipantId(fc);
  1189. }
  1190. crfVisit.afterParticipantId=
  1191. function(fc){
  1192. this.print("Setting participantId to "+fc.participantId);
  1193. let config=this.config;
  1194. config.upload.participantId=fc.participantId;
  1195. //another select rows to update all queries from setup
  1196. //just use registration for test
  1197. let formSetupRows=config.formConfig.formSetupRows;
  1198. config.upload.queries=new Array();
  1199. this.print("Form rows: "+formSetupRows.length);
  1200. for (let i=0;i<formSetupRows.length;i++){
  1201. let entry=formSetupRows[i];
  1202. //skip reviews
  1203. if (entry.showFlag=="REVIEW") continue;
  1204. //use lookup table to convert from id to name
  1205. let queryName=config.formConfig.queryMap[entry.queryName];
  1206. config.upload.queries.push({queryName:queryName,queryStatus:"QUEUED"});
  1207. this.print('form ['+i+']='+queryName+' '+entry.showFlag+'/'+entry.showQuery);
  1208. if (entry.showQuery=="NONE")
  1209. continue;
  1210. config.upload.queries.push({queryName:entry.showQuery,queryStatus:"QUEUED"});
  1211. }
  1212. //add reviews
  1213. config.upload.queries.push({queryName:"reviewComments",queryStatus:"QUEUED"});
  1214. config.upload.queryId=0;
  1215. this.copyToDataset();
  1216. }
  1217. crfVisit.copyToDataset=
  1218. function(){
  1219. let fName='[copyToDataset]: ';
  1220. let config=this.config;
  1221. this.print(fName+'['+config.upload.queryId+'/'+config.upload.queries.length+']');
  1222. //watch dog + scheduler
  1223. //
  1224. let that=this;
  1225. //watchdog part
  1226. if (config.upload.queryId==config.upload.queries.length) {
  1227. this.print(fName+'completing');
  1228. let targetStatus=config.formConfig.targetStatus['onDatabaseUpload'];
  1229. let targetRecipient=config.formConfig.targetRecipient['onDatabaseUpload'];
  1230. let action=new Object();
  1231. action.name='onDatabaseUpload';
  1232. let redirect=function(){that.redirect();};
  1233. action.cb=function(data){that.sendEmail(data,targetRecipient,redirect,'Form uploaded');}
  1234. this.updateFlag(targetStatus,action);//Approved
  1235. return;
  1236. }
  1237. //scheduler
  1238. let queryName=config.upload.queries[config.upload.queryId].queryName;
  1239. this.print("copyToDataset["+config.upload.queryId+"/"+
  1240. config.upload.queries.length+"]: "+queryName);
  1241. let filters=[LABKEY.Filter.create('crfRef',this.getCRFref())];
  1242. let action=function(data){that.afterListData(data);};
  1243. this.selectRows('lists',queryName,filters,action,this.getContainer('data'));
  1244. }
  1245. crfVisit.afterListData=
  1246. function(data){
  1247. let fName='[afterListData]: ';
  1248. let config=this.config;
  1249. let queryName=config.upload.queries[config.upload.queryId].queryName;
  1250. this.print(fName+" ["+queryName+"/list]: "+data.rows.length+" entries");
  1251. config.upload.queries[config.upload.queryId].listData=data;
  1252. let id=config.upload.participantId;
  1253. let filters=[LABKEY.Filter.create('crfRef',this.getCRFref()),LABKEY.Filter.create('ParticipantId',id)];
  1254. let that=this;
  1255. let action=function(data){that.afterStudyData(data);};
  1256. this.selectRows('study',queryName,filters,action,this.getContainer('data'));
  1257. }
  1258. crfVisit.afterStudyData=
  1259. function(data){
  1260. let fName='[afterStudyData]: ';
  1261. let config=this.config;
  1262. let queryObj=config.upload.queries[config.upload.queryId];
  1263. queryObj.studyData=data;
  1264. let msg=fName+"["+queryObj.queryName+"/study]: "+data.rows.length+" entries";
  1265. this.print(msg);
  1266. let listRows=queryObj.listData.rows;
  1267. //skip uploading an empty set
  1268. if (listRows.length==0){
  1269. this.printErr("List "+queryObj.queryName+" empty.");
  1270. queryObj.queryStatus="DONE";
  1271. config.upload.queryId+=1;
  1272. //back to watchdog
  1273. this.copyToDataset();
  1274. return;
  1275. }
  1276. let studyRows=queryObj.studyData.rows;
  1277. for (let i=0;i<studyRows.length;i++){
  1278. let entry=studyRows[i];
  1279. //
  1280. if (! (i<listRows.length) ) continue;
  1281. let entryList=listRows[i];
  1282. //keeps study only variables (ParticipantId, SequenceNum)
  1283. for (let f in entryList) {
  1284. entry[f]=entryList[f];
  1285. this.print(fName+"Copying ["+f+"]: "+entry[f]+"/"+entryList[f]);
  1286. }
  1287. }
  1288. this.print(fName+' copying completed');
  1289. if (studyRows.length>0) {
  1290. let that=this;
  1291. let action=function(data){that.afterStudyUpload(data);};
  1292. this.modifyRows('update','study',queryObj.queryName,studyRows,action,this.getContainer('data'));
  1293. this.print(fName+'updateRows sent');
  1294. }
  1295. else{
  1296. let data=new Object();
  1297. data.rows=new Array();
  1298. this.afterStudyUpload(data);
  1299. }
  1300. }
  1301. crfVisit.afterStudyUpload=
  1302. function(data){
  1303. let fName='[afterStudyUpload] ';
  1304. let config=this.config;
  1305. let that=this;
  1306. this.print(fName);
  1307. //let participantField=config.participantField;
  1308. let participantField=config.formConfig.studyData["SubjectColumnName"];
  1309. this.print(fName+' participantField: '+participantField);
  1310. let queryObj=config.upload.queries[config.upload.queryId];
  1311. let queryName=queryObj.queryName;
  1312. this.printErr("Updated "+data.rows.length+" rows to "+queryName);
  1313. let studyRows=queryObj.studyData.rows;
  1314. let listRows=queryObj.listData.rows;
  1315. let rows=new Array();
  1316. //also updating existing rows, if they exist
  1317. for (let i=studyRows.length;i<listRows.length;i++){
  1318. let entry=listRows[i];
  1319. //make sure you have the participantField right
  1320. //
  1321. entry[participantField]=config.upload.participantId;
  1322. entry.crfRef=this.getCRFref();
  1323. entry.SequenceNum=this.getCRFref();
  1324. entry.SequenceNum=entry.SequenceNum % 1000000000;
  1325. if (listRows.length>1){
  1326. entry.SequenceNum+=i/100;
  1327. }
  1328. this.print( "Adding sequence number "+entry.SequenceNum);
  1329. rows.push(entry);
  1330. }
  1331. if (rows.length>0){
  1332. let action=function(data){that.afterListUpload(data);};
  1333. this.insertRows('study',queryName,rows,action,this.getContainer('data'));
  1334. }
  1335. else{
  1336. let data=new Object();
  1337. data.rows=rows;
  1338. this.afterListUpload(data);
  1339. }
  1340. }
  1341. crfVisit.afterListUpload=
  1342. function(data){
  1343. let config=this.config;
  1344. let queryObj=config.upload.queries[config.upload.queryId];
  1345. let queryName=queryObj.queryName;
  1346. this.printErr("Inserted "+data.rows.length+" rows to "+queryName);
  1347. queryObj.queryStatus="DONE";
  1348. config.upload.queryId+=1;
  1349. this.copyToDataset();
  1350. }
  1351. //*************************update for further review *************************
  1352. crfVisit.onUpdateForReview=
  1353. function(){
  1354. let config=this.config;
  1355. let targetStatus=config.formConfig.targetStatus['onUpdateForReview'];
  1356. let targetRecipient=config.formConfig.targetRecipient['onUpdateForReview'];
  1357. let action=new Object();
  1358. action.name='onUpdateForReview';
  1359. let that=this;
  1360. let redirect=function(){that.redirect();};
  1361. action.cb=function(data){that.sendEmail(data,targetRecipient,redirect,'Form updated for review');};
  1362. this.updateFlag(targetStatus,action);
  1363. }
  1364. crfVisit.updateFlag=
  1365. function(flag,action){
  1366. let fName='[updateFlag 1]';
  1367. let config=this.config;
  1368. let entry=config.formConfig.crfEntry;
  1369. entry.FormStatus=flag;
  1370. let uId=config.formConfig.currentUser.UserId;
  1371. entry[config.formConfig.operator]=uId;
  1372. this.print(fName+': Form: '+entry.Form);
  1373. this.print(fName+": set form status to "+entry.FormStatus);
  1374. let that=this;
  1375. let cb=function(data){that.completeWithFlag(data,action);};
  1376. this.modifyRows('update','lists','crfEntry',[entry],cb,this.getContainer('data'));
  1377. }
  1378. crfVisit.completeWithFlag=
  1379. function(data,action){
  1380. let fName='[completeWithFlag]';
  1381. this.print(fName+': nrows '+data.rows.length);
  1382. let fentry=data.rows[0];
  1383. this.print(fName+': form status '+fentry.FormStatus);
  1384. this.print(fName+': form '+fentry.Form);
  1385. let crfStatus=this.createCrfStatus(fentry);
  1386. let config=this.config;
  1387. crfStatus.operator=config.formConfig.operator;
  1388. crfStatus.action=action.name;
  1389. let that=this;
  1390. let cb=function(){that.doNothing();};
  1391. if (action.cb) cb=action.cb;
  1392. this.insertRows('lists','crfStatus',[crfStatus],cb,this.getContainer('data'));
  1393. }
  1394. //************************************************ submit *******************************************
  1395. crfVisit.onSubmit=
  1396. function(){
  1397. //update list storage and change status
  1398. this.hideErr();
  1399. this.clearErr();
  1400. this.printErr("onSubmit");
  1401. let that=this;
  1402. let action=function(){that.verifyData();};
  1403. this.setData(action);
  1404. }
  1405. crfVisit.verifyData=
  1406. function(){
  1407. let fName='[verifyData]';
  1408. let config=this.config;
  1409. let qList=this.getQueryList();
  1410. let that=this;
  1411. let doNothing=function(data){that.doNothing();};
  1412. for (q in qList){
  1413. let qData=this.getQuerySnapshot(q);
  1414. if (q=="reviewComments") continue;
  1415. //copy snapshot to history
  1416. if (qData.rows.length==0){
  1417. this.print(fName+' no rows for '+q);
  1418. }
  1419. else
  1420. this.insertRows('lists',q+'History',qData.rows,doNothing,this.getContainer('data'));
  1421. //if it doesn't have additionalData, it is a sub query
  1422. if (!(q in config.formConfig.additionalData)){
  1423. continue;
  1424. }
  1425. if (qData.rows.length<1){
  1426. this.printErr('Missing entry for query '+q);
  1427. return false;
  1428. }
  1429. }
  1430. //this is necessary only for Generated to Generation completed step
  1431. let actionSettings=config.formConfig.actionSettings['onSubmit'];
  1432. if (variableList.hasVariable(actionSettings,"updateRegistration")){
  1433. this.updateRegistration();
  1434. }
  1435. let targetStatus=config.formConfig.targetStatus['onSubmit'];
  1436. let targetRecipient=config.formConfig.targetRecipient['onSubmit'];
  1437. this.print(fName+' targetStatus: '+targetStatus);
  1438. let finalStep=function(){that.redirect();};
  1439. if (variableList.hasVariable(actionSettings,"finalStep")){
  1440. //set to doNothing to remain on submit window
  1441. if (actionSettings.finalStep=="doNothing"){
  1442. finalStep=doNothing;
  1443. }
  1444. }
  1445. let action=new Object();
  1446. action.name='onSubmit';
  1447. action.cb=function(data){that.sendEmail(data,targetRecipient,finalStep,'Form sumbitted');};
  1448. this.updateFlag(targetStatus,action);
  1449. }
  1450. crfVisit.getEmail=
  1451. function(recipientCode){
  1452. this.print('getEmail w/'+recipientCode);
  1453. let config=this.config;
  1454. let recipients=new Array();
  1455. let typeTo=LABKEY.Message.recipientType.to;
  1456. let create=LABKEY.Message.createRecipient;
  1457. let currentUser=config.formConfig.currentUser;
  1458. let formCreator=config.formConfig.formCreator;
  1459. let currentSite=config.formConfig.currentSite;
  1460. let userRows=config.formConfig.userRows;
  1461. let parentUser=undefined;
  1462. if ("parentCrfData" in config.formConfig){
  1463. let parentCrf=config.formConfig.parentCrfData;
  1464. parentUser=this.getUser(parentCrf.rows[0].UserId,'parentUser');
  1465. }
  1466. let recipientCategories=recipientCode.split(',');
  1467. for (let i=0;i<recipientCategories.length;i++){
  1468. let recipient=recipientCategories[i];
  1469. this.print('Checking '+recipient);
  1470. if (recipient=='crfEditor'){
  1471. this.print('Adding :'+formCreator.Email);
  1472. recipients.push(create(typeTo,formCreator.Email));
  1473. if (parentUser==undefined) continue;
  1474. this.print('Adding :'+parentUser.Email);
  1475. recipients.push(create(typeTo,parentUser.Email));
  1476. continue;
  1477. }
  1478. //Monitor or Sponsor
  1479. let fList=recipient+'s';
  1480. let fRows=config.formConfig[fList];
  1481. for (let i=0;i<fRows.length;i++){
  1482. this.print('Checking '+fRows[i].User+'/'+fRows[i].Site);
  1483. if (fRows[i].Site!=currentSite.siteNumber) continue;
  1484. for (let j=0;j<userRows.length;j++){
  1485. if (userRows[j].UserId!=fRows[i].User) continue;
  1486. this.print('Adding :'+userRows[j].Email);
  1487. recipients.push(create(typeTo,userRows[j].Email));
  1488. break;
  1489. }
  1490. }
  1491. }
  1492. return recipients;
  1493. }
  1494. crfVisit.sendEmail=
  1495. function(data,recipient='crfEditor',cb=null,subj='Form submitted'){
  1496. this.print('sendEmail; recipient: '+recipient);
  1497. let config=this.config;
  1498. let that=this;
  1499. if (!cb)
  1500. cb=function(){that.redirect();};
  1501. let st=config.formConfig.settings;
  1502. let cvar='sendEmail';
  1503. if (cvar in st){
  1504. this.print(cvar+' set to '+st[cvar]);
  1505. if (st[cvar]=='FALSE'){
  1506. this.print('Skipping sending emails');
  1507. cb();
  1508. return;
  1509. }
  1510. }
  1511. if (recipient==null){
  1512. this.print('Skipping sending emails w/ no recipients');
  1513. cb();
  1514. return;
  1515. }
  1516. this.print('send email '+data.rows.length);
  1517. let crf=data.rows[0]['entryId'];
  1518. let formId=data.rows[0]['Form'];
  1519. let link=LABKEY.ActionURL.getBaseURL();
  1520. link+=LABKEY.ActionURL.getContainer();
  1521. link+='/crf_tecant-visit.view?';
  1522. link+='entryId='+crf;
  1523. link+='&formId='+formId;
  1524. link+='&role='+recipient;
  1525. //debug
  1526. let recipients=this.getEmail(recipient);
  1527. //from crfManagers list
  1528. let typeHtml=LABKEY.Message.msgType.html;
  1529. let typePlain=LABKEY.Message.msgType.plain;
  1530. let msg1=LABKEY.Message.createMsgContent(typePlain,link);
  1531. //let cb=doNothing;
  1532. //let cb=redirect;
  1533. LABKEY.Message.sendMessage({
  1534. msgFrom:'labkey@fmf.uni-lj.si',
  1535. msgSubject:subj,
  1536. msgRecipients:recipients,
  1537. msgContent:[msg1],
  1538. success: cb
  1539. });
  1540. }
  1541. crfVisit.hideErr=
  1542. function(){
  1543. let el=this.getElement("errorDiv");
  1544. el.style.display="none";
  1545. }
  1546. crfVisit.clearErr=
  1547. function(){
  1548. let el=this.getElement("errorTxt");
  1549. el.value="";
  1550. }
  1551. crfVisit.showErr=
  1552. function(){
  1553. let el=this.getElement("errorDiv");
  1554. el.style.display="block";
  1555. }
  1556. crfVisit.printErr=
  1557. function(msg){
  1558. this.showErr();
  1559. el=this.getElement("errorTxt");
  1560. el.style.color="red";
  1561. el.value+="\n"+msg;
  1562. }
  1563. //**************************************************
  1564. //
  1565. crfVisit.onRemoveCRF=
  1566. function(){
  1567. let fName='[onRemoveCRF]';
  1568. let config=this.config;
  1569. config.inputListsIterator=0;
  1570. this.print(fName+' starting loop');
  1571. //let rd=function(data){redirect();};
  1572. //let cb=function(){cvInsertRows('lists','crfStatus',[crfStatus],rd,getContainer('data'));};
  1573. let that=this;
  1574. let action=function(){that.redirect();};
  1575. let cb=function(){that.removeCrfEntries(action);};
  1576. this.removeCRFLoop(cb);
  1577. }
  1578. crfVisit.removeCRFLoop=
  1579. function(cb){
  1580. let fName='[removeCRFLoop()]';
  1581. let config=this.config;
  1582. let that=this;
  1583. let i=config.inputListsIterator;
  1584. let iMax=config.formConfig.inputLists.rows.length;
  1585. //in fact, we are adding two additional passages of the loop, one for
  1586. //crfEntry, the second for the same query, but using parentCrf as the
  1587. //selection variable
  1588. //let iTotal=iMax+1;
  1589. //let iTotal=iMax+1;
  1590. //
  1591. let actionSettings=config.formConfig.actionSettings['onRemoveCRF'];
  1592. let queryNameDeleteWithParentCrf='NONE';
  1593. if (variableList.hasVariable(actionSettings,'removeWithParentCrf')){
  1594. queryNameDeleteWithParentCrf=actionSettings['removeWithParentCrf'];
  1595. }
  1596. this.print(fName+" ["+i+"/"+iMax+"]");
  1597. if (!(i<iMax)){
  1598. cb();
  1599. return;
  1600. }
  1601. //in all but crfEntry, variable is called crfRef
  1602. let queryName=config.formConfig.inputLists.rows[i].queryName;
  1603. let idVar="crfRef";
  1604. let idValue=config.formConfig.crfEntry['entryId'];
  1605. //delete also crfEntries where parentCrf is set to crf that we are deleting
  1606. if (queryNameDeleteWithParentCrf==queryName){
  1607. idValue=config.formConfig.crfEntry['parentCrf'];
  1608. }
  1609. this.print(fName+" ["+i+"/"+iMax+"] "+queryName+":"+idVar+'/'+idValue);
  1610. let filters=[LABKEY.Filter.create(idVar,idValue)];
  1611. let action=function(data){that.removeListCRF(data,cb);};
  1612. let failure=function(errorInfo){that.skipListCRF(errorInfo,cb);};
  1613. this.selectRows('lists',queryName,filters,action,this.getContainer('data'),failure);
  1614. //selectRows.failure=skipListCRF;
  1615. }
  1616. crfVisit.removeListCRF=
  1617. function(data,cb){
  1618. let fName="[removeListCRF]";
  1619. let config=this.config;
  1620. let that=this;
  1621. this.print(fName+" "+data.queryName+": "+data.rows.length);
  1622. config.inputListsIterator+=1;
  1623. if (data.rows.length==0){
  1624. this.removeCRFLoop(cb);
  1625. return;
  1626. }
  1627. let action=function(data){that.removeCRFLoop(cb)};
  1628. this.deleteRows(data.schemaName,data.queryName,data.rows,action,this.getContainer('data'));
  1629. }
  1630. crfVisit.skipListCRF=
  1631. function(errorInfo,cb){
  1632. let fName='[skipListCRF]';
  1633. this.print(fName+" error in removeCRF: "+errorInfo.exception);
  1634. let config=this.config;
  1635. config.inputListsIterator+=1;
  1636. this.removeCRFLoop(cb);
  1637. }
  1638. crfVisit.removeCrfEntries=
  1639. function(cb){
  1640. let queryName="crfEntry";
  1641. let idVar="entryId";
  1642. let crfRef=this.getCRFref();
  1643. let that=this;
  1644. let filters=[LABKEY.Filter.create('entryId',crfRef)];
  1645. let action=function(data){that.deleteAndUpdateCrfStatus(data,null);}
  1646. this.selectRows('lists',queryName,filters,action,this.getContainer('CRF'));
  1647. let action1=function(data){that.deleteAndUpdateCrfStatus(data,cb);}
  1648. let filters1=[LABKEY.Filter.create('parentCrf',crfRef)];
  1649. this.selectRows('lists',queryName,filters1,action1,this.getContainer('CRF'));
  1650. }
  1651. crfVisit.deleteAndUpdateCrfStatus=
  1652. function(data,cb){
  1653. let fName='[deleteAndUpdateCrfStatus]';
  1654. let config=this.config;
  1655. let that=this;
  1656. let rows=data.rows;
  1657. let stack=new Array();
  1658. stack.push(cb);
  1659. for (let i=0;i<rows.length;i++){
  1660. //generate crfStatus entry out of crfEntry
  1661. let crfStatus=this.createCrfStatus(rows[i]);
  1662. crfStatus.action='onRemoveCRF';
  1663. crfStatus.FormStatus=config.formConfig.targetStatus[crfStatus.action];
  1664. this.print(fName+' status '+crfStatus.FormStatus);
  1665. crfStatus.operator=config.formConfig.operator;
  1666. let k=stack.length-1;
  1667. let containerPath=this.getContainer('CRF');
  1668. stack.push(function(){that.insertRows('lists','crfStatus',[crfStatus],stack[k],containerPath);});
  1669. let k1=k+1;
  1670. stack.push(function(){that.deleteRows('lists','crfEntry',[rows[i]],stack[k1],containerPath);});
  1671. }
  1672. //execute the whole stack
  1673. let m=stack.length-1;
  1674. stack[m]();
  1675. }
  1676. crfVisit.redirect=
  1677. function(){
  1678. let debug=false;
  1679. let formUrl="begin";
  1680. let params=new Object();
  1681. params.name=formUrl;
  1682. params.pageId="CRF";
  1683. //points to crf container
  1684. let containerPath=this.getContainer('CRF');
  1685. // This changes the page after building the URL.
  1686. //Note that the wiki page destination name is set in params.
  1687. var homeURL = LABKEY.ActionURL.buildURL(
  1688. "project", formUrl , containerPath, params);
  1689. this.print("Redirecting to "+homeURL);
  1690. if (debug) return;
  1691. window.location = homeURL;
  1692. }
  1693. //master section, entry point from html files
  1694. crfVisit.generateMasterForm=
  1695. function(){
  1696. let that=this;
  1697. let action=function(){that.setFormConfig();}
  1698. this.init(action);
  1699. }
  1700. //helper function to set basic parameters on web page
  1701. //(fields defined in html file)
  1702. crfVisit.populateBasicData=
  1703. function(){
  1704. let staticData=new Object();
  1705. let titles=new Object();
  1706. let config=this.config;
  1707. staticData['version']=config.formConfig.softwareVersion;
  1708. titles['version']='Software version';
  1709. let varRows=config.formConfig['crfStaticVariables'].rows;
  1710. for (let i=0;i<varRows.length;i++){
  1711. let vName=varRows[i].staticVariable;
  1712. let val=config.formConfig.crfEntry[vName];
  1713. if (val==undefined) continue;
  1714. staticData[vName]=val;
  1715. titles[vName]=varRows[i].Title;
  1716. }
  1717. staticData['investigatorName']=config.formConfig.user['DisplayName'];
  1718. titles['investigatorName']='Investigator';
  1719. staticData['email']=config.formConfig.user['Email'];
  1720. titles['email']='Email';
  1721. staticData['siteName']=config.formConfig.currentSite['siteName'];
  1722. titles['siteName']='Site';
  1723. staticData['sitePhone']=config.formConfig.currentSite['sitePhone'];
  1724. titles['sitePhone']='Telephone(site)';
  1725. for (f in staticData){
  1726. this.addStaticData(f,titles[f],staticData[f]);
  1727. }
  1728. }
  1729. crfVisit.addStaticData=
  1730. function(f,title,value){
  1731. let el=this.getElement(f);
  1732. //populate only
  1733. if (el!=undefined){
  1734. el.innerText=value;
  1735. return;
  1736. }
  1737. //add row to table if element cannot be found
  1738. let table=this.getElement('staticTable');
  1739. let row=table.insertRow();
  1740. let cell=row.insertCell();
  1741. cell.innerText=title;
  1742. let cell1=row.insertCell();
  1743. cell1.id=f;
  1744. cell1.style.fontWeight='bold';
  1745. //populate
  1746. cell1.innerText=value;
  1747. }
  1748. //come here after the layout is read from labkey page
  1749. //
  1750. crfVisit.generateErrorMsg=
  1751. function(msg){
  1752. let config=this.config;
  1753. let txt=config.document.createElement('p');
  1754. txt.innerText=msg;
  1755. this.getElement(config.masterForm).appendChild(txt);
  1756. this.generateButton("submitDiv",'Exit','Exit','redirect');
  1757. }
  1758. crfVisit.getUser=
  1759. function(id,field){
  1760. let config=this.config;
  1761. if (field in config.formConfig) return config.formConfig[field];
  1762. let uRows=config.formConfig.userRows;
  1763. for (let i=0;i<uRows.length;i++){
  1764. let userId=uRows[i].UserId;
  1765. if (userId!=id) continue;
  1766. config.formConfig[field]=uRows[i];
  1767. return config.formConfig[field];
  1768. }
  1769. return null;
  1770. }
  1771. crfVisit.afterConfig=
  1772. function(){
  1773. let fName='[afterConfig]';
  1774. let config=this.config;
  1775. this.print(fName);
  1776. this.populateBasicData();
  1777. //check if user has permission on the form
  1778. let currentUser=this.getUser(LABKEY.Security.currentUser.id,'currentUser');
  1779. let currentSite=config.formConfig.currentSite;
  1780. let formCreator=this.getUser(config.formConfig.crfEntry.UserId,'formCreator');
  1781. let formCreatorId=formCreator.UserId;
  1782. //let formSite=config.formConfig.crfEntry.Site;
  1783. let fList=config.formConfig.operator+'s';
  1784. let fRows=config.formConfig[fList];
  1785. //let currentSiteId=-1;
  1786. let operatorSites=new Array();
  1787. for (let i=0;i<fRows.length;i++){
  1788. if (fRows[i].User!=currentUser.UserId) continue;
  1789. operatorSites.push(fRows[i].Site);
  1790. }
  1791. //depending on operator mode, we should decide what is right
  1792. let operator=config.formConfig.operator;
  1793. if (operator=='crfEditor'){
  1794. //editor can only edit its own forms
  1795. if (currentUser.UserId!=formCreatorId){
  1796. if ("allowFormReassignment" in config.formConfig.settings){
  1797. if (!operatorSites.includes(currentSite.siteNumber)){
  1798. let msg='User '+currentUser.DisplayName;
  1799. msg+=' has no permission for site '+currentSite.siteName;
  1800. this.generateErrorMsg(msg);
  1801. return;
  1802. }
  1803. let that=this;
  1804. let action=new Object();
  1805. action.name="formReassignement";
  1806. action.cb=function(){that.doNothing();}
  1807. config.formConfig.crfEntry['UserId']=currentUser.UserId;
  1808. let status=config.formConfig.crfEntry['FormStatus'];
  1809. this.updateFlag(status,action);
  1810. }
  1811. else{
  1812. let msg='User '+currentUser.DisplayName;
  1813. msg+=' has no permission on this form';
  1814. this.generateErrorMsg(msg);
  1815. return;
  1816. }
  1817. }
  1818. }
  1819. if (operator=='crfMonitor' || operator=='crfSponsor'){
  1820. //monitor can look at forms based on his site
  1821. //find monitor line
  1822. this.print('operator Site: '+operatorSites.length);
  1823. if (operatorSites.length==0){
  1824. let msg='User '+currentUser.DisplayName;
  1825. msg+=' is not a '+operator;
  1826. this.generateErrorMsg(msg);
  1827. return;
  1828. }
  1829. let selectedSite=-1;
  1830. let siteCandidates="[";
  1831. for (let i=0;i<operatorSites.length;i++){
  1832. if (i>0) siteCandidates+=", ";
  1833. siteCandidates+=operatorSites[i];
  1834. if (operatorSites[i]!=currentSite.siteNumber) continue;
  1835. selectedSite=currentSite.siteNumber;
  1836. break;
  1837. }
  1838. siteCandidates+="]";
  1839. if (selectedSite==-1){
  1840. let msg='User '+currentUser.DisplayName;
  1841. msg+=' is not a '+operator+' for site ';
  1842. msg+=currentSite.siteName+'('+currentSite.siteNumber+')';
  1843. msg+='/'+siteCandidates;
  1844. this.generateErrorMsg(msg);
  1845. return;
  1846. }
  1847. }
  1848. this.print('User '+currentUser.DisplayName+'/'+
  1849. config.formConfig.currentSite['siteName']+
  1850. ' acting as '+config.formConfig.operator);
  1851. let rows=config.formConfig.crfButtons.rows;
  1852. config.formConfig.targetStatus=new Array();
  1853. config.formConfig.targetRecipient=new Array();
  1854. config.formConfig.actionSettings=new Array();
  1855. for (let i=0; i<rows.length; i++){
  1856. let action=rows[i].action;//String
  1857. let tstatus=rows[i].targetFormStatus;
  1858. let trecip=rows[i].targetRecipient;
  1859. config.formConfig.targetStatus[action]=tstatus;
  1860. config.formConfig.targetRecipient[action]=trecip;
  1861. //allow for settings to be promoted with each action (and potentially parsed and acted upon)
  1862. config.formConfig.actionSettings[action]=undefined;
  1863. let aSet=rows[i].actionSettings;
  1864. if (aSet){
  1865. config.formConfig.actionSettings[action]=variableList.parseVariables(aSet);
  1866. variableList.printVariables(this,config.formConfig.actionSettings[action]);
  1867. }
  1868. }
  1869. let formStatus=config.formConfig.formStatus;
  1870. //let functionArray=new Array();
  1871. this.print("Generating buttons for formStatus \""+ formStatus+"\"");
  1872. let allButtonRows=config.formConfig.crfButtons.rows;
  1873. let buttonRows=new Array();
  1874. //specifying role=X in actionSettings will limit button to that role
  1875. for (let i=0;i<allButtonRows.length;i++){
  1876. let action=allButtonRows[i]['action'];
  1877. //filter on actionSettings
  1878. let as=config.formConfig.actionSettings[action];
  1879. if (variableList.hasVariable(as,'role')){
  1880. this.print('Role['+config.formConfig.operator+'/'+as['role']+'] limited for action '+action);
  1881. //mismatch skips addition of button to buttonRows
  1882. if (config.formConfig.operator!=as['role']) continue;
  1883. }
  1884. buttonRows.push(allButtonRows[i]);
  1885. }
  1886. for (let i=0;i<buttonRows.length;i++){
  1887. let bt=buttonRows[i];
  1888. //if (typeof window[bt.action]==="function"){
  1889. this.generateButton("submitDiv",bt.caption,bt.label,bt.action,null);
  1890. //}
  1891. //else{
  1892. // this.print('No match for function :'+bt.action+
  1893. // ' obj: '+window[bt.action]);
  1894. //}
  1895. }
  1896. this.print('Here');
  1897. //here we should get data. For now, just initialize objects that will hold data
  1898. let that=this;
  1899. let action=function(){that.afterDataLayout();};
  1900. this.setDataLayout(action);//callback is afterDataLayout
  1901. }
  1902. crfVisit.afterDataLayout=
  1903. function(){
  1904. let that=this;
  1905. let action=function(){that.afterData();};
  1906. //let action=function(){that.doNothing();};
  1907. this.setData(action);//callback is afterData
  1908. }
  1909. crfVisit.updateRegistration=
  1910. function(){
  1911. let fName="[updateRegistration]";
  1912. let config=this.config;
  1913. this.print(fName);
  1914. let pM=this.getIdManager();
  1915. let idFieldName=participantIdManager.getCrfEntryFieldName(pM,"STUDY");
  1916. //have to reload query data
  1917. let regQueryPars=variableList.parseVariables(config.formConfig.settings['registrationQuery']);
  1918. let regQuery=regQueryPars['query'];
  1919. let fQuery=this.getQuerySnapshot(regQuery);
  1920. if (fQuery.rows.length==0) {
  1921. this.print(fName+" registration is empty");
  1922. return; //registration is empty
  1923. }
  1924. let regEntry=fQuery.rows[0];
  1925. for (x in regEntry){
  1926. this.print(fName+" ["+x+"] "+regEntry[x]);
  1927. }
  1928. let studyId=fQuery.rows[0][idFieldName];
  1929. if (!studyId) {
  1930. this.print(fName+" study id not set ("+idFieldName+'/'+studyId+")");
  1931. return; //study id not set
  1932. }
  1933. //set
  1934. participantIdManager.setParticipantIdToCrfEntry(pM,studyId,"STUDY");
  1935. //this will only update crfEntry in memory, but not on LabKey,
  1936. //we are counting on updateFlag to follow updateRegistration
  1937. //update parentCRF as well, here we schedule update of data entry as well
  1938. if ("parentCrfData" in config.formConfig){
  1939. let parentCrfEntry=config.formConfig.parentCrfData.rows[0];
  1940. parentCrfEntry[idFieldName]=studyId;
  1941. let that=this;
  1942. let action={name:"updateRegistration",cb:function(){that.doNothing();}};
  1943. let cb=function(data){that.completeWithFlag(data,action);};
  1944. this.modifyRows('update','lists','crfEntry',[parentCrfEntry],cb,this.getContainer('CRF'));
  1945. }
  1946. }
  1947. crfVisit.afterData=
  1948. function(){
  1949. let fName='afterData';
  1950. let config=this.config;
  1951. //operatorBasedAccessMode
  1952. let accessMode=config.formConfig.operator+'Mode';
  1953. let rowsSetup=config.formConfig.formSetupRows;
  1954. let idMode=config.formConfig.form['idMode'];
  1955. //set default value if no value is in the list (read value is null)
  1956. if (!idMode) idMode="STUDY:EDIT";
  1957. this.print(fName+': idMode '+idMode);
  1958. //add print to config so participantManager can use it
  1959. let pM=this.getIdManager();
  1960. //extend object
  1961. let that=this;
  1962. let action=new Object();
  1963. action.name='updateCrfEntry';
  1964. action.cb=function(){that.doNothing();};
  1965. pM.updateCrfEntry=function(){that.updateFlag(config.formConfig.crfEntry['FormStatus'],action);};
  1966. let idModeArray=idMode.split(':');
  1967. pM.mode="STUDY";
  1968. if (idModeArray.includes("LOCAL")) {
  1969. pM.mode="LOCAL";
  1970. //OK, but check if CRF or registration indicate that study id is already set
  1971. participantIdManager.verifyCrfStudyId(pM);
  1972. //study id should already be set by updateRegistration
  1973. //verifyRegistration(pM);
  1974. }
  1975. if (idModeArray.includes("READONLY")){
  1976. pM.readOnly="TRUE";
  1977. }
  1978. let pId=participantIdManager.getParticipantIdFromCrfEntry(pM);
  1979. if (!pId){
  1980. participantIdManager.setEditMode(pM);
  1981. }
  1982. else{
  1983. let label=pId;
  1984. if (pM.mode=="STUDY"){
  1985. let loc=participantIdManager.getParticipantIdFromCrfEntry(pM,'LOCAL');
  1986. label=pId+':'+loc;
  1987. pM.readOnly="true";
  1988. }
  1989. participantIdManager.setLabelMode(pM,label);
  1990. //in STUDY mode also change LOCAL ID from crfEntry
  1991. }
  1992. for (let i=0;i<rowsSetup.length;i++){
  1993. let entry=rowsSetup[i];
  1994. let queryName=config.formConfig.queryMap[entry['queryName']];
  1995. this.print(fName+" ["+queryName+"]: showFlag: "+entry["showFlag"]);
  1996. this.print(fName+" ["+queryName+"]: accessMode: "+entry[accessMode]);
  1997. const nData=this.getQuerySnapshot(queryName).rows.length;
  1998. this.print(fName+" ["+queryName+"]: nData: "+nData);
  1999. //skip sections
  2000. //also from fields
  2001. if (entry[accessMode]=="NONE") continue;
  2002. //skip readonly empty records
  2003. //if (entry[accessMode]=="READ" && nData==0) continue;
  2004. //let additionalData=new Object();
  2005. //setAdditionalData(additionalData,entry);
  2006. //section fits one dataset/list
  2007. this.generateSection(entry);
  2008. //generateSection(queryName,entry["title"],entry[accessMode],
  2009. // additionalData);
  2010. }
  2011. }
  2012. crfVisit.findSetupRow=
  2013. function(queryName,formId){
  2014. let config=this.config;
  2015. let rowsSetup=config.formConfig.formSetupRows;
  2016. for (let i=0;i<rowsSetup.length;i++){
  2017. let e=rowsSetup[i];
  2018. let queryName1=config.formConfig.queryMap[e['queryName']];
  2019. if (e.formName!=formId) continue;
  2020. if (queryName1!=queryName) continue;
  2021. return e;
  2022. }
  2023. return null;
  2024. }
  2025. crfVisit.populateSection=
  2026. function(queryName){
  2027. let fName='[populateSection/'+queryName+']';
  2028. let config=this.config;
  2029. this.print(fName);
  2030. //old setting
  2031. let formId=config.formId;
  2032. //new setting
  2033. formId=config.formConfig.formId;
  2034. let entry=this.findSetupRow(queryName,formId);
  2035. //ignore names without associated entry in formSetup
  2036. if (entry==undefined){
  2037. this.print(fName+': no matching FormSetup entry found');
  2038. return;
  2039. }
  2040. //populate comes after generate, we should be pretty safe in taking
  2041. //already generated additionalData
  2042. if (!(queryName in config.formConfig.additionalData)){
  2043. this.print(fName+': no additionalData generated for '+queryName);
  2044. return;
  2045. }
  2046. let additionalData=config.formConfig.additionalData[queryName];
  2047. this.print(fName+': using additionalData '+additionalData);
  2048. if ("isReview" in additionalData){
  2049. let action=function(){crfReviewSection.CB();};
  2050. crfReviewSection.generateSection(queryName,queryName,action);
  2051. return;
  2052. }
  2053. let accessMode=config.formConfig.operator+'Mode';
  2054. let aM=entry[accessMode];
  2055. this.print(fName+': accessMode '+aM);
  2056. if (aM!='GENERATE'){
  2057. let writeMode=entry[accessMode]=='EDIT';
  2058. this.print(fName+': mode='+writeMode);
  2059. this.populateTable(queryName,writeMode);
  2060. return;
  2061. }
  2062. //deal with generate
  2063. //
  2064. //already available -> shift to READ mode
  2065. let divTable=queryName+'Table';
  2066. let divObj=this.getElement(divTable);
  2067. let divRev=this.getElement(queryName+'Review');
  2068. let divRLi=this.getElement(queryName+'ReviewList');
  2069. let divGBu=this.getElement(queryName+'GenerateButton');
  2070. this.print('div GBU: '+divGBu);
  2071. divObj.style.display="block";
  2072. divRev.style.display="block";
  2073. divRLi.style.display="block";
  2074. if (divGBu!=undefined) divGBu.style.display="none";
  2075. let nData=this.getQuerySnapshot(queryName).rows.length;
  2076. this.print('['+queryName+']: nrows '+nData);
  2077. if (nData>0){
  2078. this.populateTable(queryName,0);
  2079. return;
  2080. }
  2081. //hide table
  2082. divObj.style.display="none";
  2083. divRev.style.display="none";
  2084. divRLi.style.display="none";
  2085. if (divGBu!=undefined) divGBu.style.display="block";
  2086. //add buttons?
  2087. //is button already generated?
  2088. //populateTable(entry);
  2089. }
  2090. //******* generateQuery infrastructure *********************
  2091. crfVisit.onGenerateQuery=
  2092. function(queryName){
  2093. let fName='[onGenerateQuery]';
  2094. this.print(fName+' '+queryName);
  2095. //
  2096. let config=this.config;
  2097. let cfgRows=config.formConfig.generateConfigData.rows;
  2098. // //queryName to queryId?
  2099. let queryId=config.formConfig.fields[queryName].queryId;
  2100. let cfgRow=undefined;
  2101. for (let i=0;i<cfgRows.length;i++){
  2102. if (cfgRows[i].queryId!=queryId) continue;
  2103. cfgRow=cfgRows[i];
  2104. break;
  2105. }
  2106. if (cfgRow==undefined){
  2107. this.print('generateConfig for queryName['+queryId+']='+queryName+' not found');
  2108. return;
  2109. }
  2110. //add config to the list
  2111. if (!("generateConfig" in config.formConfig)){
  2112. config.formConfig.generateConfig=new Object();
  2113. }
  2114. config.formConfig.generateConfig[queryName]=cfgRow;
  2115. if (!("generateForm" in config.formConfig)){
  2116. config.formConfig.generateForm=new Object();
  2117. }
  2118. //
  2119. let formRows=config.formConfig.formRows;
  2120. let formId=cfgRow.formId;
  2121. for (let i=0;i<formRows.length;i++){
  2122. if (formRows[i].Key==formId) {
  2123. config.formConfig.generateForm[queryName]=formRows[i];
  2124. break;
  2125. }
  2126. }
  2127. //this.print('XcfgRow '+config.formConfig.generateForm[queryName]);
  2128. //
  2129. // //check if all required datasets were at least saved
  2130. this.checkGenerationFields(queryName);
  2131. }
  2132. crfVisit.checkGenerationFields=
  2133. function(queryName){
  2134. let fName='[checkGenerationFields]';
  2135. let config=this.config;
  2136. let genForm=config.formConfig.generateForm[queryName];
  2137. let genCfg=config.formConfig.generateConfig[queryName];
  2138. let mailRecipient=genCfg.emailRecipient;
  2139. //list of queries that are part of Registration form
  2140. this.print(fName);
  2141. this.print(fName+' setRecipient: '+mailRecipient);
  2142. let formId=genForm.Key;
  2143. this.print(fName+" Checking form w/id "+formId);
  2144. let selectGenerationRows=this.selectFormSetupRows(formId);
  2145. //registration rows
  2146. for (let i=0;i<selectGenerationRows.length;i++){
  2147. let row=selectGenerationRows[i];
  2148. let queryId=row.queryName;
  2149. let fQueryName=config.formConfig.queryMap[queryId];
  2150. if (fQueryName==queryName) continue;
  2151. let fQuery=this.getQuerySnapshot(fQueryName);
  2152. this.print('Checking '+fQueryName+' nrows: '+fQuery.rows.length);
  2153. if (fQuery.rows.length==0){
  2154. this.generateError(queryName,fQueryName);
  2155. return;
  2156. }
  2157. }
  2158. this.generateMessage(queryName,'Vailidation OK');
  2159. this.print('callback: set recipient: '+mailRecipient);
  2160. let that=this;
  2161. let cb=function(){that.prepareForm(queryName,formId,mailRecipient);};
  2162. this.generateListEntry(formId,queryName,cb);
  2163. }
  2164. crfVisit.prepareForm=
  2165. function(queryName,formId,mailRecipient){
  2166. let fName="[prepareForm]";
  2167. this.print(fName+' recipient '+mailRecipient);
  2168. //look for existing registration entry
  2169. let that=this;
  2170. let action=function(data){that.generateForm(data,queryName,mailRecipient);};
  2171. let formFilter=LABKEY.Filter.create('Form',formId);
  2172. let parentCrfFilter=LABKEY.Filter.create('parentCrf',this.getCRFref());
  2173. let filters=[formFilter,parentCrfFilter];
  2174. this.selectRows('lists','crfEntry',filters,action,this.getContainer('data'));
  2175. }
  2176. crfVisit.generateError=
  2177. function(queryName,fQueryName){
  2178. let elName=queryName+'GenerateButton'+'_reportField';
  2179. let el=this.getElement(elName);
  2180. el.innerText='Error: '+fQueryName+' was not set';
  2181. el.style.color='red';
  2182. }
  2183. crfVisit.generateMessage=
  2184. function(queryName,msg){
  2185. let elName=queryName+'GenerateButton'+'_reportField';
  2186. let el=this.getElement(elName);
  2187. el.innerText=msg;
  2188. el.style.color='green';
  2189. }
  2190. crfVisit.generateForm=
  2191. function(data,queryName,mailRecipient){
  2192. let fName='[generateForm]';
  2193. this.print(fName+' recipient: '+mailRecipient);
  2194. //
  2195. const nData=data.rows.length;
  2196. this.print(fName+' Registration: '+nData+' rows');
  2197. let config=this.config;
  2198. let formRow=config.formConfig.generateForm[queryName];
  2199. let formCfg=config.formConfig.generateConfig[queryName];
  2200. //we have to generate masterQuery with parentCrf and crfRef
  2201. //and crfEntry with new entryId and parentCrf equal to crfRef
  2202. if (nData>0) {
  2203. this.generateMessage(queryName,'Registration already generated.');
  2204. return;
  2205. }
  2206. let formId=formRow.Key;
  2207. let formName=formRow.formName;
  2208. let crfBase=config.formConfig.crfEntry;
  2209. let crfEntry=new Object();
  2210. //add new reference
  2211. crfEntry.entryId=Date.now();
  2212. crfEntry.parentCrf=this.getCRFref();
  2213. crfEntry["Date"]=new Date();
  2214. crfEntry["View"]="[VIEW]";
  2215. crfEntry.formStatus=1;//In progress
  2216. //checks for both field presence (if not in query, undefined) and field value (if not set, null)
  2217. this.print(fName+' setup status: '+formCfg.formStatus);
  2218. if (formCfg.formStatus){
  2219. crfEntry.formStatus=formCfg.formStatus;
  2220. }
  2221. //get local Id
  2222. let pM=this.getIdManager();
  2223. crfEntry[participantIdManager.getCrfEntryFieldName(pM)]=participantIdManager.getParticipantIdFromCrfEntry(pM);
  2224. // //set other variables
  2225. //requires studyData as part of formConfig
  2226. // let studyData=config.formConfig.studyData;
  2227. this.print('Adding study: '+crfBase.EudraCTNumber);
  2228. crfEntry.EudraCTNumber=crfBase.EudraCTNumber;
  2229. crfEntry.StudyCoordinator=crfBase.StudyCoordinator;
  2230. crfEntry.StudySponsor=crfBase.StudySponsor;
  2231. crfEntry.RegulatoryNumber=crfBase.RegulatoryNumber;
  2232. //
  2233. // //find sponsor for site
  2234. let site=crfBase.Site;
  2235. let crfSponsors=config.formConfig.crfSponsors;
  2236. let users=config.formConfig.userRows;
  2237. for (let i=0;i<crfSponsors.length;i++){
  2238. //this.print('Checking for site '+crfSponsors[i].Site);
  2239. if (crfSponsors[i].Site!=site) continue;
  2240. config.formConfig.sponsorId=crfSponsors[i].User;
  2241. //this.print('Setting id '+config.formConfig.sponsorId);
  2242. //finds first
  2243. break;
  2244. }
  2245. for (let j=0;j<users.length;j++){
  2246. if (config.formConfig.sponsorId!=users[j].UserId) continue;
  2247. config.formConfig.sponsor=users[j];
  2248. //finds first (should be unique)
  2249. break;
  2250. }
  2251. this.print('Selecting '+config.formConfig.sponsor.DisplayName+' as sponsor');
  2252. //different user than the original form...
  2253. //should be set to the study sponsor
  2254. crfEntry.UserId=config.formConfig.sponsor.UserId;
  2255. crfEntry.Site=site;
  2256. // //set formId to one found through registration search
  2257. crfEntry.Form=formId;
  2258. ////
  2259. let crfStatus=this.createCrfStatus(crfEntry);
  2260. crfStatus.operator=config.formConfig.operator;
  2261. crfStatus.action='generateForm';
  2262. let that=this;
  2263. let action=function(){that.doNothing();};
  2264. let cb=function(data){that.sendEmail(data,mailRecipient,action,formName+' generated');}
  2265. let containerPath=this.getContainer('data');
  2266. let pass=function(data){that.insertRows('lists','crfStatus',[crfStatus],cb,containerPath);};
  2267. this.insertRows('lists','crfEntry',[crfEntry],pass,this.getContainer('data'));
  2268. }
  2269. crfVisit.generateListEntry=
  2270. function(formId,queryName,cb){
  2271. //check if registration was already generated
  2272. let config=this.config;
  2273. let formRows=config.formConfig.formRows;
  2274. let qForm=undefined;
  2275. for (let i=0;i<formRows.length;i++){
  2276. if (formRows[i].Key!=formId) continue;
  2277. qForm=formRows[i];
  2278. }
  2279. let nData=this.getQuerySnapshot(queryName).rows.length;
  2280. if (nData>0) return;
  2281. //create new list entry
  2282. let pM=this.getIdManager();
  2283. let e2=new Object();
  2284. e2.crfRef=this.getCRFref();
  2285. e2.registrationStatus=0;
  2286. e2.submissionDate=new Date();
  2287. e2[participantIdManager.getCrfEntryFieldName(pM)]=participantIdManager.getParticipantIdFromCrfEntry(pM);
  2288. this.print('set values');
  2289. this.insertRows('lists',queryName,[e2],cb,this.getContainer('data'));
  2290. }
  2291. // ******************** end form generator (Registration) ********************
  2292. //jump to populate table/generate review, etc defined at the begining of the file
  2293. //entry point from generateMasterForm
  2294. crfVisit.setFormConfig=
  2295. function(){
  2296. let fName="[setFormConfig]";
  2297. let config=this.config;
  2298. //add object to store form related data
  2299. config.formConfig=new Object();
  2300. config.formConfig.softwareVersion='T.15.68';
  2301. this.print(fName+" generateMasterForm");
  2302. //set containers for data and configuration
  2303. //TODO: set this from a query
  2304. //
  2305. this.setContainer('data',LABKEY.ActionURL.getContainer());
  2306. this.setContainer('config',LABKEY.ActionURL.getContainer());
  2307. this.setContainer('CRF',LABKEY.ActionURL.getContainer());
  2308. //this is local data
  2309. let that=this;
  2310. let action=function(data){that.afterSettings(data);};
  2311. this.selectRows('lists','crfSettings',[],action,this.getContainer('CRF'));
  2312. //store form related data to this object
  2313. }
  2314. crfVisit.afterSettings=
  2315. function(data){
  2316. let fName='[afterSettings]';
  2317. let config=this.config;
  2318. config.formConfig.settings=variableList.convertToDictionary(data.rows);
  2319. let st=config.formConfig.settings;
  2320. this.print('afterSettings');
  2321. for (let k in st){
  2322. this.print(fName+'\t'+k+'='+st[k]);
  2323. }
  2324. //if ('dataContainer' in st){
  2325. // setContainer('data',st['dataContainer']);
  2326. //}
  2327. let vname='configContainer';
  2328. if (vname in st){
  2329. this.setContainer('config',st[vname]);
  2330. }
  2331. this.print('Config: '+this.getContainer('config'));
  2332. this.print('Data: '+this.getContainer('data'));
  2333. //use first-> we must first establish link to the rigth crf entry
  2334. let filters=[LABKEY.Filter.create('entryId',this.getCRFrefFirst())];
  2335. let that=this;
  2336. let action=function(data){that.afterCRFEntry(data);};
  2337. this.selectRows('lists','crfEntry',filters,action,this.getContainer('data'));
  2338. }
  2339. crfVisit.afterCRFEntry=
  2340. function(data){
  2341. let config=this.config;
  2342. let fName='[afterCRFEntry]';
  2343. config.formConfig.crfEntry=data.rows[0];
  2344. this.print("Setting crfEntry (x) to "+config.formConfig.crfEntry["entryId"]);
  2345. //for empty records or those with parentCrf not set, parentCrf comes up as null
  2346. //nevertheless, with two equal signs, check against undefined also works
  2347. this.print('parentCrf set to '+config.formConfig.crfEntry.parentCrf);
  2348. this.collectData();
  2349. }
  2350. crfVisit.collectData=
  2351. function(){
  2352. let config=this.config;
  2353. let targetObject=config.formConfig;
  2354. let queryArray=new Array();
  2355. //k
  2356. //site
  2357. queryArray.push(runQuery.makeQuery(targetObject,'config','site','siteData',[]));
  2358. //users
  2359. queryArray.push(runQuery.makeQuery(targetObject,'CRF','users','userData',[]));
  2360. queryArray[queryArray.length-1].schemaName='core';
  2361. //crfEditors
  2362. queryArray.push(runQuery.makeQuery(targetObject,'config','crfEditors','crfEditorsData',[]));
  2363. //crfMonitors
  2364. queryArray.push(runQuery.makeQuery(targetObject,'config','crfMonitors','crfMonitorsData',[]));
  2365. //crfSponsors
  2366. queryArray.push(runQuery.makeQuery(targetObject,'config','crfSponsors','crfSponsorsData',[]));
  2367. //crfManagers
  2368. queryArray.push(runQuery.makeQuery(targetObject,'config','crfManagers','crfManagersData',[]));
  2369. //study static data
  2370. queryArray.push(
  2371. runQuery.makeQuery(targetObject,'data','crfStaticVariables','crfStaticVariables',[]));
  2372. queryArray.push(runQuery.makeQuery(targetObject,'data','specialFields','specialFieldsQuery',[]));
  2373. //study
  2374. queryArray.push(runQuery.makeQuery(targetObject,'data','Study','studyDataAll1',[]));
  2375. let e=queryArray[queryArray.length-1];
  2376. //overload schema name
  2377. e.schemaName='study';
  2378. //make sure variables not part of default view are loaded
  2379. //here we should already have read crfStaticVariables table
  2380. e.columns="SubjectColumnName,EudraCTNumber,StudySponsor";
  2381. e.columns+=",StudyCoordinator,RegulatoryNumber";
  2382. //formStatus
  2383. let varLabel='sourceFormStatus';
  2384. let formStatus=config.formConfig.crfEntry['FormStatus'];
  2385. let formFilter=LABKEY.Filter.create('Key',formStatus);
  2386. queryArray.push(
  2387. runQuery.makeQuery(targetObject,'config','FormStatus','formStatusData',[formFilter]));
  2388. //crfButtons
  2389. let statusFilter=LABKEY.Filter.create(varLabel,formStatus);
  2390. queryArray.push(
  2391. runQuery.makeQuery(targetObject,'config','crfButtons','crfButtons',[statusFilter]));
  2392. //Forms
  2393. queryArray.push(runQuery.makeQuery(targetObject,'config','Forms','formData',[]));
  2394. //FormSetup
  2395. queryArray.push(runQuery.makeQuery(targetObject,'config','FormSetup','formSetup',[]));
  2396. //generateConfig
  2397. queryArray.push(
  2398. runQuery.makeQuery(targetObject,'config','generateConfig','generateConfigData',[]));
  2399. //inputLists
  2400. queryArray.push(
  2401. runQuery.makeQuery(targetObject,'config','inputLists','inputLists',[]));
  2402. //parentCrf
  2403. let parentCrf=config.formConfig.crfEntry['parentCrf'];
  2404. if (parentCrf!=undefined){
  2405. let crfFilter=LABKEY.Filter.create('entryId',parentCrf);
  2406. queryArray.push(runQuery.makeQuery(targetObject,'data','crfEntry','parentCrfData',[crfFilter]));
  2407. }
  2408. //crfEntries
  2409. queryArray.push(
  2410. runQuery.makeQuery(targetObject,'data','crfEntry','crfEntries',[]));
  2411. this.print('running getDataFromQueries');
  2412. let that=this;
  2413. //let action=function(data){that.doNothing();};
  2414. let action=function(){that.addStudyData();};
  2415. runQuery.getDataFromQueries(this,queryArray,action);
  2416. }
  2417. crfVisit.addStudyData=
  2418. function(){
  2419. let fName='addStudyData';
  2420. let config=this.config;
  2421. //convert specialFields to array
  2422. let q=config.formConfig["specialFieldsQuery"].rows;
  2423. config.formConfig.specialFields=variableList.convertToAssociatedArray(q,"fieldUID");
  2424. this.print(fName);
  2425. let queryArray=new Array();
  2426. let targetObject=config.formConfig;
  2427. //study
  2428. queryArray.push(runQuery.makeQuery(targetObject,'data','Study','studyDataAll',[]));
  2429. //queryArray.push(runQuery.makeQuery('data','Study','studyDataAll',[]));
  2430. let e=queryArray[queryArray.length-1];
  2431. //overload schema name
  2432. e.schemaName='study';
  2433. //make sure variables not part of default view are loaded
  2434. //here we should already have read crfStaticVariables table
  2435. let staticVarRows=config.formConfig['crfStaticVariables'].rows;
  2436. let columnModel=""
  2437. for (let i=0;i<staticVarRows.length;i++){
  2438. if (i>0) columnModel+=',';
  2439. columnModel+=staticVarRows[i]['staticVariable'];
  2440. }
  2441. e.columns=columnModel;
  2442. //also collect ids already in study
  2443. //registrationQuery should be a dataset
  2444. //since monitors can review late, it might be profitable to use lists
  2445. //rather than study
  2446. let regQueryPars=variableList.parseVariables(config.formConfig.settings['registrationQuery']);
  2447. let regQuery=regQueryPars['query'];
  2448. let regSchema='study';
  2449. if ('schema' in regQueryPars){
  2450. regSchema=regQueryPars['schema'];
  2451. }
  2452. queryArray.push(runQuery.makeQuery(targetObject,'data',regQuery,'registrationData',[]));
  2453. queryArray[queryArray.length-1].schemaName=regSchema;
  2454. let that=this;
  2455. let action=function(){that.fcontinue();};
  2456. runQuery.getDataFromQueries(this,queryArray,action);
  2457. }
  2458. crfVisit.fcontinue=
  2459. function(){
  2460. //debug
  2461. let fName='[fcontinue]';
  2462. let config=this.config;
  2463. let varRows=config.formConfig['crfStaticVariables'].rows;
  2464. let studyVars=config.formConfig['studyDataAll'].rows[0];
  2465. for (let i=0;i<varRows.length;i++){
  2466. let vName=varRows[i].staticVariable;
  2467. this.print(fName+' '+vName+': '+studyVars[vName]);
  2468. }
  2469. //parse site
  2470. config.formConfig.siteRows=config.formConfig.siteData.rows;
  2471. let sRows=config.formConfig.siteRows;
  2472. for (let i=0;i<sRows.length;i++){
  2473. let siteId=sRows[i].siteNumber;
  2474. this.print('site '+siteId);
  2475. if (siteId==config.formConfig.crfEntry.Site){
  2476. config.formConfig.currentSite=sRows[i];
  2477. break;
  2478. }
  2479. }
  2480. //config.formConfig.site=data.rows[0];
  2481. this.print("Setting site name to "+config.formConfig.currentSite.siteName);
  2482. //study
  2483. config.formConfig.studyData=config.formConfig.studyDataAll.rows[0];
  2484. this.print("XSetting participantField to "+
  2485. config.formConfig.studyData["SubjectColumnName"]);
  2486. config.formConfig.crfEditors=config.formConfig.crfEditorsData.rows;
  2487. config.formConfig.crfMonitors=config.formConfig.crfMonitorsData.rows;
  2488. config.formConfig.crfSponsors=config.formConfig.crfSponsorsData.rows;
  2489. config.formConfig.crfManagers=config.formConfig.crfManagersData.rows;
  2490. config.formConfig.userRows=config.formConfig.userData.rows;
  2491. let uRows=config.formConfig.userRows;
  2492. for (let i=0;i<uRows.length;i++){
  2493. let userId=uRows[i].UserId;
  2494. if (userId==config.formConfig.crfEntry.UserId){
  2495. config.formConfig.user=uRows[i];
  2496. break;
  2497. }
  2498. }
  2499. //config.formConfig.user=data.rows[0];
  2500. this.print("Setting user to "+config.formConfig.user["DisplayName"]);
  2501. let fsRows=config.formConfig.formStatusData.rows;
  2502. config.formConfig.formStatus=fsRows[0].formStatus;
  2503. config.formConfig.operator=config.role;
  2504. //config.formConfig.operator=fsRows[0].operator;
  2505. this.print('Setting operator to: '+config.formConfig.operator);
  2506. config.formConfig.formRows=config.formConfig.formData.rows;
  2507. //point formId to point to form set in crfEntry
  2508. config.formConfig.formId=config.formConfig.crfEntry['Form'];
  2509. //old setting, set from URL in visit.html
  2510. let formId=config.formId;
  2511. //new setting, set from crfEntry
  2512. formId=config.formConfig.formId;
  2513. let formRows=config.formConfig.formRows;
  2514. //filter out the current form
  2515. for (let i=0;i<formRows.length;i++){
  2516. if (formRows[i].Key==formId){
  2517. config.formConfig.form=formRows[i];
  2518. break;
  2519. }
  2520. }
  2521. config.formConfig.formSetupRows=this.selectFormSetupRows(formId);
  2522. this.print("Number of datasets for form ["+formId+"]: "+
  2523. config.formConfig.formSetupRows.length);
  2524. let fields=config.formConfig.formSetup.metaData.fields;
  2525. //get the lookup for queryName column
  2526. let formQueryName='queryName';
  2527. let field="NONE";
  2528. for (f in fields){
  2529. if (fields[f]['name']!=formQueryName) continue;
  2530. field=fields[f];
  2531. break;
  2532. }
  2533. let lookup=field.lookup;
  2534. this.print("Getting dataset names from "+lookup.queryName);
  2535. //inputLists should be in configuration container
  2536. let that=this;
  2537. let action=function(data){that.afterFormDatasets(data);};
  2538. //let action=function(data){that.doNothing();};
  2539. this.selectRows(lookup.schemaName,lookup.queryName,[],action,this.getContainer('config'));
  2540. }
  2541. crfVisit.afterFormDatasets=
  2542. function(data){
  2543. let fName='[afterFormDatasets]';
  2544. this.print(fName+' nrows '+data.rows.length);
  2545. let config=this.config;
  2546. config.formConfig.formDatasets=data;//inputLists
  2547. config.formConfig.fields=new Object();
  2548. config.formConfig.queryMap=new Object();
  2549. config.formConfig.additionalData=new Object();
  2550. let rows=config.formConfig.formSetupRows;
  2551. //should skip report only rows
  2552. for (let i=0;i<rows.length;i++){
  2553. let entry=rows[i];
  2554. let reviewField=(entry['showFlag']=='REVIEW');
  2555. //is the operator set yet?
  2556. let accessMode=config.formConfig.operator+'Mode';
  2557. let skipField=(entry[accessMode]=="NONE");
  2558. let queryId=entry['queryName'];
  2559. let lookupRows=config.formConfig.formDatasets.rows;
  2560. this.print('QueryID['+i+']='+queryId);
  2561. let dentry;
  2562. for (let j=0;j<lookupRows.length;j++){
  2563. if (queryId!=lookupRows[j]['Key']) continue;
  2564. dentry=lookupRows[j];
  2565. break;
  2566. }
  2567. let qName=dentry['queryName'];
  2568. //update list of dataset formConfig is observing (fields/queryMap)
  2569. while (1){
  2570. //review contains no data
  2571. if (reviewField) break;
  2572. if (skipField) break;
  2573. //already in fields
  2574. if (qName in config.formConfig.fields) break;
  2575. config.formConfig.fields[qName]=new Object();
  2576. break;
  2577. }
  2578. while(1){
  2579. //already done
  2580. if (queryId in config.formConfig.queryMap) break;
  2581. config.formConfig.queryMap[queryId]=qName;
  2582. break;
  2583. }
  2584. if (reviewField) continue;
  2585. if (skipField) continue;
  2586. //only do this for real lists
  2587. let field=config.formConfig.fields[qName];
  2588. field.title=entry['title'];
  2589. field.queryId=queryId;
  2590. }
  2591. this.print("List of datasets in form : ");
  2592. for (f in config.formConfig.fields){
  2593. let field=config.formConfig.fields[f];
  2594. this.print("\t"+f+" ID: "+field.queryId+' title '+field.title);
  2595. }
  2596. this.afterConfig();
  2597. }
  2598. //>>>>>>>>>>>>>>>>>new>>>>>>>>>>>>
  2599. crfVisit.setDataLayout=
  2600. function(cb){
  2601. let fName='[setDataLayout]';
  2602. let config=this.config;
  2603. this.print(fName);
  2604. let rowsSetup=config.formConfig.formSetupRows;
  2605. let queryArray=new Array();
  2606. let dS=this.getLayoutObject();//reference only
  2607. let qList=this.getQueryList();
  2608. let qMap=config.formConfig.queryMap;
  2609. //config.formConfig.lookup=new Object();
  2610. for (let i=0;i<rowsSetup.length;i++){
  2611. let entry=rowsSetup[i];
  2612. //skip review rows
  2613. if (entry['showFlag']=='REVIEW')
  2614. continue;
  2615. let queryId=entry['queryName'];
  2616. let q=qMap[queryId];
  2617. queryArray.push(runQuery.makeQuery(dS,'data',q,q,[]));
  2618. qList[q]=0;
  2619. this.print(fName+' adding '+q);
  2620. if (entry['showQuery']!="NONE"){
  2621. let sq=entry['showQuery'];
  2622. queryArray.push(runQuery.makeQuery(dS,'data',sq,sq,[]));
  2623. qList[sq]=0;
  2624. this.print(fName+' adding '+sq);
  2625. }
  2626. }
  2627. //always add reviews
  2628. let q='reviewComments';
  2629. queryArray.push(runQuery.makeQuery(dS,'data',q,q,[]));
  2630. qList[q]=0;
  2631. let that=this;
  2632. let action=function(){that.processLayout(cb);};
  2633. runQuery.getDataFromQueries(this,queryArray,action);
  2634. }
  2635. //this happens after the for loop, so all dataQueries objects are set
  2636. crfVisit.processLayout=
  2637. function(cb){
  2638. let fName='[processLayout]';
  2639. let qList=this.getQueryList();
  2640. //for layouts
  2641. let queryArray=new Array();
  2642. let targetObject=this.getLookupObject();
  2643. let lookupSet=new Object();
  2644. for (let q in qList){
  2645. let qobject=this.getQueryLayout(q);
  2646. this.print(fName+" inspecting layout for "+q+" "+qobject);
  2647. qobject.fields=qobject.metaData.fields;
  2648. qobject.title=this.findTitle(q);
  2649. //check for lookups
  2650. for (let f in qobject.fields){
  2651. //anything else is simple but lookup
  2652. let field=qobject.fields[f];
  2653. if (!("lookup" in field)) continue;
  2654. let lookup=field.lookup;
  2655. let qObject=this.getLookup(lookup.queryName);
  2656. if (qObject) continue;
  2657. //add to list
  2658. let qName=lookup.queryName;
  2659. let qCode=qName+':'+lookup.keyColumn+':'+lookup.displayColumn;
  2660. let e=runQuery.makeQuery(targetObject,'data',qName,qCode,[]);
  2661. //adjust minor settings
  2662. if (lookup.containerPath) e.containerPath=lookup.containerPath;
  2663. e.schemaName=lookup.schemaName;
  2664. e.columns=lookup.keyColumn+','+lookup.displayColumn;
  2665. lookupSet[qCode]=e;
  2666. this.print(fName+' inserting '+qCode);
  2667. }
  2668. }
  2669. for (let x in lookupSet){
  2670. queryArray.push(lookupSet[x]);
  2671. this.print(fName+' adding '+x);
  2672. for (let v in lookupSet[x]){
  2673. this.print(fName+' value ['+v+'] '+lookupSet[x][v]);
  2674. }
  2675. }
  2676. //this.print(fName+' print '+targetObject.print);
  2677. let that=this;
  2678. let action=function(){that.processLookup(cb);};
  2679. this.print(fName+' getDataFromQueries');
  2680. runQuery.getDataFromQueries(this,queryArray,action);
  2681. this.print(fName+' getDataFromQueries done');
  2682. }
  2683. crfVisit.processLookup=
  2684. function(cb){
  2685. let fName="[processLookup]";
  2686. let obj=this.getLookupObject();
  2687. for (let q in obj){
  2688. this.print(fName+" "+q);
  2689. let a=q.split(':');
  2690. if (a.length<3) continue;
  2691. let lookupName=a[0];
  2692. let key=a[1];
  2693. let val=a[2];
  2694. obj[lookupName]=new Object();
  2695. this.print(fName+' adding ['+lookupName+'] '+key+'/'+val);
  2696. let lObject=obj[lookupName];
  2697. lObject.LUT=new Array();//key to value
  2698. lObject.ValToKey=new Array();//value to key
  2699. lObject.keyColumn=key
  2700. lObject.displayColumn=val;
  2701. let qRows=obj[q].rows;
  2702. for (let i=0;i<qRows.length;i++){
  2703. let r=qRows[i];
  2704. this.print(fName+' LUT ['+r[key]+'] '+r[val]);
  2705. lObject.LUT[r[key]]=r[val];
  2706. lObject.ValToKey[r[val]]=r[key];
  2707. }
  2708. }
  2709. cb();
  2710. }
  2711. crfVisit.setData=
  2712. function(cb){
  2713. fName='[setData]';
  2714. let crfMatch=this.getCRFref();
  2715. let config=this.config;
  2716. let parentCrf=config.formConfig.crfEntry['parentCrf'];
  2717. if (parentCrf!=undefined) crfMatch=parentCrf;
  2718. this.print(fName+' form crf ['+this.getCRFref()+'] matching for crfRef='+crfMatch);
  2719. let queryArray=new Array();
  2720. let targetObject=this.getSnapshotObject();
  2721. //collect data and execute callback cb for queries in cb.queryList
  2722. let qList=this.getQueryList();
  2723. for (q in qList){
  2724. let filters=[LABKEY.Filter.create("crfRef",crfMatch)];
  2725. queryArray.push(runQuery.makeQuery(targetObject,'data',q,q,filters));
  2726. }
  2727. runQuery.getDataFromQueries(this,queryArray,cb);
  2728. }
  2729. crfVisit.uploadFile=
  2730. function(inputElement,context){
  2731. //context should have ID and dirName attributes;
  2732. //path will be dirName/ID/fieldName_ID.suf
  2733. //where suf is identical to localPath content picked from
  2734. //inputElement
  2735. this.print('uploadFile: '+inputElement.value+'/');
  2736. if (inputElement.type=="text") return;
  2737. this.print('uploadFile: '+inputElement.files+'/');
  2738. this.print('uploadFile: '+inputElement.files.length+'/');
  2739. if (inputElement.files.length>0){
  2740. let file=inputElement.files[0];
  2741. this.print('uploadFile: '+inputElement.value+'/'+file.size);
  2742. webdav.uploadFile(file,context);
  2743. }
  2744. }
  2745. crfVisit.printForm=
  2746. function(){
  2747. crfPrint.printForm();
  2748. }