')
- .addClass((parent) ? 'child-of-entity-' + parent.uuid : '')
- .attr('id', 'entity-' + entity.uuid)
- .append($('')
- .addClass('visibility')
- .css('background-color', entity.color)
- .append($('')
- .attr('type', 'checkbox')
- .attr('checked', entity.active)
- .bind('change', entity, function(event) {
- var state = $(this).attr('checked');
- event.data.active = state;
-
- if (entity.type == 'group') {
- entity.children.each(function(child) {
- $('#entity-' + child.uuid + '.child-of-entity-' + entity.uuid + ' input[type=checkbox]').attr('checked', state);
- child.active = state;
- });
- }
-
- vz.drawPlot();
- })
- )
- )
- .append($(' | ').addClass('expander'))
- .append($(' | ')
- .append($('')
- .text(entity.title)
- .addClass('indicator')
- .addClass((entity.type == 'group') ? 'group' : 'channel')
- )
- )
- .append($(' | ').text(vz.capabilities.definitions.get('entities', entity.type).translation[vz.options.language])) // channel type
- .append($(' | ').addClass('min')) // min
- .append($(' | ').addClass('max')) // max
- .append($(' | ').addClass('average')) // avg
- .append($(' | ').addClass('consumption')) // consumption
- .append($(' | ').addClass('last')) // last
- .append($(' | ') // operations
- .addClass('ops')
- .append($('')
- .attr('type', 'image')
- .attr('src', 'images/information.png')
- .attr('alt', 'details')
- .bind('click', entity, function(event) { event.data.showDetails(); })
- )
- );
-
- if (parent == null) {
- $('td.ops', row).prepend($('')
- .attr('type', 'image')
- .attr('src', 'images/delete.png')
- .attr('alt', 'delete')
- .bind('click', entity, function(event) {
- vz.uuids.remove(event.data.uuid);
- vz.uuids.save();
- vz.entities.loadDetails();
- })
- );
- }
-
- $('#entity-list tbody').append(row);
- });
-
- // http://ludo.cubicphuse.nl/jquery-plugins/treeTable/doc/index.html
- $('#entity-list table').treeTable({
- treeColumn: 2,
- clickableNodeNames: true
- });
-
- // load data and show plot
- vz.entities.loadData();
-};
-
-/**
- * Overwritten each iterator for entity array
- */
-vz.entities.each = function(cb) {
- for (var i = 0; i < this.length; i++) {
- this[i].each(cb);
- }
-}
-
-/**
- * Load json data from the backend
- */
-vz.entities.loadData = function() {
- vz.wui.updateHeadline();
- $('#overlay').html(' loading... ');
- this.each(function(entity, parent) {
- //var delta = vz.options.plot.xaxis.max - vz.options.plot.xaxis.min;
- //var offset = delta * 0.1;
- var offset = 1000*60*60; // load additional data to avoid paddings
-
- if (entity.active && entity.type != 'group') { // TODO add group data aggregation
- vz.load('data', entity.uuid,
- {
- from: Math.floor(vz.options.plot.xaxis.min - offset), // fuzy-logic to get enough data
- to: Math.ceil(vz.options.plot.xaxis.max + offset),
- tuples: vz.options.tuples
- },
- waitAsync(function(json) {
- entity.data = json.data;
-
- if (entity.data.min !== null && entity.data.min[1] < vz.options.plot.yaxis.min) { // allow negative values for temperature sensors
- vz.options.plot.yaxis.min = null;
- }
-
- // update entity table
- // TODO add units
- $('#entity-' + entity.uuid + ' .min')
- .text((entity.data.min !== null) ? vz.wui.formatNumber(entity.data.min[1]) : '-')
- .attr('title', (entity.data.min !== null) ? $.plot.formatDate(new Date(entity.data.min[0]), '%d. %b %h:%M:%S', vz.options.plot.xaxis.monthNames) : '');
- $('#entity-' + entity.uuid + ' .max')
- .text((entity.data.max !== null) ? vz.wui.formatNumber(entity.data.max[1]) : '-')
- .attr('title', (entity.data.max !== null) ? $.plot.formatDate(new Date(entity.data.max[0]), '%d. %b %h:%M:%S', vz.options.plot.xaxis.monthNames) : '');
- $('#entity-' + entity.uuid + ' .average').text((entity.data.average !== null) ? vz.wui.formatNumber(entity.data.average) : '-');
- $('#entity-' + entity.uuid + ' .consumption').text(vz.wui.formatNumber(entity.data.consumption));
- $('#entity-' + entity.uuid + ' .last').text((entity.data.tuples) ? vz.wui.formatNumber(entity.data.tuples.last()[1]) : '-');
- }, vz.drawPlot, 'data')
- );
- }
- });
-};
-
/**
* Rounding precission
*
@@ -417,12 +339,253 @@ vz.wui.updateHeadline = function() {
$('#title').text(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 backend
+ */
+vz.entities.loadDetails = function() {
+ vz.entities.clear();
+
+ vz.uuids.each(function(index, value) {
+ vz.load({
+ context: 'entity',
+ identifier: value,
+ success: vz.wait(function(json) {
+ vz.entities.push(new Entity(json.entity));
+ }, vz.entities.showTable, 'information')
+ });
+ });
+};
+
+/**
+ * Create nested entity list
+ *
+ * @todo move to Entity class
+ */
+vz.entities.showTable = function() {
+ $('#entity-list tbody').empty();
+
+ var c = 0; // for colors
+
+ vz.entities = vz.entities.sort(function(e1, e2) {
+ e1.title > e2.title;
+ });
+
+ vz.entities.each(function(entity, parent) {
+ entity.color = vz.options.plot.colors[c++ % vz.options.plot.colors.length];
+ entity.active = (entity.active) ? entity.active : true; // TODO check
+
+ var row = $(' |
')
+ .addClass((parent) ? 'child-of-entity-' + parent.uuid : '')
+ .addClass((entity.definition.model == 'Volkszaehler\\Model\\Aggregator') ? 'aggregator' : 'channel')
+ .attr('id', 'entity-' + entity.uuid)
+ .append($('')
+ .addClass('visibility')
+ .css('background-color', entity.color)
+ .append($('')
+ .attr('type', 'checkbox')
+ .attr('checked', entity.active)
+ .bind('change', function(event) {
+ var state = $(this).attr('checked');
+
+ entity.each(function(child) {
+ $('#entity-' + child.uuid + '.child-of-entity-' + entity.uuid + ' input[type=checkbox]').attr('checked', state);
+ child.active = state;
+ });
+
+ vz.wui.drawPlot();
+ })
+ )
+ )
+ .append($(' | ').addClass('expander'))
+ .append($(' | ')
+ .append($('')
+ .text(entity.title)
+ .addClass('indicator')
+ )
+ )
+ .append($(' | ').text(entity.definition.translation[vz.options.language])) // channel type
+ .append($(' | ').addClass('min')) // min
+ .append($(' | ').addClass('max')) // max
+ .append($(' | ').addClass('average')) // avg
+ .append($(' | ').addClass('consumption')) // consumption
+ .append($(' | ').addClass('last')) // last
+ .append($(' | ') // operations
+ .addClass('ops')
+ .append($('')
+ .attr('type', 'image')
+ .attr('src', 'images/information.png')
+ .attr('alt', 'details')
+ .bind('click', entity, function(event) { event.data.showDetails(); })
+ )
+ )
+ .data('entity', entity);
+
+ if (vz.uuids.contains(entity.uuid)) { // removable from cookies?
+ $('td.ops', row).prepend($('')
+ .attr('type', 'image')
+ .attr('src', 'images/delete.png')
+ .attr('alt', 'delete')
+ .bind('click', entity, function(event) {
+ vz.uuids.remove(event.data.uuid);
+ vz.uuids.save();
+ vz.entities.loadDetails();
+ })
+ );
+ }
+
+ $('#entity-list tbody').append(row);
+ });
+
+ /*
+ * 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',
+ 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 {
+ to.addChild(child); // add to new aggregator
+
+ if (typeof from != 'undefined') {
+ 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 {
+ $(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 data and show plot
+ vz.entities.loadData();
+};
+
+/**
+ * Load json data from the backend
+ *
+ * @todo move to Entity class
+ */
+vz.entities.loadData = function() {
+ $('#overlay').html(' loading... ');
+ vz.entities.each(function(entity) {
+ if (entity.active && entity.type != 'group') { // TODO add group data aggregation
+ //var delta = vz.options.plot.xaxis.max - vz.options.plot.xaxis.min;
+ //var offset = delta * 0.1;
+ var offset = 1000*60*60; // load additional data to avoid paddings
+
+ vz.load({
+ context: 'data',
+ identifier: entity.uuid,
+ data: {
+ from: Math.floor(vz.options.plot.xaxis.min - offset), // TODO fuzy-logic to get enough data
+ to: Math.ceil(vz.options.plot.xaxis.max + offset),
+ tuples: vz.options.tuples
+ },
+ success: vz.wait(function(json) {
+ entity.data = json.data;
+
+ if (entity.data.min !== null && entity.data.min[1] < vz.options.plot.yaxis.min) { // allow negative values for temperature sensors
+ vz.options.plot.yaxis.min = null;
+ }
+
+ // update entity table
+ var unit = ' ' + entity.definition.unit;
+ $('#entity-' + entity.uuid + ' .min')
+ .text(
+ (entity.data.min !== null) ? vz.wui.formatNumber(entity.data.min[1]) + unit : '-')
+ .attr('title', (entity.data.min !== null) ? $.plot.formatDate(new Date(entity.data.min[0]), '%d. %b %h:%M:%S', vz.options.plot.xaxis.monthNames) : '');
+ $('#entity-' + entity.uuid + ' .max')
+ .text((entity.data.max !== null) ? vz.wui.formatNumber(entity.data.max[1]) + unit : '-')
+ .attr('title', (entity.data.max !== null) ? $.plot.formatDate(new Date(entity.data.max[0]), '%d. %b %h:%M:%S', vz.options.plot.xaxis.monthNames) : '');
+ $('#entity-' + entity.uuid + ' .average').text((entity.data.average !== null) ? vz.wui.formatNumber(entity.data.average) + unit : '');
+ $('#entity-' + entity.uuid + ' .last').text((entity.data.tuples) ? vz.wui.formatNumber(entity.data.tuples.last()[1]) + unit : '');
+ if (entity.definition.interpreter == 'Volkszaehler\\Interpreter\\MeterInterpreter') { // sensors have no consumption
+ $('#entity-' + entity.uuid + ' .consumption').text(vz.wui.formatNumber(entity.data.consumption) + unit + 'h');
+ }
+ }, vz.wui.drawPlot, 'data')
+ });
+ }
+ });
+};
+
/**
* Draws plot to container
*/
-vz.drawPlot = function () {
+vz.wui.drawPlot = function () {
+ vz.wui.updateHeadline();
+
var data = new Array;
- vz.entities.each(function(entity, parent) {
+ vz.entities.each(function(entity) {
if (entity.active && entity.data && entity.data.tuples && entity.data.tuples.length > 0) {
data.push({
data: entity.data.tuples,
@@ -445,84 +608,20 @@ vz.drawPlot = function () {
vz.plot = $.plot($('#flot'), data, vz.options.plot);
};
-/**
- * Universal helper for backend ajax requests with error handling
- */
-vz.load = function(context, identifier, data, success) {
- $.ajax({
- success: success,
- url: this.options.backendUrl + '/' + context + '/' + identifier + '.json',
- dataType: 'json',
- data: data,
- error: function(xhr) {
- json = JSON.parse(xhr.responseText);
- vz.wui.dialogs.error(xhr.statusText, json.exception.message, xhr.status); // TODO or throw exception?
- }
- });
-};
-
-/**
- * Parse URL GET parameters
- */
-vz.parseUrlParams = function() {
- var vars = $.getUrlParams();
- 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 */ }
- });
- break;
-
- case 'from':
- vz.options.plot.xaxis.min = parseInt(vars[key]);
- break;
-
- case 'to':
- vz.options.plot.xaxis.max = parseInt(vars[key]);
- break;
-
- case 'debug':
- $.getScript('javascripts/firebug-lite.js');
- break;
- }
- }
- }
-};
-
-/**
- * Load capabilities from backend
- */
-vz.capabilities.load = function() {
- $.ajax({
- cache: true,
- dataType: 'json',
- url: vz.options.backendUrl + '/capabilities/definitions.json',
- success: function(json) {
- $.extend(true, vz.capabilities, json.capabilities);
-
- // load entity details & properties
- vz.entities.loadDetails();
- }
- });
-};
-
-vz.capabilities.definitions.get = function(section, name) {
- for (var i in this[section]) {
- if (this[section][i].name == name) {
- return this[section][i];
- }
- }
-}
-
/*
* 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 (typeof code != undefined) {
+ if (typeof code != 'undefined') {
error = code + ': ' + error;
}
|