From 3493bce3bc1f13a6f998e008e2115081d954fbb3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Fri, 24 Jun 2011 17:44:19 +0200 Subject: [PATCH 1/4] fixed JSON padding --- lib/View/JSON.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; } From e4e077f4127a39c620aaa134e906a7d8895e5867 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 26 Jun 2011 04:38:13 +0200 Subject: [PATCH 2/4] first bunch of changes to subscribe to remote channels --- htdocs/frontend/images/cross.png | Bin 0 -> 655 bytes htdocs/frontend/images/tick.png | Bin 0 -> 537 bytes htdocs/frontend/index.html | 52 ++-- htdocs/frontend/javascripts/entities.js | 191 +++++++++++++ htdocs/frontend/javascripts/entity.js | 342 +++++++++++++---------- htdocs/frontend/javascripts/functions.js | 64 ++++- htdocs/frontend/javascripts/init.js | 30 +- htdocs/frontend/javascripts/options.js | 8 +- htdocs/frontend/javascripts/uuid.js | 81 ------ htdocs/frontend/javascripts/wui.js | 251 +++-------------- htdocs/frontend/stylesheets/style.css | 8 +- 11 files changed, 527 insertions(+), 500 deletions(-) create mode 100644 htdocs/frontend/images/cross.png create mode 100644 htdocs/frontend/images/tick.png create mode 100644 htdocs/frontend/javascripts/entities.js delete mode 100644 htdocs/frontend/javascripts/uuid.js diff --git a/htdocs/frontend/images/cross.png b/htdocs/frontend/images/cross.png new file mode 100644 index 0000000000000000000000000000000000000000..1514d51a3cf1b67e1c5b9ada36f1fd474e2d214a GIT binary patch literal 655 zcmV;A0&x9_P)uEoyT++I zn$b9r%cFfhHe2K68PkBu*@^<$y+7xQ$wJ~;c5aBx$R=xq*41Wo zhwQus_VOgm0hughj}MhOvs#{>Vg09Y8WxjWUJY5YW zJ?&8eG!59Cz=|E%Ns@013KLWOLV)CObIIj_5{>{#k%TEAMs_GbdDV`x-iYsGH z#=Z{USAQA>NY(}X7=3{K8#Hs{AQG2a)rMyf zFQK~pm1x3+7!nu%-M`k}``c>^00{o_1pjWJUTfl8mg=3qGEl8H@}^@w`VUx0_$uy4 z2FhRqKX}xI*?Tv1DJd8z#F#0c%*~rM30HE1@2o5m~}ZyoWhqv>ql{V z1ZGE0lgcoK^lx+eqc*rAX1Ky;Xx3U%u#zG!m-;eD1Qsn@kf3|F9qz~|95=&g3(7!X zB}JAT>RU;a%vaNOGnJ%e1=K6eAh43c(QN8RQ6~GP%O}Jju$~Ld*%`mO1p - - - - - - - + + + + @@ -113,10 +110,6 @@ -
@@ -144,30 +137,35 @@

Hier können Sie einen existierenden Kanal über seine UUID hinzufügen

-

- -

- + + + +
+

Hier können Sie öffentliche Kanäle abonnieren.

-

-

- + + + +
+

-
+ - - - - - - - + + + + + + + +
Middleware URL:

Bsp: http://volkszaehler.org/demo/middleware.php

Typ:
Öffentlich: ja
nein
Titel:
Auflösung:
Kosten:

pro Wh

Beschreibung:
EigenschaftWert
Middleware URL:
Typ:
Öffentlich: ja   nein
Titel:
Auflösung:
Kosten:

pro Wh

Beschreibung:
+

-

Es wird ein neuer Kanal erstellt. Die Antwort der Middlewarenthält dann die UUID.
+

Es wird ein neuer Kanal erstellt. Die Antwort der Middleware enthält dann die UUID.
Diese muss dann im Controller angegeben werden (z.B. AVR Net-IO).

