From 8c5dfe01c1b32bff45be8d217aee29fe405b5e54 Mon Sep 17 00:00:00 2001
From: rudolfkoenig <>
Date: Mon, 15 Jul 2013 19:34:35 +0000
Subject: [PATCH] Modularizing the widget javascripts
git-svn-id: https://svn.fhem.de/fhem/trunk@3428 2b470e98-0d58-463d-a4d8-8e2adae1ed80
---
fhem/CHANGED | 3 +-
fhem/FHEM/01_FHEMWEB.pm | 29 ++--
fhem/fhem.pl | 1 +
fhem/www/pgm2/fhemweb.js | 242 +++++---------------------------
fhem/www/pgm2/fhemweb_slider.js | 143 +++++++++++++++++++
fhem/www/pgm2/fhemweb_svg.js | 28 ++++
fhem/www/pgm2/fhemweb_time.js | 63 +++++++++
7 files changed, 292 insertions(+), 217 deletions(-)
create mode 100644 fhem/www/pgm2/fhemweb_slider.js
create mode 100644 fhem/www/pgm2/fhemweb_svg.js
create mode 100644 fhem/www/pgm2/fhemweb_time.js
diff --git a/fhem/CHANGED b/fhem/CHANGED
index 69cc2b084..74f7f69cf 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,6 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII
- SVN
- - feature: longpoll in multiple browserwindows, some css ids changed to class
+ - feature: FHEMWEB widget (slider/etc) javascript handler modularized
+ - feature: FHEMWEB longpoll in multiple browserwindows
- feature: fhem.pl: version command added
- feature: LightScene: add html overview of all configured scenes in
detail view. allow usage of overview in a weblink.
diff --git a/fhem/FHEM/01_FHEMWEB.pm b/fhem/FHEM/01_FHEMWEB.pm
index 686c13ca0..6dc0ef791 100755
--- a/fhem/FHEM/01_FHEMWEB.pm
+++ b/fhem/FHEM/01_FHEMWEB.pm
@@ -76,6 +76,7 @@ use vars qw(%FW_webArgs); # all arguments specified in the GET
my $FW_zlib_checked;
my $FW_use_zlib = 1;
my $FW_activateInform = 0;
+my @FW_fhemwebjs;
#########################
# As we are _not_ multithreaded, it is safe to use global variables.
@@ -133,6 +134,10 @@ FHEMWEB_Initialize($)
$FW_icondir = "$FW_dir/images";
$FW_cssdir = "$FW_dir/pgm2";
$FW_gplotdir = "$FW_dir/gplot";
+ if(opendir(DH, "$FW_dir/pgm2")) {
+ @FW_fhemwebjs = sort grep /^fhemweb.*js$/, readdir(DH);
+ closedir(DH);
+ }
$data{webCmdFn}{slider} = "FW_sliderFn";
$data{webCmdFn}{timepicker} = "FW_timepickerFn";
@@ -552,7 +557,9 @@ FW_answerCall($)
my $jsTemplate = '';
FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/svg.js") if($FW_plotmode eq "SVG");
- FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/fhemweb.js");
+ foreach my $js (@FW_fhemwebjs) {
+ FW_pO sprintf($jsTemplate, "$FW_ME/pgm2/$js");
+ }
my $onload = AttrVal($FW_wname, "longpoll", 1) ?
"onload=\"FW_delayedStart()\"" : "";
@@ -1107,7 +1114,6 @@ FW_showRoom()
FW_pO "
$txt | ";
-
######
# Commands, slider, dropdown
if(!$FW_ss && $cmdlist) {
@@ -2609,7 +2615,7 @@ FW_htmlEscape($)
}
sub
-FW_sliderFn($$$)
+FW_sliderFn($$$$$)
{
my ($FW_wname, $d, $FW_room, $cmd, $values) = @_;
@@ -2618,17 +2624,18 @@ FW_sliderFn($$$)
my ($min,$stp, $max) = ($1, $2, $3);
my $srf = $FW_room ? "&room=$FW_room" : "";
my $cv = ReadingsVal($d, $cmd, Value($d));
- $cmd = "" if($cmd eq "state");
my $id = ($cmd eq "state") ? "" : "-$cmd";
+ $cmd = "" if($cmd eq "state");
$cv =~ s/.*?(\d+).*/$1/; # get first number
$cv = 0 if($cv !~ m/\d/);
return "".
- "".
- "".
+ "".
+ "".
" | ";
}
@@ -2645,7 +2652,7 @@ FW_timepickerFn()
my $c = "\"$FW_ME?cmd=set $d $cmd %$srf\"";
return "".
"".
- "".
+ "".
" | ";
}
diff --git a/fhem/fhem.pl b/fhem/fhem.pl
index 220c0f86d..ca13c03c0 100755
--- a/fhem/fhem.pl
+++ b/fhem/fhem.pl
@@ -2401,6 +2401,7 @@ DoTrigger($$@)
my $r = CallFn($n, "NotifyFn", $defs{$n}, $hash);
$ret .= $r if($r);
}
+ delete($hash->{NTFY_TRIGGERTIME});
################
# Inform
diff --git a/fhem/www/pgm2/fhemweb.js b/fhem/www/pgm2/fhemweb.js
index f272ec52b..d19869ad7 100644
--- a/fhem/www/pgm2/fhemweb.js
+++ b/fhem/www/pgm2/fhemweb.js
@@ -1,6 +1,7 @@
/*************** LONGPOLL START **************/
var FW_pollConn;
var FW_curLine; // Number of the next line in FW_pollConn.responseText to parse
+var FW_widgets = new Object(); // to be filled by fhemweb_*.js
function
FW_cmd(arg) /* see also FW_devState */
@@ -33,9 +34,8 @@ FW_doUpdate()
var d = lines[i].split("<<", 3); // Complete arg
if(d.length != 3)
continue;
-
var elArr = document.querySelectorAll("[informId="+d[0]+"]");
- for (var k=0; k maxX) offX = maxX;
- val = min+(offX/maxX * (max-min));
- val = Math.floor(Math.floor(val/stp)*stp);
- sh.innerHTML = val;
- sh.setAttribute('style', 'left:'+offX+'px;');
- if(cmd && cmd.substring(0,3) == "js:") {
- eval(cmd.substring(3).replace('%',val));
- }
- }
- document.onmousemove = mouseMove;
- document.ontouchmove = function(e) { touchFn(e, mouseMove); }
-
- document.onmouseup = document.ontouchend = function(e)
- {
- document.onmousemove = oldFn1; document.onmouseup = oldFn2;
- document.ontouchmove = oldFn3; document.ontouchend = oldFn4;
- if(cmd) {
- if(cmd.substring(0,3) != "js:") {
- document.location = cmd.replace('%',val);
- }
- } else {
- slider.nextSibling.setAttribute('value', val);
- }
- };
- };
-
- sh.onselectstart = function() { return false; }
- sh.onmousedown = mouseDown;
- sh.ontouchstart = function(e) { touchFn(e, mouseDown); }
-}
-
-
-function
-setTime(el,name,val)
-{
- var el = el.parentNode.parentNode.firstChild;
- var v = el.value.split(":");
- v[name] = ''+val;
- if(v[0].length < 2) v[0] = '0'+v[0];
- if(v[1].length < 2) v[1] = '0'+v[1];
- el.value = v[0]+":"+v[1];
- el.setAttribute('value', el.value);
-}
-
-function
-addTime(el,cmd)
-{
- var par = el.parentNode;
- var v = par.firstChild.value;
- var brOff = par.innerHTML.indexOf("
");
-
- if(brOff > 0) {
- par.innerHTML = par.innerHTML.substring(0, brOff).replace('"-"','"+"');
- if(cmd)
- document.location = cmd.replace('%',v);
- return;
- }
-
- el.setAttribute('value', '-');
- if(v.indexOf(":") < 0)
- par.firstChild.value = v = "12:00";
- var val = v.split(":");
-
- for(var i = 0; i < 2; i++) {
- par.appendChild(document.createElement('br'));
-
- var sl = document.createElement('div');
- sl.innerHTML = '';
- par.appendChild(sl);
- sl.setAttribute('class', par.getAttribute('class'));
-
- Slider(sl.firstChild, val[i]);
- }
-}
-
/*************** Select **************/
/** Change attr/set argument type to input:text or select **/
function
@@ -277,61 +123,54 @@ FW_selChange(sel, list, elName)
}
}
var el = document.getElementsByName(elName)[0];
- var name = el.getAttribute('name');
var qFn, qArg;
var devName="";
if(elName.indexOf("val.attr")==0) devName = elName.substring(8);
- if(elName.indexOf("val.set")==0) devName = elName.substring(7);
+ if(elName.indexOf("val.set") ==0) devName = elName.substring(7);
+ var o;
if(value==undefined) {
- newEl = document.createElement('input');
- newEl.type='text'; newEl.size=30;
- qFn = 'qArg.setAttribute("value", "%")';
- qArg = newEl;
-
+ o = new Object();
+ o.newEl = document.createElement('input');
+ o.newEl.type='text';
+ o.newEl.size=30;
+ o.qFn = 'qArg.setAttribute("value", "%")';
+ o.qArg = o.newEl;
} else {
var vArr = value.split(",");
- if(vArr.length == 4 && vArr[0] == "slider") {
- var min=parseFloat(vArr[1]),
- stp=parseFloat(vArr[2]),
- max=parseFloat(vArr[3]);
- newEl = document.createElement('div');
- newEl.innerHTML=
- ''+
- '';
- Slider(newEl.firstChild, undefined);
- qFn = 'FW_querySetSlider(qArg, "%")';
- qArg = newEl.firstChild;
- } else if(vArr.length == 1 && vArr[0] == "time") {
- newEl = document.createElement('div');
- newEl.innerHTML=''+
- '';
-
- } else {
- newEl = document.createElement('select');
- for(var j=0; j < vArr.length; j++) {
- newEl.options[j] = new Option(vArr[j], vArr[j]);
+ for(var w in FW_widgets) {
+ if(FW_widgets[w].selChange) {
+ o = FW_widgets[w].selChange(elName, devName, vArr);
+ if(o)
+ break;
}
- qFn = 'FW_querySetSelected(qArg, "%")';
- qArg = newEl;
+ }
+
+ if(!o) {
+ o = new Object();
+ o.newEl = document.createElement('select');
+ for(var j=0; j < vArr.length; j++) {
+ o.newEl.options[j] = new Option(vArr[j], vArr[j]);
+ }
+ o.qFn = 'FW_querySetSelected(qArg, "%")';
+ o.qArg = o.newEl;
}
}
- newEl.setAttribute('class', el.getAttribute('class'));
- newEl.setAttribute('name', name);
- el.parentNode.replaceChild(newEl, el);
+ o.newEl.setAttribute('class', el.getAttribute('class'));
+ o.newEl.setAttribute('name', elName);
+ el.parentNode.replaceChild(o.newEl, el);
- if((typeof qFn == "string")) {
+ if((typeof o.qFn == "string")) {
if(elName.indexOf("val.attr")==0)
- FW_queryValue('{AttrVal("'+devName+'","'+sel+'","")}', qFn, qArg);
+ FW_queryValue('{AttrVal("'+devName+'","'+sel+'","")}', o.qFn, o.qArg);
if(elName.indexOf("val.set")==0)
- FW_queryValue('{ReadingsVal("'+devName+'","'+sel+'","")}', qFn, qArg);
+ FW_queryValue('{ReadingsVal("'+devName+'","'+sel+'","")}', o.qFn, o.qArg);
}
}
@@ -361,10 +200,3 @@ FW_querySetSelected(el, val)
if(el.options[j].value == val)
el.selectedIndex = j;
}
-
-function
-FW_querySetSlider(el, val)
-{
- val = val.replace(/[^\d\.]/g, ""); // remove non numbers
- Slider(el, val);
-}
diff --git a/fhem/www/pgm2/fhemweb_slider.js b/fhem/www/pgm2/fhemweb_slider.js
new file mode 100644
index 000000000..52e0684b0
--- /dev/null
+++ b/fhem/www/pgm2/fhemweb_slider.js
@@ -0,0 +1,143 @@
+/*************** SLIDER **************/
+function
+FW_sliderUpdateLine(d)
+{
+ for(var k=0; k<2; k++) {
+ var name = "slider."+d[0];
+ if(k == 1)
+ name = name+"-"+d[1].replace(/[ \d].*$/,'');
+ el = document.getElementById(name);
+
+ if(el) {
+ var doSet = 1; // Only set the "state" slider in the detail view
+ if(el.parentNode.getAttribute("name") == "val.set"+d[0]) {
+ var el2 = document.getElementsByName("arg.set"+d[0])[0];
+ if(el2.nodeName.toLowerCase() == "select" &&
+ el2.options[el2.selectedIndex].value != "state")
+ doSet = 0;
+ }
+
+ if(doSet) {
+ var val = d[1].replace(/^.*?(\d+).*/g, "$1"); // get first number
+ if(!val.match(/\d+/))
+ val = 0;
+ FW_sliderCreate(el, val);
+ }
+
+ }
+ }
+}
+
+function
+FW_sliderCreate(slider, curr)
+{
+ var sh = slider.firstChild;
+ var lastX=-1, offX=0, maxX=0, val=-1;
+ var min = parseFloat(slider.getAttribute("min"));
+ var stp = parseFloat(slider.getAttribute("stp"));
+ var max = parseFloat(slider.getAttribute("max"));
+ var cmd = slider.getAttribute("cmd");
+
+ function
+ init()
+ {
+ maxX = slider.offsetWidth-sh.offsetWidth;
+ if(curr) {
+ offX += (curr-min)*maxX/(max-min);
+ sh.innerHTML = curr;
+ sh.setAttribute('style', 'left:'+offX+'px;');
+ }
+ }
+ init();
+
+ function
+ touchFn(e, fn)
+ {
+ e.preventDefault(); // Prevents Safari from scrolling!
+ if(e.touches == null || e.touches.length == 0)
+ return;
+ e.clientX = e.touches[0].clientX;
+ fn(e);
+ }
+
+ function
+ mouseDown(e)
+ {
+ var oldFn1 = document.onmousemove, oldFn2 = document.onmouseup,
+ oldFn3 = document.ontouchmove, oldFn4 = document.ontouchend;
+
+ if(maxX == 0)
+ init();
+ lastX = e.clientX;
+
+ function
+ mouseMove(e)
+ {
+ var diff = e.clientX-lastX; lastX = e.clientX;
+ offX += diff;
+ if(offX < 0) offX = 0;
+ if(offX > maxX) offX = maxX;
+ val = min+(offX/maxX * (max-min));
+ val = Math.floor(Math.floor(val/stp)*stp);
+ sh.innerHTML = val;
+ sh.setAttribute('style', 'left:'+offX+'px;');
+ if(cmd && cmd.substring(0,3) == "js:") {
+ eval(cmd.substring(3).replace('%',val));
+ }
+ }
+ document.onmousemove = mouseMove;
+ document.ontouchmove = function(e) { touchFn(e, mouseMove); }
+
+ document.onmouseup = document.ontouchend = function(e)
+ {
+ document.onmousemove = oldFn1; document.onmouseup = oldFn2;
+ document.ontouchmove = oldFn3; document.ontouchend = oldFn4;
+ if(cmd) {
+ if(cmd.substring(0,3) != "js:") {
+ document.location = cmd.replace('%',val);
+ }
+ } else {
+ slider.nextSibling.setAttribute('value', val);
+ }
+ };
+ };
+
+ sh.onselectstart = function() { return false; }
+ sh.onmousedown = mouseDown;
+ sh.ontouchstart = function(e) { touchFn(e, mouseDown); }
+}
+
+
+function
+FW_sliderSelChange(name, devName, vArr)
+{
+ if(vArr.length != 4 || vArr[0] != "slider")
+ return undefined;
+
+ var o = new Object();
+ var min=parseFloat(vArr[1]),
+ stp=parseFloat(vArr[2]),
+ max=parseFloat(vArr[3]);
+ o.newEl = document.createElement('div');
+ o.newEl.innerHTML =
+ ''+
+ '';
+ FW_sliderCreate(o.newEl.firstChild, undefined);
+
+ o.qFn = 'FW_querySetSlider(qArg, "%")';
+ o.qArg = o.newEl.firstChild;
+ return o;
+}
+
+function
+FW_querySetSlider(el, val)
+{
+ val = val.replace(/[^\d\.]/g, ""); // remove non numbers
+ FW_sliderCreate(el, val);
+}
+
+FW_widgets['slider'] = {
+ updateLine:FW_sliderUpdateLine,
+ selChange:FW_sliderSelChange
+};
diff --git a/fhem/www/pgm2/fhemweb_svg.js b/fhem/www/pgm2/fhemweb_svg.js
new file mode 100644
index 000000000..93b0fa35c
--- /dev/null
+++ b/fhem/www/pgm2/fhemweb_svg.js
@@ -0,0 +1,28 @@
+function
+FW_svgUpdateDevs(devs)
+{
+ // if matches, refresh the SVG by removing and readding the embed tag
+ var embArr = document.getElementsByTagName("embed");
+ for(var i = 0; i < embArr.length; i++) {
+ var svg = embArr[i].getSVGDocument();
+ if(svg == null) // too many events sometimes.
+ continue;
+ svg = svg.firstChild.nextSibling;
+ var flog = svg.getAttribute("flog");
+ for(var j=0; j < devs.length; j++) {
+ if(flog !== null && flog.match(" "+devs[j]+" ")) {
+ var e = embArr[i];
+ var newE = document.createElement("embed");
+ for(var k=0; k");
+
+ if(brOff > 0) {
+ par.innerHTML = par.innerHTML.substring(0, brOff).replace('"-"','"+"');
+ if(cmd)
+ document.location = cmd.replace('%',v);
+ return;
+ }
+
+ el.setAttribute('value', '-');
+ if(v.indexOf(":") < 0)
+ par.firstChild.value = v = "12:00";
+ var val = v.split(":");
+
+ for(var i = 0; i < 2; i++) {
+ par.appendChild(document.createElement('br'));
+
+ var sl = document.createElement('div');
+ sl.innerHTML = '';
+ par.appendChild(sl);
+ sl.setAttribute('class', par.getAttribute('class'));
+
+ FW_sliderCreate(sl.firstChild, val[i]);
+ }
+}
+
+function
+FW_timeSelChange(name, devName, vArr)
+{
+ if(vArr.length != 1 || vArr[0] != "time")
+ return undefined;
+
+ var o = new Object();
+ o.newEl = document.createElement('div');
+ o.newEl.innerHTML=''+
+ '';
+ return o;
+}
+
+FW_widgets['time'] = {
+ selChange:FW_timeSelChange
+};