')
+ .addClass((parent) ? 'child-of-entity-' + parent.uuid : '')
+ .attr('id', 'entity-' + entity.uuid)
+ .append($('')
+ .css('background-color', entity.color)
+ .css('width', 19)
+ .append($(' ')
+ .attr('type', 'checkbox')
+ .attr('checked', entity.active)
+ .bind('change', entity, function(event) {
+ event.data.active = $(this).attr('checked');
+ loadData();
+ })
+ )
+ )
+ .append($(' ')
+ .css('width', 20)
+ )
+ .append($(' ')
+ .append($('')
+ .text(entity.title)
+ .addClass('indicator')
+ .addClass((entity.type == 'group') ? 'group' : 'channel')
+ )
+ )
+ .append($(' ').text(entity.type))
+ .append($(' ')) // min
+ .append($(' ')) // max
+ .append($(' ')) // avg
+ .append($(' ') // operations
+ .css('text-align', 'right')
+ .append($(' ')
+ .attr('type', 'image')
+ .attr('src', 'images/information.png')
+ .attr('alt', 'details')
+ .bind('click', entity, function(event) { showEntityDetails(event.data); })
+ )
+ .append($(' ')
+ .attr('type', 'image')
+ .attr('src', 'images/delete.png')
+ .attr('alt', 'delete')
+ .bind('click', entity, function(event) { removeUUID(event.data.uuid); })
+ )
+ )
+ );
+ });
+
+ // http://ludo.cubicphuse.nl/jquery-plugins/treeTable/doc/index.html
+ $('#entities table').treeTable({
+ treeColumn: 2,
+ clickableNodeNames: true
+ });
+
+ // load data and show plot
+ loadData();
+}
+
+/**
+ * Show and edit entity details
+ * @param entity
+ */
+function showEntityDetails(entity) {
+ var properties = $('');
+
+ $.each(entity, function(key, value) {
+ properties.append($('')
+ .append($('')
+ .addClass('key')
+ .text(key)
+ )
+ .append($(' ')
+ .addClass('value')
+ .text(value)
+ )
+ );
+ });
+
+ $('')
+ .addClass('details')
+ .append(properties)
+ .dialog({
+ title: 'Entity Details',
+ width: 450
+ });
+}
+
+function validateChannel(form) {
+ var entity = getDefinition(entities, form.type.value);
+
+ $.each(entity.required, function(index, property) {
+ var property = getDefinition(properties, property);
+ if (!validateProperty(property, form.elements[property.name].value)) {
+ alert('Error: invalid property: ' + property.name + ' = ' + form.elements[property.name].value);
+ return false;
+ }
+ });
+
+ $.each(entity.optional, function(index, property) {
+ var property = getDefinition(properties, property);
+ });
+
+ return true;
+}
+
+function validateProperty(property, value) {
+ switch (property.type) {
+ case 'string':
+ case 'text':
+ // TODO check pattern
+ // TODO check string length
+ return true;
+
+ case 'float':
+ // TODO check format
+ // TODO check min/max
+ return true;
+
+ case 'integer':
+ // TODO check format
+ // TODO check min/max
+ return true;
+
+ case 'boolean':
+ return value == '1' || value == '';
+
+ case 'multiple':
+ return $.inArray(value, property.options);
+
+ default:
+ alert('Error: unknown property!');
+ }
+}
+
+/**
+ * Get entities from backend
+ */
+function fetchEntities() {
+ $.getJSON(backend + '/capabilities/definition/entity.json', function(data) {
+ entities = data.definition.entity;
+
+ // Add channel types to dropdown
+ $('#new select').empty();
+ $.each(entities, function(index, entity) {
+ if (entity.model == 'Volkszaehler\\Model\\Channel') {
+ $('#new select').append('
' + entity.translation.de + ' ');
+ }
+ });
+
+ // show related properties
+ $('#new select').trigger('change');
+ });
+}
+
+/**
+ * Get properties from backend
+ */
+function fetchProperties() {
+ $.getJSON(backend + '/capabilities/definition/property.json', function(data) {
+ properties = data.definition.property;
+
+ // show related properties
+ $('#new select').trigger('change');
+ });
+}
+
+/**
+ * Get channels from controller
+ */
+function fetchChannels() {
+ $.getJSON(controller, function(data) {
+ channels = data;
+
+ // add fetched channels to table
+ showChannels();
+ });
+}
+
+/**
+ * Show from for new Channel
+ *
+ * @param type
+ * @return
+ */
+function showEntityForm(type) {
+ $('#properties').empty();
+ var entity = getDefinition(entities, type);
+
+ $.each(entity.required, function(index, property) {
+ var property = getDefinition(properties, property);
+
+ if (property) {
+ $('#properties').append('
' + property.translation.de + ': ' + getPropertyForm(property) + ' (*) ');
+ }
+ });
+
+ $.each(entity.optional, function(index, property) {
+ var property = getDefinition(properties, property);
+
+ if (property) {
+ $('#properties').append('
' + property.translation.de + ': ' + getPropertyForm(property) + ' ');
+ }
+ });
+}
+
+/**
+ * @param uuid
+ * @return
+ */
+function deleteChannel(uuid) {
+ $.getJSON(controller, { operation: 'delete', uuid: uuid }, function(data) {
+ channels = data;
+ showChannels();
+ });
+}
+
+function addChannel(form) {
+ var uuid = false;
+
+ if (validateChannel(form)) {
+ //if (uuid = addChannelBackend(form)) {
+ if (addChannelController(form, randomUUID)) { //uuid)) {
+ fetchChannels();
+ return true;
+ }
+ else {
+ //removeChannelBackend(uuid);
+ alert('Error: adding channel to controller');
+ }
+ /*}
+ else {
+ alert('Error: adding channel to backend');
+ }*/
+ }
+ else {
+ alert('Please correct your input');
+ }
+}
+
+function addChannelController(form, uuid) {
+ $.getJSON(controller, { operation: 'add', uuid: uuid, port: form.port.value, type: form.type.value }, function(data) {
+ channels = data;
+ showChannels();
+ });
+
+ return true; // TODO
+}
+
+function addChannelBackend(form) {
+ $.getJSON(backend + '/channel.json', { operation: 'add' }, function(data) {
+
+ });
+
+ return true; // TODO
+}
+
+function getDefinition(definition, type) {
+ for (var i in definition) {
+ if (definition[i].name == type) {
+ return definition[i];
+ }
+ }
+}
+
+function getPropertyForm(property) {
+ switch (property.type) {
+ case 'string':
+ case 'float':
+ case 'integer':
+ return '
';
+
+ case 'text':
+ return '
';
+
+ case 'boolean':
+ return '
';
+
+ case 'multiple':
+ $.each(property.options, function(index, option) {
+ options.push('
' + option + '<\option>');
+ });
+ return '' + options.join() + ' ';
+
+ default:
+ alert('Error: unknown property!');
+ }
+}
\ No newline at end of file
diff --git a/frontend/javascripts/frontend.js b/frontend/javascripts/frontend.js
new file mode 100644
index 0000000..06f06d2
--- /dev/null
+++ b/frontend/javascripts/frontend.js
@@ -0,0 +1,157 @@
+/**
+ * Javascript functions for the frontend
+ *
+ * @author Florian Ziegler
+ * @author Justin Otherguy
+ * @author Steffen Vogel
+ * @copyright Copyright (c) 2010, 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 .
+ */
+
+/*
+ * Frontend related functions
+ */
+
+/**
+ * Initialize the WUI (Web User Interface)
+ */
+function initInterface() {
+ $('#accordion h3').click(function() {
+ $(this).next().toggle('fast');
+ return false;
+ }).next().hide();
+
+ $('button').button();
+
+ $('button[name=addUUID]').click(function() {
+ $('#addUUID').dialog({
+ title: 'UUID hinzufügen',
+ width: 400
+ });
+ });
+
+ $('button[name=newEntity]').click(function() {
+ $('#newEntity').dialog({
+ title: 'Entity erstellen',
+ width: 400
+ });
+ });
+
+ // bind controls
+ $('#move input').click(panPlot);
+
+ // options
+ $('input[name=trendline]').attr('checked', vz.options.plot.seriesDefaults.trendline.show).change(function() {
+ vz.options.plot.seriesDefaults.trendline.show = $(this).attr('checked');
+ drawPlot();
+ });
+
+ $('input[name=backendUrl]').val(vz.options.backendUrl).change(function() {
+ vz.options.backendUrl = $(this).val();
+ });
+
+ $('#tuples input').val(vz.options.tuples).change(function() {
+ vz.options.tuples = $(this).val();
+ });
+
+ $('#tuples .slider').slider({
+ min: 1,
+ max: 1000,
+ step: 10
+ });
+
+ $('#refresh .slider').slider({
+ min: 500,
+ max: 60000,
+ step: 500
+ });
+}
+
+/**
+ * Refresh plot with new data
+ */
+function refreshWindow() {
+ if ($('input[name=refresh]').attr('checked')) {
+ loadData();
+ }
+}
+
+/**
+ * Move & zoom in the plotting area
+ */
+function panPlot() {
+ delta = vz.to - vz.from;
+
+ switch(this.value) {
+ case 'move_last':
+ vz.to = (new Date()).getTime();
+ vz.from = vz.to - delta;
+ break;
+
+ case 'move_back':
+ vz.from -= delta;
+ vz.to -= delta;
+ break;
+ case 'move_forward':
+ vz.from += delta;
+ vz.to += delta;
+ break;
+
+ case 'zoom_reset':
+ // TODO
+ break;
+
+ case 'zoom_in':
+ // TODO
+ break;
+
+ case 'zoom_out':
+ // TODO
+ break;
+
+ case 'refresh':
+ // do nothing; just loadData()
+ }
+
+ loadData();
+}
+
+/**
+ * Load json data with given time window
+ */
+function loadData() {
+ eachRecursive(vz.entities, function(entity, parent) {
+ if (entity.active && entity.type != 'group') {
+ $.getJSON(vz.options.backendUrl + '/data/' + entity.uuid + '.json', { from: vz.from, to: vz.to, tuples: vz.options.tuples }, ajaxWait(function(json) {
+ entity.data = json.data[0]; // TODO filter for correct uuid
+ }, drawPlot, 'data'));
+ }
+ });
+}
+
+function drawPlot() {
+ vz.plot.axes.xaxis.min = vz.from;
+ vz.plot.axes.xaxis.max = vz.to;
+
+ vz.plot.replot({
+ resetAxes: 'yaxis',
+ clear: true
+ });
+}
+
diff --git a/frontend/javascripts/functions.js b/frontend/javascripts/functions.js
deleted file mode 100644
index eacdee8..0000000
--- a/frontend/javascripts/functions.js
+++ /dev/null
@@ -1,380 +0,0 @@
-/**
- * Javascript functions for the frontend
- *
- * @author Florian Ziegler
- * @author Justin Otherguy
- * @author Steffen Vogel
- * @copyright Copyright (c) 2010, 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 .
- */
-
-
-/*
- * Frontend related functions
- */
-
-/**
- * Initialize the WUI (Web User Interface)
- */
-function initInterface() {
- $('#accordion h3').click(function() {
- $(this).next().toggle('fast');
- return false;
- }).next().hide();
-
- $('button').button();
-
- $('button[name=addUUID]').click(function() {
- $('#addUUID').dialog({
- title: 'UUID hinzufügen',
- width: 400
- });
- });
-
- $('button[name=newEntity]').click(function() {
- $('#newEntity').dialog({
- title: 'Entity erstellen',
- width: 400
- });
- });
-
- // bind controls
- $('#move input').click(panPlot);
-
- // options
- $('input[name=trendline]').attr('checked', vz.options.plot.seriesDefaults.trendline.show).change(function() {
- vz.options.plot.seriesDefaults.trendline.show = $(this).attr('checked');
- drawPlot();
- });
-
- $('input[name=backendUrl]').val(vz.options.backendUrl).change(function() {
- vz.options.backendUrl = $(this).val();
- });
-
- $('#tuples input').val(vz.options.tuples).change(function() {
- vz.options.tuples = $(this).val();
- });
-
- $('#tuples .slider').slider({
- min: 1,
- max: 1000,
- step: 10
- });
-
- $('#refresh .slider').slider({
- min: 500,
- max: 60000,
- step: 500
- });
-}
-
-/**
- * Refresh plot with new data
- */
-function refreshWindow() {
- if ($('input[name=refresh]').attr('checked')) {
- loadData();
- }
-}
-
-/**
- * Move & zoom in the plotting area
- */
-function panPlot() {
- delta = vz.to - vz.from;
-
- switch(this.value) {
- case 'move_last':
- vz.to = (new Date()).getTime();
- vz.from = vz.to - delta;
- break;
-
- case 'move_back':
- vz.from -= delta;
- vz.to -= delta;
- break;
- case 'move_forward':
- vz.from += delta;
- vz.to += delta;
- break;
-
- case 'zoom_reset':
- // TODO
- break;
-
- case 'zoom_in':
- // TODO
- break;
-
- case 'zoom_out':
- // TODO
- break;
-
- case 'refresh':
- // do nothing; just loadData()
- }
-
- loadData();
-}
-
-/**
- * Load json data with given time window
- */
-function loadData() {
- eachRecursive(vz.entities, function(entity, parent) {
- if (entity.active && entity.type != 'group') {
- $.getJSON(vz.options.backendUrl + '/data/' + entity.uuid + '.json', { from: vz.from, to: vz.to, tuples: vz.options.tuples }, ajaxWait(function(json) {
- entity.data = json.data[0]; // TODO filter for correct uuid
- }, drawPlot, 'data'));
- }
- });
-}
-
-function drawPlot() {
- //vz.plot.axes.xaxis.min = vz.from;
- //vz.plot.axes.xaxis.min = vz.to;
-
- var i = 0;
-
- eachRecursive(vz.entities, function(entity, parent) {
- vz.plot.series[i++].data = entity.data.tuples;
- });
-
- vz.plot.replot({
- resetAxes: true
- });
-}
-
-/*
- * Entity list related functions
- */
-
-/**
- * Get all entity information from backend
- */
-function loadEntities() {
- $.each(vz.uuids, function(index, value) {
- $.getJSON(vz.options.backendUrl + '/entity/' + value + '.json', ajaxWait(function(json) {
- vz.entities.push(json.entity);
- }, showEntities, 'information'));
- });
-}
-
-/**
- * Create nested entity list
- * @param data
- */
-function showEntities() {
- $('#entities tbody').empty();
-
- var i = 0;
-
- eachRecursive(vz.entities, function(entity, parent) {
- entity.active = true; // TODO active by default or via backend property?
- entity.color = vz.options.plot.seriesColors[i++ % vz.options.plot.seriesColors.length];
-
- $('#entities tbody').append(
- $('')
- .addClass((parent) ? 'child-of-entity-' + parent.uuid : '')
- .attr('id', 'entity-' + entity.uuid)
- .append($('')
- .css('background-color', entity.color)
- .css('width', 19)
- .append($(' ')
- .attr('type', 'checkbox')
- .attr('checked', entity.active)
- .bind('change', entity, function(event) {
- event.data.active = $(this).attr('checked');
- loadData();
- })
- )
- )
- .append($(' ')
- .css('width', 20)
- )
- .append($(' ')
- .append($('')
- .text(entity.title)
- .addClass('indicator')
- .addClass((entity.type == 'group') ? 'group' : 'channel')
- )
- )
- .append($(' ').text(entity.type))
- .append($(' ')) // min
- .append($(' ')) // max
- .append($(' ')) // avg
- .append($(' ') // operations
- .css('text-align', 'right')
- .append($(' ')
- .attr('type', 'image')
- .attr('src', 'images/information.png')
- .attr('alt', 'details')
- .bind('click', entity, function(event) { showEntityDetails(event.data); })
- )
- .append($(' ')
- .attr('type', 'image')
- .attr('src', 'images/delete.png')
- .attr('alt', 'delete')
- .bind('click', entity, function(event) { removeUUID(event.data.uuid); })
- )
- )
- );
- });
-
- // http://ludo.cubicphuse.nl/jquery-plugins/treeTable/doc/index.html
- $('#entities table').treeTable({
- treeColumn: 2,
- clickableNodeNames: true
- });
-
- // load data and show plot
- loadData();
-}
-
-/**
- * Show and edit entity details
- * @param entity
- */
-function showEntityDetails(entity) {
- var properties = $('');
-
- $.each(entity, function(key, value) {
- properties.append($('')
- .append($('')
- .addClass('key')
- .text(key)
- )
- .append($(' ')
- .addClass('value')
- .text(value)
- )
- );
- });
-
- $('')
- .addClass('details')
- .append(properties)
- .dialog({
- title: 'Entity Details',
- width: 450
- });
-}
-
-/*
- * Cookie & UUID related functions
- */
-function getUUIDs() {
- if ($.getCookie('uuids')) {
- return JSON.parse($.getCookie('uuids'));
- }
- else {
- return new Array();
- }
-}
-
-function addUUID(uuid) {
- if (!vz.uuids.contains(uuid)) {
- vz.uuids.push(uuid);
- $.setCookie('uuids', JSON.stringify(vz.uuids));
- }
-}
-
-function removeUUID(uuid) {
- if (uuids.contains(uuid)) {
- uuids.filter(function(value) {
- return value != uuid;
- });
- $.setCookie('uuids', JSON.stringify(uuids));
- }
-}
-
-/*
- * General helper functions
- */
-
-function ajaxWait(callback, finished, identifier) {
- if (!ajaxWait.counter) { ajaxWait.counter = new Array(); }
- if (!ajaxWait.counter[identifier]) { ajaxWait.counter[identifier] = 0; }
-
- ajaxWait.counter[identifier]++;
-
- return function (data, textStatus) {
- callback(data, textStatus);
-
- if (!--ajaxWait.counter[identifier]) {
- finished();
- }
- };
-}
-
-function eachRecursive(array, callback, parent) {
- $.each(array, function(index, value) {
- callback(value, parent);
-
- if (value.children) { // has children?
- eachRecursive(value.children, callback, value); // call recursive
- }
- });
-}
-
-/**
- * Checks if value of part of the array
- *
- * @param needle the value to search for
- * @return boolean
- */
-Array.prototype.contains = function(needle) {
- return this.key(needle) ? true : false;
-};
-
-/**
- * Calculates the diffrence between this and another Array
- *
- * @param compare the Array to compare with
- * @return array
- */
-Array.prototype.diff = function(compare) {
- return this.filter(function(elem) {
- return !compare.contains(elem);
- });
-};
-
-/**
- * Find the key to an given value
- *
- * @param needle the value to search for
- * @return integer
- */
-Array.prototype.key = function(needle) {
- for (var i=0; i
+ * @author Justin Otherguy
+ * @author Steffen Vogel
+ * @copyright Copyright (c) 2010, 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 .
+ */
+
+function ajaxWait(callback, finished, identifier) {
+ if (!ajaxWait.counter) { ajaxWait.counter = new Array(); }
+ if (!ajaxWait.counter[identifier]) { ajaxWait.counter[identifier] = 0; }
+
+ ajaxWait.counter[identifier]++;
+
+ return function (data, textStatus) {
+ callback(data, textStatus);
+
+ if (!--ajaxWait.counter[identifier]) {
+ finished();
+ }
+ };
+}
+
+function eachRecursive(array, callback, parent) {
+ $.each(array, function(index, value) {
+ callback(value, parent);
+
+ if (value.children) { // has children?
+ eachRecursive(value.children, callback, value); // call recursive
+ }
+ });
+}
+
+/**
+ * Checks if value of part of the array
+ *
+ * @param needle the value to search for
+ * @return boolean
+ */
+Array.prototype.contains = function(needle) {
+ return this.key(needle) ? true : false;
+};
+
+/**
+ * Calculates the diffrence between this and another Array
+ *
+ * @param compare the Array to compare with
+ * @return array
+ */
+Array.prototype.diff = function(compare) {
+ return this.filter(function(elem) {
+ return !compare.contains(elem);
+ });
+};
+
+/**
+ * Find the key to an given value
+ *
+ * @param needle the value to search for
+ * @return integer
+ */
+Array.prototype.key = function(needle) {
+ for (var i=0; i
+ * @author Justin Otherguy
+ * @author Steffen Vogel
+ * @copyright Copyright (c) 2010, 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 .
+ */
+
+/*
+ * Cookie & UUID related functions
+ */
+function getUUIDs() {
+ if ($.getCookie('uuids')) {
+ return JSON.parse($.getCookie('uuids'));
+ }
+ else {
+ return new Array();
+ }
+}
+
+function addUUID(uuid) {
+ if (!vz.uuids.contains(uuid)) {
+ vz.uuids.push(uuid);
+ $.setCookie('uuids', JSON.stringify(vz.uuids));
+ }
+}
+
+function removeUUID(uuid) {
+ if (uuids.contains(uuid)) {
+ uuids.filter(function(value) {
+ return value != uuid;
+ });
+ $.setCookie('uuids', JSON.stringify(uuids));
+ }
+}
+
+/**
+ * Create and return a "version 4" RFC-4122 UUID string
+ *
+ * @todo remove after got backend handling working
+ */
+function randomUUID() {
+ var s = [], itoh = '0123456789ABCDEF';
+
+ // make array of random hex digits. The UUID only has 32 digits in it, but we
+ // allocate an extra items to make room for the '-'s we'll be inserting.
+ for (var i = 0; i <36; i++) s[i] = Math.floor(Math.random()*0x10);
+
+ // conform to RFC-4122, section 4.4
+ s[14] = 4; // Set 4 high bits of time_high field to version
+ s[19] = (s[19] & 0x3) | 0x8; // Specify 2 high bits of clock sequence
+
+ // convert to hex chars
+ for (var i = 0; i <36; i++) s[i] = itoh[s[i]];
+
+ // insert '-'s
+ s[8] = s[13] = s[18] = s[23] = '-';
+
+ return s.join('');
+}
\ No newline at end of file