crfPortal.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. function drawForm(par){
  2. populateSourceTable(par);
  3. let tableId="entryTable";
  4. generateTable("formDiv",tableId);
  5. generateRow(tableId, par,"User");
  6. populateSelectTableEntry(par,"User");
  7. generateRow(tableId, par,"Site");
  8. generateRow(tableId, par, "FormStatus");
  9. generateRow(tableId, par,"Crf");
  10. populateSelectTableEntry(par,"Site");
  11. populateSelectTableEntry(par,"FormStatus");
  12. let formTableId="selectFormTable";
  13. generateTable("selectFormDiv",formTableId);
  14. generateRow(formTableId,par,"Form");
  15. generateButtonRow(formTableId,"Add new CRF","Add", par, addNewEntry);
  16. populateSelectTableEntry(par,"Form");
  17. generateTable("startDiv","startTable");
  18. generateButtonRow("startTable","Start filling the selected form","Start", par, startForm);
  19. }
  20. function generateQConfig(listName){
  21. let qConfig=new Object();
  22. qConfig.containerPath="TECANT/Data";
  23. qConfig.schemaName="lists";
  24. qConfig.queryName=listName;
  25. return qConfig;
  26. }
  27. function sourceVar(crfEntryName,elementId,sourceName){
  28. let f=new Object();
  29. f.masterSelectVarName=crfEntryName;
  30. f.selectId=elementId;
  31. f.inputType="innerHTML";
  32. f.sourceSelectVarName=sourceName;
  33. return f;
  34. }
  35. function generateHead(config, headDivName,divName,title){
  36. print(config,"generateHead");
  37. let tb=config.document.createElement('table');
  38. tb.className='t2';
  39. let row=tb.insertRow();
  40. let cell=config.document.createElement('th');
  41. row.appendChild(cell);
  42. cell.setAttribute("colspan","4");
  43. cell.style.fontSize="20px";
  44. cell.style.textAlign="center";
  45. let cellData=config.document.createTextNode(title);
  46. cell.appendChild(cellData);
  47. cell=row.insertCell();
  48. cell.style.fontSize="20px";
  49. let input=config.document.createElement("input");
  50. input.type="button";
  51. input.value="Show";
  52. input.id="toggle"+divName+"VisbilityButton";
  53. input.onclick=function(){toggleVisibility(config,divName,input.id)};
  54. cell.appendChild(input);
  55. config.document.getElementById(headDivName).appendChild(tb);
  56. print(config,"generateHead: Done");
  57. }
  58. function toggleVisibility(config,divName,buttonName){
  59. let x = config.document.getElementById(divName);
  60. if (x.style.display === "none") {
  61. x.style.display = "block";
  62. config.document.getElementById(buttonName).value="Hide";
  63. } else {
  64. x.style.display = "none";
  65. config.document.getElementById(buttonName).value="Show";
  66. }
  67. }
  68. function populateSourceTable(par){
  69. let debug=true;
  70. if (debug){
  71. document.getElementById('formStatus').value +=
  72. "\npopulateSourceTable: Starting";
  73. }
  74. let config=generateQConfig(par.source.queryName);
  75. config.schemaName=par.source.schemaName;
  76. if (!("source" in par)) return;
  77. if (debug){
  78. print(par.config,"populateSourceTable ["+par.source.queryName+"]");
  79. }
  80. config.success=function(data){populateSourceTableData(data,par)};
  81. config.failure=function(errorTxt){print(par.config,"populateSourceData:fail")};
  82. LABKEY.Query.selectRows(config);
  83. }
  84. function print(config,msg){
  85. config.document.getElementById(config.debugId).value +="\n"+msg;
  86. }
  87. function populateSourceTableData(data,par){
  88. let debug=true;
  89. if (debug){
  90. document.getElementById('formStatus').value +=
  91. "\npopulateSourceTableData: nrow: "+data.rows.length;
  92. }
  93. let entry=data.rows[0];
  94. for (let i=0;i < par.source.vars.length;i++){
  95. let srcVarName=par.source.vars[i];
  96. if (debug){
  97. document.getElementById('formStatus').value +=
  98. "\npopulateSourceTable ["+srcVarName+"]";
  99. }
  100. let row=par.vars[srcVarName];
  101. let el=document.getElementById(row.selectId);
  102. if (debug){
  103. document.getElementById('formStatus').value +=
  104. "\nElement: "+el;
  105. }
  106. el.innerHTML=entry[row.sourceSelectVarName];
  107. }
  108. }
  109. function populateSelectNotLookup(config,data,parameters,rowId, entry){
  110. //selectId
  111. //masterSelectVarName
  112. let debug=true;
  113. if (debug)
  114. print(config,"populateSelectNonLookup on "+data.queryName);
  115. let row=parameters.vars[rowId];
  116. let varName=row.masterSelectVarName;
  117. if (debug) print(config,"var "+varName+" rows "+data.rows.length);
  118. if (debug) print(config,"Getting element "+row.selectId);
  119. let el=document.getElementById(row.selectId);
  120. if (!el) {
  121. print(config,"Element not found");
  122. return;
  123. }
  124. if (debug) print(config,"Element "+el);
  125. if (debug) print(config,"Clearing entries");
  126. //remove previous options
  127. for(i = el.options.length; i >= 0; i--) {
  128. el.remove(i);
  129. }
  130. if (debug)
  131. print(config,"Adding entries");
  132. if ("addSelect" in row){
  133. if (debug)
  134. print(config,"adding <Select>");
  135. let opt = document.createElement("option");
  136. opt.text = "<Select>";
  137. opt.value = -2;
  138. el.options[0] = opt;
  139. }
  140. if ("addNewFlag" in row){
  141. if (debug) print(config,"adding Add new");
  142. let opt = document.createElement("option");
  143. opt.text = "Add New";
  144. opt.value = row.addNewFlag;
  145. el.options[el.options.length] = opt;
  146. }
  147. for (let i=0;i< data.rows.length;i++){
  148. let valEntry=data.rows[i];
  149. if (debug)
  150. print(config,"adding "+valEntry[varName]);
  151. let opt = document.createElement("option");
  152. opt.text = valEntry[varName];
  153. opt.value = valEntry[varName];
  154. if (entry){
  155. if (opt.value==entry[varName])
  156. el.selectedIndex=el.options.length-1;
  157. }
  158. el.options[el.options.length] = opt;
  159. }
  160. if (entry)
  161. row.callback(parameters,rowId);
  162. }
  163. function populateSelect(data,selectedData, parameters, rowId){
  164. //data is the set of lookup entries, selectedData is a subset of entries valued at lookup.keyColumn
  165. let debug=true;
  166. if (debug)
  167. print("populateSelect Data: "+data.queryName+" selectedData:"+selectedData.queryName);
  168. let row=parameters.vars[rowId];
  169. let selectId=row.selectId;
  170. let varName=row.masterSelectVarName;
  171. if ("filter" in row){
  172. varName=row.filter.filterVarName;
  173. }
  174. let field=getField(selectedData,varName);
  175. let displayColumn=field.lookup.displayColumn;
  176. let keyColumn=field.lookup.keyColumn;
  177. if (debug){
  178. document.getElementById('formStatus').value+="\n Query: "+data.queryName;
  179. document.getElementById('formStatus').value+="\n ElementId: "+selectId;
  180. document.getElementById('formStatus').value+="\n keyColumn: "+keyColumn;
  181. document.getElementById('formStatus').value+="\n displayColumn: "+displayColumn;
  182. }
  183. let el = document.getElementById(selectId);
  184. if (debug)
  185. document.getElementById('formStatus').value+="\n Element: "+el;
  186. for(i = el.options.length; i >= 0; i--) {
  187. el.remove(i);
  188. }
  189. if ("addSelect" in row){
  190. let opt = document.createElement("option");
  191. opt.text = "<Select>";
  192. opt.value = -1;
  193. el.options[0] = opt;
  194. }
  195. if ("addNewFlag" in row){
  196. let opt = document.createElement("option");
  197. opt.text = "Add New"
  198. opt.value = row.addNewFlag;
  199. el.options[el.options.length] = opt;
  200. }
  201. for (var i = 0; i < data.rows.length; i++) {
  202. let key=data.rows[i][keyColumn];
  203. let skip=true;
  204. if (row.selectAll){
  205. skip=false;
  206. }
  207. else{
  208. if (debug)
  209. print("Selecting from: "+selectedData.rows.length);
  210. for (let j=0; j< selectedData.rows.length; j++){
  211. let entry=selectedData.rows[j];
  212. if (debug)
  213. print("Comparing: "+entry[varName]+"/"+key);
  214. if (key!=entry[varName]) continue;
  215. skip=false;
  216. break;
  217. }
  218. }
  219. if (skip) continue;
  220. let opt = document.createElement("option");
  221. opt.text = data.rows[i][displayColumn];
  222. opt.value = data.rows[i][keyColumn];
  223. if (debug)
  224. print("Adding: "+opt.value+" : "+opt.text);
  225. el.options[el.options.length] = opt;
  226. if ("selectedKey" in row){
  227. if (debug)
  228. print("Comparing: " + opt.value + "/" + row["selectedKey"]);
  229. if (opt.value==row["selectedKey"]){
  230. el.selectedIndex=el.options.length-1;
  231. if (debug)
  232. print("Equal; "+el.selectedIndex);
  233. }
  234. }
  235. }
  236. if (debug)
  237. print("Running callback");
  238. row.callback(parameters,rowId);
  239. }
  240. function saveData(queryName){
  241. document.getElementById('formStatus').value+="\n saveData: "+queryName;
  242. }
  243. function populateSelectTableEntry(parameters,rowId){
  244. //parameters should include
  245. //tableId - update this table (unused)
  246. //masterQuery - the master query that will collect al the data
  247. //masterSelectVarName - variable that is going to fill the content of select.
  248. // Typically, the variable is a lookup in the master query
  249. //masterUserVarName - variable that stores the user id in the master query
  250. // only entries matching current user in the master query will be selected
  251. //authorization - additional data to check:
  252. // * if the current user is authorized to perform action and/or
  253. // * limit number of different queryVariable values user is entitled to use
  254. //authorization should contain:
  255. // * queryName - query of user/queryVariable pairs to check for authorized access
  256. // * authUserVarName - name of the variable in authorization.queryName that contain usesId
  257. // * authSelectVarName - name of the selectVar in authorization query
  258. //callback - function that executes when value of the select changes (onchange).
  259. // argument to callback are the parameters
  260. //selectId - id of the DOM element where select is rendered - to check for value in callback
  261. //dataDiv - div element to render potential output of the callback
  262. let debug=true;
  263. let row=parameters.vars[rowId];
  264. if (debug)
  265. document.getElementById('formStatus').value+="\n populateSelectTableEntry:"
  266. +parameters.masterQuery+"/"+row.masterSelectVarName;
  267. let config=generateQConfig(parameters.masterQuery);
  268. if ("filter" in row){
  269. //populateSelect on authorizationQuery with authSelectVarName
  270. let filter=row.filter;
  271. if (debug){
  272. print("Filter:"+filter.queryName);
  273. print("FilterVar "+filter.filterVarName);
  274. }
  275. config.queryName=filter.queryName;
  276. config.filterArray=[];
  277. for (f in filter.filters){
  278. if (debug) print("Adding filter: "+f+" val "+filter.filters[f]);
  279. config.filterArray.push(LABKEY.Filter.create(f,filter.filters[f]));
  280. }
  281. }
  282. else{
  283. config.queryName=parameters.masterQuery;
  284. }
  285. config.success=function(data){populateTableRow(data,parameters,rowId)};
  286. LABKEY.Query.selectRows(config);
  287. if (debug)
  288. print("generateSelect: End");
  289. return;
  290. }
  291. function getField(data, varName){
  292. let debug=false;
  293. if (debug) print("getField");
  294. let fields=data.metaData.fields;
  295. for (f in fields){
  296. if (debug) print("Checking "+f+": name "+fields[f].name+"/"+varName);
  297. if (fields[f].name!=varName) continue;
  298. return fields[f];
  299. }
  300. return null;
  301. }
  302. function getCaption(data, varName){
  303. let field=getField(data,varName);
  304. if (field) return field.shortCaption;
  305. return "NONE";
  306. }
  307. function generateTable(divName,elementId){
  308. let debug=true;
  309. if (debug)
  310. document.getElementById('formStatus').value+="\n generateTable";
  311. let tb=document.createElement('table');
  312. tb.className="t2";
  313. tb.id=elementId;
  314. document.getElementById(divName).appendChild(tb);
  315. if (debug)
  316. document.getElementById('formStatus').value+="\n generateTable: Done";
  317. }
  318. function generateRow(tableId, parameters,rowId){
  319. let debug=true;
  320. if (debug)
  321. document.getElementById('formStatus').value+="\n generateRow: Start";
  322. let config=generateQConfig(parameters.masterQuery);
  323. config.success=function(data){generateTableRow(data,tableId, parameters,rowId)};
  324. LABKEY.Query.selectRows(config);
  325. if (debug)
  326. document.getElementById('formStatus').value+="\n generateRow: End";
  327. return;
  328. }
  329. function generateTableRow(data,tableId, parameters,rowId){
  330. let tb=document.getElementById(tableId);
  331. let row=parameters.vars[rowId];
  332. let field=getField(data,row.masterSelectVarName);
  333. let trow=tb.insertRow();
  334. let cell=document.createElement('th');
  335. trow.appendChild(cell);
  336. let text = document.createTextNode(field.shortCaption);
  337. cell.appendChild(text);
  338. cell=trow.insertCell();
  339. let input = document.createElement("select");
  340. input.id = row.selectId;
  341. input.onchange=function(){row.callback(parameters,rowId)};
  342. cell.appendChild(input);
  343. }
  344. function populateTableRow(data,parameters,rowId){
  345. //data is output of selectRows on either
  346. // * masterQuery looking at masterSelectVarName or
  347. // * authQuery looking at authSelectVarName
  348. //in both cases, query[varName] is a lookup variable, so do populateSelect with lookupData,queryData and parameters
  349. let debug=true;
  350. let row=parameters.vars[rowId];
  351. let varName=row.masterSelectVarName;
  352. if ("filter" in row){
  353. if (row.filter.queryName==data.queryName){
  354. varName=row.filter.filterVarName;
  355. }
  356. }
  357. if (debug)
  358. print("generateSelectVar: "+data.queryName+"/"+varName+" size "+data.rows.length);
  359. let field=getField(data,varName);
  360. if (!field) {
  361. print("Field "+varName+" not found");
  362. return;
  363. }
  364. if (!("lookup" in field)){
  365. let entry=data.rows[0];
  366. print("Field "+varName+" not a lookup");
  367. populateSelectNotLookup(data,parameters,rowId, entry);
  368. return;
  369. }
  370. let config=generateQConfig(field.lookup.queryName);
  371. config.schemaName=field.lookup.schemaName;
  372. config.success=function(lookupData){populateSelect(lookupData,data,parameters,rowId)};
  373. LABKEY.Query.selectRows(config);
  374. if (debug)
  375. print("generateSelectVar: End");
  376. }
  377. function generateButtonRow(tableId,caption,label,parameters,callback){
  378. let tb=document.getElementById(tableId);
  379. let trow=tb.insertRow();
  380. let cell=document.createElement('th');
  381. trow.appendChild(cell);
  382. let text = document.createTextNode(caption);
  383. cell.appendChild(text);
  384. cell=trow.insertCell();
  385. let input = document.createElement("input");
  386. input.type="button";
  387. input.value=label;
  388. input.onclick=function(){callback(parameters)};
  389. cell.appendChild(input);
  390. }
  391. function generateListAndPopulateDaughterSelect(parameters,rowId){
  392. let debug=true;
  393. if (debug){
  394. print("generateListAndPopulateDaughter");
  395. }
  396. generateList(parameters,rowId);
  397. let row=parameters.vars[rowId];
  398. if ("daughterSelect" in row){
  399. populateDaughterSelect(parameters,rowId,row["daughterSelect"],null);
  400. }
  401. }
  402. function populateDaughterSelect(parameters,rowId,daughterRowId,entry){
  403. let debug=true;
  404. if (debug)
  405. print("populateDaughterSelect: "+rowId+" "+daughterRowId);
  406. let row=parameters.vars[rowId];
  407. if (debug)
  408. print("row["+rowId+"]:"+row);
  409. let daughterRow=parameters.vars[daughterRowId];
  410. if (debug)
  411. print("daughterRow["+daughterRowId+"]:"+daughterRow);
  412. let el=document.getElementById(row.selectId);
  413. if (debug)
  414. print("\n Element:"+el);
  415. let varValue=el.options[el.selectedIndex].value;
  416. if (debug)
  417. print("\nAdding filter ["+row.masterSelectVarName+"]:"+varValue);
  418. let config=generateQConfig(parameters.masterQuery)
  419. config.filterArray=[];
  420. for (let i=0;i < parameters.filters.length;i++){
  421. let filterRowId=parameters.filters[i];
  422. let filterRow=parameters.vars[filterRowId];
  423. let filterValue=document.getElementById(filterRow.selectId).value;
  424. config.filterArray.push(LABKEY.Filter.create(filterRow.masterSelectVarName,filterValue));
  425. }
  426. config.success=function(data){populateSelectNotLookup(data,parameters,daughterRowId,entry)};
  427. LABKEY.Query.selectRows(config);
  428. }
  429. function generateList(parameters,rowId){
  430. let row=parameters.vars[rowId];
  431. let debug=true;
  432. if (debug)
  433. print("generateList: "+parameters.masterQuery);
  434. //ignore authorization, just select on select variable
  435. let el=document.getElementById(row.selectId);
  436. let varValue=el.options[el.selectedIndex].value;
  437. if (debug)
  438. print("Using value "+varValue+" from "+row.selectId);
  439. let iValue=parseInt(varValue);
  440. let div=document.getElementById(parameters.addDiv);
  441. div.style.display="none";
  442. //add new crf entry
  443. if ("addNewFlag" in row){
  444. if (debug)
  445. print("Comparing " + iValue + "/" + row.addNewFlag);
  446. if (iValue==row.addNewFlag) {
  447. addNew(parameters);
  448. return;
  449. }
  450. }
  451. //do filtering
  452. let filterArray=[];
  453. for (let i=0;i < parameters.filters.length;i++){
  454. let filterRowId=parameters.filters[i];
  455. let filterRow=parameters.vars[filterRowId];
  456. let filterValue=document.getElementById(filterRow.selectId).value;
  457. filterArray.push(LABKEY.Filter.create(filterRow.masterSelectVarName,filterValue));
  458. }
  459. //show all for system entries (Select, Add New)
  460. if (debug)
  461. print("Using iValue "+iValue);
  462. if (iValue<0) {
  463. if (debug)
  464. print("Ignoring ["+row.masterSelectVarName+ "]: "+varValue);
  465. }
  466. else{
  467. if (debug)
  468. print("Filtering ["+row.masterSelectVarName+"]: "+varValue);
  469. if (rowId==="Crf"){
  470. filterArray.push(LABKEY.Filter.create(row.masterSelectVarName,varValue));
  471. if (debug)
  472. print("Filtering ["+row.masterSelectVarName+"]: "+varValue);
  473. }
  474. }
  475. LABKEY.QueryWebPart({renderTo: parameters.dataDiv, schemaName: 'lists',
  476. queryName: parameters.masterQuery,
  477. buttonBarPosition: 'top',filters: filterArray, viewName:"sparseView",
  478. success:updateSuccess, failure:updateFailure });
  479. }
  480. function updateSuccess(){
  481. document.getElementById('formStatus').value+="\n Update success";
  482. }
  483. function updateFailure(json){
  484. document.getElementById('formStatus').value+="\n Update failed";
  485. }
  486. function addNewEntry(parameters){
  487. print("Add new, npar ");
  488. let entry=new Object();
  489. for (vv in parameters.vars){
  490. let f=parameters.vars[vv];
  491. print("New: Adding "+f.masterSelectVarName);
  492. setValue(entry,f);
  493. }
  494. for (f in entry){
  495. print("entry ["+f+"]="+entry[f]);
  496. }
  497. entry.entryId=Date.now();
  498. entry.Date=new Date();
  499. entry.formStatus=1;//In Progress
  500. let config=generateQConfig(parameters.masterQuery);
  501. config.rows=[entry];
  502. config.success=function(data){
  503. populateDaughterSelect(parameters,"Site","Crf",data.rows[0]);
  504. selectEntry(data,parameters.vars["Crf"]);
  505. generateList(parameters,"Crf");};
  506. LABKEY.Query.insertRows(config);
  507. }
  508. function selectEntry(data,row){
  509. let entry=data.rows[0];
  510. let varName=row.masterSelectVarName;
  511. let el=document.getElementById(row.selectId);
  512. for (let i=0;i< el.options.length;i++){
  513. print("selectEntry: "+el.options[i].value+"/"+entry[varName]);
  514. if (el.options[i].value!=entry[varName]) continue;
  515. el.selectedIndex=i;
  516. return;
  517. }
  518. }
  519. function setValue(entry,f){
  520. let el=document.getElementById(f.selectId);
  521. print("setValue: Element: "+el);
  522. if (f.inputType=="select"){
  523. entry[f.masterSelectVarName]=el.value;
  524. }
  525. if (f.inputType=="innerHTML"){
  526. entry[f.masterSelectVarName]=el.innerHTML;
  527. }
  528. }
  529. function addNew(parameters){
  530. print("Show Add new");
  531. let div=document.getElementById(parameters.addDiv);
  532. div.style.display="block";
  533. }
  534. function startForm(parameters){
  535. let crfVar=parameters.vars["Crf"];
  536. let el=document.getElementById(crfVar.selectId);
  537. let config=generateQConfig(parameters.masterQuery);
  538. config.filterArray=[LABKEY.Filter.create(crfVar.masterSelectVarName,el.value)]
  539. config.success=function(data){findURL(data,parameters)};
  540. LABKEY.Query.selectRows(config);
  541. // The set of URL parameters.
  542. }
  543. function findURL(data,parameters){
  544. let entry=data.rows[0];
  545. let fields=data.metaData.fields;
  546. let formVar=parameters.vars["Form"];
  547. let formVarName=formVar.masterSelectVarName;
  548. let lookup;
  549. for (f in fields){
  550. if (fields[f].name!=formVarName) continue;
  551. lookup=fields[f].lookup;
  552. break;
  553. }
  554. let config=generateQConfig(lookup.queryName);
  555. config.schemaName=lookup.schemaName;
  556. config.filterArray=[LABKEY.Filter.create(lookup.keyColumn,entry[formVarName])];
  557. config.success=function(data){finalRedirect(data,entry,parameters)};
  558. LABKEY.Query.selectRows(config);
  559. }
  560. function finalRedirect(data,entry,parameters){
  561. let formEntry=data.rows[0];
  562. let formVar=parameters.vars["Form"];
  563. let formUrl=formEntry[formVar.urlName];
  564. var params = {
  565. "name": formUrl, // The destination wiki page. The name of this parameter is not arbitrary.
  566. "userid": entry[parameters.vars["User"].masterSelectVarName],
  567. "entryId": entry[parameters.vars["Crf"].masterSelectVarName]
  568. };
  569. // This changes the page after building the URL.
  570. //Note that the wiki page destination name is set in params.
  571. var wikiURL = LABKEY.ActionURL.buildURL("wiki", "page", LABKEY.ActionURL.getContainer(), params);
  572. print("Redirecting to "+wikiURL);
  573. window.location = wikiURL;
  574. }
  575. </script>