FB_CALLIST: update only the changed items via inform mechanism. don't update all items allways. (Forum: #80376)

git-svn-id: https://svn.fhem.de/fhem/trunk@15880 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
markusbloch
2018-01-13 21:46:04 +00:00
parent 0fbe4c7028
commit 0f55894198
2 changed files with 186 additions and 109 deletions

View File

@@ -334,7 +334,7 @@ sub FB_CALLLIST_Notify($$)
if(grep(m/^(?:ATTR $name icon-mapping .*|INITIALIZED|REREADCFG)$/, @{$events}))
{
my $value = AttrVal($name,"icon-mapping","");
$value =~ s/"([^"]+?)"/'$1'/g; # workaround for array variable interpretation
my $table = eval($value);
@@ -434,7 +434,7 @@ sub FB_CALLLIST_Notify($$)
$hash->{helper}{DATA}{$timestamp} = undef;
$data = \%{$hash->{helper}{DATA}{$timestamp}};
$data->{internal_index} = $timestamp;
$data->{external_number} = ReadingsVal($fb, "external_number", undef);
$data->{external_name} = ReadingsVal($fb, "external_name", undef);
$data->{external_connection} = ReadingsVal($fb, "external_connection", undef);
@@ -489,8 +489,8 @@ sub FB_CALLLIST_Notify($$)
# clean up the list
FB_CALLLIST_cleanupList($hash);
# Inform all FHEMWEB clients
FB_CALLLIST_updateFhemWebClients($hash);
# inform about changes of current call index
FB_CALLLIST_updateOneItemInFHEMWEB($hash,$data->{internal_index});
# save current list state to file/configDB
FB_CALLLIST_saveList($hash);
@@ -561,6 +561,7 @@ sub FB_CALLLIST_cleanupList($)
foreach $index (@list)
{
Log3 $name, 5, "FB_CALLLIST ($name) - deleting old call $index";
FW_directNotify($name, "{\"action\":\"delete\",\"index\":\"$index\"}", 1) if(defined($FW_ME));
delete($hash->{helper}{DATA}{$index});
}
@@ -576,11 +577,11 @@ sub FB_CALLLIST_cleanupList($)
# check if calls are expired and delete them
sub FB_CALLLIST_deleteExpiredCalls($;$)
{
my ($hash, $inform) = @_;
my ($hash, $save) = @_;
if(ref($hash) ne "HASH")
{
($hash, $inform) = ($defs{$hash}, 1);
($hash, $save) = ($defs{$hash}, 1);
}
my $name = $hash->{NAME};
@@ -631,6 +632,10 @@ sub FB_CALLLIST_deleteExpiredCalls($;$)
foreach my $index (@list)
{
Log3 $name, 5, "FB_CALLLIST ($name) - deleting expired call $index";
# Inform Web Client
FW_directNotify($name, "{\"action\":\"delete\",\"index\":\"$index\"}", 1) if(defined($FW_ME));
delete($hash->{helper}{DATA}{$index});
}
}
@@ -648,14 +653,8 @@ sub FB_CALLLIST_deleteExpiredCalls($;$)
}
}
if($inform)
{
# Inform all FHEMWEB clients
FB_CALLLIST_updateFhemWebClients($hash);
# save current list state to file/configDB
FB_CALLLIST_saveList($hash);
}
# save current list state to file/configDB
FB_CALLLIST_saveList($hash) if($save);
}
}
@@ -771,50 +770,101 @@ sub FB_CALLLIST_getListItems($)
my ($hash) = @_;
my $name = $hash->{NAME};
my @list = FB_CALLLIST_createOrderedIndexList($hash);
my @result;
if(exists($hash->{helper}{DATA}) and (scalar keys %{$hash->{helper}{DATA}}) > 0)
if(@list)
{
my $count = 0;
my @list = sort { (AttrVal($name, "list-order","descending") eq "descending") ? $b <=> $a : $a <=> $b } keys %{$hash->{helper}{DATA}};
if(AttrVal($hash->{NAME}, "list-type", "all") eq "missed-calls")
{
@list = grep { !$hash->{helper}{DATA}{$_}{running_call} } @list;
}
if(AttrVal($hash->{NAME}, "list-type", "all") eq "completed")
{
@list = grep { !$hash->{helper}{DATA}{$_}{running_call} } @list;
}
foreach my $index (@list)
{
$count++;
my $data = \%{$hash->{helper}{DATA}{$index}};
push @result, FB_CALLLIST_index2line($hash, $index);
}
}
my $number = $data->{external_number};
return @result;
}
my $line = {
#####################################
# creates a line hash from index
sub FB_CALLLIST_index2line($$)
{
my ($hash, $index) = @_;
my $name = $hash->{NAME};
if(exists($hash->{helper}{DATA}{$index}))
{
my $data = \%{$hash->{helper}{DATA}{$index}};
my $count = FB_CALLLIST_getItemLineNumberFromIndex($hash,$index);
my $line = {
index => $index,
line => $count, # internal line identifier for JavaScript, must be present
row => $count, # column "row" to display or not
state => FB_CALLLIST_returnCallState($hash, $index),
timestamp => strftime(AttrVal($name, "time-format-string", "%a, %d %b %Y %H:%M:%S"), localtime($index)),
name => ($data->{external_name} eq "unknown" ? "-" : $data->{external_name}),
number => $number,
number => $data->{external_number},
external => ($data->{external_connection} ? ((exists($hash->{helper}{EXTERNAL_MAP}) and exists($hash->{helper}{EXTERNAL_MAP}{$data->{external_connection}})) ? $hash->{helper}{EXTERNAL_MAP}{$data->{external_connection}} : $data->{external_connection} ) : "-"),
internal => ((exists($hash->{helper}{INTERNAL_FILTER}) and exists($hash->{helper}{INTERNAL_FILTER}{$data->{internal_number}})) ? $hash->{helper}{INTERNAL_FILTER}{$data->{internal_number}} : $data->{internal_number} ),
connection => ($data->{internal_connection} ? ((exists($hash->{helper}{CONNECTION_MAP}) and exists($hash->{helper}{CONNECTION_MAP}{$data->{internal_connection}})) ? $hash->{helper}{CONNECTION_MAP}{$data->{internal_connection}} : $data->{internal_connection} ) : "-"),
duration => FB_CALLLIST_formatDuration($hash, $index)
};
};
return $line;
}
push @result, $line;
return undef;
}
#####################################
# creates an array of data indices in order to display
sub FB_CALLLIST_createOrderedIndexList($)
{
my ($hash) = @_;
my $name = $hash->{NAME};
my @list;
if(exists($hash->{helper}{DATA}) and (scalar keys %{$hash->{helper}{DATA}}) > 0)
{
my $count = 0;
@list = sort { (AttrVal($name, "list-order","descending") eq "descending") ? $b <=> $a : $a <=> $b } keys %{$hash->{helper}{DATA}};
if(AttrVal($name, "list-type", "all") eq "missed-calls")
{
@list = grep { !$hash->{helper}{DATA}{$_}{running_call} } @list;
}
if(AttrVal($name, "list-type", "all") eq "completed")
{
@list = grep { !$hash->{helper}{DATA}{$_}{running_call} } @list;
}
}
return @result;
return @list;
}
#####################################
# get formated list items to display
sub FB_CALLLIST_getItemLineNumberFromIndex($$)
{
my ($hash,$index) = @_;
my $name = $hash->{NAME};
my @list = FB_CALLLIST_createOrderedIndexList($hash);
if(@list)
{
my $count = 0;
foreach my $tmp (@list)
{
$count++;
return $count if($tmp eq $index);
}
}
return undef;
}
#####################################
@@ -863,14 +913,7 @@ sub FB_CALLLIST_list2html($)
{
foreach $line (@item_list)
{
if(defined(my $cmd = AttrVal($name, "number-cmd", undef)))
{
$cmd =~ s/\$NUMBER/$line->{number}/g;
$line->{number} = '<a href=\'#\' onclick="FW_cmd(FW_root+\'?XHR=1&cmd='.urlEncode($cmd).'\');return false;">'.$line->{number}."</a>";
}
$ret .= FB_CALLLIST_returnOrderedHTMLOutput($hash, $line, 'number="'.$line->{line}.'" class="fbcalllist '.($line->{line} % 2 == 1 ? "odd" : "even").'"', 'class="fbcalllist" '.$td_style);
$ret .= FB_CALLLIST_returnOrderedHTMLOutput($hash, $line, 'number="'.$line->{line}.'" index="'.$line->{index}.'" class="fbcalllist item '.($line->{line} % 2 == 1 ? "odd" : "even").'"', 'class="fbcalllist cell" '.$td_style);
}
}
else
@@ -897,7 +940,6 @@ sub FB_CALLLIST_list2html($)
setlocale(LC_ALL, $old_locale);
return $ret;
}
@@ -935,13 +977,6 @@ sub FB_CALLLIST_list2json($)
{
FB_CALLLIST_updateReadings($hash, $line) if($create_readings eq "1");
if(defined(my $cmd = AttrVal($name, "number-cmd", undef)))
{
$cmd =~ s/\$NUMBER/$line->{number}/g;
$line->{number} = '<a href=\'#\' onclick="FW_cmd(FW_root+\'?XHR=1&cmd='.urlEncode($cmd).'\');return false;">'.$line->{number}."</a>";
}
push @json_output, FB_CALLLIST_returnOrderedJSONOutput($hash, $line);
}
}
@@ -969,7 +1004,6 @@ sub FB_CALLLIST_list2json($)
return @json_output;
}
#####################################
# format duration in seconds into hh:mm:ss
sub FB_CALLLIST_formatDuration($$)
@@ -1106,7 +1140,7 @@ sub FB_CALLLIST_loadList($)
sub FB_CALLLIST_returnOrderedHTMLOutput($$$$)
{
my ($hash,$line, $tr_additions, $td_additions) = @_;
my ($hash, $line, $tr_additions, $td_additions) = @_;
my $name = $hash->{NAME};
@@ -1114,6 +1148,13 @@ sub FB_CALLLIST_returnOrderedHTMLOutput($$$$)
my @ret = ();
if(defined(my $cmd = AttrVal($name, "number-cmd", undef)) and $line->{number} =~/\d$/)
{
$cmd =~ s/\$NUMBER/$line->{number}/g;
$line->{number} = '<a href=\'#\' onclick="FW_cmd(FW_root+\'?XHR=1&cmd='.urlEncode($cmd).'\');return false;">'.$line->{number}."</a>";
}
push @ret, '<tr align="center" '.$tr_additions.'>';
foreach my $col (@order)
@@ -1136,6 +1177,13 @@ sub FB_CALLLIST_returnOrderedJSONOutput($$)
my @ret = ();
if(defined(my $cmd = AttrVal($name, "number-cmd", undef)) and $line->{number} =~/\d$/)
{
$cmd =~ s/\$NUMBER/$line->{number}/g;
$line->{number} = '<a href=\'#\' onclick="FW_cmd(FW_root+\'?XHR=1&cmd='.urlEncode($cmd).'\');return false;">'.$line->{number}."</a>";
}
push @ret, '"line":"'.$line->{line}.'"';
foreach my $col (@order)
@@ -1212,14 +1260,12 @@ sub FB_CALLLIST_updateFhemWebClients($)
# inform all FHEMWEB clients about changes
my $count = 0;
foreach my $line (@list)
{
FW_directNotify($name, $line, 1);
FW_directNotify($name, "{\"action\":\"updateItem\",\"item\":$line}", 1);
$count++;
}
# send the current row count to ensure all other rows are deleted via JS
FW_directNotify($name,"max-lines,$count", 1);
}
else
{
@@ -1239,10 +1285,25 @@ sub FB_CALLLIST_updateFhemWebClients($)
$string = "empty";
}
FW_directNotify($name, "clear,$additional_columns,$string", 1);
FW_directNotify($name, "{\"action\":\"clear\",\"content\":\"$string\"}", 1);
}
}
#####################################
# update one particular item of the call list of all connected FHEMWEB clients via inform mechanism
sub FB_CALLLIST_updateOneItemInFHEMWEB($$)
{
my ($hash, $index) = @_;
my $name = $hash->{NAME};
my $json = FB_CALLLIST_returnOrderedJSONOutput($hash, FB_CALLLIST_index2line($hash,$index));
FW_directNotify($name, "{\"action\":\"update\",\"index\":\"$index\",\"order\":\"".AttrVal($name, "list-order","descending")."\",\"item\":$json}", 1);
return undef;
}
#####################################
# returns the table header in the configured language
sub FB_CALLLIST_returnTableHeader($)

