diff --git a/frontend/index.html b/frontend/index.html index c23d45e..009f70e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -17,9 +17,12 @@ - - - + + + + + + diff --git a/frontend/javascripts/backend.js b/frontend/javascripts/backend.js new file mode 100644 index 0000000..f946e41 --- /dev/null +++ b/frontend/javascripts/backend.js @@ -0,0 +1,339 @@ +/** + * Backend related javascript code + * + * @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 . + */ + +/** + * 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]; + + vz.plot.series[vz.plot.series.length] = vz.plot.seriesDefault; + + + $('#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($(''); + } + }); + + $.each(entity.optional, function(index, property) { + var property = getDefinition(properties, property); + + if (property) { + $('#properties').append(''); + } + }); +} + +/** + * @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('') - .addClass((parent) ? 'child-of-entity-' + parent.uuid : '') - .attr('id', 'entity-' + entity.uuid) - .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(''); + } + }); + + // 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('
' + getPropertyForm(property) + '(*)
' + getPropertyForm(property) + '
') - .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