Merge branch 'collectd-5.8'
[collectd.git] / contrib / php-collection / browser.js
1 /*
2  * Copyright (C) 2009  Bruno PrĂ©mont <bonbons AT linux-vserver.org>
3  *
4  * This program is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free Software
6  * Foundation; only version 2 of the License is applicable.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
11  * details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16  */
17
18 // Toggle visibility of a div
19 function toggleDiv(divID) {
20         var div   = document.getElementById(divID);
21         var label = document.getElementById(divID+'_sw');
22         var label_txt = null;
23         if (div) {
24                 if (div.style.display == 'none') {
25                         div.style.display = 'block';
26                         label_txt = 'Hide';
27                 } else {
28                         div.style.display = 'none';
29                         label_txt = 'Show';
30                 }
31         }
32         if (label_txt && label) {
33                 var childCnt = label.childNodes.length;
34                 while (childCnt > 0)
35                         label.removeChild(label.childNodes[--childCnt]);
36                 label.appendChild(document.createTextNode(label_txt));
37         }
38         GraphPositionToolbox(null);
39 }
40
41 var req = null;
42
43 // DHTML helper code to asynchronous loading of content
44 function loadXMLDoc(url, query) {
45         if (window.XMLHttpRequest) {
46                 req = new XMLHttpRequest();
47                 req.onreadystatechange = processReqChange;
48                 req.open('POST', url, true);
49                 req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 
50                 req.send(query);
51         } else if (window.ActiveXObject) {
52                 req = new ActiveXObject("Microsoft.XMLHTTP");
53                 if (req) {
54                         req.onreadystatechange = processReqChange;
55                         req.open('POST', url, true);
56                         req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); 
57                         req.send(query);
58                 }
59         }
60 }
61
62 // DHTML new-content dispatcher
63 function processReqChange(evt) {
64         if (req.readyState == 4) {
65                 if (req.status == 200) {
66                         var response = req.responseXML.documentElement;
67                         var method = response.getElementsByTagName('method')[0].firstChild.data;
68                         var result = response.getElementsByTagName('result')[0];
69                         req = null;
70                         eval(method + '(result)');
71                 }
72         }
73 }
74
75 // Update contents of a <select> drop-down list
76 function refillSelect(options, select) {
77         if (!select)
78                 return -1;
79
80         var childCnt = select.childNodes.length;
81         var oldValue = select.selectedIndex > 0 ? select.options[select.selectedIndex].value : '/';
82         while (childCnt > 0)
83                 select.removeChild(select.childNodes[--childCnt]);
84
85         var optCnt = options ? options.length : 0;
86         if (optCnt == 0) {
87                 select.setAttribute('disabled', 'disabled');
88                 return -1;
89         } else {
90                 select.removeAttribute('disabled');
91                 var keepSelection = false;
92                 if (optCnt == 1) {
93                         keepSelection = true;
94                         oldValue = options[0].firstChild ? options[0].firstChild.data : '';
95                 } else if (oldValue != '/') {
96                         for (i = 0; i < optCnt && !keepSelection; i++)
97                                 if (oldValue == (options[i].firstChild ? options[i].firstChild.data : ''))
98                                         keepSelection = true;
99                 }
100                 newOption = document.createElement("option");
101                 newOption.value = '/';
102                 if (keepSelection)
103                         newOption.setAttribute('disabled', 'disabled');
104                 else
105                         newOption.setAttribute('selected', 'selected');
106                 newOption.setAttribute('style', 'font-style: italic');
107                 newOption.appendChild(document.createTextNode('- please select -'));
108                 select.appendChild(newOption);
109                 for (i = 0; i < optCnt; i++) {
110                         newOption = document.createElement("option");
111                         newOption.value = options[i].firstChild ? options[i].firstChild.data : '';
112                         if (keepSelection && newOption.value == oldValue)
113                                 newOption.setAttribute('selected', 'selected');
114                         if (newOption.value[0] == '@') {
115                                 newOption.setAttribute('style', 'font-style: italic');
116                                 if (newOption.value == '@' || newOption.value == '@merge')
117                                         newOption.appendChild(document.createTextNode('Meta graph'));
118                                 else if (newOption.value == '@all')
119                                         newOption.appendChild(document.createTextNode('All entries'));
120                                 else if (newOption.value == '@merge_sum')
121                                         newOption.appendChild(document.createTextNode('Meta summed graph'));
122                                 else if (newOption.value == '@merge_avg')
123                                         newOption.appendChild(document.createTextNode('Meta averaged graph'));
124                                 else if (newOption.value == '@merge_stack')
125                                         newOption.appendChild(document.createTextNode('Meta stacked graph'));
126                                 else if (newOption.value == '@merge_line')
127                                         newOption.appendChild(document.createTextNode('Meta lines graph'));
128                                 else
129                                         newOption.appendChild(document.createTextNode(newOption.value));
130                         } else
131                                 newOption.appendChild(document.createTextNode(newOption.value));
132                         select.appendChild(newOption);
133                 }
134                 return keepSelection ? select.selectedIndex : -1;
135         }
136 }
137
138 // Request refresh of host list
139 function ListRefreshHost() {
140         var query = 'action=list_hosts';
141         loadXMLDoc(dhtml_url, query);
142 }
143
144 // Handle update to host list
145 function ListOfHost(response) {
146         var select = document.getElementById('host_list');
147         var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
148         if (idx > 0) {
149                 ListRefreshPlugin();
150         } else
151                 ListOfPlugin(null);
152 }
153
154 // Request refresh of plugin list
155 function ListRefreshPlugin() {
156         var host_list = document.getElementById('host_list');
157         var host      = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
158         if (host != '/') {
159                 var query = 'action=list_plugins&host='+encodeURIComponent(host);
160                 loadXMLDoc(dhtml_url, query);
161         } else {
162                 ListOfPlugin(null);
163         }
164 }
165
166 // Handle update to plugin list
167 function ListOfPlugin(response) {
168         var select = document.getElementById('plugin_list');
169         var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
170         if (idx > 0) {
171                 ListRefreshPluginInstance();
172         } else
173                 ListOfPluginInstance(null);
174 }
175
176 // Request refresh of plugin instance list
177 function ListRefreshPluginInstance() {
178         var host_list   = document.getElementById('host_list');
179         var host        = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
180         var plugin_list = document.getElementById('plugin_list');
181         var plugin      = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
182         if (host != '/' && plugin != '/') {
183                 var query = 'action=list_pinsts&host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin);
184                 loadXMLDoc(dhtml_url, query);
185         } else {
186                 ListOfPluginInstance(null);
187         }
188 }
189
190 // Handle update of plugin instance list
191 function ListOfPluginInstance(response) {
192         var select = document.getElementById('pinst_list');
193         var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
194         if (idx > 0) {
195                 ListRefreshType();
196         } else
197                 ListOfType(null);
198 }
199
200 // Request refresh of type list
201 function ListRefreshType() {
202         var host_list   = document.getElementById('host_list');
203         var host        = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
204         var plugin_list = document.getElementById('plugin_list');
205         var plugin      = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
206         var pinst_list  = document.getElementById('pinst_list');
207         var pinst       = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
208         if (host != '/' && plugin != '/' && pinst != '/') {
209                 var query = 'action=list_types&host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst);
210                 loadXMLDoc(dhtml_url, query);
211         } else {
212                 ListOfType(null);
213         }
214 }
215
216 // Handle update of type list
217 function ListOfType(response) {
218         var select = document.getElementById('type_list');
219         var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
220         if (idx > 0) {
221                 ListRefreshTypeInstance();
222         } else
223                 ListOfTypeInstance(null);
224 }
225
226 // Request refresh of type instance list
227 function ListRefreshTypeInstance() {
228         var host_list   = document.getElementById('host_list');
229         var host        = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
230         var plugin_list = document.getElementById('plugin_list');
231         var plugin      = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
232         var pinst_list  = document.getElementById('pinst_list');
233         var pinst       = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
234         var type_list   = document.getElementById('type_list');
235         var type        = type_list.selectedIndex >= 0 ? type_list.options[type_list.selectedIndex].value : '/';
236         if (host != '/' && plugin != '/' && pinst != '/' && type != '/') {
237                 var query = 'action=list_tinsts&host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst)+'&type='+encodeURIComponent(type);
238                 loadXMLDoc(dhtml_url, query);
239         } else {
240                 ListOfTypeInstance(null);
241         }
242 }
243
244 // Handle update of type instance list
245 function ListOfTypeInstance(response) {
246         var select = document.getElementById('tinst_list');
247         var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
248         if (idx > 0) {
249                 // Enable add button
250                 RefreshButtons();
251         } else {
252                 // Disable add button
253                 RefreshButtons();
254         }
255 }
256
257 function RefreshButtons() {
258         var host_list   = document.getElementById('host_list');
259         var host        = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
260         var plugin_list = document.getElementById('plugin_list');
261         var plugin      = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
262         var pinst_list  = document.getElementById('pinst_list');
263         var pinst       = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
264         var type_list   = document.getElementById('type_list');
265         var type        = type_list.selectedIndex >= 0 ? type_list.options[type_list.selectedIndex].value : '/';
266         var tinst_list  = document.getElementById('tinst_list');
267         var tinst       = tinst_list.selectedIndex >= 0 ? tinst_list.options[tinst_list.selectedIndex].value : '/';
268         if (host != '/' && plugin != '/' && pinst != '/' && type != '/' && tinst != '/') {
269                 document.getElementById('btnAdd').removeAttribute('disabled');
270         } else {
271                 document.getElementById('btnAdd').setAttribute('disabled', 'disabled');
272         }
273
274         var graphs = document.getElementById('graphs');
275         if (graphs.getElementsByTagName('div').length > 1) {
276                 document.getElementById('btnClear').removeAttribute('disabled');
277                 document.getElementById('btnRefresh').removeAttribute('disabled');
278         } else {
279                 document.getElementById('btnClear').setAttribute('disabled', 'disabled');
280                 document.getElementById('btnRefresh').setAttribute('disabled', 'disabled');
281         }
282 }
283
284 var nextGraphId = 1;
285 var graphList = new Array();
286
287 function GraphAppend() {
288         var host_list   = document.getElementById('host_list');
289         var host        = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
290         var plugin_list = document.getElementById('plugin_list');
291         var plugin      = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
292         var pinst_list  = document.getElementById('pinst_list');
293         var pinst       = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
294         var type_list   = document.getElementById('type_list');
295         var type        = type_list.selectedIndex >= 0 ? type_list.options[type_list.selectedIndex].value : '/';
296         var tinst_list  = document.getElementById('tinst_list');
297         var tinst       = tinst_list.selectedIndex >= 0 ? tinst_list.options[tinst_list.selectedIndex].value : '/';
298         var time_list   = document.getElementById('timespan');
299         var timespan    = time_list.selectedIndex >= 0 ? time_list.options[time_list.selectedIndex].value : '';
300         var tinyLegend  = document.getElementById('tinylegend').checked;
301         var logarithmic = document.getElementById('logarithmic').checked;
302         if (host[0] == '@' || plugin[0] == '@' || pinst[0] == '@' || type[0] == '@' || (tinst[0] == '@' && tinst.substr(0, 5) != '@merge')) {
303                 var query = 'action=list_graphs&host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst);
304                 query = query+'&type='+encodeURIComponent(type)+'&type_instance='+encodeURIComponent(tinst)+'&timespan='+encodeURIComponent(timespan);
305                 query = query+(logarithmic ? '&logarithmic=1' : '')+(tinyLegend ? '&tinylegend=1' : '');
306                 loadXMLDoc(dhtml_url, query);
307         } else
308                 GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic);
309 }
310
311 function ListOfGraph(response) {
312         var graphs = response ? response.getElementsByTagName('graph') : null;
313         if (graphs && graphs.length > 0) {
314                 for (i = 0; i < graphs.length; i++)
315                         GraphDoAppend(graphs[i].getAttribute('host'), graphs[i].getAttribute('plugin'), graphs[i].getAttribute('plugin_instance'),
316                                       graphs[i].getAttribute('type'), graphs[i].getAttribute('type_instance'), graphs[i].getAttribute('timespan'),
317                                       graphs[i].getAttribute('tinyLegend') == '1', graphs[i].getAttribute('logarithmic') == '1');
318         } else
319                 alert('No graph found for adding');
320 }
321
322 function GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic) {
323         var graphs      = document.getElementById('graphs');
324
325         if (host != '/' && plugin != '/' && pinst != '/' && type != '/') {
326                 var graph_id   = 'graph_'+nextGraphId++;
327                 var graph_src  = graph_url+'?host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst)+'&type='+encodeURIComponent(type);
328                 var graph_alt  = '';
329                 var grap_title = '';
330                 if (tinst == '@') {
331                         graph_alt   = host+'/'+plugin+(pinst.length > 0 ? '-'+pinst : '')+'/'+type;
332                         graph_title = type+' of '+plugin+(pinst.length > 0 ? '-'+pinst : '')+' plugin for '+host;
333                 } else {
334                         graph_alt   = host+'/'+plugin+(pinst.length > 0 ? '-'+pinst : '')+'/'+type+(tinst.length > 0 ? '-'+tinst : '');
335                         graph_title = type+(tinst.length > 0 ? '-'+tinst : '')+' of '+plugin+(pinst.length > 0 ? '-'+pinst : '')+' plugin for '+host;
336                         graph_src  += '&type_instance='+encodeURIComponent(tinst);
337                 }
338                 if (logarithmic)
339                         graph_src += '&logarithmic=1';
340                 if (tinyLegend)
341                         graph_src += '&tinylegend=1';
342                 if (timespan)
343                         graph_src += '&timespan='+encodeURIComponent(timespan);
344                 var now    = new Date();
345                 graph_src += '&ts='+now.getTime();
346                 graphList.push(graph_id+' '+encodeURIComponent(graph_alt)+(logarithmic ? '&logarithmic=1' : '')+(tinyLegend ? '&tinylegend=1' : '')+'&timespan='+encodeURIComponent(timespan));
347
348                 // Graph container
349                 newGraph = document.createElement('div');
350                 newGraph.setAttribute('class', 'graph');
351                 newGraph.setAttribute('id', graph_id);
352                 // Graph cell + graph
353                 newImg = document.createElement('img');
354                 newImg.setAttribute('src', graph_src);
355                 newImg.setAttribute('alt', graph_alt);
356                 newImg.setAttribute('title', graph_title);
357                 newImg.setAttribute('onclick', 'GraphToggleTools("'+graph_id+'")');
358                 newGraph.appendChild(newImg);
359                 graphs.appendChild(newGraph);
360         }
361         document.getElementById('nograph').style.display = 'none';
362         RefreshButtons();
363 }
364
365 function GraphDropAll() {
366         var graphs = document.getElementById('graphs');
367         var childCnt = graphs.childNodes.length;
368         while (childCnt > 0)
369                 if (graphs.childNodes[--childCnt].id != 'nograph' && (graphs.childNodes[childCnt].nodeName == 'div' || graphs.childNodes[childCnt].nodeName == 'DIV'))
370                         graphs.removeChild(graphs.childNodes[childCnt]);
371                 else if (graphs.childNodes[childCnt].id == 'nograph')
372                         graphs.childNodes[childCnt].style.display = 'block';
373         graphList = new Array();
374         RefreshButtons();
375 }
376
377 function GraphToggleTools(graph) {
378         var graphId = document.getElementById('ge_graphid').value;
379         var ref_img = null;
380         if (graphId == graph || graph == '') {
381                 ref_img = null;
382         } else {
383                 var graphDiv = document.getElementById(graph);
384                 var imgs     = graphDiv ? graphDiv.getElementsByTagName('img') : null;
385                 var imgCnt   = imgs ? imgs.length : 0;
386                 while (imgCnt > 0)
387                         if (imgs[--imgCnt].parentNode.getAttribute('class') == 'graph')
388                                 ref_img = imgs[imgCnt];
389         }
390         if (ref_img) {
391                 var ts_sel  =  document.getElementById('ge_timespan');
392                 var src_url = ref_img.src;
393                 var ge      = document.getElementById('ge');
394                 // Fix field values
395                 var ts = src_url.match(/&timespan=[^&]*/);
396                 ts = ts ? ts[0].substr(10) : '';
397                 document.getElementById('ge_graphid').value = graph;
398                 document.getElementById('ge_tinylegend').checked = src_url.match(/&tinylegend=1/);
399                 document.getElementById('ge_logarithmic').checked = src_url.match(/&logarithmic=1/);
400                 for (i = 0; i < ts_sel.options.length; i++)
401                         if (ts_sel.options[i].value == ts) {
402                                 ts_sel.selectedIndex = i;
403                                 break;
404                         }
405                 // show tools box and position it properly
406                 ge.style.display = 'table';
407                 GraphPositionToolbox(ref_img);
408         } else {
409                 // hide tools box
410                 document.getElementById('ge').style.display = 'none';
411                 document.getElementById('ge_graphid').value = '';
412         }
413 }
414
415 function GraphPositionToolbox(ref_img) {
416         var ge      = document.getElementById('ge');
417         if (ge.style.display != 'none') {
418                 var wl = 0; var wt = 0;
419                 var x = ref_img;
420                 if (ref_img == null) {
421                         var graphDiv = document.getElementById(document.getElementById('ge_graphid').value);
422                         var imgs     = graphDiv ? graphDiv.getElementsByTagName('img') : null;
423                         var imgCnt   = imgs ? imgs.length : 0;
424                         while (imgCnt > 0)
425                                 if (imgs[--imgCnt].parentNode.getAttribute('class') == 'graph')
426                                         ref_img = imgs[imgCnt];
427
428                         if (ref_img == null) {
429                                 document.getElementById('ge_graphid').value = '';
430                                 ge.style.display = 'none';
431                                 return;
432                         } else
433                                 x = ref_img;
434                 }
435                 while (x != null) {
436                         wl += x.offsetLeft;
437                         wt += x.offsetTop;
438                         x = x.offsetParent;
439                 }
440                 ge.style.left    = (wl + (ref_img.offsetWidth - ge.offsetWidth) / 2)+'px';
441                 ge.style.top     = (wt + (ref_img.offsetHeight - ge.offsetHeight) / 2)+'px';
442         }
443 }
444
445 function GraphRefreshAll() {
446         var imgs   = document.getElementById('graphs').getElementsByTagName('img');
447         var imgCnt = imgs.length;
448         var now    = new Date();
449         var newTS  = '&ts='+now.getTime();
450         while (imgCnt > 0)
451                 if (imgs[--imgCnt].parentNode.getAttribute('class') == 'graph') {
452                         var oldSrc = imgs[imgCnt].src;
453                         var newSrc = oldSrc.replace(/&ts=[0-9]+/, newTS);
454                         if (newSrc == oldSrc)
455                                 newSrc = newSrc + newTS;
456                         imgs[imgCnt].setAttribute('src', newSrc);
457                 }
458 }
459
460 function GraphRefresh(graph) {
461         var graphElement = null;
462         if (graph == null) {
463                 var graphId = document.getElementById('ge_graphid').value;
464                 if (graphId != '')
465                         graphElement = document.getElementById(graphId);
466         } else 
467                 graphElement = document.getElementById(graph);
468         if (graphElement != null) {
469                 var imgs = graphElement.getElementsByTagName('img');
470                 var imgCnt = imgs.length;
471                 while (imgCnt > 0)
472                         if (imgs[--imgCnt].parentNode.getAttribute('class') == 'graph') {
473                                 var now    = new Date();
474                                 var newTS  = '&ts='+now.getTime();
475                                 var oldSrc = imgs[imgCnt].src;
476                                 var newSrc = oldSrc.replace(/&ts=[0-9]+/, newTS);
477                                 if (newSrc == oldSrc)
478                                         newSrc = newSrc+newTS;
479                                 imgs[imgCnt].setAttribute('src', newSrc);
480                                 break;
481                         }
482         }
483 }
484
485 function GraphAdjust(graph) {
486         var graphId = graph == null ? document.getElementById('ge_graphid').value : graph;
487         var graphElement = document.getElementById(graphId);
488         if (graphElement != null) {
489                 var time_list   = document.getElementById('ge_timespan');
490                 var timespan    = time_list.selectedIndex >= 0 ? time_list.options[time_list.selectedIndex].value : '';
491                 var tinyLegend  = document.getElementById('ge_tinylegend').checked;
492                 var logarithmic = document.getElementById('ge_logarithmic').checked
493                 var imgs = graphElement.getElementsByTagName('img');
494                 var imgCnt = imgs.length;
495                 var ref_img     = null;
496                 while (imgCnt > 0)
497                         if (imgs[--imgCnt].parentNode.getAttribute('class') == 'graph') {
498                                 var now    = new Date();
499                                 var newTS  = '&ts='+now.getTime();
500                                 var oldSrc = imgs[imgCnt].src;
501                                 var newSrc = oldSrc.replace(/&ts=[^&]*/, newTS);
502                                 if (newSrc == oldSrc)
503                                         newSrc = newSrc+newTS;
504                                 newSrc     = newSrc.replace(/&logarithmic=[^&]*/, '');
505                                 if (logarithmic)
506                                         newSrc += '&logarithmic=1';
507                                 newSrc     = newSrc.replace(/&tinylegend=[^&]*/, '');
508                                 if (tinyLegend)
509                                         newSrc += '&tinylegend=1';
510                                 newSrc     = newSrc.replace(/&timespan=[^&]*/, '');
511                                 if (timespan)
512                                         newSrc += '&timespan='+encodeURIComponent(timespan);
513                                 imgs[imgCnt].setAttribute('src', newSrc);
514
515                                 var myList = Array();
516                                 for (i = 0; i < graphList.length; i++)
517                                         if (graphList[i].substring(0, graphId.length) == graphId && graphList[i].charAt(graphId.length) == ' ') {
518                                                 newSrc = graphList[i];
519                                                 newSrc = newSrc.replace(/&logarithmic=[^&]*/, '');
520                                                 newSrc = newSrc.replace(/&tinylegend=[^&]*/, '');
521                                                 newSrc = newSrc.replace(/&timespan=[^&]*/, '');
522                                                 newSrc = newSrc+(logarithmic ? '&logarithmic=1' : '')+(tinyLegend ? '&tinylegend=1' : '')+'&timespan='+encodeURIComponent(timespan);
523                                                 myList.push(newSrc);
524                                                 continue;
525                                         } else
526                                                 myList.push(graphList[i]);
527                                 graphList = myList;
528                                 window.setTimeout("GraphPositionToolbox(null)", 10);
529                                 // GraphPositionToolbox(imgs[imgCnt]);
530                                 break;
531                         }
532         }
533 }
534
535 function GraphRemove(graph) {
536         var graphs = document.getElementById('graphs');
537         var graphId = graph == null ? document.getElementById('ge_graphid').value : graph;
538         var graphElement = document.getElementById(graphId);
539         if (graphElement) {
540                 GraphToggleTools('');
541                 graphs.removeChild(graphElement);
542                 RefreshButtons();
543                 if (graphs.getElementsByTagName('div').length == 1)
544                         document.getElementById('nograph').style.display = 'block';
545
546                 var myList = Array();
547                 for (i = 0; i < graphList.length; i++)
548                         if (graphList[i].substring(0, graphId.length) == graphId && graphList[i].charAt(graphId.length) == ' ')
549                                 continue;
550                         else
551                                 myList.push(graphList[i]);
552                 graphList = myList;
553         }
554 }
555
556 function GraphMoveUp(graph) {
557         var graphs    = document.getElementById('graphs');
558         var graphId   = graph == null ? document.getElementById('ge_graphid').value : graph;
559         var childCnt  = graphs.childNodes.length;
560         var prevGraph = null;
561         for (i = 0; i < childCnt; i++)
562                 if (graphs.childNodes[i].nodeName == 'div' || graphs.childNodes[i].nodeName == 'DIV') {
563                         if (graphs.childNodes[i].id == 'nograph') {
564                                 // Skip
565                         } else if (graphs.childNodes[i].id == graphId) {
566                                 var myGraph = graphs.childNodes[i];
567                                 if (prevGraph) {
568                                         graphs.removeChild(myGraph);
569                                         graphs.insertBefore(myGraph, prevGraph);
570                                 }
571                                 break;
572                         } else
573                                 prevGraph = graphs.childNodes[i];
574                 }
575         for (i = 0; i < graphList.length; i++)
576                 if (graphList[i].substring(0, graphId.length) == graphId && graphList[i].charAt(graphId.length) == ' ') {
577                         if (i > 0) {
578                                 var tmp = graphList[i-1];
579                                 graphList[i-1] = graphList[i];
580                                 graphList[i]   = tmp;
581                         }
582                         break;
583                 }
584         GraphPositionToolbox(null);
585 }
586
587 function GraphMoveDown(graph) {
588         var graphs    = document.getElementById('graphs');
589         var graphId   = graph == null ? document.getElementById('ge_graphid').value : graph;
590         var childCnt  = graphs.childNodes.length;
591         var nextGraph = null;
592         var myGraph   = null;
593         for (i = 0; i < childCnt; i++)
594                 if (graphs.childNodes[i].nodeName == 'div' || graphs.childNodes[i].nodeName == 'DIV') {
595                         if (graphs.childNodes[i].id == 'nograph') {
596                                 // Skip
597                         } else if (graphs.childNodes[i].id == graphId) {
598                                 myGraph = graphs.childNodes[i];
599                         } else if (myGraph) {
600                                 nextGraph = graphs.childNodes[i];
601                                 graphs.removeChild(nextGraph);
602                                 graphs.insertBefore(nextGraph, myGraph);
603                                 break;
604                         }
605                 }
606         for (i = 0; i < graphList.length; i++)
607                 if (graphList[i].substring(0, graphId.length) == graphId && graphList[i].charAt(graphId.length) == ' ') {
608                         if (i+1 < graphList.length) {
609                                 var tmp = graphList[i+1];
610                                 graphList[i+1] = graphList[i];
611                                 graphList[i]   = tmp;
612                         }
613                         break;
614                 }
615         GraphPositionToolbox(null);
616 }
617
618 function GraphListFromCookie(lname) {
619         if (document.cookie.length > 0) {
620                 var cname= 'graphLst'+lname+'=';
621                 var cookies = document.cookie.split('; ');
622                 for (i = 0; i < cookies.length; i++)
623                         if (cookies[i].substring(0, cname.length) == cname)
624                                 return cookies[i].substring(cname.length).split('/');
625         }
626         return new Array();
627 }
628
629 function GraphListNameSort(a, b) {
630         if (a[0] > b[0])
631                 return 1
632         else if (a[0] < b[0])
633                 return -1;
634         else
635                 return 0;
636 }
637
638 function GraphListRefresh() {
639         var select   = document.getElementById('GraphList');
640         var childCnt = select.childNodes.length;
641         var oldValue = select.selectedIndex > 0 ? select.options[select.selectedIndex].value : '/';
642         while (childCnt > 0)
643                 select.removeChild(select.childNodes[--childCnt]);
644
645         // Determine available names
646         var options = new Array();
647         if (document.cookie.length > 0) {
648                 var cookies = document.cookie.split('; ');
649                 for (i = 0; i < cookies.length; i++)
650                         if (cookies[i].substring(0, 8) == 'graphLst') {
651                                 var p = cookies[i].indexOf('=');
652                                 if (p < 0)
653                                         continue;
654                                 options.push(new Array(cookies[i].substring(8, p), cookies[i].substring(p+1).split('/').length));
655                         }
656         }
657         options.sort(GraphListNameSort);
658
659         var optCnt  = options ? options.length : 0;
660         if (optCnt == 0) {
661                 select.setAttribute('disabled', 'disabled');
662                 return -1;
663         } else {
664                 select.removeAttribute('disabled');
665                 for (i = 0; i < optCnt; i++) {
666                         newOption = document.createElement("option");
667                         newOption.value = options[i][0];
668                         if (newOption.value == oldValue)
669                                 newOption.setAttribute('selected', 'selected');
670                         if (options[i][1] == 1)
671                                 newOption.appendChild(document.createTextNode(newOption.value+' (1 graph)'));
672                         else
673                                 newOption.appendChild(document.createTextNode(newOption.value+' ('+options[i][1]+' graphs)'));
674                         select.appendChild(newOption);
675                 }
676                 return select.selectedIndex;
677         }
678 }
679
680 function GraphListCheckName(doalert) {
681         var lname = document.getElementById('GraphListName');
682         if (lname) {
683                 if (lname.value.match(/^[a-zA-Z0-9_-]+$/)) {
684                         lname.style.backgroundColor = '';
685                         return lname.value;
686                 } else {
687                         lname.style.backgroundColor = '#ffdddd';
688                         if (doalert && lname.value.length == 0)
689                                 alert('Graph list name is empty.\n\n'+
690                                       'Please fill in a name and try again.');
691                         else if (doalert)
692                                 alert('Graph list name contains non-permitted character.\n\n'+
693                                       'Only anlphanumerical characters (a-z, A-Z, 0-9), hyphen (-) and underscore (_) are permitted.\n'+
694                                       'Please correct and try again.');
695                         lname.focus();
696                 }
697         }
698         return '';
699 }
700
701 function GraphSave() {
702         var lstName = GraphListCheckName(true);
703         if (lstName.length == 0)
704                 return;
705         if (graphList.length > 0) {
706                 // Save graph list to cookie
707                 var str = '';
708                 for (i = 0; i < graphList.length; i++) {
709                         var g = graphList[i].indexOf(' ');
710                         if (i > 0)
711                                 str += '/';
712                         str += graphList[i].substring(g+1);
713                 }
714
715                 document.cookie = 'graphLst'+lstName+'='+str;
716                 if (GraphListFromCookie(lstName).length == 0)
717                         alert("Failed to save graph list '"+lstName+"' to cookie.");
718                 else
719                         alert("Successfully saved current graph list.");
720         } else {
721                 document.cookie = 'graphLst'+lstName+'=; expires='+new Date().toGMTString();
722                 alert("Cleared saved graph list.");
723         }
724         GraphListRefresh();
725 }
726
727 function GraphDrop() {
728         var cname = document.getElementById('GraphList');
729         if (cname && cname.selectedIndex >= 0) {
730                 cname = cname.options[cname.selectedIndex].value;
731                 document.cookie = 'graphLst'+cname+'=; expires='+new Date().toGMTString();
732                 GraphListRefresh();
733         } else
734                 return;
735 }
736
737 function GraphLoad() {
738         var cname = document.getElementById('GraphList');
739         if (cname && cname.selectedIndex >= 0)
740                 cname = cname.options[cname.selectedIndex].value;
741         else
742                 return;
743         // Load graph list from cookie
744         var grLst = GraphListFromCookie(cname);
745         var oldLength = graphList.length;
746         for (i = 0; i < grLst.length; i++) {
747                 var host        = '';
748                 var plugin      = '';
749                 var pinst       = '';
750                 var type        = '';
751                 var tinst       = '';
752                 var timespan    = '';
753                 var logarithmic = false;
754                 var tinyLegend  = false;
755                 var graph = grLst[i].split('&');
756                 for (j = 0; j < graph.length; j++)
757                         if (graph[j] == 'logarithmic=1')
758                                 logarithmic = true;
759                         else if (graph[j] == 'tinylegend=1')
760                                 tinyLegend = true;
761                         else if (graph[j].substring(0, 9) == 'timespan=')
762                                 timespan = decodeURIComponent(graph[j].substring(9));
763                 graph = decodeURIComponent(graph[0]).split('/');
764                 host = graph[0];
765                 if (graph.length > 1) {
766                         var g = graph[1].indexOf('-');
767                         if (g >= 0) {
768                                 plugin = graph[1].substring(0, g);
769                                 pinst  = graph[1].substring(g+1);
770                         } else
771                                 plugin = graph[1];
772                 }
773                 if (graph.length > 2) {
774                         var g = graph[2].indexOf('-');
775                         if (g >= 0) {
776                                 type  = graph[2].substring(0, g);
777                                 tinst = graph[2].substring(g+1);
778                         } else
779                                 type  = graph[2];
780                 }
781
782                 if (host && plugin && type)
783                         GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic);
784         }
785         if (grLst.length == 0)
786                 alert("No list '"+cname+"' found for loading.");
787         else if (grLst.length + oldLength != graphList.length)
788                 alert("Could not load all graphs, probably damaged cookie.");
789 }
790