')
- .addClass((this.parent) ? 'child-of-entity-' + this.parent.uuid : '')
+ .addClass((parent) ? 'child-of-entity-' + parent.uuid : '')
.addClass((this.definition.model == 'Volkszaehler\\Model\\Aggregator') ? 'aggregator' : 'channel')
+ .addClass('entity')
.attr('id', 'entity-' + this.uuid)
.append($('')
.addClass('visibility')
@@ -170,82 +251,62 @@ Entity.prototype.getRow = function() {
)
)
.data('entity', this);
-
- if (vz.uuids.contains(this.uuid)) { // removable from cookies?
+
+ if (this.cookie) {
$('td.ops', row).prepend($(' ')
.attr('type', 'image')
.attr('src', 'images/delete.png')
.attr('alt', 'delete')
.bind('click', this, function(event) {
- vz.uuids.remove(event.data.uuid);
- vz.uuids.save();
-
vz.entities.remove(event.data);
+ vz.entities.saveCookie();
vz.entities.showTable();
-
vz.wui.drawPlot();
})
);
}
-
+
return row;
};
-Entity.prototype.loadData = function() {
- return vz.load({
- controller: 'data',
- identifier: this.uuid,
- context: this,
- data: {
- from: Math.floor(vz.options.plot.xaxis.min),
- to: Math.ceil(vz.options.plot.xaxis.max),
- tuples: vz.options.tuples
- },
- success: function(json) {
- this.data = json.data;
-
- var year = 60*60*24*365*1000; /* in seconds */
- var delta = this.data.to - this.data.from;
+Entity.prototype.updateDOMRow = function() {
+ var row = $('#entity-' + this.uuid);
+
+ var delta = this.data.to - this.data.from;
+ var year = 365*24*60*60*1000;
+
+ if (this.data.count > 0) { // update statistics if data available
+ $('.min', row)
+ .text(vz.wui.formatNumber(this.data.min[1], true) + this.definition.unit)
+ .attr('title', $.plot.formatDate(new Date(this.data.min[0]), '%d. %b %y %h:%M:%S', vz.options.plot.xaxis.monthNames));
+ $('.max', row)
+ .text(vz.wui.formatNumber(this.data.max[1], true) + this.definition.unit)
+ .attr('title', $.plot.formatDate(new Date(this.data.max[0]), '%d. %b %y %h:%M:%S', vz.options.plot.xaxis.monthNames));
+ $('.average', row)
+ .text(vz.wui.formatNumber(this.data.average, true) + this.definition.unit);
+ $('.last', row)
+ .text(vz.wui.formatNumber(this.data.tuples.last()[1], true) + this.definition.unit);
- if (this.data.count > 0) {
- if (this.data.min[1] < vz.options.plot.yaxis.min) { // allow negative values for temperature sensors
- vz.options.plot.yaxis.min = null;
- }
-
- // update details in table
- $('#entity-' + this.uuid + ' .min')
- .text(vz.wui.formatNumber(this.data.min[1]) + ' ' + this.definition.unit)
- .attr('title', $.plot.formatDate(new Date(this.data.min[0] + vz.options.timezoneOffset), '%d. %b %h:%M:%S', vz.options.plot.xaxis.monthNames));
- $('#entity-' + this.uuid + ' .max')
- .text(vz.wui.formatNumber(this.data.max[1]) + ' ' + this.definition.unit)
- .attr('title', $.plot.formatDate(new Date(this.data.max[0] + vz.options.timezoneOffset), '%d. %b %h:%M:%S', vz.options.plot.xaxis.monthNames));
- $('#entity-' + this.uuid + ' .average')
- .text(vz.wui.formatNumber(this.data.average) + ' ' + this.definition.unit);
- $('#entity-' + this.uuid + ' .last')
- .text(vz.wui.formatNumber(this.data.tuples.last()[1]) + ' ' + this.definition.unit);
- if (this.definition.interpreter == 'Volkszaehler\\Interpreter\\MeterInterpreter') { // sensors have no consumption
- $('#entity-' + this.uuid + ' .consumption')
- .text(vz.wui.formatNumber((this.data.consumption > 1000) ? this.data.consumption / 1000 : this.data.consumption) +
- ((this.data.consumption > 1000) ? ' k' : ' ') + this.definition.unit + 'h')
- .attr('title', vz.wui.formatNumber((this.data.consumption * (year/delta) > 1000) ? (this.data.consumption * (year/delta)) / 1000 : this.data.consumption * (year/delta)) +
- ((this.data.consumption * (year/delta) > 1000) ? ' k' : ' ') + this.definition.unit + 'h' + '/Jahr');
- }
- if (this.cost !== undefined) {
- $('#entity-' + this.uuid + ' .cost')
- .text(vz.wui.formatNumber(this.cost * this.data.consumption) + ' €')
- .attr('title', vz.wui.formatNumber(this.cost * this.data.consumption * (year/delta)) + ' €/Jahr');
- }
- }
- else { // no data available, clear table
- $('#entity-' + this.uuid + ' .min').text('').attr('title', '');
- $('#entity-' + this.uuid + ' .max').text('').attr('title', '');
- $('#entity-' + this.uuid + ' .average').text('');
- $('#entity-' + this.uuid + ' .last').text('');
- $('#entity-' + this.uuid + ' .consumption').text('');
- $('#entity-' + this.uuid + ' .cost').text('');
- }
+ if (this.definition.interpreter == 'Volkszaehler\\Interpreter\\MeterInterpreter') { // sensors have no consumption
+ $('.consumption', row)
+ .text(vz.wui.formatNumber(this.data.consumption, true) + this.definition.unit + 'h')
+ .attr('title', vz.wui.formatNumber(this.data.consumption * (year/delta), true) + this.definition.unit + 'h' + '/Jahr');
}
- });
+
+ if (this.cost) {
+ $('.cost', row)
+ .text(vz.wui.formatNumber(this.cost * this.data.consumption) + ' €')
+ .attr('title', vz.wui.formatNumber(this.cost * this.data.consumption * (year/delta)) + ' €/Jahr');
+ }
+ }
+ else { // no data available, clear table
+ $('.min', row).text('').attr('title', '');
+ $('.max', row).text('').attr('title', '');
+ $('.average', row).text('');
+ $('.last', row).text('');
+ $('.consumption', row).text('');
+ $('.cost', row).text('');
+ }
};
/**
@@ -255,10 +316,11 @@ Entity.prototype.addChild = function(child) {
if (this.definition.model != 'Volkszaehler\\Model\\Aggregator') {
throw new Exception('EntityException', 'Entity is not an Aggregator');
}
-
+
return vz.load({
controller: 'group',
identifier: this.uuid,
+ url: this.middleware,
data: {
uuid: child.uuid
},
@@ -273,6 +335,7 @@ Entity.prototype.removeChild = function(child) {
return vz.load({
controller: 'group',
identifier: this.uuid,
+ url: this.middleware,
data: {
uuid: child.uuid,
operation: 'delete'
@@ -280,38 +343,19 @@ Entity.prototype.removeChild = function(child) {
});
};
-/**
- * Validate Entity for required and optional properties and their values
- *
- * @return boolean
- * @todo implement/test
- */
-Entity.prototype.validate = function() {
- this.definition.required.each(function(index, property) {
- var propertyDefinition = vz.capabilities.definitions.get('properties', property);
- if (!validateProperty(property, form.elements[property.name].value)) {
- throw new Exception('EntityException', 'Invalid property: ' + property.name + ' = ' + form.elements[property.name].value);
- }
- });
-
- entity.optional.each(function(index, property) {
- var property = getDefinition(properties, property);
- });
-
- return true;
-};
-
/**
* Calls the callback function for the entity and all nested children
*
* @param cb callback function
*/
-Entity.prototype.each = function(cb) {
- cb(this, this.parent);
-
+Entity.prototype.each = function(cb, recursive) {
if (this.children) {
for (var i = 0; i < this.children.length; i++) {
- this.children[i].each(cb, this); // call recursive
+ cb(this.children[i], this);
+
+ if (recursive) {
+ this.children[i].each(cb, true); // call recursive
+ }
}
}
};
diff --git a/htdocs/frontend/javascripts/functions.js b/htdocs/frontend/javascripts/functions.js
index 70b700a..8e9a785 100644
--- a/htdocs/frontend/javascripts/functions.js
+++ b/htdocs/frontend/javascripts/functions.js
@@ -24,13 +24,20 @@
* volkszaehler.org. If not, see .
*/
+var Exception = function(type, message, code) {
+ return {
+ type: type,
+ message: message,
+ code: code
+ };
+}
+
/**
* Universal helper for middleware ajax requests with error handling
*/
vz.load = function(args) {
$.extend(args, {
- url: this.options.middlewareUrl,
- dataType: 'json',
+ accepts: 'application/json',
error: function(xhr) {
try {
if (xhr.getResponseHeader('Content-type') == 'application/json') {
@@ -40,8 +47,9 @@ vz.load = function(args) {
throw new Exception(json.exception.type, json.exception.message, (json.exception.code) ? json.exception.code : xhr.status);
}
}
-
- throw new Exception(xhr.statusText, 'Unknown middleware response', xhr.status)
+ else {
+ throw new Exception(xhr.statusText, 'Unknown middleware response', xhr.status)
+ }
}
catch (e) {
vz.wui.dialogs.exception(e);
@@ -49,14 +57,28 @@ vz.load = function(args) {
}
});
- if (args.controller) {
+ if (args.url === undefined) { // local middleware by default
+ args.url = vz.middleware[0].url;
+ }
+
+ if (args.url == vz.middleware[0].url) { // local request
+ args.dataType = 'json';
+ }
+ else { // remote request
+ args.dataType = 'jsonp';
+ args.jsonp = 'padding';
+ }
+
+ if (args.controller !== undefined) {
args.url += '/' + args.controller;
}
- if (args.identifier) {
+
+ if (args.identifier !== undefined) {
args.url += '/' + args.identifier;
}
+
args.url += '.json';
-
+
return $.ajax(args);
};
@@ -65,14 +87,18 @@ vz.load = function(args) {
*/
vz.parseUrlParams = function() {
var vars = $.getUrlParams();
+ var uuids = new Array;
+ var save = false;
+
for (var key in vars) {
if (vars.hasOwnProperty(key)) {
switch (key) {
case 'uuid': // add optional uuid from url
- var uuids = (typeof vars[key] == 'string') ? [vars[key]] : vars[key]; // handle multiple uuids
- uuids.each(function(index, uuid) {
- try { vz.uuids.add(uuid); } catch (exception) { /* ignore exception */ }
- });
+ uuids = (typeof vars[key] == 'string') ? [vars[key]] : vars[key]; // handle multiple uuids
+ break;
+
+ case 'save': // save new uuids in cookie
+ save = true;
break;
case 'from':
@@ -85,6 +111,22 @@ vz.parseUrlParams = function() {
}
}
}
+
+ uuids.each(function(index, uuid) {
+ try {
+ vz.entities.push(new Entity({
+ middleware: vz.middleware[0].url,
+ uuid: uuid,
+ cookie: save
+ }));
+ } catch (exception) {
+ /* ignore exception */
+ }
+ });
+
+ if (save) {
+ vz.entities.saveCookie();
+ }
};
/**
diff --git a/htdocs/frontend/javascripts/init.js b/htdocs/frontend/javascripts/init.js
index fdf8667..608bc44 100644
--- a/htdocs/frontend/javascripts/init.js
+++ b/htdocs/frontend/javascripts/init.js
@@ -32,8 +32,10 @@
* we dont want to pollute the global namespace
*/
var vz = {
- // entity properties + data
- entities: new Array, // TODO new Entity?
+ entities: new Array, // entity properties + data
+ middleware: [{ // default middleware
+ url: '../middleware.php',
+ }],
// web user interface
wui: {
@@ -41,17 +43,14 @@ var vz = {
timeout: null
},
- // known UUIDs in the browser
- uuids: new Array,
-
- // flot instance
- plot: { },
-
// debugging and runtime information from middleware
capabilities: {
definitions: { } // definitions of entities & properties
},
-
+
+ // flot instance
+ plot: { },
+
// options loaded from cookies in options.js
options: { }
};
@@ -72,15 +71,15 @@ $(document).ready(function() {
vz.wui.dialogs.error('Javascript Runtime Error', errorMsg);
};
- vz.uuids.load(); // load uuids from cookie
- vz.options.load(); // load options from cookie
+ vz.entities.loadCookie(); // load uuids from cookie
+ vz.options.loadCookies(); // load options from cookie
vz.parseUrlParams(); // parse additional url params (new uuid etc..)
// initialize user interface
vz.wui.init();
vz.wui.initEvents();
- if (vz.uuids.length == 0) {
+ if (vz.entities.length == 0) {
$('#entity-add').dialog('open');
}
@@ -90,7 +89,12 @@ $(document).ready(function() {
$('#snapshot').show();
}
- vz.entities.loadDetails().done(function(a, b, c, d) {
+ var queue = new Array;
+ vz.entities.each(function(entity) {
+ queue.push(entity.loadDetails());
+ }, true);
+
+ $.when.apply($, queue).done(function() {
vz.entities.showTable();
vz.entities.loadData().done(vz.wui.drawPlot);
});
diff --git a/htdocs/frontend/javascripts/jquery/jquery-treeTable.js b/htdocs/frontend/javascripts/jquery/jquery-treeTable.js
index 70c52c4..2731b24 100644
--- a/htdocs/frontend/javascripts/jquery/jquery-treeTable.js
+++ b/htdocs/frontend/javascripts/jquery/jquery-treeTable.js
@@ -1,8 +1,8 @@
/*
- * jQuery treeTable Plugin 2.3.0
- * http://ludo.cubicphuse.nl/jquery-plugins/treeTable/
+ * jQuery treeTable Plugin unreleased
+ * http://ludo.cubicphuse.nl/jquery-plugins/treeTable/doc/
*
- * Copyright 2010, Ludo van den Boom
+ * Copyright 2011, Ludo van den Boom
* Dual licensed under the MIT or GPL Version 2 licenses.
*/
(function($) {
@@ -11,21 +11,21 @@
// trees on a page. The options shouldn't be global to all these instances!
var options;
var defaultPaddingLeft;
-
+
$.fn.treeTable = function(opts) {
options = $.extend({}, $.fn.treeTable.defaults, opts);
-
+
return this.each(function() {
$(this).addClass("treeTable").find("tbody tr").each(function() {
// Initialize root nodes only if possible
if(!options.expandable || $(this)[0].className.search(options.childPrefix) == -1) {
// To optimize performance of indentation, I retrieve the padding-left
- // value of the first root node. This way I only have to call +css+
+ // value of the first root node. This way I only have to call +css+
// once.
if (isNaN(defaultPaddingLeft)) {
defaultPaddingLeft = parseInt($($(this).children("td")[options.treeColumn]).css('padding-left'), 10);
}
-
+
initialize($(this));
} else if(options.initialState == "collapsed") {
this.style.display = "none"; // Performance! $(this).hide() is slow...
@@ -33,46 +33,51 @@
});
});
};
-
+
$.fn.treeTable.defaults = {
childPrefix: "child-of-",
clickableNodeNames: false,
expandable: true,
indent: 19,
initialState: "collapsed",
+ onNodeShow: null,
treeColumn: 0
};
-
+
// Recursively hide all node's children in a tree
$.fn.collapse = function() {
$(this).addClass("collapsed");
-
+
childrenOf($(this)).each(function() {
if(!$(this).hasClass("collapsed")) {
$(this).collapse();
}
-
+
this.style.display = "none"; // Performance! $(this).hide() is slow...
});
-
+
return this;
};
-
+
// Recursively show all node's children in a tree
$.fn.expand = function() {
$(this).removeClass("collapsed").addClass("expanded");
-
+
childrenOf($(this)).each(function() {
initialize($(this));
-
+
if($(this).is(".expanded.parent")) {
$(this).expand();
}
-
+
// this.style.display = "table-row"; // Unfortunately this is not possible with IE :-(
$(this).show();
+
+ if($.isFunction(options.onNodeShow)) {
+ options.onNodeShow.call();
+ }
});
-
+
return this;
};
@@ -82,7 +87,7 @@
initialize($(this));
$(this).expand().show();
});
-
+
return this;
};
@@ -90,9 +95,9 @@
$.fn.appendBranchTo = function(destination) {
var node = $(this);
var parent = parentOf(node);
-
+
var ancestorNames = $.map(ancestorsOf($(destination)), function(a) { return a.id; });
-
+
// Conditions:
// 1: +node+ should not be inserted in a location in a branch if this would
// result in +node+ being an ancestor of itself.
@@ -102,22 +107,22 @@
// 3: +node+ should not be inserted as a child of +node+ itself.
if($.inArray(node[0].id, ancestorNames) == -1 && (!parent || (destination.id != parent[0].id)) && destination.id != node[0].id) {
indent(node, ancestorsOf(node).length * options.indent * -1); // Remove indentation
-
+
if(parent) { node.removeClass(options.childPrefix + parent[0].id); }
-
+
node.addClass(options.childPrefix + destination.id);
move(node, destination); // Recursively move nodes to new location
indent(node, ancestorsOf(node).length * options.indent);
}
-
+
return this;
};
-
+
// Add reverse() function from JS Arrays
$.fn.reverse = function() {
return this.pushStack(this.get().reverse(), arguments);
};
-
+
// Toggle an entire branch
$.fn.toggleBranch = function() {
if($(this).hasClass("collapsed")) {
@@ -125,12 +130,12 @@
} else {
$(this).removeClass("expanded").collapse();
}
-
+
return this;
};
-
+
// === Private functions
-
+
function ancestorsOf(node) {
var ancestors = [];
while(node = parentOf(node)) {
@@ -138,47 +143,47 @@
}
return ancestors;
};
-
+
function childrenOf(node) {
return $("table.treeTable tbody tr." + options.childPrefix + node[0].id);
};
-
+
function getPaddingLeft(node) {
var paddingLeft = parseInt(node[0].style.paddingLeft, 10);
return (isNaN(paddingLeft)) ? defaultPaddingLeft : paddingLeft;
}
-
+
function indent(node, value) {
var cell = $(node.children("td")[options.treeColumn]);
cell[0].style.paddingLeft = getPaddingLeft(cell) + value + "px";
-
+
childrenOf(node).each(function() {
indent($(this), value);
});
};
-
+
function initialize(node) {
if(!node.hasClass("initialized")) {
node.addClass("initialized");
-
+
var childNodes = childrenOf(node);
-
+
if(!node.hasClass("parent") && childNodes.length > 0) {
node.addClass("parent");
}
-
+
if(node.hasClass("parent")) {
var cell = $(node.children("td")[options.treeColumn]);
var padding = getPaddingLeft(cell) + options.indent;
-
+
childNodes.each(function() {
$(this).children("td")[options.treeColumn].style.paddingLeft = padding + "px";
});
-
+
if(options.expandable) {
cell.prepend(' ');
$(cell[0].firstChild).click(function() { node.toggleBranch(); });
-
+
if(options.clickableNodeNames) {
cell[0].style.cursor = "pointer";
$(cell).click(function(e) {
@@ -188,7 +193,7 @@
}
});
}
-
+
// Check for a class set explicitly by the user, otherwise set the default class
if(!(node.hasClass("expanded") || node.hasClass("collapsed"))) {
node.addClass(options.initialState);
@@ -201,19 +206,21 @@
}
}
};
-
+
function move(node, destination) {
node.insertAfter(destination);
childrenOf(node).reverse().each(function() { move($(this), node[0]); });
};
-
+
function parentOf(node) {
var classNames = node[0].className.split(' ');
-
- for(key in classNames) {
+
+ for(var key=0; key
- * @author Justin Otherguy
- * @author Steffen Vogel
- * @copyright Copyright (c) 2011, The volkszaehler.org project
- * @package default
- * @license http://opensource.org/licenses/gpl-license.php GNU Public License
- */
-/*
- * This file is part of volkzaehler.org
- *
- * volkzaehler.org is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or any later version.
- *
- * volkzaehler.org is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along with
- * volkszaehler.org. If not, see .
- */
-
-/**
- * Add given UUID and update cookie
- */
-vz.uuids.add = function(uuid) {
- if (this.validate(uuid)) {
- if (!this.contains(uuid)) {
- this.push(uuid);
- }
- else {
- throw new Exception('UUIDException', 'UUID already added: ' + uuid);
- }
- }
- else {
- throw new Exception('UUIDException', 'Invalid UUID');
- }
-};
-
-/**
- * Remove UUID and update cookie
- */
-vz.uuids.remove = function(uuid) {
- if (this.contains(uuid)) {
- this.splice(this.indexOf(uuid), 1); // remove uuid from array
- }
- else {
- throw new Exception('UUIDException', 'Unknown UUID: ' + uuid);
- }
-};
-
-/**
- * Validate UUID
- */
-vz.uuids.validate = function(uuid) {
- return uuid.match(/^[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}$/);
-};
-
-/**
- * Save uuids as cookie
- */
-vz.uuids.save = function() {
- var expires = new Date(new Date().getTime() + 31536e6); // expires in a year
- $.setCookie('vz_uuids', this.join(';'), {expires: expires});
-};
-
-/**
- * Load uuids from cookie
- */
-vz.uuids.load = function() {
- var cookie = $.getCookie('vz_uuids');
- if (cookie) {
- cookie.split(';').each(function(index, uuid) {
- vz.uuids.add(uuid);
- });
- }
-};
diff --git a/htdocs/frontend/javascripts/wui.js b/htdocs/frontend/javascripts/wui.js
index 02850f5..b71bb46 100644
--- a/htdocs/frontend/javascripts/wui.js
+++ b/htdocs/frontend/javascripts/wui.js
@@ -28,6 +28,8 @@
* Initialize the WUI (Web User Interface)
*/
vz.wui.init = function() {
+ vz.options.tuples = Math.round($('#flot').width() / 3);
+
// initialize dropdown accordion
$('#accordion h3').click(function() {
$(this).next().toggle('fast');
@@ -37,7 +39,7 @@ vz.wui.init = function() {
// buttons
$('button, input[type=button],[type=image],[type=submit]').button();
- $('button[name=options-save]').click(vz.options.save);
+ $('button[name=options-save]').click(vz.options.saveCookies);
$('button[name=entity-add]').click(this.dialogs.init);
$('#permalink').click(function() { window.location = vz.wui.getPermalink(); });
$('#snapshot').click(function() { window.location = vz.wui.getSnaplink(); }).hide();
@@ -46,20 +48,6 @@ vz.wui.init = function() {
$('#controls button').click(this.handleControls);
$('#controls').buttonset();
- // tuple resolution
- vz.options.tuples = Math.round($('#flot').width() / 4);
- $('#tuples').val(vz.options.tuples).change(function() {
- vz.options.tuples = $(this).val();
- vz.entities.loadData().done(vz.wui.drawPlot);
- });
-
- // middleware address
- $('#middleware-url')
- .val(vz.options.middlewareUrl)
- .change(function() {
- vz.options.middlewareUrl = $(this).val();
- });
-
// auto refresh
if (vz.options.refresh) {
$('#refresh').attr('checked', true);
@@ -102,7 +90,8 @@ vz.wui.dialogs.init = function() {
controller: 'entity',
success: function(json) {
if (json.entities.length > 0) {
- json.entities.each(function(index, entity) {
+ json.entities.each(function(index, json) {
+ var entity = new Entity(json);
$('#entity-subscribe-public select#public').append(
$('').html(entity.title).data('entity', entity)
);
@@ -119,25 +108,20 @@ vz.wui.dialogs.init = function() {
});
$('#entity-create option[value=power]').attr('selected', 'selected');
- /*$('#entity-create select[name=type] option:selected').data('definition').required.each(function(index, property) {
- $('#entity-create #properties').append(
- vz.capabilities.definitions.get('properties', property).getDOM()
- )
- });*/
-
- $('#entity-create-middlware').val(vz.options.middlewareUrl);
+ $('#entity-create-middleware').val(vz.middleware[0].url);
// actions
$('#entity-subscribe input[type=button]').click(function() {
try {
- var uuid = $('#entity-subscribe input#uuid');
- vz.uuids.add(uuid.val());
-
- if ($('#entity-subscribe input.cookie').attr('checked')) {
- vz.uuids.save();
- }
+ var entity = new Entity({
+ uuid: $('#entity-subscribe input#uuid').val(),
+ middleware: $('#entity-subscribe input#middleware').val(),
+ cookie: Boolean($('#entity-subscribe input.cookie').attr('checked'))
+ });
- vz.entities.loadDetails().done(function() {
+ entity.loadDetails().done(function() {
+ vz.entities.push(entity);
+ vz.entities.saveCookie();
vz.entities.showTable();
vz.entities.loadData().done(vz.wui.drawPlot);
}); // reload entity details and load data
@@ -147,8 +131,6 @@ vz.wui.dialogs.init = function() {
}
finally {
$('#entity-add').dialog('close');
- $('#entity-add input[type!=button]').val(''); // reset form
- $('#entity-add input.cookie').attr('checked', false); // reset form
}
});
@@ -156,24 +138,19 @@ vz.wui.dialogs.init = function() {
var entity = $('#entity-subscribe-public select#public option:selected').data('entity');
try {
- vz.uuids.add(entity.uuid);
-
- if ($('#entity-subscribe-public input.cookie').attr('checked')) {
- vz.uuids.save();
- }
+ entity.cookie = Boolean($('#entity-subscribe-public input.cookie').attr('checked'));
+ entity.middleware = vz.middleware[0].url;
- vz.entities.loadDetails().done(function() {
- vz.entities.showTable();
- vz.entities.loadData().done(vz.wui.drawPlot);
- }); // reload entity details and load data
+ vz.entities.push(entity);
+ vz.entities.saveCookie();
+ vz.entities.showTable();
+ vz.entities.loadData().done(vz.wui.drawPlot);
}
catch (e) {
vz.wui.dialogs.exception(e);
}
finally {
$('#entity-add').dialog('close');
- $('#entity-add input[type!=button]').val(''); // reset form
- $('#entity-add input.cookie').attr('checked', false); // reset form
}
});
@@ -200,7 +177,7 @@ vz.wui.getPermalink = function() {
if (entity.active && entity.definition.model == 'Volkszaehler\\Model\\Channel') {
uuids.push(entity.uuid);
}
- });
+ }, true); // recursive!
var params = $.param({
from: Math.floor(vz.options.plot.xaxis.min),
@@ -222,7 +199,7 @@ vz.wui.getSnaplink = function() {
if (entity.active) {
uuids.push(entity.uuid);
}
- });
+ }, true); // recursive!
return vz.options.middlewareUrl + '/data/' + uuids[0] + '.png?' + $.param({
from: Math.floor(vz.options.plot.xaxis.min),
@@ -404,169 +381,30 @@ vz.wui.clearTimeout = function(text) {
* therefore "vz.options.precision" needs
* to be set to 1 (for 1 decimal) in that case
*/
-vz.wui.formatNumber = function(number) {
- return Math.round(number * Math.pow(10, vz.options.precision)) / Math.pow(10, vz.options.precision);
+vz.wui.formatNumber = function(number, prefix) {
+ var siPrefixes = ['k', 'M', 'G', 'T'];
+ var siIndex = 0;
+
+ while (prefix && number > 1000 && siIndex < siPrefixes.length-1) {
+ number /= 1000;
+ siIndex++;
+ }
+
+ number = Math.round(number * Math.pow(10, vz.options.precision)) / Math.pow(10, vz.options.precision); // rounding
+
+ if (prefix) {
+ number += (siIndex > 0) ? ' ' + siPrefixes[siIndex-1] : ' ';
+ }
+
+ return number;
}
vz.wui.updateHeadline = function() {
- var from = $.plot.formatDate(new Date(vz.options.plot.xaxis.min + vz.options.timezoneOffset), '%d. %b %y %h:%M', vz.options.plot.xaxis.monthNames);
- var to = $.plot.formatDate(new Date(vz.options.plot.xaxis.max + vz.options.timezoneOffset), '%d. %b %y %h:%M', vz.options.plot.xaxis.monthNames);
+ var from = $.plot.formatDate(new Date(vz.options.plot.xaxis.min), '%d. %b %y %h:%M', vz.options.plot.xaxis.monthNames);
+ var to = $.plot.formatDate(new Date(vz.options.plot.xaxis.max), '%d. %b %y %h:%M', vz.options.plot.xaxis.monthNames);
$('#title').html(from + ' - ' + to);
}
-/**
- * Overwritten each iterator to iterate recursively throug all entities
- */
-vz.entities.each = function(cb) {
- for (var i = 0; i < this.length; i++) {
- this[i].each(cb);
- }
-}
-
-/**
- * Get all entity information from middleware
- */
-vz.entities.loadDetails = function() {
- this.clear();
-
- var queue = new Array;
-
- vz.uuids.each(function(index, uuid) {
- queue.push(vz.load({
- controller: 'entity',
- identifier: uuid,
- success: function(json) {
- vz.entities.push(new Entity(json.entity));
- }
- }));
- });
-
- return $.when.apply($, queue);
-};
-
-/**
- * Create nested entity list
- *
- * @todo move to Entity class
- */
-vz.entities.showTable = function() {
- $('#entity-list tbody').empty();
-
- vz.entities.sort(Entity.compare);
-
- var c = 0; // for colors
- vz.entities.each(function(entity, parent) {
- entity.color = vz.options.plot.colors[c++ % vz.options.plot.colors.length];
-
- $('#entity-list tbody').append(entity.getRow());
- });
-
- /*
- * Initialize treeTable
- *
- * http://ludo.cubicphuse.nl/jquery-plugins/treeTable/doc/index.html
- * https://github.com/ludo/jquery-plugins/tree/master/treeTable
- */
- // configure entities as draggable
- $('#entity-list tr.channel span.indicator, #entity-list tr.aggregator span.indicator').draggable({
- helper: 'clone',
- opacity: .75,
- refreshPositions: true, // Performance?
- revert: 'invalid',
- revertDuration: 300,
- scroll: true
- });
-
- // configure aggregators as droppable
- $('#entity-list tr.aggregator span.indicator').each(function() {
- $(this).parents('tr').droppable({
- //accept: 'tr.channel span.indicator, tr.aggregator span.indicator', // TODO
- drop: function(event, ui) {
- var child = $(ui.draggable.parents('tr')[0]).data('entity');
- var from = child.parent;
- var to = $(this).data('entity');
-
- $('#entity-move').dialog({ // confirm prompt
- resizable: false,
- modal: true,
- title: 'Verschieben',
- width: 400,
- buttons: {
- 'Verschieben': function() {
- try {
- var queue = new Array;
- queue.push(to.addChild(child)); // add to new aggregator
-
- if (from !== undefined) {
- queue.push(from.removeChild(child)); // remove from aggregator
- }
- else {
- vz.uuids.remove(child.uuid); // remove from cookies
- vz.uuids.save();
- }
- } catch (e) {
- vz.wui.dialogs.exception(e);
- } finally {
- $.when(queue).done(function() {
- // wait for middleware
- vz.entities.loadDetails().done(vz.entities.showTable);
- });
- $(this).dialog('close');
- }
- },
- 'Abbrechen': function() {
- $(this).dialog('close');
- }
- }
- });
- },
- hoverClass: 'accept',
- over: function(event, ui) {
- // make the droppable branch expand when a draggable node is moved over it
- if (this.id != $(ui.draggable.parents('tr')[0]).id && !$(this).hasClass('expanded')) {
- $(this).expand();
- }
- }
- });
- });
-
- // make visible that a row is clicked
- $('#entity-list table tbody tr').mousedown(function() {
- $('tr.selected').removeClass('selected'); // deselect currently selected rows
- $(this).addClass('selected');
- });
-
- // make sure row is selected when span is clicked
- $('#entity-list table tbody tr span').mousedown(function() {
- $($(this).parents('tr')[0]).trigger('mousedown');
- });
-
- $('#entity-list table').treeTable({
- treeColumn: 2,
- clickableNodeNames: true,
- initialState: 'expanded'
- });
-};
-
-/**
- * Load json data from the middleware
- *
- * @todo move to Entity class
- */
-vz.entities.loadData = function() {
- $('#overlay').html('loading...
');
-
- var queue = new Array;
-
- vz.entities.each(function(entity) {
- if (entity.active && entity.definition.model == 'Volkszaehler\\Model\\Channel') {
- queue.push(entity.loadData());
- }
- });
-
- return $.when.apply($, queue);
-};
-
/**
* Draws plot to container
*/
@@ -588,7 +426,7 @@ vz.wui.drawPlot = function () {
series.push(serie);
}
- });
+ }, true); // recursive!
if (series.length == 0) {
$('#overlay').html('nothing to plot...
');
@@ -612,14 +450,6 @@ vz.wui.drawPlot = function () {
/*
* Error & Exception handling
*/
-
-var Exception = function(type, message, code) {
- return {
- type: type,
- message: message,
- code: code
- };
-}
vz.wui.dialogs.error = function(error, description, code) {
if (code !== undefined) {
diff --git a/htdocs/frontend/stylesheets/style.css b/htdocs/frontend/stylesheets/style.css
index 7f22f17..e514940 100644
--- a/htdocs/frontend/stylesheets/style.css
+++ b/htdocs/frontend/stylesheets/style.css
@@ -11,14 +11,18 @@ table {
width: 100%;
}
-thead tr th {
+tr th {
border-bottom: 2px solid grey;
text-align: left;
font-size: 0.9em;
}
-tbody tr td {
+tr.property td {
+ border-top: 1px solid #A7A7A7;
+}
+
+tr.entity td {
border-top: 1px solid #A7A7A7;
}
diff --git a/lib/View/JSON.php b/lib/View/JSON.php
index 590b2e2..6583af3 100644
--- a/lib/View/JSON.php
+++ b/lib/View/JSON.php
@@ -94,7 +94,7 @@ class JSON extends View {
$json = $this->json->encode((Util\Debug::isActivated()) ? JSON_PRETTY : 0);
if ($this->padding) {
- $json = 'if (' . $this->padding . ') { ' . $this->padding . '(' . $json . '); }';
+ $json = $this->padding . '(' . $json . ');';
}
echo $json;
}