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 */
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 }
40 var req = null;
42 // DHTML helper code to asynchronous loading of content
43 function loadXMLDoc(url, query) {
44 if (window.XMLHttpRequest) {
45 req = new XMLHttpRequest();
46 req.onreadystatechange = processReqChange;
47 req.open('POST', url, true);
48 req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
49 req.send(query);
50 } else if (window.ActiveXObject) {
51 req = new ActiveXObject("Microsoft.XMLHTTP");
52 if (req) {
53 req.onreadystatechange = processReqChange;
54 req.open('POST', url, true);
55 req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
56 req.send(query);
57 }
58 }
59 }
61 // DHTML new-content dispatcher
62 function processReqChange(evt) {
63 if (req.readyState == 4) {
64 if (req.status == 200) {
65 var response = req.responseXML.documentElement;
66 var method = response.getElementsByTagName('method')[0].firstChild.data;
67 var result = response.getElementsByTagName('result')[0];
68 req = null;
69 eval(method + '(result)');
70 }
71 }
72 }
74 // Update contents of a <select> drop-down list
75 function refillSelect(options, select) {
76 if (!select)
77 return -1;
79 var childCnt = select.childNodes.length;
80 var oldValue = select.selectedIndex > 0 ? select.options[select.selectedIndex].value : '/';
81 while (childCnt > 0)
82 select.removeChild(select.childNodes[--childCnt]);
84 var optCnt = options ? options.length : 0;
85 if (optCnt == 0) {
86 select.setAttribute('disabled', 'disabled');
87 return -1;
88 } else {
89 select.removeAttribute('disabled');
90 var keepSelection = false;
91 if (optCnt == 1) {
92 keepSelection = true;
93 oldValue = options[0].firstChild ? options[0].firstChild.data : '';
94 } else if (oldValue != '/') {
95 for (i = 0; i < optCnt && !keepSelection; i++)
96 if (oldValue == (options[i].firstChild ? options[i].firstChild.data : ''))
97 keepSelection = true;
98 }
99 newOption = document.createElement("option");
100 newOption.value = '/';
101 if (keepSelection)
102 newOption.setAttribute('disabled', 'disabled');
103 else
104 newOption.setAttribute('selected', 'selected');
105 newOption.setAttribute('style', 'font-style: italic');
106 newOption.appendChild(document.createTextNode('- please select -'));
107 select.appendChild(newOption);
108 for (i = 0; i < optCnt; i++) {
109 newOption = document.createElement("option");
110 newOption.value = options[i].firstChild ? options[i].firstChild.data : '';
111 if (keepSelection && newOption.value == oldValue)
112 newOption.setAttribute('selected', 'selected');
113 if (keepSelection && optCnt == 1 && newOption.value == '@') {
114 newOption.setAttribute('style', 'font-style: italic');
115 newOption.appendChild(document.createTextNode('Meta graph'));
116 } else
117 newOption.appendChild(document.createTextNode(newOption.value));
118 select.appendChild(newOption);
119 }
120 return keepSelection ? select.selectedIndex : -1;
121 }
122 }
124 // Request refresh of host list
125 function ListRefreshHost() {
126 var query = 'action=list_hosts';
127 loadXMLDoc(dhtml_url, query);
128 }
130 // Handle update to host list
131 function ListOfHost(response) {
132 var select = document.getElementById('host_list');
133 var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
134 if (idx > 0) {
135 ListRefreshPlugin();
136 } else
137 ListOfPlugin(null);
138 }
140 // Request refresh of plugin list
141 function ListRefreshPlugin() {
142 var host_list = document.getElementById('host_list');
143 var host = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
144 if (host != '/') {
145 var query = 'action=list_plugins&host='+encodeURIComponent(host);
146 loadXMLDoc(dhtml_url, query);
147 } else {
148 ListOfPlugin(null);
149 }
150 }
152 // Handle update to plugin list
153 function ListOfPlugin(response) {
154 var select = document.getElementById('plugin_list');
155 var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
156 if (idx > 0) {
157 ListRefreshPluginInstance();
158 } else
159 ListOfPluginInstance(null);
160 }
162 // Request refresh of plugin instance list
163 function ListRefreshPluginInstance() {
164 var host_list = document.getElementById('host_list');
165 var host = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
166 var plugin_list = document.getElementById('plugin_list');
167 var plugin = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
168 if (host != '/' && plugin != '/') {
169 var query = 'action=list_pinsts&host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin);
170 loadXMLDoc(dhtml_url, query);
171 } else {
172 ListOfPluginInstance(null);
173 }
174 }
176 // Handle update of plugin instance list
177 function ListOfPluginInstance(response) {
178 var select = document.getElementById('pinst_list');
179 var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
180 if (idx > 0) {
181 ListRefreshType();
182 } else
183 ListOfType(null);
184 }
186 // Request refresh of type list
187 function ListRefreshType() {
188 var host_list = document.getElementById('host_list');
189 var host = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
190 var plugin_list = document.getElementById('plugin_list');
191 var plugin = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
192 var pinst_list = document.getElementById('pinst_list');
193 var pinst = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
194 if (host != '/' && plugin != '/' && pinst != '/') {
195 var query = 'action=list_types&host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst);
196 loadXMLDoc(dhtml_url, query);
197 } else {
198 ListOfType(null);
199 }
200 }
202 // Handle update of type list
203 function ListOfType(response) {
204 var select = document.getElementById('type_list');
205 var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
206 if (idx > 0) {
207 ListRefreshTypeInstance();
208 } else
209 ListOfTypeInstance(null);
210 }
212 // Request refresh of type instance list
213 function ListRefreshTypeInstance() {
214 var host_list = document.getElementById('host_list');
215 var host = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
216 var plugin_list = document.getElementById('plugin_list');
217 var plugin = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
218 var pinst_list = document.getElementById('pinst_list');
219 var pinst = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
220 var type_list = document.getElementById('type_list');
221 var type = type_list.selectedIndex >= 0 ? type_list.options[type_list.selectedIndex].value : '/';
222 if (host != '/' && plugin != '/' && pinst != '/' && type != '/') {
223 var query = 'action=list_tinsts&host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst)+'&type='+encodeURIComponent(type);
224 loadXMLDoc(dhtml_url, query);
225 } else {
226 ListOfTypeInstance(null);
227 }
228 }
230 // Handle update of type instance list
231 function ListOfTypeInstance(response) {
232 var select = document.getElementById('tinst_list');
233 var idx = refillSelect(response ? response.getElementsByTagName('option') : null, select);
234 if (idx > 0) {
235 // Enable add button
236 RefreshButtons();
237 } else {
238 // Disable add button
239 RefreshButtons();
240 }
241 }
243 function RefreshButtons() {
244 var host_list = document.getElementById('host_list');
245 var host = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
246 var plugin_list = document.getElementById('plugin_list');
247 var plugin = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
248 var pinst_list = document.getElementById('pinst_list');
249 var pinst = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
250 var type_list = document.getElementById('type_list');
251 var type = type_list.selectedIndex >= 0 ? type_list.options[type_list.selectedIndex].value : '/';
252 var tinst_list = document.getElementById('tinst_list');
253 var tinst = tinst_list.selectedIndex >= 0 ? tinst_list.options[tinst_list.selectedIndex].value : '/';
254 if (host != '/' && plugin != '/' && pinst != '/' && type != '/' && tinst != '/') {
255 document.getElementById('btnAdd').removeAttribute('disabled');
256 } else {
257 document.getElementById('btnAdd').setAttribute('disabled', 'disabled');
258 }
260 var graphs = document.getElementById('graphs');
261 if (graphs.getElementsByTagName('div').length > 1) {
262 document.getElementById('btnClear').removeAttribute('disabled');
263 document.getElementById('btnRefresh').removeAttribute('disabled');
264 } else {
265 document.getElementById('btnClear').setAttribute('disabled', 'disabled');
266 document.getElementById('btnRefresh').setAttribute('disabled', 'disabled');
267 }
268 }
270 var nextGraphId = 1;
271 var graphList = new Array();
273 function GraphAppend() {
274 var host_list = document.getElementById('host_list');
275 var host = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
276 var plugin_list = document.getElementById('plugin_list');
277 var plugin = plugin_list.selectedIndex >= 0 ? plugin_list.options[plugin_list.selectedIndex].value : '/';
278 var pinst_list = document.getElementById('pinst_list');
279 var pinst = pinst_list.selectedIndex >= 0 ? pinst_list.options[pinst_list.selectedIndex].value : '/';
280 var type_list = document.getElementById('type_list');
281 var type = type_list.selectedIndex >= 0 ? type_list.options[type_list.selectedIndex].value : '/';
282 var tinst_list = document.getElementById('tinst_list');
283 var tinst = tinst_list.selectedIndex >= 0 ? tinst_list.options[tinst_list.selectedIndex].value : '/';
284 var time_list = document.getElementById('timespan');
285 var timespan = time_list.selectedIndex >= 0 ? time_list.options[time_list.selectedIndex].value : '';
286 var tinyLegend = document.getElementById('tinylegend').checked;
287 var logarithmic = document.getElementById('logarithmic').checked
288 GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic);
289 }
291 function GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic) {
292 var graphs = document.getElementById('graphs');
294 if (host != '/' && plugin != '/' && pinst != '/' && type != '/') {
295 var graph_id = 'graph_'+nextGraphId++;
296 var graph_src = graph_url+'?host='+encodeURIComponent(host)+'&plugin='+encodeURIComponent(plugin)+'&plugin_instance='+encodeURIComponent(pinst)+'&type='+encodeURIComponent(type);
297 var graph_alt = '';
298 var grap_title = '';
299 if (tinst == '@') {
300 graph_alt = host+'/'+plugin+(pinst.length > 0 ? '-'+pinst : '')+'/'+type;
301 graph_title = type+' of '+plugin+(pinst.length > 0 ? '-'+pinst : '')+' plugin for '+host;
302 } else {
303 graph_alt = host+'/'+plugin+(pinst.length > 0 ? '-'+pinst : '')+'/'+type+(tinst.length > 0 ? '-'+tinst : '');
304 graph_title = type+(tinst.length > 0 ? '-'+tinst : '')+' of '+plugin+(pinst.length > 0 ? '-'+pinst : '')+' plugin for '+host;
305 graph_src += '&type_instance='+encodeURIComponent(tinst);
306 }
307 if (logarithmic)
308 graph_src += '&logarithmic=1';
309 if (tinyLegend)
310 graph_src += '&tinylegend=1';
311 if (timespan)
312 graph_src += '×pan='+encodeURIComponent(timespan);
313 var now = new Date();
314 graph_src += '&ts='+now.getTime();
315 graphList.push(graph_id+' '+encodeURIComponent(graph_alt)+(logarithmic ? '&logarithmic=1' : '')+(tinyLegend ? '&tinylegend=1' : '')+'×pan='+encodeURIComponent(timespan));
317 // Graph container
318 newGraph = document.createElement('div');
319 newGraph.setAttribute('class', 'graph');
320 newGraph.setAttribute('id', graph_id);
321 // Graph cell + graph
322 newDiv = document.createElement('div');
323 newDiv.setAttribute('class', 'graph_img');
324 newImg = document.createElement('img');
325 newImg.setAttribute('src', graph_src);
326 newImg.setAttribute('alt', graph_alt);
327 newImg.setAttribute('title', graph_title);
328 newDiv.appendChild(newImg);
329 newGraph.appendChild(newDiv);
330 // Graph tools
331 newDiv = document.createElement('div');
332 newDiv.setAttribute('class', 'graph_opts');
333 // - move up
334 newImg = document.createElement('img');
335 newImg.setAttribute('src', 'move-up.png');
336 newImg.setAttribute('alt', 'UP');
337 newImg.setAttribute('title', 'Move graph up');
338 newA = document.createElement('a');
339 newA.setAttribute('href', 'javascript:GraphMoveUp("'+graph_id+'")');
340 newA.appendChild(newImg);
341 newDiv.appendChild(newA);
342 newDiv.appendChild(document.createElement('br'));
343 // - refresh
344 newImg = document.createElement('img');
345 newImg.setAttribute('src', 'refresh.png');
346 newImg.setAttribute('alt', 'R');
347 newImg.setAttribute('title', 'Refresh graph');
348 newA = document.createElement('a');
349 newA.setAttribute('href', 'javascript:GraphRefresh("'+graph_id+'")');
350 newA.appendChild(newImg);
351 newDiv.appendChild(newA);
352 newDiv.appendChild(document.createElement('br'));
353 // - remove
354 newImg = document.createElement('img');
355 newImg.setAttribute('src', 'delete.png');
356 newImg.setAttribute('alt', 'RM');
357 newImg.setAttribute('title', 'Remove graph');
358 newA = document.createElement('a');
359 newA.setAttribute('href', 'javascript:GraphRemove("'+graph_id+'")');
360 newA.appendChild(newImg);
361 newDiv.appendChild(newA);
362 newDiv.appendChild(document.createElement('br'));
363 // - move down
364 newImg = document.createElement('img');
365 newImg.setAttribute('src', 'move-down.png');
366 newImg.setAttribute('alt', 'DN');
367 newImg.setAttribute('title', 'Move graph down');
368 newA = document.createElement('a');
369 newA.setAttribute('href', 'javascript:GraphMoveDown("'+graph_id+'")');
370 newA.appendChild(newImg);
371 newDiv.appendChild(newA);
372 newGraph.appendChild(newDiv);
374 graphs.appendChild(newGraph);
375 }
376 document.getElementById('nograph').style.display = 'none';
377 RefreshButtons();
378 }
380 function GraphDropAll() {
381 var graphs = document.getElementById('graphs');
382 var childCnt = graphs.childNodes.length;
383 while (childCnt > 0)
384 if (graphs.childNodes[--childCnt].id != 'nograph' && (graphs.childNodes[childCnt].nodeName == 'div' || graphs.childNodes[childCnt].nodeName == 'DIV'))
385 graphs.removeChild(graphs.childNodes[childCnt]);
386 else if (graphs.childNodes[childCnt].id == 'nograph')
387 graphs.childNodes[childCnt].style.display = 'block';
388 graphList = new Array();
389 RefreshButtons();
390 }
392 function GraphRefresh(graph) {
393 if (graph == null) {
394 var imgs = document.getElementById('graphs').getElementsByTagName('img');
395 var imgCnt = imgs.length;
396 var now = new Date();
397 var newTS = '&ts='+now.getTime();
398 while (imgCnt > 0)
399 if (imgs[--imgCnt].parentNode.getAttribute('class') == 'graph_img') {
400 var oldSrc = imgs[imgCnt].src;
401 var newSrc = oldSrc.replace(/&ts=[0-9]+/, newTS);
402 if (newSrc == oldSrc)
403 newSrc = newSrc + newTS;
404 imgs[imgCnt].setAttribute('src', newSrc);
405 }
406 } else if (document.getElementById(graph)) {
407 var imgs = document.getElementById(graph).getElementsByTagName('img');
408 var imgCnt = imgs.length;
409 while (imgCnt > 0)
410 if (imgs[--imgCnt].parentNode.getAttribute('class') == 'graph_img') {
411 var now = new Date();
412 var newTS = '&ts='+now.getTime();
413 var oldSrc = imgs[imgCnt].src;
414 var newSrc = oldSrc.replace(/&ts=[0-9]+/, newTS);
415 if (newSrc == oldSrc)
416 newSrc = newSrc+newTS;
417 imgs[imgCnt].setAttribute('src', newSrc);
418 break;
419 }
420 }
421 }
423 function GraphRemove(graph) {
424 var graphs = document.getElementById('graphs');
425 if (document.getElementById(graph)) {
426 graphs.removeChild(document.getElementById(graph));
427 RefreshButtons();
428 if (graphs.getElementsByTagName('div').length == 1)
429 document.getElementById('nograph').style.display = 'block';
431 var myList = Array();
432 for (i = 0; i < graphList.length; i++)
433 if (graphList[i].substring(0, graph.length) == graph && graphList[i].charAt(graph.length) == ' ')
434 continue;
435 else
436 myList.push(graphList[i]);
437 graphList = myList;
438 }
439 }
441 function GraphMoveUp(graph) {
442 var graphs = document.getElementById('graphs');
443 var childCnt = graphs.childNodes.length;
444 var prevGraph = null;
445 for (i = 0; i < childCnt; i++)
446 if (graphs.childNodes[i].nodeName == 'div' || graphs.childNodes[i].nodeName == 'DIV') {
447 if (graphs.childNodes[i].id == 'nograph') {
448 // Skip
449 } else if (graphs.childNodes[i].id == graph) {
450 var myGraph = graphs.childNodes[i];
451 if (prevGraph) {
452 graphs.removeChild(myGraph);
453 graphs.insertBefore(myGraph, prevGraph);
454 }
455 break;
456 } else
457 prevGraph = graphs.childNodes[i];
458 }
459 for (i = 0; i < graphList.length; i++)
460 if (graphList[i].substring(0, graph.length) == graph && graphList[i].charAt(graph.length) == ' ') {
461 if (i > 0) {
462 var tmp = graphList[i-1];
463 graphList[i-1] = graphList[i];
464 graphList[i] = tmp;
465 }
466 break;
467 }
468 }
470 function GraphMoveDown(graph) {
471 var graphs = document.getElementById('graphs');
472 var childCnt = graphs.childNodes.length;
473 var nextGraph = null;
474 var myGraph = null;
475 for (i = 0; i < childCnt; i++)
476 if (graphs.childNodes[i].nodeName == 'div' || graphs.childNodes[i].nodeName == 'DIV') {
477 if (graphs.childNodes[i].id == 'nograph') {
478 // Skip
479 } else if (graphs.childNodes[i].id == graph) {
480 myGraph = graphs.childNodes[i];
481 } else if (myGraph) {
482 nextGraph = graphs.childNodes[i];
483 graphs.removeChild(nextGraph);
484 graphs.insertBefore(nextGraph, myGraph);
485 break;
486 }
487 }
488 for (i = 0; i < graphList.length; i++)
489 if (graphList[i].substring(0, graph.length) == graph && graphList[i].charAt(graph.length) == ' ') {
490 if (i+1 < graphList.length) {
491 var tmp = graphList[i+1];
492 graphList[i+1] = graphList[i];
493 graphList[i] = tmp;
494 }
495 break;
496 }
497 }
499 function GraphListFromCookie() {
500 if (document.cookie.length > 0) {
501 cookies = document.cookie.split('; ');
502 for (i = 0; i < cookies.length; i++)
503 if (cookies[i].substring(0, 9) == 'graphLst=')
504 return cookies[i].substring(9).split('/');
505 }
506 return new Array();
507 }
509 function GraphSave() {
510 if (graphList.length > 0) {
511 // Save graph list to cookie
512 var str = '';
513 for (i = 0; i < graphList.length; i++) {
514 var g = graphList[i].indexOf(' ');
515 if (i > 0)
516 str += '/';
517 str += graphList[i].substring(g+1);
518 }
520 document.cookie = 'graphLst='+str;
521 if (GraphListFromCookie().length == 0)
522 alert("Failed to save graph list to cookie.");
523 else
524 alert("Successfully saved current graph list.");
525 } else {
526 document.cookie = 'graphLst=; expires='+new Date().toGMTString();
527 alert("Cleared saved graph list.");
528 }
529 }
531 function GraphLoad() {
532 // Load graph list from cookie
533 var grLst = GraphListFromCookie();
534 for (i = 0; i < grLst.length; i++) {
535 var host = '';
536 var plugin = '';
537 var pinst = '';
538 var type = '';
539 var tinst = '';
540 var timespan = '';
541 var logarithmic = false;
542 var tinyLegend = false;
543 var graph = grLst[i].split('&');
544 for (j = 0; j < graph.length; j++)
545 if (graph[j] == 'logarithmic=1')
546 logarithmic = true;
547 else if (graph[j] == 'tinylegend=1')
548 tinyLegend = true;
549 else if (graph[j].substring(0, 9) == 'timespan=')
550 timespan = decodeURIComponent(graph[j].substring(9));
551 graph = decodeURIComponent(graph[0]).split('/');
552 host = graph[0];
553 if (graph.length > 1) {
554 var g = graph[1].indexOf('-');
555 if (g >= 0) {
556 plugin = graph[1].substring(0, g);
557 pinst = graph[1].substring(g+1);
558 } else
559 plugin = graph[1];
560 }
561 if (graph.length > 2) {
562 var g = graph[2].indexOf('-');
563 if (g >= 0) {
564 type = graph[2].substring(0, g);
565 tinst = graph[2].substring(g+1);
566 } else
567 type = graph[2];
568 }
570 if (host && plugin && type)
571 GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic);
572 }
573 if (grLst.length == 0)
574 alert("No list found for loading.");
575 else if (grLst.length != graphList.length)
576 alert("Could not load all graphs, probably damaged cookie.");
577 }