otsdaq_utilities  v2_05_02_indev
DeleteWiz_ConfigurationGUI.js
1 
2 
3 // Description of Delete Wizard Configuration GUI Functionality/Behavior:
4 //
5 // Example call:
6 // DeleteWiz.createWiz(
7 // function(atLeastOneRecordWasDeleted)
8 // {
9 // Debug.log("Done at Template! " + atLeastOneRecordWasDeleted,
10 // Debug.INFO_PRIORITY);
11 // });
12 //
13 // - User can have LOCK
14 //
15 // Display:
16 // - walk through steps at center of window
17 // - use popup dialog to place at center
18 // - steps:
19 // - (error if unrecognized base path)
20 // - "what is the name of your <delete type>?"
21 // - note the active context and table group being modified, with dropdown to
22 // change them.
23 // - "which one?"
24 // - "How deep?"
25 //
26 //
27 
30 
31 //public functions:
32 // DeleteWiz.createWiz(doneHandler)
33 // - when the user closes the wizard dialog,
34 // doneHandler is called with a bool parameter with true indicating
35 // at least one record was deleted.
36 
37 
39 //functions:
40  //localParameterCheck()
41  //xdaqContextTooltip()
42  //xdaqApplicationTooltip()
43  //initDeleteWizard()
44  //showPrompt(stepIndex,paramObj)
45  // localAddContent()
46  // switch statements
47  // localAlsoDescendantContent() _STEP_ALSO_DESCENDANTS
48  // localAddHandlers()
49  // switch statements
50  // localAlsoDescendantsHandlers _STEP_ALSO_DESCENDANTS
51  // localRecurseDeleteChildren(children,table,depth) _STEP_ALSO_DESCENDANTS
52 
53  // share scope functions (between switch and next/prev handlers)
54  // localDeleteRootRecord()
55 
56  // localNextButtonHandler() switch
57  // localScopeSetRecordSaveModifiedDoIt() _STEP_SAVE_MODIFIED
58  // scopeWhichRecordTypeNext() _STEP_WHICH_RECORD_TYPE
59 
60  // localPrevButtonHandler() switch
61 
62  //htmlOpen(tag,attObj,innerHTML,closeTag)
63  //htmlClearDiv()
64 
65  //getRecordConfiguration()
66  //getRecordFilter()
67 
68 
71 
72 
73 /*
74 <script type="text/JavaScript" src="/WebPath/js/Globals.js"></script>
75 <script type="text/JavaScript" src="/WebPath/js/Debug.js"></script>
76 <script type="text/JavaScript" src="/WebPath/js/DesktopContent.js"></script>
77 <script type="text/JavaScript" src="/WebPath/js/js_lib/SimpleContextMenu.js"></script>
78 <script type="text/JavaScript" src="/WebPath/js/js_lib/ConfigurationAPI.js"></script>
79 */
80 
81 var DeleteWiz = DeleteWiz || {}; //define DeleteWiz namespace
82 
83 if (typeof Debug == 'undefined')
84  console.log('ERROR: Debug is undefined! Must include Debug.js before DeleteWiz_ConfigurationGUI.js');
85 else if (typeof Globals == 'undefined')
86  console.log('ERROR: Globals is undefined! Must include Globals.js before DeleteWiz_ConfigurationGUI.js');
87 else
88  DeleteWiz.wiz; //this is THE DeleteWiz variable
89 
90 
93 //call createWiz to create instance of a DeleteWiz
96 DeleteWiz.createWiz = function(doneHandler) {
97 
98 
99  var _TABLE_BOOL_TYPE_TRUE_COLOR = "rgb(201, 255, 201)";
100  var _TABLE_BOOL_TYPE_FALSE_COLOR = "rgb(255, 178, 178)";
101 
102 
103 
104  //global vars for params
105  var _recordAlias;
106  var _doneHandler = doneHandler;
107  var _aRecordWasDeleted = false;
108 
109  var _RECORD_TYPE_CONTEXT = "Context";
110  var _RECORD_TYPE_APP = "Supervisor";
111  var _validRecordTypes = [_RECORD_TYPE_CONTEXT,_RECORD_TYPE_APP];
112 
113 
115  function localParameterCheck()
116  {
117  //check for valid record alias
118  var i=_validRecordTypes.length-1;
119  for(i;i>=0;--i)
120  if(_validRecordTypes[i] == _recordAlias) break;
121  if(i<0) //alias error!!
122  {
123  var str = "Invalid Record Alias '" + _recordAlias + "' was specified. " +
124  "The only valid record aliases are as follows: ";
125 
126  for(i=_validRecordTypes.length-1;i>=0;--i)
127  str += "<br>\t_validRecordTypes[i]";
128  Debug.log(str,Debug.HIGH_PRIORITY);
129  return;
130  }
131  } //end localParameterCheck()
132 
133  //global vars for creation
134  var _subsetUIDs; //array of UIDs already defined at base path
135  var _systemGroups; //object of aliases and groups w/active groups
136  var _paramObjMap; //allows for lookup of parameter objects based on stepIndex
137  var _furthestStep = -1;
138  var _lastNextStep = -1;
139 
140  //global vars for saving tables
141  var _modifiedTables;
142 
143 
144  var _STEP_OUT_OF_SEQUENCE = 1000; //steps greater or equal are ignored in _furthestStep
145 
146  var
147  //_STEP_ALSO_APP_CHILDREN = 200,
148 
149  //_STEP_WHICH_APP = 103,
150  //_STEP_SET_CONTEXT_HOST = 102,
151  _STEP_ALSO_DESCENDANTS = 101,
152  _STEP_CHANGE_GROUP = 1000,
153  _STEP_GET_RECORD_NAME = 100,
154  _STEP_SAVE_MODIFIED = 500,
155  _STEP_WHICH_RECORD_TYPE = 20;
156 
157 
160  // end variable declaration
161  Debug.log("DeleteWiz.wiz constructed");
162  DeleteWiz.wiz = this;
163 
164  var windowTooltip= "Welcome to the Delete Wizard GUI. Here you can delete hierarchical records for " +
165  "your <i>otsdaq</i> system. \n\n" +
166  "The Delete Wizard is presented as a step-by-step process that will walk you through deleting a record and its children.\n\n" +
167 
168  "Briefly, here is a description of the steps: " +
169  "\n\t- 'What is the name of your record?'" +
170  "\n\t- 'How deep into the hierachy do you want to delete?'";
171  DesktopContent.tooltip("Delete Wizard Introduction",
172  windowTooltip);
173  DesktopContent.setWindowTooltip(windowTooltip);
174  xdaqContextTooltip();
175  xdaqApplicationTooltip();
176 
177  showPrompt(_STEP_WHICH_RECORD_TYPE);
178 
179 
180  return;
181 
184  // start funtion declaration
185 
186 
187  //=====================================================================================
188  //xdaqContextTooltip ~~
189  function xdaqContextTooltip()
190  {
191  DesktopContent.tooltip("XDAQ Contexts",
192  "The lowest level parent for all records, in the <i>otsdaq</i> configuration tree, is a XDAQ Context. " +
193  "What is a XDAQ Context? Why do I need a XDAQ Context? Do I want a new one for my " + _recordAlias + " or not?" +
194  "<br><br>" +
195  "XDAQ Contexts are the fundamental executable program building blocks of <i>otsdaq</i>. " +
196  "A XDAQ Context runs a group of XDAQ Applications inside of it. If one of those XDAQ Applications crashes, " +
197  "then only the parent XDAQ Context will crash. This is one reason organizing your <i>otsdaq</i> entities into separate XDAQ Contexts makes sense." +
198  "<br><br>" +
199  "Two other useful features of XDAQ Contexts are that they can easily be turned on and off (enabled and disabled through the configuration editors), and " +
200  "they can easily be distributed to other nodes (computers) in your DAQ system when your system scales up."
201  );
202  } //end xdaqContextTooltip()
203  //=====================================================================================
204  //xdaqApplicationTooltip ~~
205  function xdaqApplicationTooltip()
206  {
207  DesktopContent.tooltip("XDAQ Applications",
208  "The second level parent for all records, in the <i>otsdaq</i> configuration tree, is a XDAQ Application. " +
209  "What is a XDAQ Application? Why do I need a XDAQ Application? Do I want a new one for my " + _recordAlias + " or not?" +
210  "<br><br>" +
211  "XDAQ Applications are server processes that can be controlled by <i>otsdaq</i> through network messages. " +
212  "Ther can be one or many XDAQ Applciation in a XDAQ Context. If one of those XDAQ Applications crashes, " +
213  "then all of the other XDAQ Applications in the parent XDAQ Context will crash. This is one reason organizing your <i>otsdaq</i> entities into separate XDAQ Contexts makes sense." +
214  "<br><br>" +
215  "Two other useful features of XDAQ Applications are that they can respond to web requests and state machine transitions."
216  );
217  } //end xdaqApplicationTooltip()
218 
219  //=====================================================================================
220  //initDeleteWizard ~~
221  // get active groups and list of all groups
222  // get list of existing records at base path
223  function initDeleteWizard()
224  {
225  _subsetUIDs = []; //reset
226  _modifiedTables = []; //reset
227  _furthestStep = -1; // reset
228  _paramObjMap = {}; //reset
229  _systemGroups = {}; //reset
230 
231  { //remove all existing dialogs
232 
233  var el = document.getElementById(ConfigurationAPI._POP_UP_DIALOG_ID);
234  while(el)
235  {
236  el.parentNode.removeChild(el); //close popup
237  el = document.getElementById(ConfigurationAPI._POP_UP_DIALOG_ID);
238  }
239  } //end remove all existing dialogs
240 
241 
242  // get groups and aliases
243  ConfigurationAPI.getAliasesAndGroups(
244  function(retObj)
245  {
246  _systemGroups = retObj;
247  console.log("_systemGroups",_systemGroups);
248  console.log("ConfigurationAPI._activeGroups",ConfigurationAPI._activeGroups);
249 
250 
251  // get existing records
252  ConfigurationAPI.getSubsetRecords(
253  getRecordConfiguration(),
254  getRecordFilter() /*_recordPreFilterList*/,
255  function(records)
256  {
257  _subsetUIDs = records;
258  Debug.log("records found = " + records.length);
259  console.log(records);
260 
261  showPrompt(_STEP_GET_RECORD_NAME);
262 
263  },_modifiedTables); //end getSubsetRecords
264 
265  }); //end getAliasesAndGroups
266 
267  } //end initDeleteWizard()
268 
269  //=====================================================================================
270  //showPrompt ~~
271  // _paramObjMap allows for lookup parameters based on stepIndex
272  // paramObj is the new object for stepIndex
273  function showPrompt(stepIndex,paramObj)
274  {
275  //default to step 0
276  if(!stepIndex) stepIndex = 0;
277 
278  if(stepIndex > _furthestStep &&
279  _furthestStep < _STEP_OUT_OF_SEQUENCE)
280  _furthestStep = stepIndex;
281 
282  Debug.log("showPrompt " + stepIndex);
283  Debug.log("_furthestStep " + _furthestStep);
284 
285  //default to empty object
286  if(!_paramObjMap) _paramObjMap = {};
287 
288 
289  if(paramObj) //store to object map
290  _paramObjMap[stepIndex] = paramObj;
291  else if(_paramObjMap[stepIndex]) //load from object map
292  paramObj = _paramObjMap[stepIndex];
293  else
294  {
295  //default to empty object
296  _paramObjMap[stepIndex] = {};
297  paramObj = _paramObjMap[stepIndex];
298  }
299 
300  console.log("_paramObjMap",_paramObjMap);
301  console.log("paramObj",paramObj);
302 
303  var el = document.getElementById(ConfigurationAPI._POP_UP_DIALOG_ID);
304 
305  //remove all existing dialogs
306  while(el)
307  {
308  el.parentNode.removeChild(el); //close popup
309  el = document.getElementById(ConfigurationAPI._POP_UP_DIALOG_ID);
310  }
311  //note el is usable in code
312 
313  //set position and size
314  var w = 480;
315  var h = 340;//250;
316 
317  var str = "";
318  var stepString = "stepIndex-" + stepIndex + "-";
319 
320  var showPrevButton = true;
321  var showNextButton = true;
322  var prevStepIndex = stepIndex-1; //default back button to last next step //stepIndex-1;
323  if(prevStepIndex > _lastNextStep)
324  prevStepIndex = _lastNextStep;
325  _lastNextStep = stepIndex;
326 
327  var nextStepIndex = stepIndex+1;
328  var prevButtonText = "Go Back";
329  var nextButtonText = "Next Step";
330 
331  var recordName = "";
332  try //try to get record name since used often
333  {
334  recordName = _paramObjMap[_STEP_GET_RECORD_NAME]["recordName"];
335  } catch(e){;}
336 
339  // add content
340  localAddContent();
341  function localAddContent()
342  {
343  switch(stepIndex)
344  {
345 
346 
347  case _STEP_SAVE_MODIFIED:
348 
349  Debug.log("_STEP_SAVE_MODIFIED ");
350 
351  nextButtonText = "Done!";
352 
353  str += "<br>";
354  str += "Things are getting real! Are you sure you want to proceed?<br><br>" +
355  "To finalize your deletions, please click 'Done!'";
356  str += "<br>";
357  str += "<br>";
358 
359  Debug.log("All deletions, so far, were made temporarily. For them to persist, " +
360  "you must follow the prompt and click the 'Done!' button.",
361  Debug.INFO_PRIORITY);
362 
363  break; //end _STEP_SET_RECORD_FIELDS
364 
365  case _STEP_ALSO_DESCENDANTS:
366 
367  localAlsoDescendantContent();
368  function localAlsoDescendantContent()
369  {
370  showNextButton = false; //replace it
371 
372  //take parameter recordName
373  Debug.log("_STEP_ALSO_DESCENDANTS " + recordName);
374 
375  // " delete only target record or include descendants?"
376  str += "<br>";
377 
378  var children = paramObj["rootChildren"];
379  if(children.length)
380  {
381  str += "Do you want to delete all the descendants along with the parent " + _recordAlias + " named '" +
382  recordName + ",' or only the chosen " + _recordAlias + " record named '" +
383  recordName + "?'";
384  str += "<br>";
385  str += "<br>";
386 
387  str += "<b>For reference, here are the first-level children of the chosen " + _recordAlias +
388  " named '" +
389  recordName + "':</b><br>";
390  { //start contexts
391  str += htmlOpen("select",
392  {
393  "id" : stepString + "rootChildren",
394  });
395 
396  for(var i=0;i<children.length;++i)
397  {
398  str += htmlOpen("option",
399  {
400  },
401  ConfigurationAPI.getTreeRecordName(children[i]) /*innerHTML*/,
402  true /*closeTag*/);
403  }
404  str += "</select>"; //end aliases dropdown
405 
406  str += htmlClearDiv();
407  str += htmlOpen("input",
408  {
409  "id": stepString + "deleteDescendants",
410  "type": "button",
411  "value": "Delete " + _recordAlias + " and ALL Descendants",
412  "title": "Delete all children of the chosen " + _recordAlias + " named &apos;" +
413  recordName + ".&apos;"
414  },
415  0 /*html*/, true /*closeTag*/);
416  } //end contexts
417  } //end existing children
418  else
419  str += "There were no Supervisor children found for the parent " + _recordAlias + " named '" +
420  recordName + "' - do you want to delete the " + _recordAlias + " named '" +
421  recordName + "?'";
422 
423 
424  str += htmlClearDiv();
425 
426  str += htmlOpen("input",
427  {
428  "style": "margin:20px;",
429  "id": stepString + "deleteOnlyRoot",
430  "type": "button",
431  "value": "Delete Only the " + _recordAlias,
432  "title": "Delete only the chosen " + _recordAlias + " named &apos;" +
433  recordName + ".&apos;"
434  },
435  0 /*html*/, true /*closeTag*/);
436 
437  } //end localAlsoDescendantContent
438 
439 
440 
441 
442 
443  break; //end _STEP_ALSO_DESCENDANTS
444 
445  case _STEP_CHANGE_GROUP:
446  //take paramter groupType
447 
448  showNextButton = false; //replace it
449  nextStepIndex = _STEP_GET_RECORD_NAME;
450  prevStepIndex = _STEP_GET_RECORD_NAME;
451 
452  str += "Choose a '" + paramObj["groupType"] +
453  "' group to activate (either a System Alias or specific group):";
454 
455  str += htmlClearDiv();
456 
457  str += "<center>";
458  str += "<table style='margin-bottom: 10px;'>";
459  if(_systemGroups.aliases[paramObj["groupType"]].length)
460  {
461  str += "<tr><td><b>System Aliases:</b></td><td>";
462  { //start aliases
463  str += htmlOpen("select",
464  {
465  "id" : stepString + "aliases",
466  });
467 
468  for(var i=0;i<_systemGroups.aliases[paramObj["groupType"]].length;++i)
469  {
470  str += htmlOpen("option",
471  {
472  },
473  _systemGroups.aliases[paramObj["groupType"]]
474  [i].alias /*innerHTML*/, true /*closeTag*/);
475  }
476  str += "</select>"; //end aliases dropdown
477  str += htmlOpen("input",
478  {
479  "id": stepString + "activateAlias",
480  "type": "button",
481  "value": "Activate Alias",
482  "title": "Activate chosen System Alias and return to creating your new " + _recordAlias + "."
483  },
484  0 /*html*/, true /*closeTag*/);
485  } //end aliases
486  str += "</td></tr>";
487  }
488  else
489  str += "<tr><td colspan='2'>No system aliases of type Context found.</td></tr>";
490 
491  var groupNames = Object.keys(_systemGroups.groups[paramObj["groupType"]]);
492  if(groupNames.length)
493  {
494  str += "<tr><td><b>Group Names:</b></td><td>";
495  { //start groups
496  str += htmlOpen("select",
497  {
498  "id" : stepString + "groupNames",
499  });
500 
501  for(var i=0;i<groupNames.length;++i)
502  {
503  str += htmlOpen("option",
504  {
505  },
506  groupNames[i] /*innerHTML*/, true /*closeTag*/);
507  }
508  str += "</select>"; //end group name dropdown
509 
510  } //end groups
511  str += "</td></tr>";
512  }
513  else
514  str += "<tr><td colspan='2'>No groups of type Context found.</td></tr>";
515 
516  if(groupNames.length)
517  {
518  str += "<tr><td><b>Group Keys:</b></td><td>";
519  { //start keys
520  str += htmlOpen("select",
521  {
522  "id" : stepString + "groupKeys",
523  });
524 
525  for(var i=0;i<_systemGroups.groups[paramObj["groupType"]]
526  [groupNames[0]].keys.length;++i)
527  {
528  str += htmlOpen("option",
529  {
530  },
531  _systemGroups.groups[paramObj["groupType"]]
532  [groupNames[0]].keys[i] /*innerHTML*/, true /*closeTag*/);
533  }
534  str += "</select>"; //end group keys dropdown
535  str += htmlOpen("input",
536  {
537  "id": stepString + "activateGroup",
538  "type": "button",
539  "value": "Activate Group",
540  "title": "Activate chosen Group and Key pair and return to creating your new " + _recordAlias + "."
541  },
542  0 /*html*/, true /*closeTag*/);
543  } //end keys
544  str += "</td></tr>";
545  }
546  str += "</table>";
547  str += "</center>";
548 
549  break; //end _STEP_CHANGE_GROUP
550 
551  case _STEP_GET_RECORD_NAME:
552 
553 
554  Debug.log("_STEP_GET_RECORD_NAME " + _recordAlias);
555 
556  _modifiedTables = []; //reset
557 
558  prevStepIndex = _STEP_WHICH_RECORD_TYPE;
559 
561  // header
562  str += htmlOpen("div",
563  {
564  "style" : "font-weight:bold; margin: 6px 0 20px 0;"
565  },
566  (_aRecordWasDeleted?
567  ("Would you like to delete another " + _recordAlias + "?"):
568  ("Welcome to the " + _recordAlias + " deletion Wizard!")) /*innerHTML*/,
569  true /*closeTag*/);
570  str += htmlClearDiv();
571 
573  // existing records
574  str += "Choose the " + _recordAlias + " record name to be deleted: ";
575  str += htmlClearDiv();
576 
577  str += htmlOpen("select",
578  {
579  "id" : stepString + "recordName",
580  "style" : "margin-bottom: 16px;"
581  });
582 
583 
584  for(var i=0;i<_subsetUIDs.length;++i)
585  {
586  str += "<option " +
587  (paramObj["recordName"] &&
588  paramObj["recordName"]==_subsetUIDs[i]?"selected":"") +
589  ">";
590  str += _subsetUIDs[i];
591  str += "</option>";
592  }
593  str += "</select>"; //end existing records dropdown
594 
595 
597  // active groups
598  str += htmlClearDiv();
599  str += "Note you are currently editing these active groups:";
600  str += "<center>";
601  str += "<table style='margin-bottom: 10px;'>";
602  str += "<tr><td><b>Active Context:</b></td><td>";
603  str += ConfigurationAPI._activeGroups.Context.groupName + " (" + ConfigurationAPI._activeGroups.Context.groupKey + ")";
604  //_systemGroups.activeGroups.Context.groupName + " (" + _systemGroups.activeGroups.Context.groupKey + ")";
605 
606  str += htmlOpen("div",
607  {
608  "id": stepString + "editContext",
609  "class": ConfigurationAPI._POP_UP_DIALOG_ID + "-editIcon",
610  "style": "float:right; display:block; margin: -3px 0 0 10px;",
611  "title": "Click to activate a different Context group.",
612 
613  }, 0 /*innerHTML*/, true /*closeTag*/);
614 
615  str += "</td></tr>";
616  str += "<tr><td><b>Active Configuration:</b></td><td>";
617  str += _systemGroups.activeGroups.Configuration.groupName + " (" + _systemGroups.activeGroups.Configuration.groupKey + ")";
618 
619  str += htmlOpen("div",
620  {
621  "id": stepString + "editConfig",
622  "class": ConfigurationAPI._POP_UP_DIALOG_ID + "-editIcon",
623  "style": "float:right; display:block; margin: -3px 0 0 10px;",
624  "title": "Click to activate a different Configuration group.",
625  }, 0 /*innerHTML*/, true /*closeTag*/);
626 
627  str += "</td></tr>";
628  str += "</table>";
629  str += "</center>";
630 
631 
632  break; // end _STEP_GET_RECORD_NAME
633 
634  case _STEP_WHICH_RECORD_TYPE:
635 
636  Debug.log("_STEP_WHICH_RECORD_TYPE ");
637 
638  nextStepIndex = _STEP_GET_RECORD_NAME;
639  prevButtonText = "Close Wizard";
640 
642  // header
643  str += htmlOpen("div",
644  {
645  "style" : "font-weight:bold; margin: 6px 0 20px 0;"
646  },
647  "Welcome to the record deletion Wizard!" /*innerHTML*/,
648  true /*closeTag*/);
649  str += htmlClearDiv();
650 
652  // existing record types
653  str += htmlClearDiv();
654  str += "Below is a dropdown of record types that this Wizard can help you delete. " +
655  " Choose one and proceed through the steps to delete the chosen record and its children:";
656  str += htmlClearDiv();
657  str += htmlOpen("select",
658  {
659  "id" : stepString + "recordTypes",
660  "style" : "margin-bottom: 16px;"
661  });
662 
663  for(var i=0;i<_validRecordTypes.length;++i)
664  {
665  str += htmlOpen("option",
666  {
667  },_validRecordTypes[i] /*innerHTML*/, true /*closeTag*/);
668  }
669  str += "</select>"; //end existing records dropdown
670 
671  break; //end _STEP_WHICH_RECORD_TYPE
672  default:
673  Debug.log("Should never happen - bad stepIndex (" + stepIndex +
674  ")!",Debug.HIGH_PRIORITY);
675  return;
676  }
677 
678  //add go back button
679  //add proceed to next step button
680  var ctrlStr = "";
681 
682  if(stepIndex && showPrevButton)
683  ctrlStr += htmlOpen("input",
684  {
685  "class": "prevButton " + stepString + "prevButton",
686  "type": "button",
687  "value": prevButtonText,
688  "title": "Return to the previous step in the " + _recordAlias + " creation wizard."
689  },
690  0 /*html*/, true /*closeTag*/);
691  if(showNextButton)
692  ctrlStr += htmlOpen("input",
693  {
694  "class": "nextButton " + stepString + "nextButton",
695  "type": "button",
696  "value": nextButtonText,
697  "title": "Proceed to the next step in the " + _recordAlias + " creation wizard."
698  },
699  0 /*html*/, true /*closeTag*/);
700 
701 
702  //make popup element
703  el = document.createElement("div");
704  el.setAttribute("id", ConfigurationAPI._POP_UP_DIALOG_ID);
705 
706  ConfigurationAPI.setPopUpPosition(el,w /*w*/,h /*h*/);
707 
708  el.innerHTML = ctrlStr + htmlClearDiv() + str + htmlClearDiv() + ctrlStr;
709  document.body.appendChild(el);
710  } //end localAddContent()
711 
712 
715  // add handlers
716  localAddHandlers();
717  function localAddHandlers()
718  {
719  var newParamObj = {};
720 
722  //add handlers specific to the step
723  //NOTE: apparently {} create "function scope" inside a switch case
724  // and, apparently switch statements create "function scope" too.
725  switch(stepIndex)
726  {
727 
728  case _STEP_ALSO_DESCENDANTS:
729 
730  localAlsoDescendantsHandlers();
731 
733  function localAlsoDescendantsHandlers()
734  {
735 
736 
738  document.getElementById(stepString + "deleteOnlyRoot").onclick =
739  function()
740  {
741  localDeleteRootRecord();
742  }; //end deleteOnlyRoot button handler
743 
745  var deleteDescendantsButton = document.getElementById(stepString + "deleteDescendants");
746  if(!deleteDescendantsButton) return;
747 
748  deleteDescendantsButton.onclick =
749  function()
750  {
751  Debug.log("deleteDescendants " + recordName);
752 
753 
754  //keep list of off-limit tables to avoid loops
755  // create a map to all deletion children by table
756  // add children to delete map until a repeat is reached.. or no more children
757 
758  var deleteMap = {}; // map of table to array of records UIDs
759  // i.e.: map<table, array<records> >
760 
761  if(_recordAlias == _RECORD_TYPE_CONTEXT)
762  localRecurseDeleteChildren(_paramObjMap[_STEP_ALSO_DESCENDANTS]["rootChildren"],
763  "XDAQApplicationConfiguration",0);
764  else if(_recordAlias == _RECORD_TYPE_APP)
765  localRecurseDeleteChildren([_paramObjMap[_STEP_ALSO_DESCENDANTS]["root"]],
766  "XDAQApplicationConfiguration",0);
767  else
768  throw("?");
770  function localRecurseDeleteChildren(children, table, depth)
771  {
772  if(table == "NO_LINK") return; //skip disconnected links
773 
774  console.log(depth,table,children);
775 
776  var childLinks;
777  var name;
778 
779  //delete children
780  for(var i=0;i<children.length;++i)
781  {
782  try
783  {
784  name = ConfigurationAPI.getTreeRecordName(children[i]);
785  }
786  catch(e)
787  {
788  Debug.log("Name extraction failed. Assuming disconnected link: " + e);
789  console.log(deleteMap);
790  continue;
791  }
792 
793  if(!deleteMap[table]) deleteMap[table] = []; //init table records
794 
795  //if child already found in deleteMap, skip it
796  if(deleteMap[table].indexOf(name) >= 0) continue;
797  //else add to delete map
798  deleteMap[table].push(name);
799  console.log(deleteMap);
800 
801  //for each link inside child, get children records
802  childLinks = ConfigurationAPI.getTreeRecordLinks(children[i]);
803 
804  for(var j=0;j<childLinks.length;++j)
805  localRecurseDeleteChildren(
806  ConfigurationAPI.getTreeLinkChildren(childLinks[j]),
807  ConfigurationAPI.getTreeLinkTable(childLinks[j]),
808  depth+1);
809  }
810  } //end localRecurseDeleteChildren()
811 
812  console.log(deleteMap);
813 
814  //delete all records in map
815  var requestCount = 0;
816  var recordCount = 0;
817  var tableCount = 0;
818  _modifiedTables = []; //reset
819  for(var table in deleteMap)
820  {
821  Debug.log("table " + table);
822 
823  if(_recordAlias == _RECORD_TYPE_CONTEXT)
824  {
825  if( table == "XDAQContextTable")
826  continue; //skip off-limit table
827  }
828  else if(table == "XDAQContextTable" ||
829  table == "XDAQApplicationConfiguration")
830  continue; //skip off-limit table
831 
832  ++requestCount;
834  //delete record
835  ConfigurationAPI.deleteSubsetRecords(
836  table,
837  deleteMap[table],
839  function(modifiedTables,err,table,deletionCount) //start deleteSubsetRecords handler
840  {
841 
842  Debug.log("modifiedTables length " + modifiedTables.length);
843  if(err)
844  {
845  //really an error
846  Debug.log("There was an error while deleting " + deletionCount +
847  " records from table '" +
848  table + ".' " + err,
849  Debug.HIGH_PRIORITY);
850  return;
851  }
852  //do not decrement requestCount on error
853  --requestCount;
854  ++tableCount;
855  recordCount += deletionCount;
856 
857  //assuming just one modified table
858  if(modifiedTables && modifiedTables[0])
859  _modifiedTables.push(modifiedTables[0]);
860 
861  //at this point context was deleted in modified tables
862  Debug.log(deletionCount + " records in table '" +
863  table + " were successfully removed!", Debug.INFO_PRIORITY);
864 
865  if(requestCount == 0)
866  {
867  Debug.log("Descendant Summary: " + recordCount + " records from " +
868  tableCount + " tables were successfully removed!",
869  Debug.INFO_PRIORITY);
870  localDeleteRootRecord();
871  }
872 
873  }, //end deleteSubsetRecords handler
874  _modifiedTables,
875  true /*silenceErrors*/); //end deleteSubsetRecords
876 
877  }
878 
879  if(!requestCount) //if no children tables, finish up anyway
880  localDeleteRootRecord();
881 
882  }; //end deleteDescendants button handler
883 
884 
885  } //end localAlsoDescendantsHandlers()
886 
887  break; //end _STEP_ALSO_DESCENDANTS
888 
889  case _STEP_GET_RECORD_NAME:
890 
891  { //start scope of _STEP_GET_RECORD_NAME
892 
893 
895  document.getElementById(stepString + "editConfig").onclick =
896  function()
897  {
898  newParamObj["groupType"] = "Configuration";
899  //save name to param for this step
900  paramObj["recordName"] = document.getElementById(stepString + "recordName").value.trim();
901  showPrompt(_STEP_CHANGE_GROUP,newParamObj);
902  };
904  document.getElementById(stepString + "editContext").onclick =
905  function()
906  {
907  newParamObj["groupType"] = "Context";
908  //save name to param for this step
909  paramObj["recordName"] = document.getElementById(stepString + "recordName").value.trim();
910  showPrompt(_STEP_CHANGE_GROUP,newParamObj);
911  };
912  } //end scope of _STEP_GET_RECORD_NAME
913 
914  break; //end _STEP_GET_RECORD_NAME
915 
916  case _STEP_CHANGE_GROUP:
917 
918  { //start scope of _STEP_CHANGE_GROUP
919 
921  document.getElementById(stepString + "activateAlias").onclick =
922  function()
923  {
924  //activate alias then go back to record name
925  var alias = document.getElementById(stepString + "aliases").value;
926  Debug.log("activateAlias " + alias);
927 
928  //find associated aliasObj
929  var aliasObj;
930  for(var i=0;i<
931  _systemGroups.aliases[paramObj["groupType"]].length;++i)
932  if(_systemGroups.aliases[paramObj["groupType"]][i].alias ==
933  alias)
934  {
935  aliasObj = _systemGroups.aliases[paramObj["groupType"]][i];
936  break;
937  }
938 
939  Debug.log("activateAlias group " + aliasObj.name +
940  "-" + aliasObj.key);
941 
942  ConfigurationAPI.activateGroup(aliasObj.name, aliasObj.key,
943  true /*ignoreWarnings*/,
944  /*doneHandler*/
945  function()
946  {
947  Debug.log("The System Alias '" + alias +
948  "' (" + aliasObj.name + " (" +
949  aliasObj.key + ")) was successfully activated!", Debug.INFO_PRIORITY);
950 
951  initDeleteWizard();
952  }); //end activate group handler
953  }; //end activate alias handler
954 
956  document.getElementById(stepString + "groupNames").onchange =
957  function()
958  {
959  //fill keys drop down
960  Debug.log("Filling dropdown with keys for " + this.value);
961  var str = "";
962  for(var i=0;i<_systemGroups.groups[paramObj["groupType"]]
963  [this.value].keys.length;++i)
964  {
965  str += htmlOpen("option",
966  {
967  },
968  _systemGroups.groups[paramObj["groupType"]]
969  [this.value].keys[i] /*innerHTML*/, true /*closeTag*/);
970  }
971  document.getElementById(stepString + "groupKeys").innerHTML =
972  str;
973  }; //end group names dropdown handler
974 
976  document.getElementById(stepString + "activateGroup").onclick =
977  function()
978  {
979  //activate alias then go back to record name
980  var name = document.getElementById(stepString + "groupNames").value;
981  var key = document.getElementById(stepString + "groupKeys").value;
982 
983  Debug.log("activateGroup " + name +
984  "-" + key);
985 
986  ConfigurationAPI.activateGroup(name, key,
987  true /*ignoreWarnings*/,
988  /*doneHandler*/
989  function()
990  {
991  Debug.log("The Group '" + name + " (" +
992  key + ") was successfully activated!", Debug.INFO_PRIORITY);
993 
994  initDeleteWizard();
995  }); //end activate group handler
996  }; //end activate alias handler
997 
998  } //end scope of _STEP_CHANGE_GROUP
999 
1000  break; //end _STEP_CHANGE_GROUP
1001  default:;
1002  }
1003 
1004 
1005 
1006 
1008  //add functions shared by handlers above and below
1009  { //fake scope for grouping
1010 
1012  // localDeleteRootRecord
1013  // deletes chosen top level record
1014  function localDeleteRootRecord()
1015  {
1016  Debug.log("localDeleteRootRecord " + recordName);
1017 
1018 
1020  //delete record
1021  ConfigurationAPI.deleteSubsetRecords(
1022  getRecordConfiguration(),
1023  recordName,
1025  function(modifiedTables,err) //start deleteSubsetRecords handler
1026  {
1027  Debug.log("modifiedTables length " + modifiedTables.length);
1028  if(!modifiedTables.length)
1029  {
1030  //really an error
1031  Debug.log("There was an error while removing the " + _recordAlias +
1032  " named '" +
1033  recordName + ".' " + err,
1034  Debug.HIGH_PRIORITY);
1035  return;
1036  }
1037  _modifiedTables = modifiedTables;
1038 
1039  //at this point context was deleted in modified tables
1040  Debug.log("The " + _recordAlias + " named '" +
1041  recordName + "' was successfully removed!",
1042  Debug.INFO_PRIORITY);
1043 
1044  showPrompt(_STEP_SAVE_MODIFIED);
1045 
1046  }, //end deleteSubsetRecords handler
1047  _modifiedTables,
1048  true /*silenceErrors*/); //end deleteSubsetRecords
1049 
1050 
1051  } //end localDeleteRootRecord()
1052 
1053 
1054  } //end fake scope for shared handler functions
1055 
1056 
1057 
1058 
1059 
1060 
1062  //add handlers for all steps
1063  try
1064  {
1065  document.getElementsByClassName(stepString + "nextButton")[0].onclick =
1066  localNextButtonHandler;
1067  document.getElementsByClassName(stepString + "nextButton")[1].onclick =
1068  localNextButtonHandler;
1069 
1070  function localNextButtonHandler()
1071  {
1072 
1073  //extract specific step parameters
1074  switch(stepIndex)
1075  {
1076  case _STEP_SAVE_MODIFIED:
1077 
1078  //set record fields and save modified tables
1079  localScopeSetRecordSaveModifiedDoIt();
1080 
1082  function localScopeSetRecordSaveModifiedDoIt() //function just for scoped vars
1083  {
1084  Debug.log("localScopeSetRecordSaveModifiedDoIt");
1085 
1086  //proceed to save (quietly) tables, groups, aliases
1087  ConfigurationAPI.saveModifiedTables(_modifiedTables,
1088  function(savedTables, savedGroups, savedAliases)
1089  {
1090  if(!savedTables.length)
1091  {
1092  Debug.log("There was an error while deleting the records.",
1093  Debug.HIGH_PRIORITY);
1094  return;
1095  }
1096 
1097  Debug.log("The deletions were successfully completed!", Debug.INFO_PRIORITY);
1098 
1099 // Debug.log("The new " +
1100 // _recordAlias + " named '" + recordName + "' was successfully created!",
1101 // Debug.INFO_PRIORITY);
1102 
1103  _modifiedTables = []; //clear after save
1104 
1105  _aRecordWasDeleted = true;
1106 
1107  initDeleteWizard(); //start over if no done handler
1108 
1109  }); //end saveModifiedTables handler
1110 
1111  } //end localScopeSetRecordFieldsDoIt()
1112 
1113  return; //prevent default next action
1114 
1115  break; //end _STEP_SET_RECORD_FIELDS
1116 
1117 
1118 
1119  case _STEP_GET_RECORD_NAME:
1120 
1121  //save name to param for this step
1122  recordName = document.getElementById(stepString + "recordName").value.trim();
1123  paramObj["recordName"] = recordName;
1124 
1125 
1126  //get children of contexts and give as parameter
1127  ConfigurationAPI.getTree(
1128  getRecordConfiguration() + "/" + recordName,
1129  40 /*depth*/,
1130  _modifiedTables,
1131  function(tree)
1132  {
1133  console.log(tree);
1134 
1135  //setup for _STEP_ALSO_DESCENDANTS
1136  if(!_paramObjMap[_STEP_ALSO_DESCENDANTS]) _paramObjMap[_STEP_ALSO_DESCENDANTS] = {}; //init
1137 
1138  var links = ConfigurationAPI.getTreeRecordLinks(tree);
1139 
1140  _paramObjMap[_STEP_ALSO_DESCENDANTS]["root"] = tree; //save tree
1141  _paramObjMap[_STEP_ALSO_DESCENDANTS]["rootChildren"] = []; //init array
1142 
1143  //concat all first level children (i.e. through links)
1144  for(var i=0;i<links.length;++i)
1145  _paramObjMap[_STEP_ALSO_DESCENDANTS]["rootChildren"] =
1146  _paramObjMap[_STEP_ALSO_DESCENDANTS]["rootChildren"].concat(
1147  ConfigurationAPI.getTreeLinkChildren(links[i]));
1148 
1149  showPrompt(_STEP_ALSO_DESCENDANTS);
1150 
1151 
1152  }); //end getSubsetRecords handler
1153  return; //prevent default show prompt, do in handler
1154  break; //end _STEP_GET_RECORD_NAME next handler
1155 
1156  case _STEP_WHICH_RECORD_TYPE:
1157 
1159  if(scopeWhichRecordTypeNext())
1160  return; //prevent default show prompt, do initDeleteWizard
1161 
1162  function scopeWhichRecordTypeNext()
1163  {
1164  var newRecordAlias = document.getElementById(stepString + "recordTypes").value.trim();
1165 
1166  var needToInit = (_recordAlias != newRecordAlias);
1167 
1168  _recordAlias = newRecordAlias;
1169  Debug.log("_recordAlias chosen as " + _recordAlias);
1170 
1171  if(needToInit) initDeleteWizard();
1172  return needToInit;
1173  } //end scopeWhichRecordTypeNext()
1174 
1175  break; //end _STEP_WHICH_RECORD_TYPE next handler
1176  default:;
1177  }
1178  showPrompt(nextStepIndex,newParamObj);
1179  } //end next handler
1180  }
1181  catch(e){ Debug.log("Caught ERROR: " + e.stack);}
1182 
1183  try
1184  {
1185  document.getElementsByClassName(stepString + "prevButton")[0].onclick =
1186  localPrevButtonHandler;
1187  document.getElementsByClassName(stepString + "prevButton")[1].onclick =
1188  localPrevButtonHandler;
1189 
1190  function localPrevButtonHandler()
1191  {
1192  //extract specific step parameters
1193  switch(stepIndex)
1194  {
1195  case _STEP_WHICH_RECORD_TYPE:
1196 
1197  //close window and clear data
1198 
1199  _subsetUIDs = []; //reset
1200  _modifiedTables = []; //reset
1201  _furthestStep = -1; // reset
1202  _paramObjMap = {}; //reset
1203  _systemGroups = {}; //reset
1204 
1205  //remove all existing dialogs
1206  var el = document.getElementById(ConfigurationAPI._POP_UP_DIALOG_ID);
1207  while(el)
1208  {
1209  el.parentNode.removeChild(el); //close popup
1210  el = document.getElementById(ConfigurationAPI._POP_UP_DIALOG_ID);
1211  }
1212 
1213  if(_doneHandler) _doneHandler(_aRecordWasDeleted);
1214  return; //prevent default prev showPrompt
1215  break;
1216  default:;
1217  }
1218  showPrompt(prevStepIndex);
1219  } //end prev handler
1220  }
1221  catch(e){ Debug.log("Caught ERROR: " + e.stack);}
1222 
1223  } //end localAddHandlers()
1224 
1225  } //end showPrompt()
1226 
1227 
1228  //=====================================================================================
1229  //getRecordConfiguration ~~
1230  function getRecordConfiguration()
1231  {
1232  var retVal = "";
1233  if(_recordAlias == _RECORD_TYPE_CONTEXT)
1234  retVal = "XDAQContextTable";
1235  else if(_recordAlias == _RECORD_TYPE_APP)
1236  retVal = "XDAQApplicationConfiguration";
1237  else
1238  throw("?");
1239 
1240  return retVal;
1241  } //end getRecordConfiguration()
1242 
1243 
1244 
1245  //=====================================================================================
1246  //getRecordFilter ~~
1247  function getRecordFilter()
1248  {
1249  var retVal = "";
1250  if(_recordAlias == _RECORD_TYPE_CONTEXT)
1251  retVal = "";
1252  else if(_recordAlias == _RECORD_TYPE_APP)
1253  retVal = "";//"ProcessorType=" + _recordAlias;
1254 
1255  return retVal;
1256  } //end getRecordFilter()
1257 
1258 
1259  //=====================================================================================
1260  //htmlOpen ~~
1261  // tab name and attribute/value map object
1262  function htmlOpen(tag,attObj,innerHTML,closeTag)
1263  {
1264  var str = "";
1265  var attKeys = Object.keys(attObj);
1266  str += "<" + tag + " ";
1267  for(var i=0;i<attKeys.length;++i)
1268  str += " " + attKeys[i] + "='" +
1269  attObj[attKeys[i]] + "' ";
1270  str += ">";
1271  if(innerHTML) str += innerHTML;
1272  if(closeTag)
1273  str += "</" + tag + ">";
1274  return str;
1275  } // end htmlOpen()
1276 
1277  //=====================================================================================
1278  //htmlClearDiv ~~
1279  function htmlClearDiv()
1280  {
1281  return "<div id='clearDiv'></div>";
1282  } //end htmlClearDiv()
1283 
1284 
1285 }; //end DeleteWiz.createWiz()
1286 
1287 
1288 
1289 
1290 
1291 
1292 
1293 
1294