diff --git a/htdocs/frontend/javascripts/entities.js b/htdocs/frontend/javascripts/entities.js new file mode 100644 index 0000000..3146047 --- /dev/null +++ b/htdocs/frontend/javascripts/entities.js @@ -0,0 +1,191 @@ +/** + * + * + * @author Florian Ziegler + * @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 . + */ + +/** + * Save minimal Entity in JSON cookie + */ +vz.entities.saveCookie = function() { + var expires = new Date(new Date().getTime() + 3e10); // in about a year + var arr = new Array; + + this.each(function(entity) { + if (entity.cookie === true) { + arr.push(entity.uuid + '@' + entity.middleware); + } + }, true); // recursive! + + $.setCookie('vz_entities', arr.join('|'), {expires: expires}); +}; + +/** + * Load entities from JSON cookie + */ +vz.entities.loadCookie = function() { + var cookie = $.getCookie('vz_entities'); + if (cookie) { + var arr = cookie.split('|'); + arr.each(function(index, entry) { + var entity = entry.split('@'); + vz.entities.push(new Entity({ + middleware: entity[1], + uuid: entity[0], + cookie: true + })); + }); + } +}; + +/** + * Load JSON data from the middleware + */ +vz.entities.loadData = function() { + $('#overlay').html('loading...

loading...

'); + + var queue = new Array; + this.each(function(entity) { + if (entity.active && entity.definition.model == 'Volkszaehler\\Model\\Channel') { + queue.push(entity.loadData()); + } + }, true); // recursive! + + return $.when.apply($, queue); +}; + +/** + * Overwritten each iterator to iterate recursively throug all entities + */ +vz.entities.each = function(cb, recursive) { + for (var i = 0; i < this.length; i++) { + cb(this[i]); + + if (recursive) { + this[i].each(cb, true); + } + } +} + +/** + * 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 + this.each(function(entity) { + entity.color = vz.options.plot.colors[c++ % vz.options.plot.colors.length]; + $('#entity-list tbody').append(entity.getDOMRow()); + }, true); // recursive! + + /* + * 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: 0.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' + }); +}; diff --git a/htdocs/frontend/javascripts/entity.js b/htdocs/frontend/javascripts/entity.js index 4f5e813..7a2ae0f 100644 --- a/htdocs/frontend/javascripts/entity.js +++ b/htdocs/frontend/javascripts/entity.js @@ -1,7 +1,6 @@ /** * Entity handling, parsing & validation * - * @author Florian Ziegler * @author Justin Otherguy * @author Steffen Vogel * @copyright Copyright (c) 2011, The volkszaehler.org project @@ -28,23 +27,70 @@ * Entity constructor * @todo add validation */ -var Entity = function(json, parent) { - $.extend(true, this, json); - this.parent = parent; - +var Entity = function(json) { + this.parseJSON(json); + if (this.active === undefined) { - this.active = true; // active by default + this.active = true; // activate by default } + +}; + +Entity.prototype.parseJSON = function(json) { + $.extend(true, this, json); + if (this.children) { for (var i = 0; i < this.children.length; i++) { - this.children[i] = new Entity(this.children[i], this); - }; + this.children[i] = new Entity(this.children[i]); + } this.children.sort(Entity.compare); } + + if (this.type !== undefined) { + this.definition = vz.capabilities.definitions.get('entities', this.type); + } +}; - this.definition = vz.capabilities.definitions.get('entities', this.type); +/** + * Query middleware for details + */ +Entity.prototype.loadDetails = function() { + return vz.load({ + url: this.middleware, + controller: 'entity', + identifier: this.uuid, + context: this, + success: function(json) { + this.parseJSON(json.entity); + } + }); +}; + +Entity.prototype.loadData = function() { + return vz.load({ + controller: 'data', + url: this.middleware, + 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; + + 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; + } + } + + this.updateDOMRow(); + } + }); }; /** @@ -53,7 +99,7 @@ var Entity = function(json, parent) { Entity.prototype.showDetails = function() { $('
') .addClass('details') - .append(this.getDOM()) + .append(this.getDOMDetails()) .dialog({ title: 'Details für ' + this.title, width: 480, @@ -66,63 +112,98 @@ Entity.prototype.showDetails = function() { * * @todo implement/test */ -Entity.prototype.getDOM = function(edit) { +Entity.prototype.getDOMDetails = function(edit) { var table = $('
EigenschaftWert
'); var data = $(''); - - for (var property in this) { - if (this.hasOwnProperty(property) && !['data', 'definition', 'children', 'parent'].contains(property)) { - switch(property) { - case 'type': - var title = 'Typ'; - var value = this.definition.translation[vz.options.language]; - break; - - case 'uuid': - var title = 'UUID'; - var value = '' + this[property] + ''; - break; + + // general properties + var general = ['uuid', 'middleware', 'type', 'color', 'cookie']; + var sections = ['required', 'optional']; + + general.each(function(index, property) { + switch(property) { + case 'type': + var title = 'Typ'; + var value = this.definition.translation[vz.options.language]; + break; - case 'color': - var title = 'Farbe'; - var value = '' + this[property] + ''; - break; - - case 'public': - var title = vz.capabilities.definitions.get('properties', property).translation[vz.options.language]; - var value = (this[property]) ? 'ja' : 'nein'; - break; - + case 'middleware': + var title = 'Middleware'; + var value = '' + this.middleware + ''; + break; - case 'active': - var title = 'Aktiv'; - var value = (this[property]) ? 'ja' : 'nein'; - break; - - default: - var title = vz.capabilities.definitions.get('properties', property).translation[vz.options.language]; - var value = this[property]; - } - - data.append($('') - .append($('') - .addClass('key') - .text(title) - ) - .append($('') - .addClass('value') - .append(value) - ) - ); + case 'uuid': + var title = 'UUID'; + var value = '' + this.uuid + ''; + break; + + case 'color': + var title = 'Farbe'; + var value = '' + this.color + ''; + break; + + case 'cookie': + var title = 'Cookie'; + value = '' + ((value) ? 'ja' : 'nein') + ''; + break; + case 'active': + var title = 'Aktiv'; + var value = '' + ((this.active) ? 'ja' : 'nein') + ''; + break; } - } + + data.append($('') + .addClass('property') + .addClass('general') + .append($('') + .addClass('key') + .text(title) + ) + .append($('') + .addClass('value') + .append(value) + ) + ); + }, this); + + sections.each(function(index, section) { + this.definition[section].each(function(index, property) { + if (this.hasOwnProperty(property)) { + var definition = vz.capabilities.definitions.get('properties', property); + var title = definition.translation[vz.options.language]; + var value = this[property]; + + if (definition.type == 'boolean') { + value = '' + ((value) ? 'ja' : 'nein') + ''; + } + + if (property == 'cost') { + value = (value * 1000 * 100) + ' ct/k' + this.definition.unit + 'h'; // ct per kWh + } + + data.append($('') + .addClass('property') + .addClass(section) + .append($('') + .addClass('key') + .text(title) + ) + .append($('') + .addClass('value') + .append(value) + ) + ); + } + }, this); + }, this); return table.append(data); }; -Entity.prototype.getRow = function() { +Entity.prototype.getDOMRow = function() { var row = $('') .addClass((this.parent) ? 'child-of-entity-' + this.parent.uuid : '') .addClass((this.definition.model == 'Volkszaehler\\Model\\Aggregator') ? 'aggregator' : 'channel') + .addClass('entity') .attr('id', 'entity-' + this.uuid) .append($('') .addClass('visibility') @@ -171,81 +252,59 @@ Entity.prototype.getRow = function() { ) .data('entity', this); - if (vz.uuids.contains(this.uuid)) { // removable from cookies? - $('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.showTable(); - - vz.wui.drawPlot(); - }) - ); - } - + $('td.ops', row).prepend($('') + .attr('type', 'image') + .attr('src', 'images/delete.png') + .attr('alt', 'delete') + .bind('click', this, function(event) { + 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(''); + } }; /** @@ -280,38 +339,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/options.js b/htdocs/frontend/javascripts/options.js index ce1ecbf..e20418c 100644 --- a/htdocs/frontend/javascripts/options.js +++ b/htdocs/frontend/javascripts/options.js @@ -27,9 +27,8 @@ // default time interval to show vz.options = { language: 'de', - middlewareUrl: '../middleware.php', // TODO default middleware, store middleware urls in cookies - tuples: 300, precision: 2, // TODO update from middleware capabilities? + tuples: null, // automatically determined by plot size render: 'lines', refresh: false, minTimeout: 3000, // minimum refresh time in ms @@ -43,7 +42,6 @@ vz.options.plot = { shadowSize: 0, points: { radius: 1, - //symbol: 'square' symbol: function(ctx, x, y, radius, shadow) { // just draw simple pixels ctx.lineWidth = 1; ctx.strokeRect(x-1, y-1, 2, 2); @@ -70,7 +68,7 @@ vz.options.plot = { } } -vz.options.save = function() { +vz.options.saveCookies = function() { for (var key in vz.options) { if (vz.options.hasOwnProperty(key) && typeof vz.options[key] != 'function' && @@ -82,7 +80,7 @@ vz.options.save = function() { } }; -vz.options.load = function() { +vz.options.loadCookies = function() { for (var key in this) { var value = $.getCookie('vz_' + key); if (value !== undefined) { diff --git a/htdocs/frontend/javascripts/uuid.js b/htdocs/frontend/javascripts/uuid.js deleted file mode 100644 index 2ce56e6..0000000 --- a/htdocs/frontend/javascripts/uuid.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * UUID handling - * - * @author Florian Ziegler - * @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 eef7569..c584e4d 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( $('