crfManager.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. //global config variable
  2. const config=new Object();
  3. function print(msg){
  4. config.document.getElementById(config.debugArea).value+="\n"+msg;
  5. }
  6. function clear(){
  7. config.document.getElementById(config.debugArea).value="";
  8. }
  9. function doNothing(){
  10. print('doNothing called');
  11. }
  12. function generateDescription(){
  13. //loop over all forms
  14. //read the setup
  15. print('Generate description');
  16. setFormConfig();
  17. }
  18. function setContainer(label,container){
  19. if (!(config.formConfig.hasOwnProperty('container'))){
  20. config.formConfig.container=new Array();
  21. }
  22. config.formConfig.container[label]=container;
  23. }
  24. function getContainer(label){
  25. return config.formConfig.container[label];
  26. }
  27. function makeQuery(containerName,queryName,fieldName,filterArray){
  28. let e=new Object();
  29. e.containerName=containerName;
  30. e.queryName=queryName;
  31. e.fieldName=fieldName;
  32. e.filterArray=filterArray;
  33. return e;
  34. }
  35. function getDataFromQueries(queryArray,cb){
  36. //queryArray should contain elements with
  37. //- fieldName to set the data variable
  38. //- containerName to select container (data,config,CRF)
  39. //- queryName to select query
  40. //- filterArray to perform filtering, empty array works
  41. //- callback cb to be called with no arguments
  42. //
  43. afterQuery(new Object(),-1,queryArray,cb);
  44. }
  45. function afterQuery(data,id,queryArray,cb){
  46. //queryArray should contain elements with
  47. //- fieldName to set the data variable
  48. //- containerName to select container (data,config,CRF)
  49. //- queryName to select query
  50. //- filterArray to perform filtering, empty array works
  51. //- callback cb to be called with no arguments
  52. //
  53. //it should be called with id -1.
  54. //
  55. print('afterQuery['+id+'/'+queryArray.length+']: ');
  56. if (id>-1){
  57. let fieldName=queryArray[id].fieldName;
  58. print('afterQuery['+fieldName+']: '+data.rows.length);
  59. config.formConfig[fieldName]=data;
  60. }
  61. id+=1;
  62. if (id==queryArray.length) {
  63. cb();
  64. return;
  65. }
  66. let e=queryArray[id];
  67. let qconfig=new Object();
  68. qconfig.containerPath=getContainer(e.containerName);
  69. qconfig.schemaName="lists";
  70. if ("schemaName" in e){
  71. print('afterQuery: schemaName='+e.schemaName);
  72. qconfig.schemaName=e.schemaName;
  73. }
  74. if ("columns" in e){
  75. print('afterQuery: columns='+e.columns);
  76. qconfig.columns=e.columns;
  77. }
  78. qconfig.queryName=e.queryName;
  79. //this should point to configuration container
  80. //don't filter -> so we can pick up other forms (say registration) later on
  81. //qconfig.filterArray=[LABKEY.Filter.create('Key',config.formId)];
  82. if ("filterArray" in e)
  83. qconfig.filterArray=e.filterArray;
  84. //qconfig.filterArray=[LABKEY.Filter.create('formStatus',1)]
  85. qconfig.success=function(data){afterQuery(data,id,queryArray,cb);};
  86. qconfig.failure=doNothing;
  87. LABKEY.Query.selectRows(qconfig);
  88. }
  89. function setFormConfig(){
  90. //add object to store form related data
  91. config.formConfig=new Object();
  92. config.formConfig.softwareVersion='0.0.1';
  93. let debug=true;
  94. if (debug)
  95. print("setFormConfig");
  96. //set containers for data and configuration
  97. //TODO: set this from a query
  98. //
  99. setContainer('data',LABKEY.ActionURL.getContainer());
  100. setContainer('config',LABKEY.ActionURL.getContainer());
  101. setContainer('CRF',LABKEY.ActionURL.getContainer());
  102. let selectRows=new Object();
  103. //this is local data
  104. selectRows.containerPath=getContainer('CRF');
  105. selectRows.schemaName='lists';
  106. selectRows.queryName='crfSettings';
  107. //store form related data to this object
  108. selectRows.success=afterSettings;
  109. LABKEY.Query.selectRows(selectRows);
  110. }
  111. function afterSettings(data){
  112. config.formConfig.settings=new Array();
  113. for (let i=0;i<data.rows.length;i++){
  114. let n=data.rows[i]['name'];
  115. let v=data.rows[i]['value'];
  116. config.formConfig.settings[n]=v;
  117. }
  118. let st=config.formConfig.settings;
  119. print('afterSettings');
  120. for (let k in st){
  121. print('\t'+k+'='+st[k]);
  122. }
  123. //if ('dataContainer' in st){
  124. // setContainer('data',st['dataContainer']);
  125. //}
  126. let vname='configContainer';
  127. if (vname in st){
  128. setContainer('config',st[vname]);
  129. }
  130. print('Config: '+getContainer('config'));
  131. print('Data: '+getContainer('data'));
  132. collectData();
  133. }
  134. function collectData(){
  135. let queryArray=new Array();
  136. //users
  137. queryArray.push(makeQuery('CRF','users','userData',[]));
  138. queryArray[queryArray.length-1].schemaName='core';
  139. //Forms
  140. queryArray.push(makeQuery('config','Forms','formData',[]));
  141. //FormSetup
  142. queryArray.push(makeQuery('config','FormSetup','formSetup',[]));
  143. //inputLists
  144. queryArray.push(makeQuery('config','inputLists','inputLists',[]));
  145. //
  146. print('running getDataFromQueries');
  147. getDataFromQueries(queryArray,fcontinue);
  148. }
  149. function findName(listId){
  150. let frows=config.formConfig.inputLists.rows;
  151. for (let i=0;i<frows.length;i++){
  152. if (frows[i]['Key']!=listId) continue;
  153. return frows[i]['queryName'];
  154. }
  155. }
  156. function fcontinue(){
  157. print('loadedData');
  158. let queryArray=new Array();
  159. let frows=config.formConfig.formSetup.rows;
  160. for (let i=0;i<frows.length;i++){
  161. let listId=frows[i]['queryName'];
  162. //skip forms only
  163. let showFlag=frows[i]['showFlag'];
  164. let showQuery=frows[i]['showQuery'];
  165. if (showFlag=='REVIEW') continue;
  166. let listName=findName(listId);
  167. print(listName);
  168. queryArray.push(makeQuery('data',listName,listName,[]));
  169. if (showFlag=='NONE') continue;
  170. queryArray.push(makeQuery('data',showQuery,showQuery,[]));
  171. }
  172. getDataFromQueries(queryArray,fcontinue1);
  173. }
  174. function getList(formId){
  175. let fList=new Array();
  176. let frows=config.formConfig.formSetup.rows;
  177. for (let i=0;i<frows.length;i++){
  178. if (frows[i]['formName']!=formId) continue;
  179. let listId=frows[i]['queryName'];
  180. let showFlag=frows[i]['showFlag'];
  181. let showQuery=frows[i]['showQuery'];
  182. if (showFlag=='REVIEW') continue;
  183. let fObj=new Object();
  184. fObj['queryName']=findName(listId);
  185. fObj['title']=frows[i]['title'];
  186. fList.push(fObj);
  187. if (showFlag=='NONE') continue;
  188. let fObj1=new Object();
  189. fObj1['queryName']=showQuery;
  190. fObj1['title']=frows[i]['title']+' (details)';
  191. fList.push(fObj1);
  192. }
  193. return fList;
  194. }
  195. function printField(field){
  196. let name=field['name'];
  197. if (name=='Key') return;
  198. if (name=='crfRef') return;
  199. let type=field['type'];
  200. let qName='';
  201. if ('lookup' in field){
  202. qName=field.lookup.queryName;
  203. }
  204. print(name+' '+type+'/'+qName);
  205. printPDF(field);
  206. }
  207. function addLookup(lookupList,field){
  208. if ('lookup' in field){
  209. lookupList.add(field.lookup.queryName);
  210. }
  211. }
  212. function printFields(lookupList,listName){
  213. let fields=config.formConfig[listName].metaData.fields;
  214. //print('getFields '+listName+': '+fields.length);
  215. for (f in fields){
  216. printField(fields[f]);
  217. addLookup(lookupList,fields[f]);
  218. //printPDF(fields[f]);
  219. }
  220. }
  221. function fcontinue1(){
  222. printLayout();
  223. }
  224. function printData(){
  225. let frows=config.formConfig.formData.rows;
  226. let lookupList=new Set();
  227. for (let i=0;i<frows.length;i++){
  228. let formId=frows[i]['Key'];
  229. print(frows[i]['formName']);
  230. printTitlePDF(20,frows[i]['formName']);
  231. let fList=getList(formId);
  232. for (let j=0;j<fList.length;j++){
  233. print(fList[j]['queryName']);
  234. printTitlePDF(16,fList[j]['title']);
  235. printFields(lookupList,fList[j]['queryName']);
  236. }
  237. }
  238. print('all done');
  239. let queryArray=new Array();
  240. for (let item of lookupList){
  241. queryArray.push(makeQuery('data',item,item,[]));
  242. }
  243. let cb=function(){printLookup(lookupList);};
  244. getDataFromQueries(queryArray,cb);
  245. }
  246. function printQuery(queryName){
  247. printTitlePDF(16,queryName);
  248. print(queryName);
  249. let frows=config.formConfig[queryName].rows;
  250. print('rows: '+frows);
  251. let fields=config.formConfig[queryName].metaData.fields;
  252. let field=undefined;
  253. for (f in fields){
  254. if (fields[f].name=='Key') continue;
  255. field=fields[f];
  256. break;
  257. }
  258. for (let i=0;i<frows.length;i++){
  259. printPDFEntry(field,frows[i]);
  260. }
  261. }
  262. function printLookup(lookupList){
  263. printTitlePDF(20,'Enumerators');
  264. for (let item of lookupList){
  265. printQuery(item);
  266. }
  267. config.doc.end();
  268. }
  269. function checkBlob(){
  270. print("checkBlob: "+config.blob);
  271. if (config.blob) {
  272. clearInterval(config.blobInterval);
  273. config.a.href = config.window.URL.createObjectURL(config.blob);
  274. print("HREF: "+config.a.href);
  275. config.a.download = 'test.pdf';
  276. config.a.click();
  277. config.window.URL.revokeObjectURL(config.a.href);
  278. }
  279. config.count=config.count+1;
  280. print("Eval: "+config.count);
  281. if (config.count>100){
  282. clearInterval(config.blobInterval);
  283. }
  284. }
  285. function printLayout(){
  286. config.doc=new PDFDocument();
  287. //config.doc.end();
  288. let stream = config.doc.pipe(blobStream()).on("finish",function(){
  289. config.blob=stream.toBlob("application/pdf");});
  290. print("BLob: "+config.blob);
  291. config.a = config.document.createElement("a");
  292. config.document.body.appendChild(config.a);
  293. config.a.innerHTML="Download PDF";
  294. config.a.style = "display: none";
  295. config.count=0;
  296. //run until blob is set
  297. config.blobInterval=setInterval(checkBlob,1000);
  298. //pick data from crfForm list
  299. print("Printing form");
  300. printData();
  301. }
  302. function printTitlePDF(fontSize,title){
  303. config.doc.y+=10;
  304. config.doc.font('Courier-Bold').fontSize(fontSize).text(title);
  305. }
  306. function printPDF(field){
  307. //object field should have a name, type, caption
  308. //entry should have field.name
  309. //lookup is null or has a lookup table LUT
  310. //for value v of entry[field.name]
  311. //
  312. //the total width of a A4 page is 598 px,
  313. //left margin is 72. With a right margin of 50,
  314. //the total available with is 476 px.
  315. let w=476;
  316. let spacing=25;
  317. let w1=(w-spacing)*0.5;
  318. let fontSize=14;
  319. print('printPDF: entry['+field.name);
  320. print('printPDF: field type:'+field.type);
  321. //measure text
  322. let label=field.caption;
  323. let opt={width:w1};
  324. config.doc.fontSize(fontSize);
  325. //for more eloquent display the height of the text
  326. //can be measured prior to output
  327. //use currentLineHeight to scale height
  328. //let lineH=config.doc.currentLineHeight(1);
  329. //let h=config.doc.heightOfString(label,opt)/lineH;
  330. //print label
  331. config.doc.font('Courier').text(label,opt);
  332. //align last row of description w/ first row of value
  333. config.doc.moveUp();
  334. //store x value for later use
  335. let tx=config.doc.x;
  336. let ty=config.doc.y;
  337. //shift for value output
  338. config.doc.x+=w1+spacing;
  339. let v=field.type;
  340. if ('lookup' in field){
  341. v+='/'+field.lookup.queryName;
  342. }
  343. print('v: '+v);
  344. config.doc.font('Courier-Bold').text(v,opt);
  345. //restore x value
  346. config.doc.x=tx;
  347. }
  348. function printPDFEntry(field,entry){
  349. //object field should have a name, type, caption
  350. //entry should have field.name
  351. //lookup is null or has a lookup table LUT
  352. //for value v of entry[field.name]
  353. //
  354. //the total width of a A4 page is 598 px,
  355. //left margin is 72. With a right margin of 50,
  356. //the total available with is 476 px.
  357. let w=476;
  358. let spacing=25;
  359. let w1=(w-spacing)*0.5;
  360. let fontSize=14;
  361. print('printPDF: entry['+field.name);
  362. print('printPDF: field type:'+field.type);
  363. //measure text
  364. let label=entry[field.name];
  365. let opt={width:w1};
  366. config.doc.fontSize(fontSize);
  367. //for more eloquent display the height of the text
  368. //can be measured prior to output
  369. //use currentLineHeight to scale height
  370. //let lineH=config.doc.currentLineHeight(1);
  371. //let h=config.doc.heightOfString(label,opt)/lineH;
  372. //print label
  373. config.doc.font('Courier').text(label,opt);
  374. }