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 "". - "
". - "
$min
". - "". + "
". + "
$min
". + "
". + "". ""; } @@ -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 = '
'+val[i]+ - '
'; - 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= - '
'+min+'
'+ - ''; - 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 = + '
'+min+'
'+ + ''; + 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 = '
'+val[i]+ + '
'; + 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 +};