diff --git a/fhem/www/frontend/controls_frontend.txt b/fhem/www/frontend/controls_frontend.txt
index 5978c6dec..77c81978f 100644
--- a/fhem/www/frontend/controls_frontend.txt
+++ b/fhem/www/frontend/controls_frontend.txt
@@ -3,6 +3,7 @@ DIR www/frontend/app/model
DIR www/frontend/app/store
DIR www/frontend/app/view
DIR www/frontend/app/controller
+DIR www/frontend/app/imagecache
DIR www/frontend/app/resources
DIR www/frontend/app/resources/icons
DIR www/frontend/lib
@@ -28,7 +29,7 @@ DIR www/frontend/lib/ext-4.2.0.663/images/window
DIR www/frontend/lib/ext-4.2.0.663/images/grid
DIR www/frontend/lib/ext-4.2.0.663/images/util
DIR www/frontend/lib/ext-4.2.0.663/images/util/splitter
-UPD 2013-12-26_09:59:17 1054 www/frontend/index.html
+UPD 2014-01-11_09:31:08 1170 www/frontend/index.html
UPD 2013-04-01_07:03:30 260475 www/frontend/lib/ext-4.2.0.663/ext-theme-gray-all.css
UPD 2013-12-07_02:00:26 1497654 www/frontend/lib/ext-4.2.0.663/ext-all.js
UPD 2013-04-01_07:03:33 1981 www/frontend/lib/ext-4.2.0.663/images/tools/tools-sprites-trans.gif
@@ -272,14 +273,16 @@ UPD 2013-03-02_01:53:05 524 www/frontend/app/resources/icons/resultset_last.png
UPD 2013-04-03_07:27:17 733 www/frontend/app/resources/icons/add.png
UPD 2013-04-03_07:27:17 389 www/frontend/app/resources/icons/resultset_previous.png
UPD 2013-06-30_11:47:12 101 www/frontend/app/resources/application.css
-UPD 2014-01-03_12:47:07 2714 www/frontend/app/app.js
+UPD 2014-01-12_11:31:30 3028 www/frontend/app/app.js
UPD 2013-04-28_02:00:20 1205 www/frontend/app/view/ChartGridPanel.js
UPD 2013-07-07_12:12:08 16201 www/frontend/app/view/DevicePanel.js
UPD 2013-12-26_08:39:37 10257 www/frontend/app/view/TableDataGridPanel.js
UPD 2014-01-03_01:24:06 65039 www/frontend/app/view/LineChartPanel.js
-UPD 2013-12-27_01:39:11 9980 www/frontend/app/view/Viewport.js
-UPD 2014-01-03_01:38:11 19171 www/frontend/app/controller/MainController.js
-UPD 2014-01-03_01:30:11 107834 www/frontend/app/controller/ChartController.js
+UPD 2014-01-12_12:09:17 5144 www/frontend/app/view/StatusPanel.js
+UPD 2014-01-12_12:55:22 10486 www/frontend/app/view/Viewport.js
+UPD 2014-01-12_02:42:27 21844 www/frontend/app/controller/MainController.js
+UPD 2014-01-12_02:49:58 16562 www/frontend/app/controller/StatusController.js
+UPD 2014-01-12_02:51:54 109250 www/frontend/app/controller/ChartController.js
UPD 2013-06-30_11:46:54 5415 www/frontend/app/controller/TableDataController.js
UPD 2013-04-01_07:04:35 202 www/frontend/app/model/ReadingsModel.js
UPD 2013-04-01_07:04:36 338 www/frontend/app/model/SavedChartsModel.js
diff --git a/fhem/www/frontend/www/frontend/app/app.js b/fhem/www/frontend/www/frontend/app/app.js
index e7324b71a..9d3b2384c 100644
--- a/fhem/www/frontend/www/frontend/app/app.js
+++ b/fhem/www/frontend/www/frontend/app/app.js
@@ -17,6 +17,7 @@ Ext.application({
],
controllers: [
+ 'FHEM.controller.StatusController',
'FHEM.controller.MainController',
'FHEM.controller.ChartController',
'FHEM.controller.TableDataController'
@@ -38,6 +39,12 @@ Ext.application({
try {
FHEM.info = Ext.decode(response.responseText);
FHEM.version = FHEM.info.Results[0].devices[0].ATTR.version;
+
+ if (window.location.href.indexOf("frontenddev") > 0) {
+ FHEM.appPath = 'www/frontenddev/app/';
+ } else {
+ FHEM.appPath = 'www/frontend/app/';
+ }
Ext.each(FHEM.info.Results, function(result) {
if (result.list === "DbLog" && result.devices[0].NAME) {
FHEM.dblogname = result.devices[0].NAME;
diff --git a/fhem/www/frontend/www/frontend/app/controller/ChartController.js b/fhem/www/frontend/www/frontend/app/controller/ChartController.js
index c27b7dd1a..2896e0b01 100644
--- a/fhem/www/frontend/www/frontend/app/controller/ChartController.js
+++ b/fhem/www/frontend/www/frontend/app/controller/ChartController.js
@@ -123,6 +123,12 @@ Ext.define('FHEM.controller.ChartController', {
},
'radiogroup[name=datasourceradio]': {
change: this.dataSourceChanged
+ },
+ 'button[name=updatepreviewchart]': {
+ loadhiddenchart: this.loadsavedchart
+ },
+ 'button[name=loadfullchart]': {
+ loadchart: this.loadsavedchart
}
});
@@ -291,8 +297,8 @@ Ext.define('FHEM.controller.ChartController', {
/**
* Triggers a request to FHEM Module to get the data from Database
*/
- requestChartData: function(stepchangecalled) {
-
+ requestChartData: function(stepchangecalled, hidden) {
+
var me = this;
//show loadmask
@@ -314,7 +320,7 @@ Ext.define('FHEM.controller.ChartController', {
dbendtime = Ext.Date.format(endtime, 'Y-m-d_H:i:s'),
dynamicradio = Ext.ComponentQuery.query('radiogroup[name=dynamictime]')[0],
chartpanel = me.getLinechartpanel(),
- chart = me.getChart();
+ hiddenchartdiv = Ext.get("hiddenchart");
//cleanup chartpanel
var existingchartgrid = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0];
@@ -334,9 +340,16 @@ Ext.define('FHEM.controller.ChartController', {
existingchart.destroy();
}
var store = Ext.create('FHEM.store.ChartStore'),
- proxy = store.getProxy();
- chart = me.createChart(store);
- chartpanel.add(chart);
+ proxy = store.getProxy(),
+ chart;
+
+
+ if (hidden === true) {
+ chart = me.createChart(store, hiddenchartdiv);
+ } else {
+ chart = me.createChart(store);
+ chartpanel.add(chart);
+ }
//reset zoomValues
chartpanel.setLastYmax(null);
@@ -455,14 +468,12 @@ Ext.define('FHEM.controller.ChartController', {
* resize the chart to fit the centerpanel
*/
resizeChart: function() {
-
var lcp = Ext.ComponentQuery.query('linechartpanel')[0];
var lcv = Ext.ComponentQuery.query('chart')[0];
var cfp = Ext.ComponentQuery.query('form[name=chartformpanel]')[0];
var cdg = Ext.ComponentQuery.query('panel[name=chartgridpanel]')[0];
if (lcv) {
-
if (lcp && lcv && cfp && cdg) {
var lcph = lcp.getHeight(),
lcpw = lcp.getWidth(),
@@ -493,7 +504,7 @@ Ext.define('FHEM.controller.ChartController', {
/**
* create the base chart
*/
- createChart: function(store) {
+ createChart: function(store, hidden) {
var me = this;
var chart = Ext.create('Ext.panel.Panel', {
@@ -502,6 +513,9 @@ Ext.define('FHEM.controller.ChartController', {
collapsible: true,
titleCollapse: true,
animCollapse: false,
+ width: hidden ? 1 : false,
+ height: hidden ? 1 : false,
+ renderTo: hidden ? hidden : false,
items: [
{
xtype: 'toolbar',
@@ -531,46 +545,51 @@ Ext.define('FHEM.controller.ChartController', {
var chart = btn.up().up().down('chart'),
cp = chart.up().up();
- chart.restoreZoom();
-
- chart.axes.get(0).minimum = cp.getLastYmin();
- chart.axes.get(0).maximum = cp.getLastYmax();
- chart.axes.get(1).minimum = cp.getLastY2min();
- chart.axes.get(1).maximum = cp.getLastY2max();
- chart.axes.get(2).minimum = cp.getLastXmin();
- chart.axes.get(2).maximum = cp.getLastXmax();
-
- //helper to reshow the hidden items after zooming back out
- if (cp.artifactSeries && cp.artifactSeries.length > 0) {
- Ext.each(cp.artifactSeries, function(serie) {
- serie.showAll();
- var showMarkers = false;
- Ext.each(serie.group.items, function(item) {
- // make sure we hit the points
- if (item.radius && item.radius > 0) {
- item.show();
- item.redraw();
- showMarkers = true;
+ //only reset zoom when chart was really zoomed, else will break layout
+ if (cp.timesZoomed !== 0) {
+
+ chart.restoreZoom();
+
+ chart.axes.get(0).minimum = cp.getLastYmin();
+ chart.axes.get(0).maximum = cp.getLastYmax();
+ chart.axes.get(1).minimum = cp.getLastY2min();
+ chart.axes.get(1).maximum = cp.getLastY2max();
+ chart.axes.get(2).minimum = cp.getLastXmin();
+ chart.axes.get(2).maximum = cp.getLastXmax();
+
+ //helper to reshow the hidden items after zooming back out
+ if (cp.artifactSeries && cp.artifactSeries.length > 0) {
+ Ext.each(cp.artifactSeries, function(serie) {
+ serie.showAll();
+ var showMarkers = false;
+ Ext.each(serie.group.items, function(item) {
+ // make sure we hit the points
+ if (item.radius && item.radius > 0) {
+ item.show();
+ item.redraw();
+ showMarkers = true;
+ }
+ });
+ if (showMarkers) {
+ serie.showMarkers = true;
}
});
- if (showMarkers) {
- serie.showMarkers = true;
- }
- });
- cp.artifactSeries = [];
+ cp.artifactSeries = [];
+ }
+ chart.redraw();
+ // restore the counter as we have zoomed out
+ cp.timesZoomed = 0;
}
-
- chart.redraw();
- // restore the counter as we have zoomed out
- cp.timesZoomed = 0;
}
}
]
},
{
xtype: 'chart',
+ isPreviewChart: hidden ? true : false,
legend: {
position: 'right',
+ visible: hidden ? false : true,
labelFont: '10px Helvetica, sans-serif',
padding: 4
},
@@ -605,35 +624,6 @@ Ext.define('FHEM.controller.ChartController', {
store: store,
enableMask: true,
mask: true,//'vertical',//true, //'horizontal',
- gradients: [{
- id: 'gradientId',
- angle: 90,
- stops: {
- 0: {
- color: '#FF0000'
- },
- 50: {
- color: '#FFFF00'
- },
- 100: {
- color: '#079400'
- }
- }
- }, {
- id: 'gradientId2',
- angle: 0,
- stops: {
- 0: {
- color: '#590'
- },
- 20: {
- color: '#599'
- },
- 100: {
- color: '#ddd'
- }
- }
- }],
listeners: {
mousedown: function(evt) {
// fix for firefox, not dragging images
@@ -687,7 +677,7 @@ Ext.define('FHEM.controller.ChartController', {
*/
createBaseLine: function(index, basestart, baseend, basefill, basecolor) {
var me = this,
- chart = me.getChart(),
+ chart = Ext.ComponentQuery.query('chart')[0],
store = chart.getStore(),
yfield = "VALUEBASE" + index;
@@ -743,7 +733,7 @@ Ext.define('FHEM.controller.ChartController', {
populateAxis: function(i, axeslength, device, yaxis, yaxisindex, styleConfig, axisside, yaxisstatistics, dbstarttime, dbendtime, logtype) {
var me = this,
- chart = me.getChart(),
+ chart = Ext.ComponentQuery.query('chart')[0],
store = chart.getStore(),
proxy = store.getProxy(),
yseries,
@@ -773,14 +763,42 @@ Ext.define('FHEM.controller.ChartController', {
// as the get command wont support absolute pathes by default...
currentlogfile = "../../../../../../../../" + currentlogfile;
}
+
+ // get the conversions keys and values from userconfig
+ var queryString;
+ if (Ext.isDefined(FHEM) && Ext.isDefined(FHEM.userconfig)) {
+ var count = 0;
+
+ Ext.iterate(FHEM.userconfig.chartkeys, function(k, v) {
+
+ if (count === 0) {
+ queryString = '$fld[' + (yaxisindex - 1) + ']=~"' + k + '"?' + v + ':';
+ } else {
+ queryString += '($fld[' + (yaxisindex - 1) + ']=~"' + k + '"?' + v + ':';
+ }
+
+ count++;
+ });
+
+ // last fallback, similar to parseint
+ queryString += '$fld[3]*1';
+
+ // add closing brackets
+ for (bracket = 1; bracket < count; bracket++) {
+ queryString += ")";
+ }
+ }
+
cmd = 'get Logfile ' +
currentlogfile + ' - ' + dbstarttime +
' ' + dbendtime + ' ' + yaxisindex + ':' + yaxis +
- '\\x3a::$fld[' + (yaxisindex - 1) +
- ']=~"ok|on|open|active|true"?1:($fld[' +
- (yaxisindex - 1) +
- ']=~"low|off|closed|inactive|false"?0:$fld[' +
- (yaxisindex - 1) + ']*1)';
+ '\\x3a::' + queryString;
+
+// '\\x3a::$fld[' + (yaxisindex - 1) +
+// ']=~"ok|on|open|active|true"?1:($fld[' +
+// (yaxisindex - 1) +
+// ']=~"low|off|closed|inactive|false"?0:$fld[' +
+// (yaxisindex - 1) + ']*1)';
} else if (!Ext.isDefined(yaxisstatistics) || yaxisstatistics === "none" || Ext.isEmpty(yaxisstatistics)) {
cmd = 'get ' + FHEM.dblogname + ' - webchart ' + dbstarttime + ' ' + dbendtime + ' ';
cmd +=device + ' timerange ' + "TIMESTAMP" + ' ' + yaxis;
@@ -993,7 +1011,6 @@ Ext.define('FHEM.controller.ChartController', {
}
chart.series.add(yseries);
-
}
},
failure: function() {
@@ -1138,9 +1155,10 @@ Ext.define('FHEM.controller.ChartController', {
chart.axes.get(2).processView();
- me.resizeChart();
-
- chart.show();
+ // only call resize function when not a hidden chart
+ if (chart.isPreviewChart === false) {
+ me.resizeChart();
+ }
me.getLinechartpanel().setLoading(false);
},
@@ -1151,7 +1169,7 @@ Ext.define('FHEM.controller.ChartController', {
createSeries: function(yfield, title, styleConfig, axisside) {
//setting axistitle and fontsize
- var chart = this.getChart(),
+ var chart = Ext.ComponentQuery.query('chart')[0],
axis;
if (axisside === "left") {
@@ -1188,46 +1206,59 @@ Ext.define('FHEM.controller.ChartController', {
//adding linked yfield to axis fields
axis.fields.push(yfield);
- var series = {
- type : 'line',
- axis : axisside,
- xField : 'TIMESTAMP',
- yField : yfield,
- title: title,
- showInLegend: (styleConfig.yaxislegendcheck === "false" || styleConfig.yaxislegendcheck === false) ? false : true,
- smooth: (styleConfig.yaxisstepcheck === "true" || styleConfig.yaxisstepcheck === true)? 0 : styleConfig.yaxissmoothing,
- highlight: {
- size: 5,
- radius: 5
+ chart.surface.addGradient({
+ id: 'gradientId',
+ angle: 90,
+ stops: {
+ 10: {
+ color: '#FFFFFF'
},
- fill: (styleConfig.yaxisfillcheck === "false" || styleConfig.yaxisfillcheck === false) ? false : true,
- style: {
- fill: '#' + styleConfig.fillcolorhexcode,
-// fill: 'url(#gradientId)',
- opacity: styleConfig.fillopacity,
- stroke: '#' + styleConfig.linecolorhexcode,
- 'stroke-width': styleConfig.linestrokewidth
- },
- markerConfig: {
- type: styleConfig.pointshape,
- radius: styleConfig.pointradius,
- stroke: '#' + styleConfig.pointcolorhexcode,
- fill: '#' + styleConfig.pointcolorhexcode
- },
- showMarkers: (styleConfig.yaxisshowpoints === "false" || styleConfig.yaxisshowpoints === false) ? false : true,
- selectionTolerance: 5,
- tips : {
- trackMouse : true,
- mouseOffset: [1,1],
- showDelay: 1000,
- width : 280,
- height : 50,
- renderer : function(storeItem, item) {
- this.setTitle(' Value: : ' + storeItem.get(yfield) +
- '
Time: ' + storeItem.get('TIMESTAMP'));
- }
+ 100: {
+ color: '#' + styleConfig.fillcolorhexcode
}
- };
+ }
+ });
+
+ var series = {
+ type : 'line',
+ axis : axisside,
+ xField : 'TIMESTAMP',
+ yField : yfield,
+ title: title,
+ showInLegend: (styleConfig.yaxislegendcheck === "false" || styleConfig.yaxislegendcheck === false) ? false : true,
+ smooth: (styleConfig.yaxisstepcheck === "true" || styleConfig.yaxisstepcheck === true)? 0 : styleConfig.yaxissmoothing,
+ highlight: {
+ size: 5,
+ radius: 5
+ },
+ fill: (styleConfig.yaxisfillcheck === "false" || styleConfig.yaxisfillcheck === false) ? false : true,
+ style: {
+// fill: '#' + styleConfig.fillcolorhexcode,
+ fill: 'url(#gradientId)',
+ opacity: styleConfig.fillopacity,
+ stroke: '#' + styleConfig.linecolorhexcode,
+ 'stroke-width': styleConfig.linestrokewidth
+ },
+ markerConfig: {
+ type: styleConfig.pointshape,
+ radius: styleConfig.pointradius,
+ stroke: '#' + styleConfig.pointcolorhexcode,
+ fill: '#' + styleConfig.pointcolorhexcode
+ },
+ showMarkers: (styleConfig.yaxisshowpoints === "false" || styleConfig.yaxisshowpoints === false) ? false : true,
+ selectionTolerance: 5,
+ tips : {
+ trackMouse : true,
+ mouseOffset: [1,1],
+ showDelay: 1000,
+ width : 280,
+ height : 50,
+ renderer : function(storeItem, item) {
+ this.setTitle(' Value: : ' + storeItem.get(yfield) +
+ '
Time: ' + storeItem.get('TIMESTAMP'));
+ }
+ }
+ };
return series;
},
@@ -1249,7 +1280,7 @@ Ext.define('FHEM.controller.ChartController', {
*/
generalizeChartData: function(generalizationfactor, index) {
- var store = this.getChart().getStore();
+ var store = Ext.ComponentQuery.query('chart')[0].getStore();
this.factorpositive = 1 + (generalizationfactor / 100),
this.factornegative = 1 - (generalizationfactor / 100),
@@ -1625,8 +1656,7 @@ Ext.define('FHEM.controller.ChartController', {
// preapre the string for the file
var finalstring = "FHEM.filelogcharts = " + Ext.encode(FHEM.filelogcharts) + ";;";
- var cmd = "{ `echo '" + finalstring + "' > www/frontend/app/filelogcharts.js`}";
-// var cmd = "{ `echo '" + finalstring + "' > www/frontenddev/app/filelogcharts.js`}";
+ var cmd = "{ `echo '" + finalstring + "' > " + FHEM.appPath + "filelogcharts.js`}";
Ext.Ajax.request({
method: 'POST',
@@ -1669,7 +1699,8 @@ Ext.define('FHEM.controller.ChartController', {
/**
* loading saved chart data and trigger the load of the chart
*/
- loadsavedchart: function(treeview, record) {
+ loadsavedchart: function(treeview, record, hidden) {
+
if (!record.raw.data) {
record.raw.data = record.raw;
}
@@ -1691,7 +1722,10 @@ Ext.define('FHEM.controller.ChartController', {
//cleanup the form before loading
this.resetFormFields();
- this.getChartformpanel().collapse();
+ // no collapsing when hidden chart, will break the panel if done hidden
+ if (hidden !== true) {
+ this.getChartformpanel().collapse();
+ }
if (chartdata && !Ext.isEmpty(chartdata)) {
@@ -1912,7 +1946,7 @@ Ext.define('FHEM.controller.ChartController', {
me.getChartformpanel().down('textfield[name=leftaxistitle]').setValue(leftaxistitle);
}
- this.requestChartData();
+ this.requestChartData(false, hidden);
this.getLinechartpanel().setTitle(name);
} else {
Ext.Msg.alert("Error", "The Chart could not be loaded! RawChartdata was:
" + chartdata);
diff --git a/fhem/www/frontend/www/frontend/app/controller/MainController.js b/fhem/www/frontend/www/frontend/app/controller/MainController.js
index 7aa693801..f6b8d1628 100644
--- a/fhem/www/frontend/www/frontend/app/controller/MainController.js
+++ b/fhem/www/frontend/www/frontend/app/controller/MainController.js
@@ -41,6 +41,9 @@ Ext.define('FHEM.controller.MainController', {
'panel[name=fhemaccordion]': {
expand: this.showFHEMPanel
},
+ 'panel[name=fhemstatusaccordion]': {
+ expand: this.showFHEMStatusPanel
+ },
'panel[name=tabledataaccordionpanel]': {
expand: this.showDatabaseTablePanel
},
@@ -68,6 +71,9 @@ Ext.define('FHEM.controller.MainController', {
},
'button[name=sortedtree]': {
click: this.setupTree
+ },
+ 'panel[name=statuspanel]': {
+ saveconfig: this.saveObjectToUserConfig
}
});
},
@@ -84,6 +90,8 @@ Ext.define('FHEM.controller.MainController', {
me.createLineChartPanel();
me.createDatabaseTablePanel();
+ me.showFHEMStatusPanel();
+
me.getMainviewport().show();
me.getMainviewport().getEl().setOpacity(0);
me.getMainviewport().getEl().animate({
@@ -95,7 +103,7 @@ Ext.define('FHEM.controller.MainController', {
if (Ext.isDefined(FHEM.version)) {
var sp = this.getStatustextfield();
- sp.setText(FHEM.version + "; Frontend Version: 1.0.7 - 2014-01-03");
+ sp.setText(FHEM.version + "; Frontend Version: 1.0.8 - 2014-01-12");
}
this.setupTree(false);
@@ -192,8 +200,10 @@ Ext.define('FHEM.controller.MainController', {
//add the charts to the tree
store.on("load", function() {
var rootNode = me.getMaintreepanel().getRootNode(),
- chartfolder = {text: "Charts", expanded: true, children: []};
+ chartfolder = {text: "Charts", expanded: true, children: []},
+ statusfolder = {text: "StatusRoom", expanded: true, children: []};
rootNode.appendChild(chartfolder);
+ rootNode.appendChild(statusfolder);
var chartfoldernode = rootNode.findChild("text", "Charts", true);
//add the filelogcharts to the store
@@ -226,6 +236,7 @@ Ext.define('FHEM.controller.MainController', {
chartchild = {text: 'Create new Chart', leaf: true, data: {template: true}, iconCls:'x-tree-icon-leaf-chart'};
chartfoldernode.appendChild(chartchild);
+ me.getMaintreepanel().fireEvent('treeloaded');
});
},
@@ -455,6 +466,15 @@ Ext.define('FHEM.controller.MainController', {
}
},
+ /**
+ *
+ */
+ showFHEMStatusPanel: function() {
+ var panel = Ext.ComponentQuery.query('statuspanel')[0];
+ this.hideCenterPanels();
+ panel.show();
+ },
+
/**
*
*/
@@ -572,6 +592,54 @@ Ext.define('FHEM.controller.MainController', {
var panel = Ext.ComponentQuery.query('tabledatagridpanel')[0];
this.hideCenterPanels();
panel.show();
- }
+ },
+ /**
+ * Method appending and saving a given object to the file userconfig.js, which is loaded on page load
+ * The location names the accesible part where the object should be saved in
+ */
+ saveObjectToUserConfig: function(objectToSave, location) {
+
+ var me = this;
+
+ if (FHEM.userconfig && objectToSave && !Ext.isEmpty(location)) {
+
+ FHEM.userconfig[location] = objectToSave;
+
+ // preapre the string for the file
+ var finalstring = "FHEM = {};;FHEM.userconfig = " + Ext.encode(FHEM.userconfig) + ";;";
+
+ var cmd = "{ `echo '" + finalstring + "' > " + FHEM.appPath + "userconfig.js`}";
+
+ Ext.Ajax.request({
+ method: 'POST',
+ disableCaching: false,
+ url: '../../../fhem?',
+ params: {
+ cmd: cmd,
+ XHR: 1
+ },
+ success: function(response){
+ if (response.status === 200) {
+ Ext.Msg.alert("Success", "Changes successfully saved!");
+ } else if (response.statusText) {
+ Ext.Msg.alert("Error", "The Changes could not be saved, error Message is:
" + response.statusText);
+ } else {
+ Ext.Msg.alert("Error", "The Changes could not be saved!");
+ }
+ },
+ failure: function(response) {
+ if (response.statusText) {
+ Ext.Msg.alert("Error", "The Changes could not be saved, error Message is:
" + response.statusText);
+ } else {
+ Ext.Msg.alert("Error", "The Changes could not be saved!");
+ }
+ }
+ });
+
+ } else {
+ Ext.Msg.alert("Error", "A save attempt was made without enough parameters!");
+ }
+
+ }
});
\ No newline at end of file
diff --git a/fhem/www/frontend/www/frontend/app/controller/StatusController.js b/fhem/www/frontend/www/frontend/app/controller/StatusController.js
new file mode 100644
index 000000000..ef338c1ac
--- /dev/null
+++ b/fhem/www/frontend/www/frontend/app/controller/StatusController.js
@@ -0,0 +1,454 @@
+/**
+ * The Controller handling Status Panel
+ */
+Ext.define('FHEM.controller.StatusController', {
+ extend: 'Ext.app.Controller',
+ requires: [
+ 'FHEM.view.StatusPanel'
+ ],
+
+ refs: [
+ ],
+
+ /**
+ * boolean indicating when the charts tree is loaded
+ */
+ treeloaded: false,
+
+ /**
+ * boolean indicating when the statuspanel is rendered
+ */
+ statuspanelrendered: false,
+
+ /**
+ * boolean indicating that we are currently updating a preview chart
+ */
+ updateRunning: false,
+
+ /**
+ * boolean indicating that we are currently updating via global autoupdater
+ */
+ autoUpdateRunning: false,
+
+ /**
+ * init function to register listeners
+ */
+ init: function() {
+ this.control({
+ 'button[name=updatepreviewchart]': {
+ click: this.updatePreviewChart
+ },
+ 'button[name=loadfullchart]': {
+ click: this.loadFullChart
+ },
+ 'panel[name=statuspanel]': {
+ afterrender: function() {
+ this.statuspanelrendered = true;
+ this.setupPanelsFromTreeContent();
+ },
+ show: this.setupGlobalUpdateTask,
+ hide: function() {
+ Ext.each(Ext.TaskManager.tasks, function(task) {
+ if (task.name === 'countdowntask') {
+ Ext.TaskManager.stop(task);
+ }
+ });
+ }
+ },
+ 'panel[name=maintreepanel]': {
+ treeloaded: function() {
+ this.treeloaded = true;
+ this.setupPanelsFromTreeContent();
+ }
+ },
+ 'button[name=applypreviewchartsize]': {
+ click: function() {
+ this.destroyAllPreviewPanels();
+ this.setupPanelsFromTreeContent();
+ }
+ },
+ 'button[name=reloadallpreviews]': {
+ click: this.triggerUpdateForAllPreviews
+ },
+ 'treeview': {
+ drop: function() {
+ this.destroyAllPreviewPanels();
+ this.setupPanelsFromTreeContent();
+ }
+ },
+ 'button[name=savepreviewchartsconfig]': {
+ click: function() {
+
+ var panel = Ext.ComponentQuery.query('panel[name=statuspanel]')[0],
+ location = 'previewchartsconfig',
+ objectToSave = {};
+
+ objectToSave.width = Ext.ComponentQuery.query('numberfield[name=previewchartwidth]')[0].getValue();
+ objectToSave.height = Ext.ComponentQuery.query('numberfield[name=previewchartheight]')[0].getValue();
+ objectToSave.autoUpdate = Ext.ComponentQuery.query('checkbox[name=autoupdatecheckbox]')[0].getValue();
+ objectToSave.updateInterval = Ext.ComponentQuery.query('numberfield[name=updateinterval]')[0].getValue();
+
+ // delegate to maincontroller
+ panel.fireEvent("saveconfig", objectToSave, location);
+ }
+ },
+ 'checkbox[name=autoupdatecheckbox]': {
+ change: this.setupGlobalUpdateTask
+ }
+ });
+
+ },
+
+ /**
+ *
+ */
+ setupGlobalUpdateTask: function() {
+
+ var me = this,
+ autoUpdate = Ext.ComponentQuery.query('checkbox[name=autoupdatecheckbox]')[0].getValue(),
+ updateInterval = Ext.ComponentQuery.query('numberfield[name=updateinterval]')[0].getValue(),
+ txt = Ext.ComponentQuery.query('text[name=countdowntext]')[0];
+
+ if (autoUpdate === true && !Ext.isEmpty(updateInterval)) {
+
+ txt.setDisabled(false);
+
+ // stop all old tasks
+ Ext.each(Ext.TaskManager.tasks, function(task) {
+ if (task.name === 'countdowntask') {
+ Ext.TaskManager.stop(task);
+ }
+ });
+
+ // start the countdown
+ Ext.ComponentQuery.query('text[name=countdowntext]')[0].counter = updateInterval;
+ var countdownTask = Ext.TaskManager.start({
+ run: function() {
+ var txt = Ext.ComponentQuery.query('text[name=countdowntext]')[0];
+ if (txt.counter > 0) {
+ txt.setText('Next Update in ' + (txt.counter - 1) + 's');
+ txt.counter--;
+ } else if (txt.counter === 0 && !me.autoUpdateRunning){
+ me.autoUpdateRunning = true;
+ me.triggerUpdateForAllPreviews();
+ txt.setText('Updating...');
+ txt.counter--;
+ } else if (!me.autoUpdateRunning){
+ var currentInterval = Ext.ComponentQuery.query('numberfield[name=updateinterval]')[0].getValue();
+ txt.setText('Next Update in ' + currentInterval + 's');
+ txt.counter = currentInterval;
+ }
+ },
+ name: 'countdowntask',
+ interval: 900
+ });
+
+ } else {
+ Ext.each(Ext.TaskManager.tasks, function(task) {
+ if (task.name === 'countdowntask') {
+ Ext.TaskManager.stop(task);
+ }
+ });
+ txt.setText('Update disabled');
+ txt.setDisabled(true);
+ }
+ },
+
+ /**
+ *
+ */
+ createPreviewChartPanel: function(record) {
+ var me = this,
+ desiredWidth = Ext.ComponentQuery.query('numberfield[name=previewchartwidth]')[0].getValue(),
+ desiredHeight = Ext.ComponentQuery.query('numberfield[name=previewchartheight]')[0].getValue(),
+ savename;
+
+ if (record.raw.ID) {
+ savename = record.raw.ID + '.svg';
+ } else {
+ savename = record.raw.data.ID + '.svg';
+ }
+ var previewchartcontainer = Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0],
+ previewpanel = Ext.create('Ext.panel.Panel', {
+ width: desiredWidth,
+ height: desiredHeight,
+ title: record.raw.text ? record.raw.text : 'No title found...',
+ record: record,
+ name: 'chartpreviewpanel',
+ items: [
+ {
+ xtype: 'toolbar',
+ ui: 'footer',
+ enableOverflow: true,
+ items: [
+ {
+ xtype: 'text',
+ name: 'lastupdatedtext',
+ text: "Last Updated: not yet"
+ },
+ '->',
+ {
+ text: 'Open Full Chart',
+ name: 'loadfullchart'
+ },
+ {
+ text: 'Reload',
+ name: 'updatepreviewchart'
+ }
+ ]
+ },
+ {
+ xtype: 'image',
+ layout: 'fit',
+ // add date to path to avoid cached images from browser
+ src: 'app/imagecache/' + savename + '?_' + new Date(),
+ width: desiredWidth,
+ height: desiredHeight - 53
+ }
+ ]
+ });
+ previewchartcontainer.add(previewpanel);
+ },
+
+ /**
+ *
+ */
+ loadFullChart: function(btn) {
+ var rec = btn.up('panel[name=chartpreviewpanel]').record;
+
+ var centerpanels = Ext.ComponentQuery.query('panel[region=center]');
+ Ext.each(centerpanels, function(panel) {
+ panel.hide();
+ });
+
+ Ext.ComponentQuery.query('linechartpanel')[0].show();
+ Ext.ComponentQuery.query('treepanel')[0].expand();
+
+ btn.fireEvent('loadchart', null, rec, false);
+
+ },
+
+ /**
+ *
+ */
+ destroyAllPreviewPanels: function() {
+ Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0].removeAll();
+ },
+
+ /**
+ *
+ */
+ setupPanelsFromTreeContent: function() {
+
+ var me = this;
+
+ if (me.statuspanelrendered && me.treeloaded) {
+ var root = Ext.ComponentQuery.query('treepanel')[0].getRootNode(),
+ statusfoldernode = root.findChild("text", "StatusRoom", true);
+
+ if (statusfoldernode.childNodes.length > 0) {
+ Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0].update('');
+ } else {
+ Ext.ComponentQuery.query('panel[name=previewchartcontainer]')[0].update(
+ 'This panel gives you an overview of your Charts by displaying them as small windows here.
' +
+ 'To add Charts to this Overview, simply drop some into the folder "StatusRoom" which you
' +
+ 'can find in the tree on the left side.
' +
+ 'Add as much charts as you want, configure their size and update options and save your
' +
+ 'settings by clicking on "Save configuration".
' +
+ 'The first time you add a new chart you need to reload it, before you can see it!');
+ }
+
+ Ext.each(statusfoldernode.childNodes, function(node) {
+ me.createPreviewChartPanel(node);
+ });
+
+ //initialize auto update
+ me.setupGlobalUpdateTask();
+ }
+
+ },
+
+ /**
+ *
+ */
+ updatePreviewChart: function(btn, panel) {
+
+ var me = this;
+ if (panel && panel.down) {
+ btn = panel.down('button[name=updatepreviewchart]');
+ }
+
+ if (me.updateRunning === true) {
+ window.setTimeout(function() {
+ me.updatePreviewChart(btn);
+ }, 500);
+ return;
+ }
+
+ me.updateRunning = true;
+
+ // destroy all old charts
+ me.destroyAllCharts();
+
+ var imgcontainer = btn.up('panel').down('image');
+ imgcontainer.setLoading(true);
+
+ // get record from panel
+ var record = btn.up('panel').record;
+ // event will get caught in chartcontroller
+ btn.fireEvent('loadhiddenchart', null, record, true);
+
+ // now we wait till the chart is rendered
+ var task = Ext.TaskManager.start({
+ run: function() {
+ me.checkForRenderedChart(imgcontainer, task);
+ },
+ name: 'hiddenchart',
+ interval: 500
+ });
+ },
+
+ /**
+ *
+ */
+ triggerUpdateForAllPreviews: function() {
+ var me = this,
+ allPanels = Ext.ComponentQuery.query('panel[name=chartpreviewpanel]');
+
+ Ext.each(allPanels, function(panel) {
+ me.updatePreviewChart(false, panel);
+ });
+ },
+
+ /**
+ * method destroys all rendered charts
+ */
+ destroyAllCharts: function() {
+ var charts = Ext.ComponentQuery.query('chart');
+ Ext.each(charts, function(chart) {
+ chart.destroy();
+ });
+ },
+
+ /**
+ *
+ */
+ checkForRenderedChart: function(imgcontainer, task){
+ var me = this,
+ desiredWidth = Ext.ComponentQuery.query('numberfield[name=previewchartwidth]')[0].getValue(),
+ desiredHeight = Ext.ComponentQuery.query('numberfield[name=previewchartheight]')[0].getValue();
+
+ var chart = Ext.ComponentQuery.query('chart')[0];
+ if (chart && chart.surface && chart.surface.el && chart.surface.el.dom) {
+ chart.setHeight(desiredHeight - 53); // removing the panels title and toolbar from height
+ chart.setWidth(desiredWidth);
+ data = chart.surface.el.dom;
+ // we need to cleanup the "ext"-invisible items because they will get rendered
+ textArray = data.getElementsByTagName("text");
+ Ext.each(textArray, function(text) {
+ if (text.getAttribute("class") && text.getAttribute("class").indexOf("x-hide-visibility") >= 0 ) {
+ text.remove();
+ }
+ });
+
+ var serializer = new XMLSerializer(),
+ svgstring = serializer.serializeToString(data),
+ canvas = document.getElementById("canvas"),
+ ctx = canvas.getContext("2d"),
+ DOMURL = self.URL || self.webkitURL || self,
+ img = new Image(),
+ svg = new Blob([svgstring], {type: "image/svg+xml;charset=utf-8"}),
+ url = DOMURL.createObjectURL(svg);
+
+ img.onload = function() {
+ ctx.drawImage(img, 0, 0);
+ DOMURL.revokeObjectURL(url);
+ };
+ img.src = url;
+ imgcontainer.setSrc(img.src);
+ imgcontainer.setLoading(false);
+
+ Ext.TaskManager.stop(task);
+ me.destroyAllCharts();
+
+ var rec = imgcontainer.up('panel').record;
+ imgcontainer.up('panel').down('text[name=lastupdatedtext]').setText(Ext.Date.format(new Date(), 'Y-m-d H:i:s'));
+
+ me.saveImageToDisk(svgstring, rec);
+ me.updateRunning = false;
+
+ // check if an autoupdate has completed
+ var sp = imgcontainer.up('panel[name=previewchartcontainer]');
+ if (me.autoUpdateRunning && imgcontainer.up('panel').title === sp.items.items[sp.items.items.length - 1].title) {
+ me.autoUpdateRunning = false;
+ }
+ }
+
+ },
+
+ /**
+ *
+ */
+ saveImageToDisk: function(svgstring, rec) {
+
+ var savename;
+
+ if (rec.raw.ID) {
+ savename = rec.raw.ID + '.svg';
+ } else {
+ savename = rec.raw.data.ID + '.svg';
+ }
+
+ //fhem specific fixes ...
+ svgstring = svgstring.replace(/;/g, ";;");
+ svgstring = svgstring.replace(/\#/g, "\\x23");
+
+ var svgArr = [],
+ lastMax = 0;
+
+ // we split up the string in onehundredthousands-packages, so fhem will accept those posts...
+ while (svgstring.length > lastMax) {
+ svgArr.push(svgstring.slice(lastMax, lastMax + 100000));
+ lastMax = lastMax + 100000;
+ }
+
+ var i = 0,
+ cmd;
+ Ext.each(svgArr, function(part) {
+ if (i === 0) {
+ cmd = "{ `echo '" + part + "' > " + FHEM.appPath + "imagecache/" + savename + "`}";
+ } else {
+ cmd = "{ `echo -n '" + part + "' >> " + FHEM.appPath + "imagecache/" + savename + "`}";
+ }
+
+ i++;
+
+ Ext.Ajax.request({
+ method: 'POST',
+ disableCaching: false,
+ async: false,
+ url: '../../../fhem?',
+ params: {
+ cmd: cmd,
+ XHR: 1
+ },
+ success: function(response){
+ if (response.status === 200) {
+ // no feedback
+ } else if (response.statusText) {
+ Ext.Msg.alert("Error", "The Chart-Image could not be saved, error Message is:
" + response.statusText);
+ } else {
+ Ext.Msg.alert("Error", "The Chart-Image could not be saved!");
+ }
+ },
+ failure: function(response) {
+ if (response.statusText) {
+ Ext.Msg.alert("Error", "The Chart-Image could not be saved, error Message is:
" + response.statusText);
+ } else {
+ Ext.Msg.alert("Error", "The Chart-Image could not be saved!");
+ }
+ }
+ });
+ });
+ }
+});
\ No newline at end of file
diff --git a/fhem/www/frontend/www/frontend/app/view/StatusPanel.js b/fhem/www/frontend/www/frontend/app/view/StatusPanel.js
new file mode 100644
index 000000000..ede456710
--- /dev/null
+++ b/fhem/www/frontend/www/frontend/app/view/StatusPanel.js
@@ -0,0 +1,123 @@
+/**
+ * A Panel containing FHEM status information
+ */
+Ext.define('FHEM.view.StatusPanel', {
+ extend: 'Ext.panel.Panel',
+ alias : 'widget.statuspanel',
+ name: 'statuspanel',
+ /**
+ *
+ */
+ title: 'FHEM Status',
+
+ /**
+ *
+ */
+ region: 'center',
+
+ /**
+ *
+ */
+ autoScroll: true,
+
+ /**
+ * init function
+ */
+ initComponent: function() {
+
+ var me = this;
+
+ me.items = [
+ {
+ xtype: 'toolbar',
+ ui: 'footer',
+ enableOverflow: true,
+ items: [
+ {
+ xtype: 'numberfield',
+ fieldLabel: "Width",
+ labelWidth: 30,
+ width: 120,
+ padding: '0 20px 0 5px',
+ name: 'previewchartwidth',
+ value: (FHEM.userconfig.previewchartsconfig &&
+ FHEM.userconfig.previewchartsconfig.width) ?
+ FHEM.userconfig.previewchartsconfig.width : 459
+ },
+ {
+ xtype: 'numberfield',
+ fieldLabel: "Height",
+ labelWidth: 30,
+ width: 120,
+ padding: '0 20px 0 5px',
+ name: 'previewchartheight',
+ value: (FHEM.userconfig.previewchartsconfig &&
+ FHEM.userconfig.previewchartsconfig.height) ?
+ FHEM.userconfig.previewchartsconfig.height : 280
+ },
+ {
+ text: 'Apply Size',
+ name: 'applypreviewchartsize'
+ },
+ {
+ xtype: 'tbseparator'
+ },
+ {
+ xtype: 'checkbox',
+ fieldLabel: "Auto Update?",
+ labelWidth: 70,
+ name: 'autoupdatecheckbox',
+ checked: (FHEM.userconfig.previewchartsconfig &&
+ FHEM.userconfig.previewchartsconfig.autoUpdate === false) ?
+ false : true
+ },
+ {
+ xtype: 'numberfield',
+ fieldLabel: "Update Interval",
+ labelWidth: 80,
+ name: 'updateinterval',
+ width: 150,
+ minValue: 60,
+ editable: false,
+ value: (FHEM.userconfig.previewchartsconfig &&
+ FHEM.userconfig.previewchartsconfig.updateInterval) ?
+ FHEM.userconfig.previewchartsconfig.updateInterval : 120
+ },
+ {
+ xtype: 'text',
+ name: 'countdowntext',
+ width: 100,
+ counter: (FHEM.userconfig.previewchartsconfig &&
+ FHEM.userconfig.previewchartsconfig.updateInterval) ?
+ FHEM.userconfig.previewchartsconfig.updateInterval - 2 : 118,
+ text: 'Updates disabled',
+ disabled: (FHEM.userconfig.previewchartsconfig &&
+ FHEM.userconfig.previewchartsconfig.autoUpdate === false) ?
+ true : false
+ },
+ {
+ text: 'Reload all now!',
+ name: 'reloadallpreviews',
+ cls:'x-btn-default-small'
+ },
+ {
+ text: 'Save configuration',
+ name: 'savepreviewchartsconfig'
+ }
+ ]
+ },
+ {
+ xtype: 'panel',
+ name: 'previewchartcontainer',
+ layout: 'column',
+ html: 'This panel gives you an overview of your Charts by displaying them as small windows here.
' +
+ 'To add Charts to this Overview, simply drop some into the folder "StatusRoom" which you
' +
+ 'can find in the tree on the left side.
' +
+ 'Add as much charts as you want, configure their size and update options and save your
' +
+ 'settings by clicking on "Save configuration".
' +
+ 'The first time you add a new chart you need to reload it, before you can see it!'
+ }
+ ];
+ me.callParent(arguments);
+ }
+});
diff --git a/fhem/www/frontend/www/frontend/app/view/Viewport.js b/fhem/www/frontend/www/frontend/app/view/Viewport.js
index 16b2b1ad8..911c6afed 100644
--- a/fhem/www/frontend/www/frontend/app/view/Viewport.js
+++ b/fhem/www/frontend/www/frontend/app/view/Viewport.js
@@ -9,6 +9,7 @@ Ext.define('FHEM.view.Viewport', {
requires: [
'FHEM.view.LineChartPanel',
'FHEM.view.TableDataGridPanel',
+ 'FHEM.view.StatusPanel',
'FHEM.controller.ChartController',
'FHEM.store.SavedChartsStore',
'Ext.layout.container.Border',
@@ -107,6 +108,13 @@ Ext.define('FHEM.view.Viewport', {
type: 'accordion'
},
items: [
+ {
+ title: 'FHEM Status',
+ name: 'fhemstatusaccordion',
+ expanded: true,
+ bodyPadding: '5 5 5 5',
+ html: 'See your current FHEM Status / Overview Information here.'
+ },
{
title: 'FHEM',
name: 'fhemaccordion',
@@ -198,28 +206,31 @@ Ext.define('FHEM.view.Viewport', {
minHeight: 30
},
{
- region: 'center',
- title: 'Welcome',
- layout: 'hbox',
- bodyStyle: 'padding:5px 5px 0',
- items: [
- {
- xtype: 'image',
- src: '../../fhem/images/default/fhemicon.png',
- height: 132,
- width: 120
- },
- {
- xtype: 'text',
- name: 'statustextfield',
- padding: '50 0 0 20',
- width: 400,
- height: 130,
- html: '
Welcome to the new FHEM Frontend.
For Informations, Problems and discussion, visit the FHEM Forums'
- }
- ],
- height: '100%'
+ xtype: 'statuspanel'
}
+// {
+// region: 'center',
+// title: 'Welcome',
+// layout: 'hbox',
+// bodyStyle: 'padding:5px 5px 0',
+// items: [
+// {
+// xtype: 'image',
+// src: '../../fhem/images/default/fhemicon.png',
+// height: 132,
+// width: 120
+// },
+// {
+// xtype: 'text',
+// name: 'statustextfield',
+// padding: '50 0 0 20',
+// width: 400,
+// height: 130,
+// html: '
Welcome to the new FHEM Frontend.
For Informations, Problems and discussion, visit the FHEM Forums'
+// }
+// ],
+// height: '100%'
+// }
]
});
diff --git a/fhem/www/frontend/www/frontend/index.html b/fhem/www/frontend/www/frontend/index.html
index cfb2aea6e..2e400eb93 100644
--- a/fhem/www/frontend/www/frontend/index.html
+++ b/fhem/www/frontend/www/frontend/index.html
@@ -28,5 +28,7 @@