otsdaq_utilities  v2_05_02_indev
ViewerRoot.js
1 //=====================================================================================
2 //
3 // Created Aug, 2013
4 // by Ryan Rivera ((rrivera at fnal.gov))
5 //
6 // ViewerRoot.js
7 //
8 // requires an omni div, that will be made full window size (window.innerWidth and
9 // window.innerHeight) at position 0,0.
10 //
11 // Note: there are some variables declared outside of the namespace ViewerRoot
12 // so take care to avoid naming collisions with:
13 // - gFile
14 // - source_dir
15 // - obj_list
16 // - ViewerRoot.objIndex
17 // - last_index
18 // - function_list
19 // - func_list
20 // - frame_id
21 // - random_id
22 //
23 // public function list:
24 // ViewerRoot.launch()
25 //
26 // from web: http://root.cern.ch/js/
27 // http://root.cern.ch/drupal/content/trevolutionjs
28 // currently using v3.5: https://root.cern.ch/js/3.5/demo/demo.htm
29 // -- to change versions, hopefully just replace folder here:
30 // -- WebGUI/js/visualizers_lib/ViewerRoot_lib/JsRoot/... tar.gz file unzipped inside JsRoot
31 //=====================================================================================
32 
33 
34 var ViewerRoot = ViewerRoot || {}; //define namespace
35 
37 //public function definitions
38 
39 //ViewerRoot ~~
40 //called to start Root viewer
41 ViewerRoot.launch = function() {
42 
43  Debug.log("ViewerRoot.launch");
44 
45  document.getElementById("omni").innerHTML = "<div id='omniHistogramViewer'></div>";
46  ViewerRoot.omni = document.getElementById("omniHistogramViewer");
47 
48  //initialize with loading message in center
49  var w = ViewerRoot.w = window.innerWidth;
50  var h = ViewerRoot.h = window.innerHeight;
51 
52  ViewerRoot.omni.style.position = "absolute";
53  ViewerRoot.omni.style.left = 0 + "px";
54  ViewerRoot.omni.style.top = 0 + "px";
55  ViewerRoot.omni.style.width = w + "px";
56  ViewerRoot.omni.style.height = h + "px";
57  ViewerRoot.omni.style.backgroundColor = "rgb(30,30,30)";
58 
59  ViewerRoot.omni.innerHTML = "<center><div id='loaderStatus' style='margin-top:" + (h/2-8) + "px'>Loading Root Viewer...</div></center>";
60 
61  //load directories of histograms
62  //and display selected histogram
63  //allow window splitting and comparing and contrasting with transparent histos
65 
66  loadScript(source_dir+'ViewerRootHud.js',function(){
67  loadScript(source_dir+'JsRoot/scripts/JSRootCore.js',function(){
68  JSROOT.AssertPrerequisites('2d;io;3d;',ViewerRoot.init);
69  }); });
70 
72  // - if rootCanvas not created, clear omni and create, full window
73  // - since root js library knows to draw in div with id='report'
74  // each root object goes in its own div, which at time of creation is given
75  // id='report'. Maintain array of references to divs holding root object
76  // that does not depend on id. And use for removal and movement and sizing?
77  // - first histo always goes full screen within rootCanvas
78  // - next histo based on RADIO: Tile, Replace, Superimpose
79  // - if TILE, tile it within rootCanvas
80  // - if REPLACE, replace previous object
81  // - if SUPERIMPOSE, place over previous object with alpha 0
82  //
83  // - implementation
84  // - keep array of all root elements drawn
85  // - keep array of their corresponding locations
86  // - keep number of locations used in tile
87 
88 
89 }
90 
91 //end public function definitions
93 
94 
95 var source_dir = "/WebPath/js/visualizers_lib/ViewerRoot_lib/";
96 //var gFile;
97 //var obj_list;
98 //var last_index;
99 //var function_list;
100 //var func_list;
101 //var frame_id;
102 //var random_id;
103 
104 ViewerRoot.STREAMER_INFO_FILE_PATH = "/WebPath/js/visualizers_lib/ViewerRoot_lib/streamerInfo.root";
105 
106 ViewerRoot.LOAD_STREAMER_INFO_CHECK_PERIOD = 100; //ms
107 ViewerRoot.DISPLAY_MIN_WIDTH = 450; //dont allow w or h to go less than this
108 ViewerRoot.DISPLAY_MIN_HEIGHT = 300; //dont allow w or h to go less than this
109 ViewerRoot.HUD_WIDTH = 300;
110 ViewerRoot.HUD_MARGIN_RIGHT = 0;
111 ViewerRoot.HUD_DROP_DOWN_SPEED = 40;
112 ViewerRoot.ROOT_CONTAINER_OFFY = 20;
113 ViewerRoot.ROOT_HEADER_HEIGHT = 20;
114 
115 ViewerRoot.TILE_MODE = 0;
116 ViewerRoot.REPLACE_MODE = 1;
117 ViewerRoot.SUPERIMPOSE_MODE = 2;
118 
119 ViewerRoot.ADMIN_PERMISSIONS_THRESHOLD = 1;
120 ViewerRoot.userPermissions = 0; //0 is no access, 1 is access
121 
122 ViewerRoot.omni;
123 ViewerRoot.rootContainer;
124 
125 ViewerRoot.objIndex;
126 
127 ViewerRoot.rootElArr;
128 ViewerRoot.rootPosArr;
129 ViewerRoot.rootObjArr;
130 ViewerRoot.rootObjIndexArr;
131 ViewerRoot.rootHeaderElArr;
132 ViewerRoot.rootObjNameArr;
133 ViewerRoot.rootIsTransparentArr;
134 ViewerRoot.rootIsAutoRefreshArr;
135 
136 ViewerRoot.numPositionsTiled;
137 ViewerRoot.rootTargetIndex; //targeted object for replace or superimpose
138 ViewerRoot.w;
139 ViewerRoot.h;
140 ViewerRoot.sFile;
141 
142 ViewerRoot.hudAutoHide = false;
143 ViewerRoot.nextObjectMode = 1;
144 ViewerRoot.clearEachRequest = true;
145 ViewerRoot.autoRefreshDefault = false;
146 ViewerRoot.autoRefreshPeriod = 1000;
147 ViewerRoot.pauseRefresh = false;
148 ViewerRoot.hardRefresh = true;
149 
150 ViewerRoot.autoRefreshTimer = 0;
151 
152 
153 ViewerRoot.iterLoading = false;
154 ViewerRoot.iterNumberRemaining;
155 ViewerRoot.iterNumPositionsTiled;
156 ViewerRoot.iterRunWildcard;
157 ViewerRoot.iterRootObjNameArr;
158 ViewerRoot.iterRootPosArr;
159 ViewerRoot.iterRootIsTransparentArr;
160 ViewerRoot.iterRootIsAutoRefreshArr;
161 ViewerRoot.iterSaveNextObjectMode;
162 ViewerRoot.iterSaveAutoRefreshDefault;
163 
164 
165 
166 //"private" function list
167 //ViewerRoot.init
168 //ViewerRoot.autoRefreshTick
169 //ViewerRoot.prepareNextLocation
170 //ViewerRoot.removeAllAtPosition
171 //ViewerRoot.manageRootHeaders
172 //ViewerRoot.toggleAllAtPositionAutoRefresh
173 //ViewerRoot.handleRootPositionSelect
174 //ViewerRoot.clearAll
175 //ViewerRoot.handleWindowResize
176 //ViewerRoot.resizeRootObjects
177 //ViewerRoot.refreshTransparency
178 //ViewerRoot.checkStreamerInfoLoaded
179 //ViewerRoot.getDirectoryContents
180 //ViewerRoot.getDirContentsHandler
181 //ViewerRoot.rootReq
182 //ViewerRoot.rootConfigReq
183 //ViewerRoot.getRootConfigHandler
184 //ViewerRoot.iterativeConfigLoader
185 //ViewerRoot.getRootDataHandler
186 //ViewerRoot.interpretObjectBuffer
187 
188 //=====================================================================================
189 ViewerRoot.init = function()
190 {
191  Debug.log("ViewerRoot.init");
192  //JSROOT.redraw('object_draw', histo, "colz");
193 
194 
195  ViewerRoot.rootElArr = [];
196  ViewerRoot.rootPosArr = [];
197  ViewerRoot.rootObjArr = [];
198  ViewerRoot.rootObjIndexArr = [];
199  ViewerRoot.rootObjNameArr = [];
200  ViewerRoot.rootObjTitleArr = [];
201  ViewerRoot.rootHeaderElArr = [];
202  ViewerRoot.rootIsTransparentArr = [];
203  ViewerRoot.rootIsAutoRefreshArr = [];
204 
205  ViewerRoot.numPositionsTiled = 0;
206  ViewerRoot.rootTargetIndex = -1;
207 
208  obj_list = new Array();
209  ViewerRoot.objIndex = 0;
210  last_index = 0;
211  function_list = new Array();
212  func_list = new Array();
213  frame_id = 0;
214  random_id = 0;
215 
216  //create and add report container
217  ViewerRoot.rootContainer = document.createElement('div');
218  ViewerRoot.rootContainer.setAttribute("id","reportContainer");
219  ViewerRoot.rootContainer.onmouseup = function(){
220  Debug.log("Deselect all root containers");
221  ViewerRoot.rootTargetIndex = -1;
222  ViewerRoot.resizeRootObjects();
223  };
224  ViewerRoot.omni.appendChild(ViewerRoot.rootContainer);
225 
226  ViewerRoot.hud = new ViewerRoot.createHud();
227  window.onresize = ViewerRoot.handleWindowResize;
228  ViewerRoot.handleWindowResize();
229 
230  window.clearInterval(ViewerRoot.autoRefreshTimer);
231  ViewerRoot.autoRefreshTimer = window.setInterval(
232  ViewerRoot.autoRefreshTick,
233  ViewerRoot.autoRefreshPeriod);
234 
235  document.getElementById("loaderStatus").innerHTML = "Root Viewer Loaded.<br>Use drop-down to make selections.";
236  ViewerRoot.getDirectoryContents("/");
237 } //end init()
238 
239 ViewerRoot.autoRefreshMatchArr = []; //use array to match request returns to index
240 
241 //=====================================================================================
242 // ViewerRoot.autoRefreshTick ~~
243 // handle autorefreshes
244 // Strategy:
245 // For each root object that is in refresh mode, push index,path to an array
246 // and send req. When req returns match path to array and remove entry.
247 // When array is empty auto refresh complete.
248 ViewerRoot.autoRefreshTick = function()
249 {
250  //Debug.log("ViewerRoot autoRefreshTick pause=" + ViewerRoot.pauseRefresh);
251  if(ViewerRoot.pauseRefresh) return;
252 
253  if(ViewerRoot.autoRefreshMatchArr.length) //not done yet with previous refresh!
254  {
255  Debug.log("ViewerRoot autoRefreshTick not done yet! Refresh period too short.");
256  ViewerRoot.autoRefreshPeriod += 500; //walk up more delay
257 
258  //reset interval if here
259  window.clearInterval(ViewerRoot.autoRefreshTimer);
260  ViewerRoot.autoRefreshTimer = window.setInterval(
261  ViewerRoot.autoRefreshTick,
262  ViewerRoot.autoRefreshPeriod);
263  return;
264  }
265 
266  ViewerRoot.autoRefreshMatchArr = []; //insert [<index>, <path>] tuples
267  for(var j=0;j<ViewerRoot.rootPosArr.length;++j)
268  if(ViewerRoot.rootIsAutoRefreshArr[j])
269  {
270  Debug.log("ViewerRoot autoRefreshTick " + j + " " + ViewerRoot.rootObjNameArr[j]);
271  ViewerRoot.autoRefreshMatchArr.push([j, ViewerRoot.rootObjNameArr[j]]);
272  ViewerRoot.rootReq(ViewerRoot.rootObjNameArr[j],j);
273  }
274 
275  //reset interval if here
276  window.clearInterval(ViewerRoot.autoRefreshTimer);
277  ViewerRoot.autoRefreshTimer = window.setInterval(
278  ViewerRoot.autoRefreshTick,
279  ViewerRoot.autoRefreshPeriod);
280 
281 } //end autoRefreshTick
282 
283 //=====================================================================================
284 // ViewerRoot.prepareNextLocation ~~
285 // Prepares next div location for root js library drawing
286 // based on RADIO: Tile, Replace, Superimpose. The div id
287 // will be "histogram"+ViewerRoot.objIndex.. this is the div
288 // the root js library will draw to.
289 ViewerRoot.prepareNextLocation = function(objName, objTitle)
290 {
291  Debug.log("ViewerRoot prepareNextLocation for ViewerRoot.objIndex " + "mode " + ViewerRoot.nextObjectMode +
292  ": " + ViewerRoot.objIndex + ": " + objName);
293 
294  //fix target just in case foul play occured
295  if(ViewerRoot.rootTargetIndex > ViewerRoot.numPositionsTiled) ViewerRoot.rootTargetIndex = -1;
296 
297  //create and add new div
298  var ri = ViewerRoot.rootElArr.length;
299  ViewerRoot.rootElArr.push(document.createElement('div')); //make container
300  ViewerRoot.rootElArr[ri].setAttribute("class","rootObjectContainer"); //set new report target
301 
302  var tmpdiv = document.createElement('div'); //make target div
303  tmpdiv.setAttribute("id","histogram"+ViewerRoot.objIndex); //set new target for root object
304  tmpdiv.setAttribute("class","rootObjectContainerTarget");
305  ViewerRoot.rootElArr[ri].appendChild(tmpdiv);
306 
307  //add report to report container
308  ViewerRoot.rootContainer.appendChild(ViewerRoot.rootElArr[ri]);
309 
310  var drawTransparently = false;
311  if(!ViewerRoot.numPositionsTiled || ViewerRoot.nextObjectMode == ViewerRoot.TILE_MODE)
312  {
313  //next tile position (or first tile)
314  ViewerRoot.rootPosArr.push(ViewerRoot.numPositionsTiled++);
315  }
316  else if(ViewerRoot.nextObjectMode == ViewerRoot.REPLACE_MODE)
317  {
318  //replace tile(s) at position ViewerRoot.rootTargetIndex, if -1 then replace last tile(s)
319  var repi = ViewerRoot.rootTargetIndex == -1? ViewerRoot.numPositionsTiled-1:ViewerRoot.rootTargetIndex;
320  ViewerRoot.removeAllAtPosition(repi); //remove all tiles that match repi
321 
322  ViewerRoot.rootPosArr.push(repi); //assign new report to position
323  }
324  else if(ViewerRoot.nextObjectMode == ViewerRoot.SUPERIMPOSE_MODE)
325  {
326  //add tile at position ViewerRoot.rootTargetIndex, if -1 then at last tile(s)
327  var supi = ViewerRoot.rootTargetIndex == -1? ViewerRoot.numPositionsTiled-1:ViewerRoot.rootTargetIndex;
328 
329  ViewerRoot.rootPosArr.push(supi); //assign new report to position
330  drawTransparently = true;
331  }
332 
333  ViewerRoot.rootIsTransparentArr.push(drawTransparently); //keep for transparent drawing
334  ViewerRoot.rootIsAutoRefreshArr.push(ViewerRoot.autoRefreshDefault);
335  ViewerRoot.rootObjNameArr.push(objName); //assign new report to position
336  ViewerRoot.rootObjTitleArr.push(objTitle);
337 
338  ViewerRoot.manageRootHeaders(); //manage headers for all positions
339  ViewerRoot.resizeRootObjects(true); //resize all root objects as a result of new element
340 }
341 
342 //=====================================================================================
343 // ViewerRoot.removeAllAtPosition ~~
344 // Remove all histogram div elements and associated root object data structures
345 // for the given position i.
346 // If isClosingPosition then redraw after and update tiled positions and renumber all above
347 // position i.
348 ViewerRoot.removeAllAtPosition = function(posi, isClosingPosition) {
349  Debug.log("ViewerRoot removeAllAtPosition " + posi);
350 
351  for(var i=0;i<ViewerRoot.rootPosArr.length;++i)
352  if(ViewerRoot.rootPosArr[i] == posi) //remove element
353  {
354  ViewerRoot.rootElArr[i].parentNode.removeChild(ViewerRoot.rootElArr[i]);
355  ViewerRoot.rootElArr.splice(i,1);
356  ViewerRoot.rootPosArr.splice(i,1);
357  delete ViewerRoot.rootObjArr[i]; ViewerRoot.rootObjArr[i] = null;
358  ViewerRoot.rootObjArr.splice(i,1);
359  ViewerRoot.rootObjIndexArr.splice(i,1);
360  ViewerRoot.rootObjNameArr.splice(i,1);
361  ViewerRoot.rootObjTitleArr.splice(i,1);
362  ViewerRoot.rootIsTransparentArr.splice(i,1);
363  ViewerRoot.rootIsAutoRefreshArr.splice(i,1);
364 
365  --i; //rewind
366  }
367  else if(isClosingPosition && ViewerRoot.rootPosArr[i] > posi) //renumber position
368  --ViewerRoot.rootPosArr[i];
369 
370  if(isClosingPosition)
371  {
372  --ViewerRoot.numPositionsTiled;
373  ViewerRoot.manageRootHeaders();
374  if(ViewerRoot.rootTargetIndex > posi) --ViewerRoot.rootTargetIndex;
375  else if(ViewerRoot.rootTargetIndex >= ViewerRoot.numPositionsTiled) ViewerRoot.rootTargetIndex = -1;
376  ViewerRoot.resizeRootObjects(true); //resize all root objects as a result of new element
377  }
378 }
379 
380 //=====================================================================================
381 // ViewerRoot.manageRootHeaders ~~
382 // handle adding/removing/drawing of root object headers
383 ViewerRoot.manageRootHeaders = function()
384 {
385  Debug.log("ViewerRoot manageRootHeaders");
386 
387  var tmpdiv;
388  while(ViewerRoot.numPositionsTiled > ViewerRoot.rootHeaderElArr.length) //add header elements
389  {
390  tmpdiv = document.createElement('div'); //make target div
391  tmpdiv.setAttribute("id","rootContainerHeader-"+ViewerRoot.rootHeaderElArr.length);
392  tmpdiv.setAttribute("class","rootContainerHeader");
393  tmpdiv.onmouseup = ViewerRoot.handleRootPositionSelect;
394  ViewerRoot.rootContainer.appendChild(tmpdiv);
395  ViewerRoot.rootHeaderElArr.push(tmpdiv);
396  }
397 
398  while(ViewerRoot.numPositionsTiled < ViewerRoot.rootHeaderElArr.length) //remove header elements
399  {
400  tmpdiv = ViewerRoot.rootHeaderElArr[ViewerRoot.rootHeaderElArr.length-1];
401  tmpdiv.parentNode.removeChild(tmpdiv);
402  ViewerRoot.rootHeaderElArr.splice(ViewerRoot.rootHeaderElArr.length-1,1);
403  }
404 
405  //give name to headers by position
406  var found;
407  var name, fullPath;
408  var str;
409  var isAtLeastOneRefreshing;
410  for(var i=0;i<ViewerRoot.rootHeaderElArr.length;++i)
411  {
412  found = 0;
413  isAtLeastOneRefreshing = false;
414  for(var j=0;j<ViewerRoot.rootPosArr.length;++j)
415  if(ViewerRoot.rootPosArr[j] == i) { ++found; fullPath = ViewerRoot.rootObjNameArr[j];
416  //name = (fullPath.length > 20)?("..." + fullPath.substr(fullPath.length-18)):fullPath;
417  name=ViewerRoot.rootObjTitleArr[j];
418  if(ViewerRoot.rootIsAutoRefreshArr[j]) isAtLeastOneRefreshing = true; //this root object is set to autorefresh
419  }
420 
421  str = "";
422 
423  //add title
424  str += "<div title='" + fullPath + "' class='rootContainerHeader-name'>" + (found == 1?name:"Multiple Files...") + "</div>";
425 
426  //add close button
427  str += "<a title='Close' href='Javascript:ViewerRoot.removeAllAtPosition("+i+",true);' onmouseup='event.cancelBubble=true;' " +
428  "class='rootContainerHeader-closeBtn'>X</a>";
429 
430  //add auto refresh icon
431  //if at least one root object is refreshing show icon as on
432 
433  //Below is original
434  str += "<a title='Close' href='Javascript:ViewerRoot.toggleAllAtPositionAutoRefresh(" + i +
435  ");' onmouseup='event.cancelBubble=true;' " +
436  "class='rootContainerHeader-refreshBtn'><img id='rootContainerHeaderRefreshImg" + i +
437  "'src='/WebPath/images/iconImages/icon-rootAutoRefresh" + (isAtLeastOneRefreshing?"On":"Off") + ".png'></a>";
438 
439 
440  //Making the refresh button do the same thing as respective histograph name
441 // str += "<a title='Refresh' href='Javascript:ViewerRoot.rootReq(\"" + fullPath +
442 // "\");' onmouseup='event.cancelBubble=true;' " +
443 // "class='rootContainerHeader-refreshBtn'><img id='rootContainerHeaderRefreshImg" + i +
444 // "'src='/WebPath/images/iconImages/icon-rootAutoRefresh" + (isAtLeastOneRefreshing?"On":"Off") + ".png'></a>";
445 //
446  ViewerRoot.rootHeaderElArr[i].innerHTML = str;
447  }
448 } //end manageRootHeaders()
449 
450 //=====================================================================================
451 // ViewerRoot.toggleAllAtPositionAutoRefresh ~~
452 // toggle auto refresh for position i
453 // Superimposed position is a special case
454 // if any of superimposed are true, then all should go false
455 // else all go true
456 ViewerRoot.toggleAllAtPositionAutoRefresh = function(i)
457 {
458  Debug.log("ViewerRoot toggleAllAtPositionAutoRefresh " + i);
459  var found = 0;
460  var v = true, lastv;
461  var doover = false;
462  do
463  {
464  for(var j=0;j<ViewerRoot.rootPosArr.length;++j)
465  if(ViewerRoot.rootPosArr[j] == i)
466  {
467  if(!doover && ViewerRoot.rootIsAutoRefreshArr[j]) v = false;
468  ViewerRoot.rootIsAutoRefreshArr[j] = v; //---------------------------------------->This is all this function does!
469 
470  Debug.log("ViewerRoot toggleAllAtPositionAutoRefresh rootObj " + j + " to " + v);
471 
472  var tmp = document.getElementById("rootContainerHeaderRefreshImg" + i );
473  tmp.src = "/WebPath/images/iconImages/icon-rootAutoRefresh" + (v?"On":"Off") + ".png";
474  if(lastv != v ){++found; lastv = v;}
475  }
476  if(!doover && found>1) doover = true;
477  else doover = false;
478  } while(doover) //may need to do it over again, because values of superimposed root objects could be wrong
479 
480 } //end toggleAllAtPositionAutoRefresh()
481 
482 //=====================================================================================
483 // ViewerRoot.handleRootPositionSelect ~~
484 ViewerRoot.handleRootPositionSelect = function(event)
485 {
486  event.cancelBubble = true;
487  var i = parseInt(this.id.substr(this.id.indexOf("-")+1))
488  Debug.log("ViewerRoot handleRootPositionSelect " + i);
489  ViewerRoot.rootTargetIndex = i;
490  ViewerRoot.resizeRootObjects();
491 } //end handleRootPositionSelect()
492 
493 //=====================================================================================
494 // ViewerRoot.clearAll ~~
495 // remove all root objects
496 ViewerRoot.clearAll = function()
497 {
498  Debug.log("ViewerRoot clearAll");
499 
500  ViewerRoot.rootTargetIndex = -1;
501  //ViewerRoot.numPositionsTiled will be 0 at end
502  for(ViewerRoot.numPositionsTiled; ViewerRoot.numPositionsTiled>0; --ViewerRoot.numPositionsTiled)
503  ViewerRoot.removeAllAtPosition(ViewerRoot.numPositionsTiled-1);
504  ViewerRoot.manageRootHeaders();
505  ViewerRoot.resizeRootObjects();
506 }
507 
508 //=====================================================================================
509 // ViewerRoot.handleWindowResize ~~
510 ViewerRoot.handleWindowResize = function() {
511 
512  var w = ViewerRoot.w = window.innerWidth < ViewerRoot.DISPLAY_MIN_WIDTH? ViewerRoot.DISPLAY_MIN_WIDTH:window.innerWidth;
513  var h = ViewerRoot.h = window.innerHeight < ViewerRoot.DISPLAY_MIN_HEIGHT? ViewerRoot.DISPLAY_MIN_HEIGHT:window.innerHeight;
514 
515  if(!ViewerRoot.hudAutoHide) //force w smaller
516  ViewerRoot.w = w -= ViewerRoot.HUD_WIDTH + ViewerRoot.HUD_MARGIN_RIGHT + (5*2); //5 is padding of mouseover region in css
517 
518  Debug.log("ViewerRoot handleWindowResize " + w + "-" + h);
519 
520  ViewerRoot.omni.style.width = w + "px";
521  ViewerRoot.omni.style.height = h + "px";
522 
523  ViewerRoot.hud.handleWindowResize();
524  ViewerRoot.resizeRootObjects(true);
525 }
526 
527 //=====================================================================================
528 // ViewerRoot.resizeRootObjects ~~
529 // Resize all root objects based on positions and tile arrangement
530 // if isForNewObject = true, then redraw all reports except last(new) report
531 // OLD: do not need to redraw for normal window resize, because obj's handler handles
532 // NEW: now on window resize the object is not redrawn.. the <svg class=root_canvas> size
533 // does not get updated.. So just redraw for normal window resize case.
534 ViewerRoot.resizeRootObjects = function(needToRedraw) {
535 
536  ViewerRoot.rootContainer.style.width = ViewerRoot.w + "px";
537  ViewerRoot.rootContainer.style.height = ViewerRoot.h + "px";
538 
539  if(ViewerRoot.numPositionsTiled < 1)
540  { //if no rootObjects, invisible container
541  ViewerRoot.rootContainer.style.backgroundColor = "rgba(0,0,0,0)";
542  return;
543  }
544  ViewerRoot.rootContainer.style.backgroundColor = "white";
545 
546 
547  var w = ViewerRoot.w;
548  var h = ViewerRoot.h - ViewerRoot.ROOT_CONTAINER_OFFY;
549 
550  var aspect = 3/4; //3/4, 9/16 , 1
551  var r = Math.round(Math.sqrt(h*ViewerRoot.numPositionsTiled/aspect/w)); //Math.ceil(Math.sqrt(ViewerRoot.numPositionsTiled));
552  if(r<1) r = 1;
553  var c = Math.ceil(ViewerRoot.numPositionsTiled/r);
554 
555  Debug.log("ViewerRoot resizeRootObjects " + r + "-" + c + " for " + ViewerRoot.numPositionsTiled);
556 
557  //calc individual position size
558  w = Math.floor(w/c);
559  h = Math.floor(h/r);
560 
561  Debug.log("ViewerRoot resizeRootObjects size " + w + "-" + h );
562 
563  //re-calc root object width based on aspect
564  var rootAspect = 3/4;
565  var rootw = h/w < rootAspect?h/rootAspect:w;
566 
567  //position all reports properly
568  for(var i=0;i<ViewerRoot.rootElArr.length;++i)
569  {
570  ViewerRoot.rootElArr[i].style.width = rootw + "px";
571  ViewerRoot.rootElArr[i].style.height = (h - ViewerRoot.ROOT_HEADER_HEIGHT) + "px";
572  ViewerRoot.rootElArr[i].style.left = w*(ViewerRoot.rootPosArr[i]%c) + (w-rootw)/2 + "px";
573  ViewerRoot.rootElArr[i].style.top = ViewerRoot.ROOT_CONTAINER_OFFY + ViewerRoot.ROOT_HEADER_HEIGHT +
574  h*Math.floor(ViewerRoot.rootPosArr[i]/c) + "px";
575 
576  // Debug.log("ViewerRoot resizeRootObjects x y " + i + " at pos " + ViewerRoot.rootPosArr[i] +
577  // ":" + ViewerRoot.rootElArr[i].style.left + "-" + ViewerRoot.rootElArr[i].style.top );
578 
579  if(needToRedraw && ViewerRoot.rootObjArr[i]) //redraw for new size, when new added rootobj not defined at this point
580  {
581  //Debug.log("ViewerRoot resizeRootObjects redraw " + i + "-" + ViewerRoot.rootObjIndexArr[i] );
582  //JSROOTPainter.drawObject(ViewerRoot.rootObjArr[i], ViewerRoot.rootObjIndexArr[i]);
583 
584  try
585  {
586  JSROOT.redraw('histogram'+
587  ViewerRoot.rootObjIndexArr[i],
588  ViewerRoot.rootObjArr[i], "colz"); //last arg, root draw option
589  }
590  catch(e)
591  {
592  Debug.log("ROOT Object type '" + ViewerRoot.rootObjArr[i]._typename +
593  "' failed to draw: " + e);//, Debug.HIGH_PRIORITY);
594  document.getElementById("histogram" +
595  ViewerRoot.rootObjIndexArr[i],).textContent =
596  ViewerRoot.rootObjArr[i].JSON;
597  //JSON.stringify(ViewerRoot.rootObjArr[i]); //fill with text
598  }
599  ViewerRoot.refreshTransparency(i);
600  }
601  }
602 
603  //position headers
604  for(var i=0;i<ViewerRoot.rootHeaderElArr.length;++i)
605  {
606  ViewerRoot.rootHeaderElArr[i].style.width = w-2 + "px";
607  ViewerRoot.rootHeaderElArr[i].style.height = ViewerRoot.ROOT_HEADER_HEIGHT + "px";
608  ViewerRoot.rootHeaderElArr[i].style.left = w*(i%c) + "px";
609  ViewerRoot.rootHeaderElArr[i].style.top = ViewerRoot.ROOT_CONTAINER_OFFY + h*Math.floor(i/c) + "px";
610 
611  ViewerRoot.rootHeaderElArr[i].style.borderColor =
612  ViewerRoot.rootTargetIndex==i?'rgb(68,156,44)':'black';
613  ViewerRoot.rootHeaderElArr[i].style.backgroundColor =
614  ViewerRoot.rootTargetIndex==i?'rgb(178,222,166)':'rgba(0,0,0,0)';
615  }
616 } //end resizeRootObjects()
617 
618 //=====================================================================================
619 // ViewerRoot.refreshTransparency ~~
620 // refresh the transparency state of histogram i and svg components
621 ViewerRoot.refreshTransparency = function(i) {
622  //if need be, make transparent
623  if(ViewerRoot.rootIsTransparentArr[i])
624  {
625  //Debug.log("superimpose draw " + i);
626  //histogram div bgColor
627  ViewerRoot.rootElArr[i].children[0].style.backgroundColor = "rgba(0,0,0,0)";
628  //svg bgColor
629  var svg = ViewerRoot.rootElArr[i].children[0].getElementsByTagName('svg')[0];
630  svg.style.backgroundColor = "rgba(0,0,0,0)";
631  //rect fill
632  if(svg.getElementsByTagName('rect')[0])
633  svg.getElementsByTagName('rect')[0].style.fill = "rgba(0,0,0,0)";
634 
635  //structure:
636  //<div id='histogram#'><svg><g>
637  //<rect x="0" y="0" width="461.48" height="281.70663849600004" fill="rgba(0,0,0,0)" style="stroke: #000000; stroke-width: 1px;"></rect>
638  //<svg>..root drawing..</svg>
639  //</g>
640  //</svg>
641  }
642 }
643 
644 //=====================================================================================
645 // ViewerRoot.checkStreamerInfoLoaded ~~
646 // periodically check to usee if the streamer info, giving information on root types has completely loaded
647 // this is a critical step before attempting to draw any root objects
648 ViewerRoot.checkStreamerInfoLoaded = function() {
649  if(ViewerRoot.sFile &&
650  ViewerRoot.sFile.fStreamerInfo &&
651  gFile.fStreamerInfo.fClassMap &&
652  gFile.fStreamerInfo.fClassMap.length > 0) //done
653  {
654  document.getElementById("loaderStatus").innerHTML = "Root Viewer Loaded.<br>Use drop-down to make selections.";
655  ViewerRoot.getDirectoryContents("/");
656  }
657  else //not done, wait longer
658  window.setTimeout(ViewerRoot.checkStreamerInfoLoaded,ViewerRoot.LOAD_STREAMER_INFO_CHECK_PERIOD);
659 }
660 
661 //=====================================================================================
662 // ViewerRoot.getDirectoryContents ~~
663 // request directory contents from server for path
664 ViewerRoot.getDirectoryContents = function(path) {
665 
666  Debug.log("ViewerRoot getDirectoryContents " + path);
667 
668  if(path.indexOf(".root/") >=0)
669  DesktopContent.XMLHttpRequest("Request?RequestType=getRoot", "RootPath="+path, ViewerRoot.getDirContentsHandler,
670  0 /*reqParam*/,
671  0 /*progressHandler*/,
672  0 /*callHandlerOnErr*/,
673  false /*doNoShowLoadingOverlay*/);
674  else
675  DesktopContent.XMLHttpRequest("Request?RequestType=getDirectoryContents", "Path="+path, ViewerRoot.getDirContentsHandler,
676  0 /*reqParam*/,
677  0 /*progressHandler*/,
678  0 /*callHandlerOnErr*/,
679  true /*doNoShowLoadingOverlay*/);
680 }
681 
682 //=====================================================================================
683 // ViewerRoot.getDirContentsHandler ~~
684 ViewerRoot.getDirContentsHandler = function(req) {
685  Debug.log("ViewerRoot getDirContentsHandler " + req.responseText);
686 
687  var permissions = DesktopContent.getXMLValue(req,'permissions');
688  if(!permissions)
689  Debug.log("ViewerRoot getDirContentsHandler permissions missing");
690  else if(ViewerRoot.userPermissions != permissions)
691  {
692  Debug.log("ViewerRoot getDirContentsHandler user permissions = " + permissions);
693  ViewerRoot.userPermissions = permissions;
694  ViewerRoot.hud.handleWindowResize();
695  }
696 
697  ViewerRoot.hud.handleDirContents(req);
698 }
699 
700 //=====================================================================================
701 // ViewerRoot.rootReq ~~
702 // if refreshIndex, then request is meant to replace root object at index
703 ViewerRoot.rootReq = function(rootPath,refreshIndex) {
704 
705  if(refreshIndex === undefined) refreshIndex = -1;
706 
707  Debug.log("ViewerRoot.rootReq " + rootPath );
708  DesktopContent.XMLHttpRequest("Request?RequestType=getRoot",
709  "RootPath="+rootPath,
710  ViewerRoot.getRootDataHandler,
711  refreshIndex /*reqParam*/,
712  0 /*progressHandler*/,
713  0 /*callHandlerOnErr*/,
714  refreshIndex<0?false:true /*doNoShowLoadingOverlay*/);
715 } //end rootReq()
716 
717 //=====================================================================================
718 //ViewerRoot.rootConfigReq ~~
719 ViewerRoot.rootConfigReq = function(rootConfigPath)
720 {
721  //Debug.log("ViewerRoot.rootReq");
722  DesktopContent.XMLHttpRequest("Request?RequestType=getRootConfig",
723  "RootConfigPath="+rootConfigPath,
724  ViewerRoot.getRootConfigHandler,
725  0 /*reqParam*/,
726  0 /*progressHandler*/,
727  0 /*callHandlerOnErr*/,
728  true /*doNoShowLoadingOverlay*/);
729 } //end rootConfigReq()
730 
731 //=====================================================================================
732 //ViewerRoot.getRootConfigHandler ~~
733 // receives saved configuration and rebuilds the view based on the configuration
734 ViewerRoot.getRootConfigHandler = function(req)
735 {
736  Debug.log("ViewerRoot getRootConfigHandler " + req.responseText );
737 
738  var status = DesktopContent.getXMLValue(req,"status");
739  if(status != "1")
740  { alert("Loading Root Pre-Made Configuration Failed: " + status); return }
741 
742  ViewerRoot.iterNumPositionsTiled = DesktopContent.getXMLValue(req,"numPositionsTiled");
743  ViewerRoot.iterRunWildcard = DesktopContent.getXMLValue(req,"runNumWildcard"); //TODO replace obj names with current run number!
744 
745  //copy NodeList to just normal arrays
746 
747  var tmp = req.responseXML.getElementsByTagName("rootObjName");
748  ViewerRoot.iterRootObjNameArr = [];
749  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootObjNameArr[i] = tmp[i].getAttribute("value");
750 
751  tmp = req.responseXML.getElementsByTagName("rootPos");
752  ViewerRoot.iterRootPosArr = [];
753  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootPosArr[i] = tmp[i].getAttribute("value") | 0; //parse as int
754 
755  tmp = req.responseXML.getElementsByTagName("rootIsTransparent");
756  ViewerRoot.iterRootIsTransparentArr = [];
757  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootIsTransparentArr[i] = tmp[i].getAttribute("value") | 0; //parse as int
758 
759  tmp = req.responseXML.getElementsByTagName("rootIsAutoRefresh");
760  ViewerRoot.iterRootIsAutoRefreshArr = [];
761  for(var i=0;i<tmp.length;++i) ViewerRoot.iterRootIsAutoRefreshArr[i] = tmp[i].getAttribute("value") | 0; //parse as int
762 
763  ViewerRoot.clearAll();
764 
765  ViewerRoot.iterLoading = true;
766  ViewerRoot.iterNumberRemaining = ViewerRoot.iterRootObjNameArr.length;
767  ViewerRoot.iterSaveNextObjectMode = ViewerRoot.nextObjectMode;
768  ViewerRoot.iterSaveAutoRefreshDefault = ViewerRoot.autoRefreshDefault;
769 
770  ViewerRoot.iterativeConfigLoader();
771 } //end getRootConfigHandler()
772 
773 //=====================================================================================
774 //ViewerRoot.iterativeConfigLoader ~~
775 // goes through every iterRootObj and loads sequentially to display
776 ViewerRoot.iterativeConfigLoader = function() {
777  //Debug.log("ViewerRoot iterativeConfigLoader " + ViewerRoot.iterNumberRemaining);
778  if(!ViewerRoot.iterNumberRemaining) //done
779  {
780  ViewerRoot.autoRefreshDefault = ViewerRoot.iterSaveAutoRefreshDefault;
781  ViewerRoot.nextObjectMode = ViewerRoot.iterSaveNextObjectMode;
782  ViewerRoot.iterLoading = false;
783  return;
784  }
785 
786  --ViewerRoot.iterNumberRemaining;
787 
788  //next is always the lowest position left
789  var min = -1;
790  for(var i=0;i<ViewerRoot.iterRootPosArr.length;++i)
791  if(min == -1 || ViewerRoot.iterRootPosArr[i] < ViewerRoot.iterRootPosArr[min]) min = i;
792 
793  ViewerRoot.nextObjectMode = ViewerRoot.iterRootIsTransparentArr[min]?ViewerRoot.SUPERIMPOSE_MODE:ViewerRoot.TILE_MODE;
794  ViewerRoot.autoRefreshDefault = ViewerRoot.iterRootIsAutoRefreshArr[min];
795 
796  ViewerRoot.rootReq(ViewerRoot.iterRootObjNameArr[min]);
797 
798  //remove from iter array
799  ViewerRoot.iterRootObjNameArr.splice(min,1);
800  ViewerRoot.iterRootPosArr.splice(min,1);
801  ViewerRoot.iterRootIsTransparentArr.splice(min,1);
802  ViewerRoot.iterRootIsAutoRefreshArr.splice(min,1);
803 
804 } //end iterativeConfigLoader()
805 
806 
807 //=====================================================================================
808 // ViewerRoot.getRootDataHandler ~~
809 // receives streamed root object from server and prepares it for js structures
810 ViewerRoot.getRootDataHandler = function(req, refreshIndex)
811 {
812 
813  //Debug.log("ViewerRoot getRootDataHandler " + req.responseText );
814 
815  var rootType = DesktopContent.getXMLValue(req,"rootType");
816  var rootStr = DesktopContent.getXMLValue(req,"rootData");
817  var rootName = DesktopContent.getXMLValue(req,"path");//
818  //"my" + rootType + ViewerRoot.objIndex;// DesktopContent.getXMLValue(req,"path");// + ViewerRoot.objIndex;
819  //if(rootName.length > 20) rootName = "..." + rootName.substr(rootName.length-18);
820 
821  var rootJSON = DesktopContent.getXMLValue(req,"rootJSON");
822 
823  //Debug.log("ViewerRoot tmpRootDataHandler JSON \n\n" + rootJSON );
824 
825  var object = JSROOT.parse(rootJSON);
826 
827  if(!object || !rootType || !rootName)
828  {
829  Debug.log("Pausing auto-refresh! \n\nPlease resolve the errors before resuming refreshes.", Debug.HIGH_PRIORITY);
830 
831  var chk = document.getElementById("hudCheckbox" + 2); //pause refresh checkbox
832  chk.checked = true;
833  ViewerRoot.pauseRefresh = true;
834 
835  Debug.log("Error reading Root object from server - Name: " + rootName, Debug.HIGH_PRIORITY);
836  ViewerRoot.autoRefreshMatchArr = []; //clearing the array so that future refreshes work
837  return;
838  }
839 
840  var rootTitle = object.fTitle;
841  object.JSON = rootJSON;
842 
843  if(refreshIndex === undefined) refreshIndex = -1;
844 
845  if(ViewerRoot.autoRefreshMatchArr.length &&
846  refreshIndex >= 0) //check if request matches auto refresh entry
847  {
848  for(var i=0;i<ViewerRoot.autoRefreshMatchArr.length;++i)
849  {
850  if(refreshIndex == ViewerRoot.autoRefreshMatchArr[i][0])
851  {
852  Debug.log("ViewerRoot handling refresh " +
853  refreshIndex + " " + rootName);
854 
855  //since handled, remove from auto refresh array
856  ViewerRoot.autoRefreshMatchArr[i] = 0;
857  ViewerRoot.autoRefreshMatchArr.splice(i,1);
858 
859  //if name in js structures has changed,
860  // assume it is users fault and throw out this refreshed object
861  if(refreshIndex >= ViewerRoot.rootObjNameArr.length ||
862  ViewerRoot.rootObjNameArr[refreshIndex] != rootName)
863  {
864  Debug.log("ViewerRoot getRootDataHandler weird unmatch!?#$@%");
865  return; //throw out object, since incomplete match
866  }
867 
868  if(ViewerRoot.autoRefreshMatchArr.length == 0)
869  {
870  //reset interval if, all requests handled now
871  window.clearInterval(ViewerRoot.autoRefreshTimer);
872  ViewerRoot.autoRefreshTimer = window.setInterval(
873  ViewerRoot.autoRefreshTick,
874  ViewerRoot.autoRefreshPeriod);
875  }
876 
877  break;
878  }
879  }
880  //if not found, assume it is a new object
881  }
882 
883  console.log("refreshIndex=" + refreshIndex +
884  " ViewerRoot.rootTargetIndex=" + ViewerRoot.rootTargetIndex);
885 
886  if(refreshIndex < 0) ViewerRoot.prepareNextLocation(rootName, rootTitle);
887  else
888  {
889  //refreshIndex is the location to target
890  //prepare a new location as though it is replace with auto-refresh on
891  //
892  // e.g.
893  // globalset = replace/on
894  // ViewerRoot.prepareNextLocation(rootName);
895  // globalset = gui settings
896 
897  // tmpHLI = HIGHLIGHT_INDEX;
898  // HIGHLIGHT_INDEX = refreshIndex
899  //refreshIndex = -1;
900  // do it
901  // HIGHLIGHT_INDEX = tmpHLI;
902 
903 
904 
905 // var tmpRootTargetIndex = ViewerRoot.rootTargetIndex;
906 // ViewerRoot.rootTargetIndex = refreshIndex;
907 //
908 // var tmpRefreshIndex = refreshIndex;
909 // refreshIndex = -1;
910 //
911 // var tmpNextObjectMode = ViewerRoot.nextObjectMode;
912 // var tmpAutoRefreshDefault = ViewerRoot.autoRefreshDefault;
913 //
914 // ViewerRoot.nextObjectMode = ViewerRoot.REPLACE_MODE;
915 // ViewerRoot.autoRefreshDefault = true;
916 //
917 //
918 // ViewerRoot.prepareNextLocation(rootName);
919 //
920 //
921 // ViewerRoot.rootTargetIndex = tmpRootTargetIndex;
922 // ViewerRoot.nextObjectMode = tmpNextObjectMode;
923 // ViewerRoot.autoRefreshDefault = tmpAutoRefreshDefault;
924  }
925 
926  ViewerRoot.interpretObjectJSON(object,rootType,rootName,refreshIndex);
927  if(ViewerRoot.iterLoading) ViewerRoot.iterativeConfigLoader();
928 } //end getRootDataHandler()
929 
930 
931 //=====================================================================================
932 // ViewerRoot.interpretObjectJSON ~~
933 // interpret and draw
934 ViewerRoot.interpretObjectJSON = function(object,rootType,objName,refreshIndex)
935 {
936 
937  if(refreshIndex == undefined) refreshIndex = -1;
938 
939 
940  if(ViewerRoot.hardRefresh) //"Hard" refresh, reloads axes for example
941  {
942  if(refreshIndex < 0)
943  {
944  ViewerRoot.rootObjArr.push(object);
945  ViewerRoot.rootObjIndexArr.push(ViewerRoot.objIndex);
946  }
947  else //use refresh index
948  {
949  delete ViewerRoot.rootObjArr[refreshIndex]; ViewerRoot.rootObjArr[refreshIndex] = null;
950  ViewerRoot.rootObjArr[refreshIndex] = object;
951  ViewerRoot.rootObjTitleArr[refreshIndex] = object.fTitle;
952  ViewerRoot.rootObjIndexArr[refreshIndex] = ViewerRoot.objIndex;
953 
954 
955  ViewerRoot.rootElArr[refreshIndex].innerHTML = ""; //cleare rootObjectContainer
956  var tmpdiv = document.createElement('div'); //make target div
957  tmpdiv.setAttribute("id","histogram"+ViewerRoot.objIndex); //set new target for root object
958  tmpdiv.setAttribute("class","rootObjectContainerTarget");
959  ViewerRoot.rootElArr[refreshIndex].appendChild(tmpdiv);
960  }
961 
962  //draw based on refresh index
963  var targetEl = document.getElementById("histogram" + ViewerRoot.objIndex);
964  try
965  {
966 
967  if(rootType == "JSON")
968  throw "Doing JSON only";
969 
970  var isFirstTime = targetEl.innerHTML == ""; //if empty, assume it is first time
971  JSROOT.redraw('histogram'+
972  (ViewerRoot.objIndex),
973  object, "colz"); //last arg, root draw option
974 
975  if(isFirstTime) //try again, to see if there are errors (because async causes craziness)
976  {
977  if(targetEl.innerHTML == "")
978  {
979  Debug.log("Empty first time handling!");
980 
981  //==============
982  function localMakeAsyncCheckerFunction(obji, type, obj)
983  {
984  Debug.log("Async Empty first time handling for histogram" +
985  obji + " type=" + type);
986  //return a function, so that the constants are stable
987  return function()
988  {
989  Debug.log("Async Empty first time handling for histogram" +
990  obji);
991  if(targetEl.innerHTML != "")
992  {
993  Debug.log("histogram" +
994  obji + " is OK, must have just taken a while");
995  return;
996  }
997 
998  try
999  {
1000  JSROOT.redraw("histogram" +
1001  obji,
1002  obj, "colz"); //last arg, root draw option
1003  }
1004  catch(e)
1005  {
1006  Debug.log("ROOT Object type '" + type +
1007  "' failed to draw histogram" +
1008  obji + ": " + e);//, Debug.HIGH_PRIORITY);
1009  targetEl.textContent = obj.JSON;//JSON.stringify(object); //fill with text
1010  }
1011  }
1012  } //end localMakeAsyncCheckerFunction()
1013 
1014  window.setTimeout(localMakeAsyncCheckerFunction(
1015  ViewerRoot.objIndex,
1016  object._typename,
1017  object),
1018  500/*ms*/); //end asynch 2nd try
1019 
1020  } //end empty first time handling
1021  } //end special first time handling
1022  }
1023  catch(e)
1024  {
1025  Debug.log("ROOT Object type '" + object._typename +
1026  "' failed to draw: " + e);//, Debug.HIGH_PRIORITY);
1027  targetEl.textContent = object.JSON;// JSON.stringify(object); //fill with text
1028  }
1029 
1030  ViewerRoot.objIndex++;
1031  }
1032  else //"Soft" refresh, doesn't reload axes for example
1033  {
1034  //draw based on refresh index
1035  try
1036  {
1037  JSROOT.redraw('histogram'+
1038  (refreshIndex<0?ViewerRoot.objIndex:
1039  ViewerRoot.rootObjIndexArr[refreshIndex]),
1040  object, "colz"); //last arg, root draw option
1041  }
1042  catch(e)
1043  {
1044  Debug.log("ROOT Object type '" + object._typename +
1045  "' failed to draw: " + e, Debug.HIGH_PRIORITY);
1046  }
1047 
1048  if(refreshIndex < 0)
1049  {
1050  ViewerRoot.rootObjArr.push(object);
1051  ViewerRoot.rootObjIndexArr.push(ViewerRoot.objIndex);
1052  ViewerRoot.objIndex++;
1053  }
1054  else //use refresh index
1055  {
1056  delete ViewerRoot.rootObjArr[refreshIndex]; ViewerRoot.rootObjArr[refreshIndex] = null;
1057  ViewerRoot.rootObjArr[refreshIndex] = object;
1058  ViewerRoot.rootObjTitleArr[refreshIndex] = object.fTitle;
1059  }
1060  }
1061 
1062  ViewerRoot.refreshTransparency(refreshIndex<0?(ViewerRoot.rootObjArr.length-1):refreshIndex);
1063  ViewerRoot.manageRootHeaders(); //manage headers for all positions
1064 
1065 } //end interpretObjectJSON()
1066 
1067 //=====================================================================================
1068 function loadScript(url, callback)
1069 {
1070  // dynamic script loader using callback
1071  // (as loading scripts may be asynchronous)
1072  var script = document.createElement("script")
1073  script.type = "text/javascript";
1074  if (script.readyState) { // Internet Explorer specific
1075  script.onreadystatechange = function() {
1076  if (script.readyState == "loaded" ||
1077  script.readyState == "complete") {
1078  script.onreadystatechange = null;
1079  callback();
1080  }
1081  };
1082  } else { // Other browsers
1083  script.onload = function(){
1084  callback();
1085  };
1086  }
1087  var rnd = Math.floor(Math.random()*80000);
1088  script.src = url;//+ "?r=" + rnd;
1089  document.getElementsByTagName("head")[0].appendChild(script);
1090 } //end loadScript()