From 96e3074f9de2b0c7ba8b0b11edfa42ffd2803037 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Wed, 30 Aug 2006 21:18:01 +0000 Subject: Reorganize things, and build and install them properly --- Makefile.am | 4 +- configure.in | 2 +- doc/httpd-sample.conf | 18 +- html/action-date.gif | Bin 1024 -> 0 bytes html/action-next.gif | Bin 877 -> 0 bytes html/action-prev.gif | Bin 874 -> 0 bytes html/action-zoom.gif | Bin 965 -> 0 bytes html/ajax/action-date.gif | Bin 0 -> 1024 bytes html/ajax/action-next.gif | Bin 0 -> 877 bytes html/ajax/action-prev.gif | Bin 0 -> 874 bytes html/ajax/action-zoom.gif | Bin 0 -> 965 bytes html/ajax/frame.html | 43 +++ html/ajax/index.html | 50 ++++ html/ajax/rrdui.js | 685 +++++++++++++++++++++++++++++++++++++++++++++ html/ajax/style.css | 164 +++++++++++ html/frame.html | 43 --- html/index.html | 36 --- html/rrdui.js | 690 ---------------------------------------------- html/style.css | 164 ----------- tools/Makefile.am | 2 +- 20 files changed, 959 insertions(+), 942 deletions(-) delete mode 100644 html/action-date.gif delete mode 100644 html/action-next.gif delete mode 100644 html/action-prev.gif delete mode 100644 html/action-zoom.gif create mode 100644 html/ajax/action-date.gif create mode 100644 html/ajax/action-next.gif create mode 100644 html/ajax/action-prev.gif create mode 100644 html/ajax/action-zoom.gif create mode 100644 html/ajax/frame.html create mode 100644 html/ajax/index.html create mode 100644 html/ajax/rrdui.js create mode 100644 html/ajax/style.css delete mode 100644 html/frame.html delete mode 100644 html/index.html delete mode 100644 html/rrdui.js delete mode 100644 html/style.css diff --git a/Makefile.am b/Makefile.am index 4ce2055..eb31b88 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ -SUBDIRS = tools +SUBDIRS = tools html -EXTRA_DIST = graphics html tools +EXTRA_DIST = graphics tools dist-hook: rm -rf `find $(distdir)/ -name .svn` diff --git a/configure.in b/configure.in index 391e676..10fa922 100644 --- a/configure.in +++ b/configure.in @@ -38,5 +38,5 @@ AC_HEADER_STDC AC_MSG_RESULT() -AC_CONFIG_FILES([Makefile tools/Makefile]) +AC_CONFIG_FILES([Makefile tools/Makefile html/Makefile]) AC_OUTPUT diff --git a/doc/httpd-sample.conf b/doc/httpd-sample.conf index 05b0dba..4e1df94 100644 --- a/doc/httpd-sample.conf +++ b/doc/httpd-sample.conf @@ -1,7 +1,15 @@ -Alias /rrdui/ /home/joe/rrdui/html/ -ScriptAlias /rrduiback /home/joe/rrdui/tools/rrdui-cgi.py - - SetEnv CONFDIR "/home/joe/rd-test/conf" - SetEnv WORKDIR "/home/joe/rd-test/work" +# The front end to use +Alias /rrdui/ /usr/local/share/rrdui/ajax/ + +# The CGI backend which manages the graphs +ScriptAlias /rrdui-back /usr/local/bin/rrdui-cgi + + + # The location of the configuration files + SetEnv CONFDIR "/usr/local/etc/rrdbot" + + # The location of the RRD files + SetEnv WORKDIR "/var/db/rrdbot" + diff --git a/html/action-date.gif b/html/action-date.gif deleted file mode 100644 index a249e30..0000000 Binary files a/html/action-date.gif and /dev/null differ diff --git a/html/action-next.gif b/html/action-next.gif deleted file mode 100644 index c01940a..0000000 Binary files a/html/action-next.gif and /dev/null differ diff --git a/html/action-prev.gif b/html/action-prev.gif deleted file mode 100644 index f7eba32..0000000 Binary files a/html/action-prev.gif and /dev/null differ diff --git a/html/action-zoom.gif b/html/action-zoom.gif deleted file mode 100644 index c1e9800..0000000 Binary files a/html/action-zoom.gif and /dev/null differ diff --git a/html/ajax/action-date.gif b/html/ajax/action-date.gif new file mode 100644 index 0000000..a249e30 Binary files /dev/null and b/html/ajax/action-date.gif differ diff --git a/html/ajax/action-next.gif b/html/ajax/action-next.gif new file mode 100644 index 0000000..c01940a Binary files /dev/null and b/html/ajax/action-next.gif differ diff --git a/html/ajax/action-prev.gif b/html/ajax/action-prev.gif new file mode 100644 index 0000000..f7eba32 Binary files /dev/null and b/html/ajax/action-prev.gif differ diff --git a/html/ajax/action-zoom.gif b/html/ajax/action-zoom.gif new file mode 100644 index 0000000..c1e9800 Binary files /dev/null and b/html/ajax/action-zoom.gif differ diff --git a/html/ajax/frame.html b/html/ajax/frame.html new file mode 100644 index 0000000..3c9aae8 --- /dev/null +++ b/html/ajax/frame.html @@ -0,0 +1,43 @@ + + + + + + +
+
+ + +
+ Move Backwards
+ Move Forwards
+ Zoom Out
+ Select a Time Span
+
+ + +
+ +
+ + diff --git a/html/ajax/index.html b/html/ajax/index.html new file mode 100644 index 0000000..3ed3264 --- /dev/null +++ b/html/ajax/index.html @@ -0,0 +1,50 @@ + + + + + + Statistics Monitoring + + + + + + +
+ + + + +
+ Text +
+ +
+ +
+ + + diff --git a/html/ajax/rrdui.js b/html/ajax/rrdui.js new file mode 100644 index 0000000..5ed315a --- /dev/null +++ b/html/ajax/rrdui.js @@ -0,0 +1,685 @@ + + +/* ----------------------------------------------------------------------------- + * STARTUP + */ + +// Fix up the ENDPOINT config setting +if(ENDPOINT.charAt(0) != '/') + ENDPOINT = '/' + ENDPOINT; + +/* TODO: Check setup variables */ +/* TODO: Loading indicator */ + +var categoryCurrent = null; +var categoryArea = document.getElementById("headers"); +var xmlData = null; +var gdoc = null; +var gwindow = null; + +function init() +{ + /* Set by frame.html */ + if(!window._frameLoaded) + { + window.setTimeout("init();", 100); + return; + } + + setupFrame(); + loadXml(makeEndpointURI(), loadedGraphData); +} + +init(); + +function loadedGraphData(doc) +{ + if(!doc) + { + displayError("Couldn't load graph data from server", categoryArea); + return; + } + + xmlData = doc; + + displayCategories(); + displayCurrentPage(); +} + + +/* ----------------------------------------------------------------------------- + * GRAPHS + */ + +function getFrameDocument() +{ + var frame = document.getElementById("main-frame"); + /* COMPAT: IE and Mozilla access the content of frames differently */ + return frame.contentDocument ? frame.contentDocument : frame.contentWindow.document; +} + +function setupFrame() +{ + gdoc = getFrameDocument(); + var frame = document.getElementById("main-frame"); + /* COMPAT: IE and Mozilla access the content of frames differently */ + gwindow = frame.contentDocument ? frame.contentDocument.defaultView : frame.contentWindow; +} + +function displayCurrentPage() +{ + var area = gdoc.getElementById("graphs"); + var img; + + /* Hide all images not from this category */ + var i, images = area.getElementsByTagName("img"); + for(i = 0; i < images.length; i++) + { + img = images.item(i); + var vis = (img._category == categoryCurrent); + + img.style.display = vis ? "inline" : "none"; + + if(vis != img._visible) + { + /* The graph needs reloading if now turning visible */ + img._visible = vis; + if(vis) + reloadGraph(img, false); + else + img._loading = false; + } + } + + var graphs = findCategoryGraphs(categoryCurrent); + if(!graphs) + { + displayError("Graph data isn't loaded from server", area); + return; + } + + var tend = nowTime(); + var tbeg = tend - 86400; /* One day by default */ + + for(i = 0; i < graphs.length; i++) + { + var child = graphs[i]; + + var name = child.getAttribute("name"); + if(!name || !name.length) + continue; + + /* Make sure we don't already have this graph */ + var id = "graph-" + categoryCurrent + "-" + name; + img = gdoc.getElementById(id); + if(img != null) + continue; + + var interval = child.getAttribute("interval"); + if(!interval || isNaN(interval) || interval <= 0) + interval = 0; + interval = Number(interval); + + img = gdoc.createElement("img"); + + var title = child.getAttribute("title"); + if(title && title.length) + { + img.setAttribute("title", child.getAttribute("title")); + img.setAttribute("alt", child.getAttribute("title")); + } + else + img.setAttribute("alt", "Graph"); + + img.className = "graph"; + img.id = id; + img.style.cursor = "crosshair"; + + area.appendChild(img); + + img._category = categoryCurrent; + img._name = name; + img._tbeg = tbeg; + img._tend = tend; + img._tinterval = interval; + img._visible = true; + img._loading = false; + + reloadGraph(img, false); + + img.onmousedown = function(evt) + { actionGotoCancel(); return zoomGraphStart(evt || gwindow.event); } + img.onmouseover = function(evt) + { return actionsDisplay(gwindow.event ? gwindow.event : evt); } + + /* Setup for an auto scroll */ + if(interval) + { + /* Bump up auto scroll interval to 5 seconds */ + var interval = img._tinterval < 5 ? 5 : img._tinterval; + window.setInterval(autoScroll, interval * 1000, img); + } + } +} + +function reloadGraph(img, force) +{ + img._last = nowTime(); + + if(!img._visible) + return; + + /* TODO: We should encode colons properly */ + + var uri = makeEndpointURI() + "/graph?category=" + img._category + "&name=" + img._name; + + /* Add date options */ + uri += "&start=" + img._tbeg + "&end=" + img._tend; + + /* And colors */ + uri += "&color=BACK" + GRAPH_COLOR_BACK + "&color=FONT" + GRAPH_COLOR_FONT + + "&color=SHADEA" + GRAPH_COLOR_BACK + "&color=SHADEB" + GRAPH_COLOR_BACK; + + /* Size */ + uri += "&height=" + GRAPH_HEIGHT + "&width=" + GRAPH_WIDTH; + + if(force || img.getAttribute("src") != uri) + { + img._loading = true; + updateCursors(img); + + /* HACK: The onload event for IMG is called with a strange event target */ + img.onload = new Function("reloadedGraph('" + img.id + "');"); + img.setAttribute("src", uri); + } +} + +function reloadedGraph(id) +{ + var img = getFrameDocument().getElementById(id); + img._loading = false; + updateCursors(img); +} + +function updateCursors(img) +{ + if(img._actions) + { + var i, acts = img._actions.getElementsByTagName("img"); + for(i = 0; i < acts.length; i++) + acts.item(i).style.cursor = img._loading ? "wait" : "pointer"; + } + + img.style.cursor = img._loading ? "wait" : "crosshair"; +} + +function autoScroll(img) +{ + /* Don't auto scroll if we have loading issues */ + if(img._loading) + return; + + /* If we're displaying 'now' somewhere in the graph... */ + var now = nowTime(); + if((img._tend + (img._tinterval * 2)) >= now) + { + var diff = now - img._last; + + if(diff > 0) + { + /* ... then scroll by X seconds to scroll the graph */ + img._tbeg += diff; + img._tend += diff; + reloadGraph(img, false); + } + } +} + + + +/* ----------------------------------------------------------------------------- + * ZOOM + */ + +function zoomGraphStart(evt) +{ + /* COMPAT: In IE the left button is 1, Mozilla is 0 */ + var lbutton = gwindow.event ? 1 : 0; + + if(evt.button != lbutton) + return; + + /* COMPAT: Target is handled differently in Internet nastiness */ + var img = evt.target || evt.srcElement; + + if(img.className != "graph") + return; + + var zoom = gdoc.getElementById("zoom"); + + zoom._img = img; + zoom._zooming = true; + zoom._from = evt.clientX + gdoc.body.scrollLeft; + + zoom._start = zoom._from - img.offsetLeft; + zoom._end = zoom._start; + + zoom.style.width = 1; + zoom.style.left = zoom._from; + zoom.style.height = img.height; + zoom.style.top = img.offsetTop; + zoom.style.display = "block"; + + zoom.onmousemove = zoom._img.onmousemove = function(evt) + { return zoomGraphUpdate(gwindow.event ? gwindow.event : evt); } + zoom.onmouseup = zoom._img.onmouseup = function(evt) + { return zoomGraphDone(gwindow.event ? gwindow.event : evt); } + document.onmouseup = gdoc.onmouseup = function(evt) + { return zoomGraphDone(gwindow.event ? gwindow.event : evt); } + + cancelEvent(evt); + return false; +} + +function zoomGraphUpdate(evt) +{ + var zoom = gdoc.getElementById("zoom"); + if(!zoom._zooming || !zoom._img) + return; + + var to = evt.clientX + gdoc.body.scrollLeft; + var width = to - zoom._from; + zoom._end = to - zoom._img.offsetLeft; + + if(width == 0) + width = 1; + + if(width < 0) + { + zoom.style.left = to; + zoom.style.width = -width; + } + else + { + zoom.style.left = zoom._from; + zoom.style.width = width; + } + + zoom.style.height = zoom._img.height; + zoom.style.top = zoom._img.offsetTop; + zoom.style.display = "block"; + + cancelEvent(evt); + return false; +} + +function zoomGraphDone(evt) +{ + var zoom = gdoc.getElementById("zoom"); + if(!zoom._zooming) + return; + + /* COMPAT: Target is handled differently in Internet nastiness */ + var targ = evt.target || evt.srcElement; + if(targ == zoom || targ == zoom._img) + zoomGraphSelect(zoom); + + zoomGraphCancel(evt); +} + +function zoomGraphSelect(zoom) +{ + var left = GRAPH_MARGIN_LEFT; + var right = zoom._img.width - GRAPH_MARGIN_RIGHT; + + var start = zoom._start > zoom._end ? zoom._end : zoom._start; + var end = zoom._start > zoom._end ? zoom._start : zoom._end; + + /* If too small selected, then punt */ + if((end - start) <= 1) + return; + + /* If entire thing selected, then punt */ + if(start < left && end > right) + return; + + /* If only margins selected, then punt */ + if(!(start < right && end > left)) + return; + + /* Limit it to the right range */ + var range = zoom._img.width - GRAPH_MARGIN_RIGHT - GRAPH_MARGIN_LEFT; + start = start < left ? 0 : start - left; + end = end - left > range ? range : end - left; + + /* Compute the ratio pixels:time */ + var ratio = (zoom._img._tend - zoom._img._tbeg) / range; + + var obeg = zoom._img._tbeg; + var oend = zoom._img._tend; + + zoom._img._tend = Math.floor((end * ratio) + zoom._img._tbeg); + zoom._img._tbeg = Math.floor((start * ratio) + zoom._img._tbeg); + + reloadGraph(zoom._img, true); +} + +function zoomGraphCancel(evt) +{ + var zoom = gdoc.getElementById("zoom"); + + if(zoom._zooming) { + if(zoom._img) + zoom._img.onmousemove = zoom._img.onmouseup = zoom._img.onmouseleave = null; + zoom._img = null; + zoom.onmousemove = zoom.onmouseup = null; + zoom._zooming = false; + } + + zoom.style.display = "none"; +} + +function zoomGraphOut(img) +{ + var factor = Math.floor((img._tend - img._tbeg) / 2.5); + var now = nowTime(); + + /* If near the end we have special behavior */ + if(img._tend >= now - 300 || img._tend <= now) + { + img._tbeg -= factor; + img._tend = now; + } + else + { + factor = Math.floor(factor / 2); + img._tbeg -= factor + img._tend += factor; + } + + reloadGraph(img, true); +} + +function zoomGraphMove(img, dir) +{ + var factor = Math.floor((img._tend - img._tbeg) / 3); + if(!dir) + factor = -factor; + img._tbeg += factor; + img._tend += factor; + reloadGraph(img, true); +} + +function actionsDisplay(evt) +{ + /* COMPAT: Target is handled differently in Internet nastiness */ + var img = evt.target || evt.srcElement; + + if(img.className != "graph") + return; + + var actions = gdoc.getElementById("actions"); + + /* Disconnect from previous image */ + if(actions._img) + actions._img._actions = null; + + /* Attach to this image */ + actions._img = img; + img._actions = actions; + updateCursors(img); + + actions._display = true; + + actions.style.top = img.offsetTop; + actions.style.left = img.offsetLeft + (img.width - 16); + actions.style.display = "block"; + + actions.onmouseout = img.onmouseout = function(evt) + { return actionsHide(gwindow.event ? gwindow.event : evt); } + + /* TODO: We only actually have to do this once */ + var i, acts = actions.getElementsByTagName("img"); + for(i = 0; i < acts.length; i++) + { + acts.item(i).onclick = function(evt) + { return actionRun(gwindow.event ? gwindow.event : evt); } + } +} + +function actionsHide(evt) +{ + var actions = gdoc.getElementById("actions"); + if(!actions._display) + return; + + var x = evt.clientX + gdoc.body.scrollLeft; + var y = evt.clientY + gdoc.body.scrollTop; + var img = actions._img; + + /* See if we're actually still within the image */ + if(x >= img.offsetLeft && x <= img.offsetLeft + img.width && + y >= img.offsetTop && y <= img.offsetTop + img.height) + return; + + actions.style.display = "none"; + img.onmouseout = actions.onmouseout = null; + img._actions = null; + actions._img = null; + actions._display = false; +} + +function actionRun(evt) +{ + /* COMPAT: Target is handled differently in Internet nastiness */ + var act = evt.target || evt.srcElement; + + if(act.className != "action") + return; + + var actions = gdoc.getElementById("actions"); + if(!actions._display) + return; + + switch(act.getAttribute("id")) + { + case "action-zoom": + zoomGraphOut(actions._img); + break; + case "action-next": + zoomGraphMove(actions._img, true); + break; + case "action-prev": + zoomGraphMove(actions._img, false); + break; + case "action-goto": + actionGoto(actions._img, act); + break; + } +} + +function actionGoto(img, act) +{ + /* Display the selection thingy */ + var got = gdoc.getElementById("goto"); + + /* TODO: Make numbers constants */ + got.style.top = img.offsetTop + 40; + got.style.left = (img.offsetLeft + img.width) - 160; + got.style.width = 120; + got.style.display = "block"; + + var sel = gdoc.getElementById("goto-select"); + sel.onchange = actionGotoChange; + sel._img = img; + sel.value = null; + sel.selectedIndex = -1; +} + +function actionGotoCancel() +{ + var got = gdoc.getElementById("goto"); + got.style.display = "none"; +} + +function actionGotoChange() +{ + var sel = gdoc.getElementById("goto-select"); + var img = sel._img; + sel.onchange = null; + sel._img = null; + + times = sel.value.split(":"); + img._tbeg = nowTime() - times[0]; + img._tend = nowTime() - times[1]; + reloadGraph(img, true); + + actionGotoCancel(); +} + +/* ----------------------------------------------------------------------------- + * GROUP CATEGORIES + */ + +function findCategoryGraphs(cat) +{ + var i; + + if(!xmlData) + return null; + + var ret = new Array(); + var graphs = xmlData.getElementsByTagName("graph"); + for(i = 0; i < graphs.length; i++) + { + if(graphs.item(i).getAttribute("category") == cat) + ret.push(graphs.item(i)); + } + return ret; +} + +function changeCategory(evt) +{ + var header = evt.target || evt.srcElement; + categoryCurrent = header.getAttribute("category"); + displayCurrentPage(); +} + +function displayCategories() +{ + var cats = new Object(); + var cat, i, name; + + /* Get the template and clean it up a bit */ + var template = document.getElementById("header-template"); + + var graphs = xmlData.getElementsByTagName("graph"); + for(i = 0; i < graphs.length; i++) + { + cat = graphs.item(i).getAttribute("category"); + if(!cat) + { + cat = "Other"; + graphs.item(i).setAttribute("category", "Other"); + } + cats[cat] = true; + } + + for(name in cats) + { + if(!categoryCurrent) + categoryCurrent = name; + + var el = template.cloneNode(false); + el.removeAttribute("id"); + el.appendChild(document.createTextNode(name)); + el.setAttribute("category", name); + + el.onclick = function(evt) + { return changeCategory(evt || window.event); } + + categoryArea.insertBefore(el, template); + } +} + +/* ----------------------------------------------------------------------------- + * HELPERS + */ + +function loadXml(uri, callback) +{ + var xmlhttp; + var xmlHttpChange = function() { + if(xmlhttp.readyState == 4) + { + if(xmlhttp.status == 200) + callback(xmlhttp.responseXML); + else + callback(null); + } + } + + /* Mozilla code */ + if(window.XMLHttpRequest) + { + xmlhttp = new XMLHttpRequest(); + xmlhttp.onreadystatechange = xmlHttpChange; + xmlhttp.open("GET", uri, true); + xmlhttp.send(null); + } + + /* And now for the Nasty */ + else if (window.ActiveXObject) + { + xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); + /* TODO: need to do something when this fails (can it fail?) */ + if(xmlhttp) + { + xmlhttp.onreadystatechange = xmlHttpChange; + xmlhttp.open("GET", uri, true); + xmlhttp.send() + } + } +} + +function displayError(message, place) +{ + var el = document.createElement("span"); + el.className = "error"; + var text = document.createTextNode(message); + el.appendChild(text); + + if(place) + place.appendChild(el); + + return el; +} + +function nowTime() +{ + return Math.floor((new Date()).getTime() / 1000); +} + +function debug(msg) +{ + setTimeout(function() { throw new Error("[debug] " + msg); }, 0); +} + +function makeEndpointURI() +{ + /* TODO: This should use the scheme of the current URI */ + return "http://" + document.location.host + ENDPOINT; +} + +function cancelEvent(evt) +{ + /* COMPAT: Totally different for IE and mozilla */ + if(evt.preventDefault) + evt.preventDefault(); + if(evt.stopPropagation) + evt.stopPropagation(); + if("cancelBubble" in evt) + evt.cancelBubble = true; + if("returnValue" in evt) + evt.returnValue = false; +} diff --git a/html/ajax/style.css b/html/ajax/style.css new file mode 100644 index 0000000..b72e4ca --- /dev/null +++ b/html/ajax/style.css @@ -0,0 +1,164 @@ + +/* ----------------------------------------------------------------------------- + * MAIN LAYOUT + */ + +* +{ + color: #E7E1CC; + font-family: sans-serif; +} + +body +{ + background-color: #1A1A1A +} + +#main-table +{ + width: 100%; + height: 100%; + padding: 10px; +} + +#top-row +{ + height: 30pt; + padding: 0px; +} + +#main-row + { height: 100%; } + +#main-cell + { background-color: #252424; padding: 5pt; } + +#main-frame +{ + border: none; + height: 100%; + width: 100%; +} + +#logo +{ + font-size: 16pt; + font-weight: bold; +} + +/* ----------------------------------------------------------------------------- + * GROUP HEADERS + */ + +/* A group button at the top */ +.header +{ + background-color: #3D2C2C; + padding: 4pt 6pt; + font-size: 8pt; + font-weight: bold; + -moz-border-radius: 3pt; + cursor: pointer; + margin-right: 5pt; +} + +/* Our sample header (which gets copied for each group) is hidden */ +#header-template + { visibility: hidden; } + +/* ----------------------------------------------------------------------------- + * GRAPHS/FRAME + */ + +body.in-frame +{ + background-color: #252424; +} + +img.graph +{ + margin: 7px; +} + +#zoom +{ + cursor: crosshair; + position: absolute; + background-color: red; + display: none; + top: 0px; + left: 0px; + width: 10px; + height: 10px; + filter: alpha(opacity=40); + -moz-opacity: 0.5; + -khtml-opacity: 0.5; + opacity: 0.5; +} + +/* ----------------------------------------------------------------------------- + * ACTION BAR + */ + +#actions +{ + background-color: #252424; + position: absolute; + left: 50px; + top: 50px; + height: 120px; + display: none; +} + +.action +{ + margin: 3px; + cursor: pointer; + + /* COMPAT: IE doesn't support :hover on anything but links + so transparency has no use whatsover */ + + -moz-opacity: 0.75; + -khtml-opacity: 0.75; + opacity: 0.75; +} + +img.action:hover +{ + -moz-opacity: 1; + -khtml-opacity: 1; + opacity: 1; +} + +#goto +{ + position: absolute; + padding: 10px; + top: 0px; + left: 0px; + background-color: #252424; + display: none; +} + +#goto-select +{ + border: 1px solid black; + font-size: 8pt; + font-weight: normal; + width: 120px; + background-color: #252424; +} + +/* ----------------------------------------------------------------------------- + * MISC + */ + +.error +{ + background-color: #F3BDBD; + border: 1px solid red; + padding: 3pt; + font-size: 8pt; + color: black; +} + diff --git a/html/frame.html b/html/frame.html deleted file mode 100644 index 3c9aae8..0000000 --- a/html/frame.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - -
-
- - -
- Move Backwards
- Move Forwards
- Zoom Out
- Select a Time Span
-
- - -
- -
- - diff --git a/html/index.html b/html/index.html deleted file mode 100644 index f60e1b1..0000000 --- a/html/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - Statistics Monitoring - - - - - - -
- - - - -
- - - Text - -
- -
- -
- - - diff --git a/html/rrdui.js b/html/rrdui.js deleted file mode 100644 index b868728..0000000 --- a/html/rrdui.js +++ /dev/null @@ -1,690 +0,0 @@ - - -/* ----------------------------------------------------------------------------- - * STARTUP - */ - -/* TODO: Check setup variables */ -/* TODO: Loading indicator */ - -var categoryCurrent = null; -var categoryArea = document.getElementById("headers"); -var xmlData = null; -var gdoc = null; -var gwindow = null; - -function init() -{ - /* Set by frame.html */ - if(!window._frameLoaded) - { - window.setTimeout("init();", 100); - return; - } - - setupFrame(); - loadXml(makeEndpointURI(), loadedGraphData); -} - -init(); - -function loadedGraphData(doc) -{ - if(!doc) - { - displayError("Couldn't load graph data from server", categoryArea); - return; - } - - xmlData = doc; - - displayCategories(); - displayCurrentPage(); -} - - -/* ----------------------------------------------------------------------------- - * GRAPHS - */ - -function getFrameDocument() -{ - var frame = document.getElementById("main-frame"); - /* COMPAT: IE and Mozilla access the content of frames differently */ - return frame.contentDocument ? frame.contentDocument : frame.contentWindow.document; -} - -function setupFrame() -{ - gdoc = getFrameDocument(); - var frame = document.getElementById("main-frame"); - /* COMPAT: IE and Mozilla access the content of frames differently */ - gwindow = frame.contentDocument ? frame.contentDocument.defaultView : frame.contentWindow; -} - -function displayCurrentPage() -{ - var area = gdoc.getElementById("graphs"); - var img; - - /* Hide all images not from this category */ - var i, images = area.getElementsByTagName("img"); - for(i = 0; i < images.length; i++) - { - img = images.item(i); - var vis = (img._category == categoryCurrent); - - img.style.display = vis ? "inline" : "none"; - - if(vis != img._visible) - { - /* The graph needs reloading if now turning visible */ - img._visible = vis; - if(vis) - reloadGraph(img, false); - else - img._loading = false; - } - } - - var graphs = findCategoryGraphs(categoryCurrent); - if(!graphs) - { - displayError("Graph data isn't loaded from server", area); - return; - } - - var tend = nowTime(); - var tbeg = tend - 86400; /* One day by default */ - - for(i = 0; i < graphs.length; i++) - { - var child = graphs[i]; - - var name = child.getAttribute("name"); - if(!name || !name.length) - continue; - - /* Make sure we don't already have this graph */ - var id = "graph-" + categoryCurrent + "-" + name; - img = gdoc.getElementById(id); - if(img != null) - continue; - - var interval = child.getAttribute("interval"); - if(!interval || isNaN(interval) || interval <= 0) - interval = 0; - interval = Number(interval); - - img = gdoc.createElement("img"); - - var title = child.getAttribute("title"); - if(title && title.length) - { - img.setAttribute("title", child.getAttribute("title")); - img.setAttribute("alt", child.getAttribute("title")); - } - else - img.setAttribute("alt", "Graph"); - - img.className = "graph"; - img.id = id; - img.style.cursor = "crosshair"; - - area.appendChild(img); - - img._category = categoryCurrent; - img._name = name; - img._tbeg = tbeg; - img._tend = tend; - img._tinterval = interval; - img._visible = true; - img._loading = false; - - reloadGraph(img, false); - - img.onmousedown = function(evt) - { actionGotoCancel(); return zoomGraphStart(evt || gwindow.event); } - img.onmouseover = function(evt) - { return actionsDisplay(gwindow.event ? gwindow.event : evt); } - - /* Setup for an auto scroll */ - if(interval) - { - /* Bump up auto scroll interval to 5 seconds */ - var interval = img._tinterval < 5 ? 5 : img._tinterval; - window.setInterval(autoScroll, interval * 1000, img); - } - } -} - -function reloadGraph(img, force) -{ - img._last = nowTime(); - - if(!img._visible) - return; - - /* TODO: Move these into settings */ - /* TODO: We should encode colons properly */ - var GRAPH_COLOR_BACK = ":252424"; - var GRAPH_COLOR_FONT = ":E7E1CC"; - var GRAPH_WIDTH = 450; - var GRAPH_HEIGHT = 120 - - var uri = makeEndpointURI() + "/graph?category=" + img._category + "&name=" + img._name; - - /* Add date options */ - uri += "&start=" + img._tbeg + "&end=" + img._tend; - - /* And colors */ - uri += "&color=BACK" + GRAPH_COLOR_BACK + "&color=FONT" + GRAPH_COLOR_FONT + - "&color=SHADEA" + GRAPH_COLOR_BACK + "&color=SHADEB" + GRAPH_COLOR_BACK; - - /* Size */ - uri += "&height=" + GRAPH_HEIGHT + "&width=" + GRAPH_WIDTH; - - if(force || img.getAttribute("src") != uri) - { - img._loading = true; - updateCursors(img); - - /* HACK: The onload event for IMG is called with a strange event target */ - img.onload = new Function("reloadedGraph('" + img.id + "');"); - img.setAttribute("src", uri); - } -} - -function reloadedGraph(id) -{ - var img = getFrameDocument().getElementById(id); - img._loading = false; - updateCursors(img); -} - -function updateCursors(img) -{ - if(img._actions) - { - var i, acts = img._actions.getElementsByTagName("img"); - for(i = 0; i < acts.length; i++) - acts.item(i).style.cursor = img._loading ? "wait" : "pointer"; - } - - img.style.cursor = img._loading ? "wait" : "crosshair"; -} - -function autoScroll(img) -{ - /* Don't auto scroll if we have loading issues */ - if(img._loading) - return; - - /* If we're displaying 'now' somewhere in the graph... */ - var now = nowTime(); - if((img._tend + (img._tinterval * 2)) >= now) - { - var diff = now - img._last; - - if(diff > 0) - { - /* ... then scroll by X seconds to scroll the graph */ - img._tbeg += diff; - img._tend += diff; - reloadGraph(img, false); - } - } -} - - - -/* ----------------------------------------------------------------------------- - * ZOOM - */ - -function zoomGraphStart(evt) -{ - /* COMPAT: In IE the left button is 1, Mozilla is 0 */ - var lbutton = gwindow.event ? 1 : 0; - - if(evt.button != lbutton) - return; - - /* COMPAT: Target is handled differently in Internet nastiness */ - var img = evt.target || evt.srcElement; - - if(img.className != "graph") - return; - - var zoom = gdoc.getElementById("zoom"); - - zoom._img = img; - zoom._zooming = true; - zoom._from = evt.clientX + gdoc.body.scrollLeft; - - zoom._start = zoom._from - img.offsetLeft; - zoom._end = zoom._start; - - zoom.style.width = 1; - zoom.style.left = zoom._from; - zoom.style.height = img.height; - zoom.style.top = img.offsetTop; - zoom.style.display = "block"; - - zoom.onmousemove = zoom._img.onmousemove = function(evt) - { return zoomGraphUpdate(gwindow.event ? gwindow.event : evt); } - zoom.onmouseup = zoom._img.onmouseup = function(evt) - { return zoomGraphDone(gwindow.event ? gwindow.event : evt); } - document.onmouseup = gdoc.onmouseup = function(evt) - { return zoomGraphDone(gwindow.event ? gwindow.event : evt); } - - cancelEvent(evt); - return false; -} - -function zoomGraphUpdate(evt) -{ - var zoom = gdoc.getElementById("zoom"); - if(!zoom._zooming || !zoom._img) - return; - - var to = evt.clientX + gdoc.body.scrollLeft; - var width = to - zoom._from; - zoom._end = to - zoom._img.offsetLeft; - - if(width == 0) - width = 1; - - if(width < 0) - { - zoom.style.left = to; - zoom.style.width = -width; - } - else - { - zoom.style.left = zoom._from; - zoom.style.width = width; - } - - zoom.style.height = zoom._img.height; - zoom.style.top = zoom._img.offsetTop; - zoom.style.display = "block"; - - cancelEvent(evt); - return false; -} - -function zoomGraphDone(evt) -{ - var zoom = gdoc.getElementById("zoom"); - if(!zoom._zooming) - return; - - /* COMPAT: Target is handled differently in Internet nastiness */ - var targ = evt.target || evt.srcElement; - if(targ == zoom || targ == zoom._img) - zoomGraphSelect(zoom); - - zoomGraphCancel(evt); -} - -function zoomGraphSelect(zoom) -{ - // Arbitrary values (TODO: Move these to CONFIG) - var GRAPH_MARGIN_LEFT = 67; - var GRAPH_MARGIN_RIGHT = 27; - - var left = GRAPH_MARGIN_LEFT; - var right = zoom._img.width - GRAPH_MARGIN_RIGHT; - - var start = zoom._start > zoom._end ? zoom._end : zoom._start; - var end = zoom._start > zoom._end ? zoom._start : zoom._end; - - /* If too small selected, then punt */ - if((end - start) <= 1) - return; - - /* If entire thing selected, then punt */ - if(start < left && end > right) - return; - - /* If only margins selected, then punt */ - if(!(start < right && end > left)) - return; - - /* Limit it to the right range */ - var range = zoom._img.width - GRAPH_MARGIN_RIGHT - GRAPH_MARGIN_LEFT; - start = start < left ? 0 : start - left; - end = end - left > range ? range : end - left; - - /* Compute the ratio pixels:time */ - var ratio = (zoom._img._tend - zoom._img._tbeg) / range; - - var obeg = zoom._img._tbeg; - var oend = zoom._img._tend; - - zoom._img._tend = Math.floor((end * ratio) + zoom._img._tbeg); - zoom._img._tbeg = Math.floor((start * ratio) + zoom._img._tbeg); - - reloadGraph(zoom._img, true); -} - -function zoomGraphCancel(evt) -{ - var zoom = gdoc.getElementById("zoom"); - - if(zoom._zooming) { - if(zoom._img) - zoom._img.onmousemove = zoom._img.onmouseup = zoom._img.onmouseleave = null; - zoom._img = null; - zoom.onmousemove = zoom.onmouseup = null; - zoom._zooming = false; - } - - zoom.style.display = "none"; -} - -function zoomGraphOut(img) -{ - var factor = Math.floor((img._tend - img._tbeg) / 2.5); - var now = nowTime(); - - /* If near the end we have special behavior */ - if(img._tend >= now - 300 || img._tend <= now) - { - img._tbeg -= factor; - img._tend = now; - } - else - { - factor = Math.floor(factor / 2); - img._tbeg -= factor - img._tend += factor; - } - - reloadGraph(img, true); -} - -function zoomGraphMove(img, dir) -{ - var factor = Math.floor((img._tend - img._tbeg) / 3); - if(!dir) - factor = -factor; - img._tbeg += factor; - img._tend += factor; - reloadGraph(img, true); -} - -function actionsDisplay(evt) -{ - /* COMPAT: Target is handled differently in Internet nastiness */ - var img = evt.target || evt.srcElement; - - if(img.className != "graph") - return; - - var actions = gdoc.getElementById("actions"); - - /* Disconnect from previous image */ - if(actions._img) - actions._img._actions = null; - - /* Attach to this image */ - actions._img = img; - img._actions = actions; - updateCursors(img); - - actions._display = true; - - actions.style.top = img.offsetTop; - actions.style.left = img.offsetLeft + (img.width - 16); - actions.style.display = "block"; - - actions.onmouseout = img.onmouseout = function(evt) - { return actionsHide(gwindow.event ? gwindow.event : evt); } - - /* TODO: We only actually have to do this once */ - var i, acts = actions.getElementsByTagName("img"); - for(i = 0; i < acts.length; i++) - { - acts.item(i).onclick = function(evt) - { return actionRun(gwindow.event ? gwindow.event : evt); } - } -} - -function actionsHide(evt) -{ - var actions = gdoc.getElementById("actions"); - if(!actions._display) - return; - - var x = evt.clientX + gdoc.body.scrollLeft; - var y = evt.clientY + gdoc.body.scrollTop; - var img = actions._img; - - /* See if we're actually still within the image */ - if(x >= img.offsetLeft && x <= img.offsetLeft + img.width && - y >= img.offsetTop && y <= img.offsetTop + img.height) - return; - - actions.style.display = "none"; - img.onmouseout = actions.onmouseout = null; - img._actions = null; - actions._img = null; - actions._display = false; -} - -function actionRun(evt) -{ - /* COMPAT: Target is handled differently in Internet nastiness */ - var act = evt.target || evt.srcElement; - - if(act.className != "action") - return; - - var actions = gdoc.getElementById("actions"); - if(!actions._display) - return; - - switch(act.getAttribute("id")) - { - case "action-zoom": - zoomGraphOut(actions._img); - break; - case "action-next": - zoomGraphMove(actions._img, true); - break; - case "action-prev": - zoomGraphMove(actions._img, false); - break; - case "action-goto": - actionGoto(actions._img, act); - break; - } -} - -function actionGoto(img, act) -{ - /* Display the selection thingy */ - var got = gdoc.getElementById("goto"); - - /* TODO: Make numbers constants */ - got.style.top = img.offsetTop + 40; - got.style.left = (img.offsetLeft + img.width) - 160; - got.style.width = 120; - got.style.display = "block"; - - var sel = gdoc.getElementById("goto-select"); - sel.onchange = actionGotoChange; - sel._img = img; - sel.value = null; - sel.selectedIndex = -1; -} - -function actionGotoCancel() -{ - var got = gdoc.getElementById("goto"); - got.style.display = "none"; -} - -function actionGotoChange() -{ - var sel = gdoc.getElementById("goto-select"); - var img = sel._img; - sel.onchange = null; - sel._img = null; - - times = sel.value.split(":"); - img._tbeg = nowTime() - times[0]; - img._tend = nowTime() - times[1]; - reloadGraph(img, true); - - actionGotoCancel(); -} - -/* ----------------------------------------------------------------------------- - * GROUP CATEGORIES - */ - -function findCategoryGraphs(cat) -{ - var i; - - if(!xmlData) - return null; - - var ret = new Array(); - var graphs = xmlData.getElementsByTagName("graph"); - for(i = 0; i < graphs.length; i++) - { - if(graphs.item(i).getAttribute("category") == cat) - ret.push(graphs.item(i)); - } - return ret; -} - -function changeCategory(evt) -{ - var header = evt.target || evt.srcElement; - categoryCurrent = header.getAttribute("category"); - displayCurrentPage(); -} - -function displayCategories() -{ - var cats = new Object(); - var cat, i, name; - - /* Get the template and clean it up a bit */ - var template = document.getElementById("header-template"); - - var graphs = xmlData.getElementsByTagName("graph"); - for(i = 0; i < graphs.length; i++) - { - cat = graphs.item(i).getAttribute("category"); - if(!cat) - { - cat = "Other"; - graphs.item(i).setAttribute("category", "Other"); - } - cats[cat] = true; - } - - for(name in cats) - { - if(!categoryCurrent) - categoryCurrent = name; - - var el = template.cloneNode(false); - el.removeAttribute("id"); - el.appendChild(document.createTextNode(name)); - el.setAttribute("category", name); - - el.onclick = function(evt) - { return changeCategory(evt || window.event); } - - categoryArea.insertBefore(el, template); - } -} - -/* ----------------------------------------------------------------------------- - * HELPERS - */ - -function loadXml(uri, callback) -{ - var xmlhttp; - var xmlHttpChange = function() { - if(xmlhttp.readyState == 4) - { - if(xmlhttp.status == 200) - callback(xmlhttp.responseXML); - else - callback(null); - } - } - - /* Mozilla code */ - if(window.XMLHttpRequest) - { - xmlhttp = new XMLHttpRequest(); - xmlhttp.onreadystatechange = xmlHttpChange; - xmlhttp.open("GET", uri, true); - xmlhttp.send(null); - } - - /* And now for the Nasty */ - else if (window.ActiveXObject) - { - xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); - /* TODO: need to do something when this fails (can it fail?) */ - if(xmlhttp) - { - xmlhttp.onreadystatechange = xmlHttpChange; - xmlhttp.open("GET", uri, true); - xmlhttp.send() - } - } -} - -function displayError(message, place) -{ - var el = document.createElement("span"); - el.className = "error"; - var text = document.createTextNode(message); - el.appendChild(text); - - if(place) - place.appendChild(el); - - return el; -} - -function nowTime() -{ - return Math.floor((new Date()).getTime() / 1000); -} - -function debug(msg) -{ - setTimeout(function() { throw new Error("[debug] " + msg); }, 0); -} - -function makeEndpointURI() -{ - /* TODO: This should use the scheme of the current URI */ - return "http://" + document.location.host + ENDPOINT; -} - -function cancelEvent(evt) -{ - /* COMPAT: Totally different for IE and mozilla */ - if(evt.preventDefault) - evt.preventDefault(); - if(evt.stopPropagation) - evt.stopPropagation(); - if("cancelBubble" in evt) - evt.cancelBubble = true; - if("returnValue" in evt) - evt.returnValue = false; -} diff --git a/html/style.css b/html/style.css deleted file mode 100644 index b72e4ca..0000000 --- a/html/style.css +++ /dev/null @@ -1,164 +0,0 @@ - -/* ----------------------------------------------------------------------------- - * MAIN LAYOUT - */ - -* -{ - color: #E7E1CC; - font-family: sans-serif; -} - -body -{ - background-color: #1A1A1A -} - -#main-table -{ - width: 100%; - height: 100%; - padding: 10px; -} - -#top-row -{ - height: 30pt; - padding: 0px; -} - -#main-row - { height: 100%; } - -#main-cell - { background-color: #252424; padding: 5pt; } - -#main-frame -{ - border: none; - height: 100%; - width: 100%; -} - -#logo -{ - font-size: 16pt; - font-weight: bold; -} - -/* ----------------------------------------------------------------------------- - * GROUP HEADERS - */ - -/* A group button at the top */ -.header -{ - background-color: #3D2C2C; - padding: 4pt 6pt; - font-size: 8pt; - font-weight: bold; - -moz-border-radius: 3pt; - cursor: pointer; - margin-right: 5pt; -} - -/* Our sample header (which gets copied for each group) is hidden */ -#header-template - { visibility: hidden; } - -/* ----------------------------------------------------------------------------- - * GRAPHS/FRAME - */ - -body.in-frame -{ - background-color: #252424; -} - -img.graph -{ - margin: 7px; -} - -#zoom -{ - cursor: crosshair; - position: absolute; - background-color: red; - display: none; - top: 0px; - left: 0px; - width: 10px; - height: 10px; - filter: alpha(opacity=40); - -moz-opacity: 0.5; - -khtml-opacity: 0.5; - opacity: 0.5; -} - -/* ----------------------------------------------------------------------------- - * ACTION BAR - */ - -#actions -{ - background-color: #252424; - position: absolute; - left: 50px; - top: 50px; - height: 120px; - display: none; -} - -.action -{ - margin: 3px; - cursor: pointer; - - /* COMPAT: IE doesn't support :hover on anything but links - so transparency has no use whatsover */ - - -moz-opacity: 0.75; - -khtml-opacity: 0.75; - opacity: 0.75; -} - -img.action:hover -{ - -moz-opacity: 1; - -khtml-opacity: 1; - opacity: 1; -} - -#goto -{ - position: absolute; - padding: 10px; - top: 0px; - left: 0px; - background-color: #252424; - display: none; -} - -#goto-select -{ - border: 1px solid black; - font-size: 8pt; - font-weight: normal; - width: 120px; - background-color: #252424; -} - -/* ----------------------------------------------------------------------------- - * MISC - */ - -.error -{ - background-color: #F3BDBD; - border: 1px solid red; - padding: 3pt; - font-size: 8pt; - color: black; -} - diff --git a/tools/Makefile.am b/tools/Makefile.am index 8863b29..ed8519b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,5 +1,5 @@ -bin_PROGRAMS = rrdui-cgi +libexec_PROGRAMS = rrdui-cgi rrdui_cgi_SOURCES = rrdui-cgi.c \ -- cgit v1.2.3