";
@@ -2079,12 +2089,12 @@ FW_Attr(@)
}
+# recursively reads .gif .ico .jpg .png files and returns filenames as array
+# recursion starts at $FW_icondir/$dir
+# filenames are relative to $FW_icondir
sub
-FW_ReadIconsFrom($$) {
- # recursively reads .gif .ico .jpg .png files and returns filenames as array
- # recursion starts at $FW_icondir/$dir
- # filenames are relative to $FW_icondir
-
+FW_ReadIconsFrom($$)
+{
my ($prepend,$dir)= @_;
return if($dir =~ m,/\.svn,);
@@ -2108,7 +2118,7 @@ FW_ReadIconsFrom($$) {
if($entry =~ m/^(.*)\.($ICONEXTENSION)$/i) {
my $logicalname= $1;
my $iconname= "${prepend}${logicalname}";
- #Debug " icon: \"$iconname\"";
+ #Debug " icon: $iconname / $filename";
$FW_icons{$iconname}= $filename;
}
}
@@ -2140,7 +2150,8 @@ FW_ReadIcons($)
# if now icons were found so far, read icons from icondir itself
FW_ReadIconsFrom("", "") unless(%FW_icons);
- $hash->{fhemIcons} = \%FW_icons;
+ my %icons = %FW_icons;
+ $hash->{fhemIcons} = \%icons;
my $dumpLevel = 4;
if($attr{global}{verbose} >= $dumpLevel) {
@@ -2149,15 +2160,6 @@ FW_ReadIcons($)
Log $dumpLevel, " $k => " . $FW_icons{$k};
}
}
-
-}
-
-# get the icon set from the device
-sub
-FW_GetIcons() {
- #Debug "Getting icons for $FW_wname.";
- my $hash= $defs{$FW_wname};
- %FW_icons= %{$hash->{fhemIcons}};
}
sub
@@ -2165,13 +2167,15 @@ FW_canonicalizeIcon($) {
my ($name)= @_;
if($name =~ m/^(.*)\.($ICONEXTENSION)$/) {
Log 1, "WARNING: argument of FW_canonicalizeIcon($name) has extension - inform the developers!";
+
$name= $1;
}
return $name;
}
sub
-FW_getIcon($) {
+FW_getIcon($)
+{
my ($name)= @_;
$name= FW_canonicalizeIcon($name);
return $FW_icons{$name} ? $name : undef;
@@ -2182,10 +2186,10 @@ FW_getIcon($) {
# FS20.on -> $FW_icondir/dark/FS20.on.png
# weather/sunny -> $FW_icondir/default/weather/sunny.gif
sub
-FW_IconPath($) {
+FW_IconPath($)
+{
my ($name)= @_;
$name= FW_canonicalizeIcon($name);
- FW_GetIcons(); # get the icon set for the current instance
my $path= $FW_icons{$name};
return $path ? $FW_icondir . "/" . $path : undef;
}
@@ -2194,7 +2198,9 @@ FW_IconPath($) {
# examples:
# FS20.on -> /icons/FS20.on
# weather/sunny -> /icons/sunny
-sub FW_IconURL($) {
+sub
+FW_IconURL($)
+{
my ($name)= @_;
$name= FW_canonicalizeIcon($name);
return "$FW_ME/icons/${name}";
@@ -2308,8 +2314,6 @@ FW_Notify($$)
my $rn = AttrVal($dn, "room", "");
if($filter eq "all" || $rn =~ m/\b$filter\b/) {
- FW_GetIcons(); # get the icon set for the current instance
-
my @old = ($FW_wname, $FW_ME, $FW_longpoll, $FW_ss, $FW_tp, $FW_subdir);
$FW_wname = $ntfy->{SNAME};
$FW_ME = "/" . AttrVal($FW_wname, "webname", "fhem");
@@ -2450,7 +2454,7 @@ FW_Get($@)
{
my ($hash, @a) = @_;
$FW_wname= $hash->{NAME};
-
+ %FW_icons= %{$hash->{fhemIcons}};
if($a[1] eq "icon") {
return "need one icon as argument" if(int(@a) != 3);
diff --git a/FHEM/11_FHT.pm b/FHEM/11_FHT.pm
index 338be664f..9713ec01b 100755
--- a/FHEM/11_FHT.pm
+++ b/FHEM/11_FHT.pm
@@ -212,7 +212,8 @@ FHT_Set($@)
my @list = map { ($_.".0", $_+0.5) } (6..30);
pop @list;
my $tmpList="on,off,".join(",",@list);
- $cmdList =~ s/-temp/-temp:$tmpList/g;
+ $cmdList =~ s/-temp/-temp:$tmpList/g; # FHEMWEB sugar
+ $cmdList =~ s/(-from.|-to.)/$1:time/g;
return "Unknown argument $cmd, choose one of $cmdList";
}
diff --git a/docs/commandref.html b/docs/commandref.html
index 0249fd2c6..2c2f6f030 100644
--- a/docs/commandref.html
+++ b/docs/commandref.html
@@ -9918,8 +9918,9 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. You need to define an RFXtrx433
If the first value references a command, for which "set
device ?" lists a number possible choices (e.g. desired-temp for FHT
devices), then a select widget will be displayed. If the values are
- "slider,min,step,max", then a javascript driven slider is displayed. If
- the command is state, then the value will be used as a command.
+ "slider,min,step,max", then a javascript driven slider is displayed.
+ if the value is "time", then a javascript timepicker is displayed.
+ If the command is state, then the value will be used as a command.
Examples:
attr lamp webCmd on:off:on-for-timer 10
@@ -9929,8 +9930,11 @@ KlikAanKlikUit, NEXA, CHACON, HomeEasy UK. You need to define an RFXtrx433
define d2 dummy
attr d2 webCmd state
attr d2 set setList state:slider,0,1,10
+ define d3 dummy
+ attr d3 webCmd state
+ attr d3 set setList state:time
- Note: this an attribute for the displayed device, not for the FHEMWEB
+ Note: this is an attribute for the displayed device, not for the FHEMWEB
instance.
diff --git a/www/pgm2/darkstyle.css b/www/pgm2/darkstyle.css
index 36249f275..066ce1d2d 100644
--- a/www/pgm2/darkstyle.css
+++ b/www/pgm2/darkstyle.css
@@ -7,10 +7,12 @@ body { background-color: #444444; background-image:url(../icons/darklogo); b
a { color: #CCCCCC; text-decoration: none;}
a:hover { color: #ffffff; }
-table.block { border:1px solid #ffffff; width: 100%; background: #333333; box-shadow:5px 5px 5px #000; }
+table.block { border:1px solid #ffffff; width: 100%;
+ background: #333333; box-shadow:5px 5px 5px #000; }
table.block tr.odd { background: #111111; }
table.block tr.sel { background: red; }
-table { -moz-border-radius:8px; border-radius:8px; border-spacing: 0px; padding-bottom: 6px; padding-top: 6px;}
+table { border-radius:8px; border-spacing: 0px;
+ padding-bottom: 6px; padding-top: 6px;}
table#room { background: #111111; width: 140px;}
table#room a { color: #CCCCCC; text-decoration: none; }
@@ -18,10 +20,15 @@ table#room a:hover { color: #ffffff; }
table#room tr.sel { background: red; }
th {color:red; text-align: left; padding-left: 10px; font-weight: bold;}
td {padding-left: 10px; padding-right: 10px; padding-top: 3px; padding-bottom: 3px;}
-input {outline:none; background-color: #111111; border: 1px solid #ffffff; color: #cccccc; padding:5px; margin-left: 10px; border-radius:8px; box-shadow: 5px 5px 5px #000000;}
+input {outline:none; background-color: #111111;
+ border: 1px solid #ffffff; color: #cccccc; padding:5px;
+ margin-left: 10px; border-radius:8px; box-shadow: 5px 5px 5px #000000;}
input:focus {border: 1px solid red;}
-textarea {min-width:1000px; background-color: #111111; border: 1px solid #ffffff; color: #cccccc; padding:5px; margin-left: 10px; border-radius:8px; box-shadow: 5px 5px 5px #000000;}
+textarea {min-width:1000px; background-color: #111111;
+ border: 1px solid #ffffff; color: #cccccc;
+ padding:5px; margin-left: 10px;
+ border-radius:8px; box-shadow: 5px 5px 5px #000000;}
/*
next lines are for commandref and faq
@@ -37,10 +44,14 @@ h2,h3,h4 { color:#EEE; line-height:1.3; margin-top:1.5em; font-family:Verdana; }
select.attr,input.attr,select.set,input.set { margin-bottom:10px; }
a img { border-style:none; }
-set,.attr { margin-bottom:10px; float:left; }
-.slider { float:right; width:250px; height:26px;}
-.set .slider { margin-left:10px; background:#101010;
- -moz-border-radius:8px; border-radius:8px; }
+/* detail-selector & slider */
+select { margin-left:5px; margin-right:5px; }
+.set,.attr { margin-bottom:5px; float:left; }
+.slider { margin-left:10px; float:left; width:250px; height:26px; }
+.set .slider { background:#101010; border-radius:8px; }
+/* timepicker */
+.set .set { margin-bottom:2px; margin-top:3px; }
+
.handle { position:relative; cursor:pointer; width:50px; height:20px;
- line-height:20px; border:3px solid; color:white; text-align:center; }
+ line-height:20px; border:2px solid; color:white; text-align:center; }
.downText { margin-top:2px; }
diff --git a/www/pgm2/fhemweb.js b/www/pgm2/fhemweb.js
index 258064906..9c7e71d11 100644
--- a/www/pgm2/fhemweb.js
+++ b/www/pgm2/fhemweb.js
@@ -100,6 +100,9 @@ Slider(slider, min, stp, max, curr, cmd)
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); }
@@ -109,7 +112,9 @@ Slider(slider, min, stp, max, curr, cmd)
document.onmousemove = oldFn1; document.onmouseup = oldFn2;
document.ontouchmove = oldFn3; document.ontouchend = oldFn4;
if(cmd) {
- document.location = cmd.replace('%',val);
+ if(cmd.substring(0,3) != "js:") {
+ document.location = cmd.replace('%',val);
+ }
} else {
slider.nextSibling.setAttribute('value', val);
}
@@ -119,10 +124,54 @@ Slider(slider, min, stp, max, curr, cmd)
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 == "H" ? 0 : 1] = ''+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, 0, (i==0 ? 1 : 5), (i==0 ? 23 : 55), val[i],
+ 'js:setTime(slider,"'+(i==0? "H":"M")+'",%)');
+ }
+}
+
/*************** Select **************/
/** Change attr/set argument type to input:text or select **/
function
@@ -156,6 +205,11 @@ FW_selChange(sel, list, elName)
'';
Slider(newEl.firstChild, min, stp, max, undefined, undefined);
+ } 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++) {
@@ -164,7 +218,7 @@ FW_selChange(sel, list, elName)
}
}
- newEl.setAttribute('class', el.getAttribute('class')); //changed from el.class
+ newEl.setAttribute('class', el.getAttribute('class'));
newEl.setAttribute('name', el.getAttribute('name'));
el.parentNode.replaceChild(newEl, el);
diff --git a/www/pgm2/style.css b/www/pgm2/style.css
index 2ddfcf0d2..c08ec46d0 100644
--- a/www/pgm2/style.css
+++ b/www/pgm2/style.css
@@ -18,7 +18,7 @@ img { border-style: none; }
table.block { border:1px solid gray; background: #F8F8E0; }
table.block tr.odd { background: #F0F0D8; }
table.block tr.sel { background: #F0F0D8; }
-table { -moz-border-radius:8px; border-radius:8px; }
+table { border-radius:8px; }
table#room { border:1px solid gray; width: 100%; background: #D7FFFF; }
table#room tr.sel { background: #A0FFFF; }
@@ -31,12 +31,15 @@ div#dist { padding-top:0.3em; }
a img { border-style:none; }
+/* detail-selector & slider */
+select { margin-left:5px; margin-right:5px; }
.set,.attr { margin-bottom:5px; float:left; }
-.slider { float:right; width:250px; height:26px; }
-.set .slider { margin-left:10px; background:#F0F0D8;
- -moz-border-radius:8px; border-radius:8px; }
+.slider { float:left; width:250px; height:26px; }
+.set .slider { background:#F0F0D8; border-radius:8px; }
+/* timepicker */
+.set .set { margin-bottom:2px; margin-top:3px; }
+
.handle { position:relative; cursor:pointer; width:50px;
- height:20px; line-height:20px;
- -moz-user-select:none; user-select:none;
+ height:20px; line-height:20px; user-select:none;
border:3px solid; color:#278727; text-align:center; }
.downText { margin-top:2px; }
|