View File

@@ -14,69 +14,85 @@ $(function () {
function FW_processCallListUpdate(data)
{
var table = $(this).find("table.fbcalllist").first();
// clear the list if data starts with "clear"
if(/^clear/.test(data))
var json_data = jQuery.parseJSON(data)
// clear the list
if(json_data.action == "clear")
{
// if the table isn't already empty
if(!table.find("tr[name=empty]").length)
{
var tmp = data.split(",");
table.find("tr[number]").remove();
table.append("<tr align=\"center\" name=\"empty\"><td style=\"padding:10px;\" colspan=\""+tmp[1]+"\"><i>"+tmp[2]+"</i></td></tr>");
table.append("<tr align=\"center\" name=\"empty\"><td style=\"padding:10px;\" colspan=\""+table.find("tr.header td").length+"\"><i>"+json_data.content+"</i></td></tr>");
}
return;
return;
}
// clear all lines greater than max-lines (e.g. after activate a filter statement)
if(/^max-lines/.test(data))
// remove deleted item
if(json_data.action == "delete")
{
var tmp = data.split(",");
table.find("tr[number]").filter(function(index,obj) {return (parseInt($(obj).attr("number")) > parseInt(tmp[1]));}).remove();
return;
table.find("tr[index='"+json_data.index+"']").remove();
FW_FbCalllistUpdateRowNumbers(table);
return;
}
// else it's JSON data with row updates
var json_data = jQuery.parseJSON(data)
if(table.find("tr[number="+json_data.line+"]").length)
// update a item with new data
if(json_data.action == "update")
{
$.each(json_data, function (key, val) {
if(key == "line")
{ return true; }
FW_setCallListValue(table,json_data.line,key,val);
});
}
else // add new tr row with the values)
{
// delete the empty tr row if it may exist
table.find("tr[name=empty]").remove();
var new_tr = '<tr align="center" number="'+json_data.line+'" class="'+((json_data.line % 2) == 1 ? "odd" : "even")+'">';
var style = "style=\"padding-left:6px;padding-right:6px;\"";
// create the corresponding <td> tags with the received data
$.each(json_data, function (key, val) {
if(key == "line")
{ return true; }
new_tr += '<td name="'+key+'" '+style+'>'+val+'</td>';
});
new_tr += "</tr>";
// insert new tr into table
table.append(new_tr);
if(table.find("tr[index='"+json_data.index+"']").length)
{
$.each(json_data.item, function (key, val) {
if(key == "index" || key == "line")
{ return true; }
FW_setCallListValue(table,json_data.index,key,val);
});
}
else // add new tr row with the values)
{
// delete the empty tr row if it may exist
table.find("tr[name=empty]").remove();
var new_tr = '<tr align="center" number="'+json_data.item.line+'" index="'+json_data.index+'" class="fbcalllist item '+((json_data.line % 2) == 1 ? "odd" : "even")+'">';
var style = "style=\"padding-left:6px;padding-right:6px;\"";
// create the corresponding <td> tags with the received data
$.each(json_data.item, function (key, val) {
if(key == "index" || key == "line")
{ return true; }
new_tr += '<td name="'+key+'" '+style+'>'+val+'</td>';
});
new_tr += "</tr>";
// insert new tr into table
if(json_data.order == "ascending")
{
table.append(new_tr);
}
else
{
table.find("tr.header").after(new_tr);
}
FW_FbCalllistUpdateRowNumbers(table);
}
}
}
function FW_setCallListValue(table,line,key,val)
function FW_FbCalllistUpdateRowNumbers(table)
{
table.find("tr[number="+line+"] td[name="+key+"]").each(function(index, obj) {
$(obj).html(val);
count = 0;
table.find("tr.item").each(function(index, obj) {
$(obj).attr("number", ++count);
$(obj).find("td[name='row']").html(count);
});
}
function FW_setCallListValue(table,index,key,val)
{
table.find("tr[index='"+index+"'] td[name="+key+"]").each(function(index, obj) {
$(obj).html(val);
});
}