From 72906a2de61f16bfa8d851991d0e50142832ab34 Mon Sep 17 00:00:00 2001 From: rudolfkoenig Date: Sat, 17 Jan 2015 21:37:05 +0000 Subject: [PATCH] fhemweb.js: add JavaScript trigger, implement red save config (Forum #31293) git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@7609 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/01_FHEMWEB.pm | 49 ++++++++++++++++++++++++++-------------- fhem/fhem.pl | 9 +++++++- fhem/www/pgm2/fhemweb.js | 25 ++++++++++++-------- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/fhem/FHEM/01_FHEMWEB.pm b/fhem/FHEM/01_FHEMWEB.pm index d4a79f381..41192607a 100755 --- a/fhem/FHEM/01_FHEMWEB.pm +++ b/fhem/FHEM/01_FHEMWEB.pm @@ -16,7 +16,7 @@ sub FW_answerCall($); sub FW_dev2image($;$); sub FW_devState($$@); sub FW_digestCgi($); -sub FW_directNotify($$); +sub FW_directNotify($@); sub FW_doDetail($); sub FW_fatal($); sub FW_fileList($); @@ -593,6 +593,7 @@ FW_answerCall($) $filter = "room!=.+" if($filter eq "room=Unsorted"); my %h = map { $_ => 1 } devspec2array($filter); + $h{"#FHEMWEB:$FW_wname"} = 1; $me->{inform}{devices} = \%h; %FW_visibleDeviceHash = FW_visibleDevices(); @@ -1262,6 +1263,11 @@ FW_roomOverview($) } else { FW_pF "", $l1 eq $FW_room ? " class=\"sel\"" : ""; + my $class = $l1; + $class =~ s/[^A-Z0-9]/_/gi; + $class .= ($lastDefChange>$lastSavedChange) ? " changed" : "" + if($l1 eq "Save config"); + # image tag if we have an icon, else empty my $icoName = "ico$l1"; map { my ($n,$v) = split(":",$_); $icoName=$v if($l1 =~ m/$n/); } @@ -1273,7 +1279,7 @@ FW_roomOverview($) if($l2 =~ m/.html$/ || $l2 =~ m/^http/) { FW_pO "
$icon$l1
"; } else { - FW_pH $l2, "$icon$l1", 1; + FW_pH $l2, "$icon$l1", 1, $class; } FW_pO ""; } @@ -2216,16 +2222,15 @@ FW_makeEdit($$$) my %jsTab = ( 92=>'\\\\', 34=>'\\"', 9=>'\\t', 13=>'\\r', 10=>'\\n' ); sub -FW_longpollInfo($$$$) +FW_longpollInfo($@) { - my ($dev, $state, $html, $fmt) = @_; + my $fmt = shift; if($fmt && $fmt eq "JSON") { - $dev =~ s/([\\"\t\r\n])/$jsTab{ord($1)}/ge; - $state =~ s/([\\"\t\r\n])/$jsTab{ord($1)}/ge; - $html =~ s/([\\"\t\r\n])/$jsTab{ord($1)}/ge; - return "[\"$dev\",\"$state\",\"$html\"]"; + my @a; + map { my $x=$_; $x=~s/([\\"\t\r\n])/$jsTab{ord($1)}/ge; push @a,$x; } @_; + return '["'.join('","', @a).'"]'; } else { - return "$dev<<$state<<$html"; + return join('<<', @_); } } @@ -2248,7 +2253,7 @@ FW_roomStatesForInform($$) my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage); if($defs{$dn} && $defs{$dn}{STATE} && $defs{$dn}{TYPE} ne "weblink") { push @data, - FW_longpollInfo($dn, $defs{$dn}{STATE}, $txt, $me->{inform}{fmt}); + FW_longpollInfo($me->{inform}{fmt}, $dn, $defs{$dn}{STATE}, $txt); } } my $data = join("\n", map { s/\n/ /gm; $_ } @data)."\n"; @@ -2260,6 +2265,16 @@ FW_Notify($$) { my ($ntfy, $dev) = @_; + if( $dev->{NAME} eq "global" ) { + my $n = "#FHEMWEB:$ntfy->{NAME}"; + if( grep(m/^SAVE|INITIALIZED|REREADCFG|SHUTDOWN$/, @{$dev->{CHANGED}}) ) { + FW_directNotify($n, '$(".Save_config a").removeClass("changed")', ''); + } elsif( grep(m/^DEFINED|MODIFIED|DELETED|ATTR|DELETEATTR$/, + @{$dev->{CHANGED}}) ) { + FW_directNotify($n, '$(".Save_config a").addClass("changed")', ''); + } + } + my $h = $ntfy->{inform}; return undef if(!$h); @@ -2294,7 +2309,7 @@ FW_Notify($$) if( !$modules{$defs{$dn}{TYPE}}{FW_atPageEnd} ) { my ($allSet, $cmdlist, $txt) = FW_devState($dn, "", \%extPage); ($FW_wname, $FW_ME, $FW_ss, $FW_tp, $FW_subdir) = @old; - push @data, FW_longpollInfo($dn, $dev->{STATE}, $txt, $h->{fmt}); + push @data, FW_longpollInfo($h->{fmt}, $dn, $dev->{STATE}, $txt); } #Add READINGS @@ -2306,9 +2321,9 @@ FW_Notify($$) next; #ignore 'set' commands } my ($readingName,$readingVal) = split(": ",$events->[$i],2); - push @data, FW_longpollInfo("$dn-$readingName", - $readingVal,$readingVal, $h->{fmt}); - push @data, FW_longpollInfo("$dn-$readingName-ts", $tn, $tn, $h->{fmt}); + push @data, FW_longpollInfo($h->{fmt}, + "$dn-$readingName", $readingVal,$readingVal); + push @data, FW_longpollInfo($h->{fmt}, "$dn-$readingName-ts", $tn, $tn); } } } @@ -2341,16 +2356,16 @@ FW_Notify($$) } sub -FW_directNotify($$) # Notify without the event overhead (Forum #31293) +FW_directNotify($@) # Notify without the event overhead (Forum #31293) { - my ($dev, $msg) = @_; + my $dev = $_[0]; foreach my $ntfy (values(%defs)) { next if(!$ntfy->{TYPE} || $ntfy->{TYPE} ne "FHEMWEB" || !$ntfy->{inform} || !$ntfy->{inform}{devices}{$dev}); if(!addToWritebuffer($ntfy, - FW_longpollInfo($dev, $msg, "", $ntfy->{inform}{fmt})."\n")) { + FW_longpollInfo($ntfy->{inform}{fmt}, @_)."\n")) { my $name = $ntfy->{NAME}; Log3 $name, 4, "Closing connection $name due to full buffer in FW_Notify"; TcpServer_Close($ntfy); diff --git a/fhem/fhem.pl b/fhem/fhem.pl index cdde65211..4c9ce0ea4 100755 --- a/fhem/fhem.pl +++ b/fhem/fhem.pl @@ -219,6 +219,7 @@ use vars qw(%readyfnlist); # devices which want a "readyfn" use vars qw(%selectlist); # devices which want a "select" use vars qw(%value); # Current values, see commandref.html use vars qw($lastDefChange); # number of last def/attr change +use vars qw($lastSavedChange); # will be synced with lastDefChange on save use vars qw($cmdFromAnalyze); # used by the warnings-sub my $AttrList = "verbose:0,1,2,3,4,5 room group comment alias ". @@ -241,6 +242,7 @@ my @cmdList; # Remaining commands in a chain. Used by sleep $init_done = 0; $lastDefChange = 0; +$lastSavedChange = 0; $readytimeout = ($^O eq "MSWin32") ? 0.1 : 5.0; @@ -506,6 +508,7 @@ foreach my $d (keys %defs) { } } +$lastSavedChange = $lastDefChange; DoTrigger("global", "INITIALIZED", 1); $fhem_started = time; @@ -1231,6 +1234,7 @@ CommandRereadCfg($$) $defs{$name} = $selectlist{$name} = $cl if($name && $name ne "__anonymous__"); $inform{$name} = $informMe if($informMe); + $lastSavedChange = $lastDefChange; DoTrigger("global", "REREADCFG", 1); $init_done = 1; @@ -1408,6 +1412,8 @@ CommandSave($$) next if($fh{$key} eq "1"); ## R/O include files $ret .= "$key: $!" if(!close($fh{$key})); } + + $lastSavedChange = $lastDefChange; return ($ret ? $ret : "Wrote configuration to $param"); } @@ -3576,8 +3582,9 @@ readingsEndUpdate($$) my $oldvalue= $userReadings{$userReading}{value}; my $oldt= $userReadings{$userReading}{t}; #Debug "Evaluating " . $userReadings{$userReading}; - # evaluate perl code + $cmdFromAnalyze = $perlCode; # For the __WARN__ sub my $value= eval $perlCode; + $cmdFromAnalyze = undef; my $result; # store result if($@) { diff --git a/fhem/www/pgm2/fhemweb.js b/fhem/www/pgm2/fhemweb.js index 926b1fc92..8f55ef30b 100644 --- a/fhem/www/pgm2/fhemweb.js +++ b/fhem/www/pgm2/fhemweb.js @@ -317,17 +317,22 @@ FW_doUpdate() if(d.length != 3) continue; - $("[informId='"+d[0]+"']").each(function(){ - if(this.setValueFn) { // change the select/etc value - this.setValueFn(d[1]); + if( d[0].match(/^#FHEMWEB:/) ) { + eval(d[1]); - } else { - $(this).html(d[2]); // Readings-Value - if(d[0].match(/-ts$/)) // timestamps - $(this).addClass('changed'); - $(this).find("a[href]").each(function() { FW_replaceLink(this) }); - } - }); + } else { + $("[informId='"+d[0]+"']").each(function(){ + if(this.setValueFn) { // change the select/etc value + this.setValueFn(d[1]); + + } else { + $(this).html(d[2]); // Readings-Value + if(d[0].match(/-ts$/)) // timestamps + $(this).addClass('changed'); + $(this).find("a[href]").each(function() { FW_replaceLink(this) }); + } + }); + } for(var w in FW_widgets) if(FW_widgets[w].updateLine) // updateLine is deprecated, use setValueFn