diff --git a/fhem/FHEM/95_Dashboard.pm b/fhem/FHEM/95_Dashboard.pm index 88b9a9798..e2761f035 100644 --- a/fhem/FHEM/95_Dashboard.pm +++ b/fhem/FHEM/95_Dashboard.pm @@ -7,7 +7,7 @@ # Released : 20.12.2013 Sascha Hermann # Version : # 1.00: Released to testers -# 1.02: Don't show link on Groups with WebLinks. Hide GroupToogle Button (new Attribut dashboard_showtooglebuttons). +# 1.02: Don't show link on Groups with WebLinks. Hide GroupToogle Button (new Attribut dashboard_showtogglebuttons). # Set the Columnheight (new Attribur dashboard_colheight). # 1.03: Dashboard Entry over the Room-List, set the Room "Dashboard" to hiddenroom. Build weblink independently. # Dashboard Row on Top and Bottom (no separately columns). Detail Button @@ -49,11 +49,21 @@ # from Attribute dashboard_showtabs. Change Buttonbar Style. Clear CSS and Dashboard.js. # 2.12: Update Docu. CSS Class Changes. Insert Configdialog for Tabs. Change handling of parameters in both directions. # 2.13: Changed View of readingsHistory. Fix Linebrake in unlock state. Bugfix Display Group with similar group names. +# 3.00: Tabs are loading via ajax (asynchronous). +# Removed attribute "dashboard_tabcount". The number of tabs is determined automatically based on the gorup definitions. +# Group names now also support regular expressions. +# Dashboard is not limited to 1 for every FHEMWEB instance. +# Dashboard link in left menu has the same name as the dashboard definition in fhem.cfg. +# dashboard_webfrontendfilter has been removed. To hide a dashboard put its name into the FHEMWEB instance's hiddenroom attribute. +# Flexible mode to be able to position groups absolutely on the dashboard screen. +# The number of columns can be defined per tab (additionally to the global definition) +# Optimized icon loading. +# Optimized fullscreen view. +# Minor improvements in javascript and css. # # Known Bugs/Todos: # BUG: Nicht alle Inhalte aller Tabs laden, bei Plots dauert die bedienung des Dashboards zu lange. -> elemente hidden? -> widgets aus js über XHR nachladen und dann anzeigen (jquery xml nachladen...) # BUG: Variabler abstand wird nicht gesichert -# BUG: dashboard_webfrontendfilter doesn't Work Antwort #469 # BUG: Überlappen Gruppen andere? ->Zindex oberer reihe > als darunter liegenden # # Log 1, "[DASHBOARD simple debug] '".$g."' "; @@ -92,7 +102,6 @@ use vars qw($FW_room); # currently selected room use vars qw(%defs); # FHEM device/button definitions #use vars qw(%FW_groups); # List of Groups use vars qw($FW_wname); # Web instance -use vars qw(%FW_hiddenroom);# hash of hidden rooms, used by weblink use vars qw(%FW_types); # device types use vars qw($FW_ss); # is smallscreen, needed by 97_GROUP/95_VIEW @@ -106,18 +115,17 @@ my %group; my $dashboard_groupListfhem; my $fwjquery = "jquery.min.js"; my $fwjqueryui = "jquery-ui.min.js"; -my $dashboardname = "Dashboard"; # Link Text -my $dashboardhiddenroom = "DashboardRoom"; # Hiddenroom my $dashboardversion = "2.13"; +my @fhemweb_instances = (); ############################################################################################# sub Dashboard_Initialize ($) { my ($hash) = @_; - + $hash->{DefFn} = "Dashboard_define"; - $hash->{SetFn} = "Dashboard_Set"; - $hash->{GetFn} = "Dashboard_Get"; + $hash->{SetFn} = "Dashboard_Set"; + $hash->{GetFn} = "Dashboard_Get"; $hash->{UndefFn} = "Dashboard_undef"; $hash->{FW_detailFn} = "Dashboard_DetailFN"; $hash->{AttrFn} = "Dashboard_attr"; @@ -129,25 +137,9 @@ sub Dashboard_Initialize ($) { "dashboard_rowbottomheight ". "dashboard_row:top,center,bottom,top-center,center-bottom,top-center-bottom ". "dashboard_showhelper:dont-use-this-attribut ". #obolet since 04.2014 - "dashboard_showtooglebuttons:0,1 ". + "dashboard_showtogglebuttons:0,1 ". #new attribute vers. 2.00 - "dashboard_tabcount:1,2,3,4,5,6,7 ". "dashboard_activetab:1,2,3,4,5,6,7 ". - "dashboard_tab1name ". - "dashboard_tab2name ". - "dashboard_tab3name ". - "dashboard_tab4name ". - "dashboard_tab5name ". - "dashboard_tab1groups ". - "dashboard_tab2groups ". - "dashboard_tab3groups ". - "dashboard_tab4groups ". - "dashboard_tab5groups ". - "dashboard_tab1sorting ". - "dashboard_tab2sorting ". - "dashboard_tab3sorting ". - "dashboard_tab4sorting ". - "dashboard_tab5sorting ". "dashboard_width ". "dashboard_rowcenterheight ". #new attribute vers. 2.01 @@ -157,30 +149,33 @@ sub Dashboard_Initialize ($) { #"dashboard_showtabs:tabs-and-buttonbar-at-the-top,tabs-at-the-top-buttonbar-hidden,tabs-and-buttonbar-on-the-bottom,tabs-on-the-bottom-buttonbar-hidden,tabs-and-buttonbar-hidden ". "dashboard_showtabs:tabs-and-buttonbar-at-the-top,tabs-and-buttonbar-on-the-bottom,tabs-and-buttonbar-hidden ". #new attribute vers. 2.03 - "dashboard_tab1icon ". - "dashboard_tab2icon ". - "dashboard_tab3icon ". - "dashboard_tab4icon ". - "dashboard_tab5icon ". - #new attribute vers. 2.04 - "dashboard_webfrontendfilter ". #new attribute vers. 2.06 - "dashboard_customcss ". - "dashboard_tab6name ". - "dashboard_tab7name ". - "dashboard_tab6groups ". - "dashboard_tab7groups ". - "dashboard_tab6sorting ". - "dashboard_tab7sorting ". - "dashboard_tab6icon ". - "dashboard_tab7icon"; + "dashboard_customcss " . + "dashboard_flexible " . + #tab-specific attributes + "dashboard_tab1name " . + "dashboard_tab1groups " . + "dashboard_tab1sorting " . + "dashboard_tab1icon " . + "dashboard_tab1colcount " . + "dashboard_tab1rowcentercolwidth " . + "dashboard_tab1backgroundimage " . + # dynamic attributes + "dashboard_tab[0-9]+name " . + "dashboard_tab[0-9]+groups " . + "dashboard_tab[0-9]+sorting " . + "dashboard_tab[0-9]+icon " . + "dashboard_tab[0-9]+colcount " . + "dashboard_tab[0-9]+rowcentercolwidth " . + "dashboard_tab[0-9]+backgroundimage " . + "dashboard_backgroundimage"; $data{FWEXT}{jquery}{SCRIPT} = "/pgm2/".$fwjquery if (!$data{FWEXT}{jquery}{SCRIPT}); $data{FWEXT}{jqueryui}{SCRIPT} = "/pgm2/".$fwjqueryui if (!$data{FWEXT}{jqueryui}{SCRIPT}); $data{FWEXT}{z_dashboard}{SCRIPT} = "/pgm2/dashboard.js" if (!$data{FWEXT}{z_dashboard}); + $data{FWEXT}{x_dashboard}{SCRIPT} = "/pgm2/svg.js" if (!$data{FWEXT}{x_dashboard}); - $data{FWEXT}{Dashboardx}{LINK} = "?room=".$dashboardhiddenroom; - $data{FWEXT}{Dashboardx}{NAME} = $dashboardname; + return undef; } @@ -192,7 +187,7 @@ sub Dashboard_DetailFN() { my $ret = ""; $ret .= "
| Helper:\n\n";
@@ -228,6 +223,7 @@ sub Dashboard_Get($@) {
my $res = "";
my $arg = (defined($a[1]) ? $a[1] : "");
+ my $arg2 = (defined($a[2]) ? $a[2] : "");
if ($arg eq "config") {
my $name = $hash->{NAME};
my $attrdata = $attr{$name};
@@ -243,7 +239,7 @@ sub Dashboard_Get($@) {
my @iconFolders = split(":", AttrVal($FW_wname, "iconPath", "$FW_sp:default:fhemSVG:openautomation"));
my $iconDirs = "";
foreach my $idir (@iconFolders) {$iconDirs .= "$attr{global}{modpath}/www/images/".$idir.",";}
- $res .= " \"icondirs\": \"$iconDirs\"";
+ $res .= " \"icondirs\": \"$iconDirs\", \"dashboard_tabcount\": " . GetTabCount($hash, 0);
$res .= ($i != $x) ? ",\n" : "\n";
foreach my $attr (sort keys %$attrdata) {
@@ -270,6 +266,16 @@ sub Dashboard_Get($@) {
%group = BuildGroupList($dashboard_groupListfhem);
$res .= BuildGroupWidgets(1,1,1212,trim($dbgroup),"t1c1,".trim($dbgroup).",true,0,0:");
return $res;
+#For dynamic loading of tabs
+ } elsif ($arg eq "tab" && $arg2 =~ /^\d+$/) {
+ return BuildDashboardTab($arg2, $hash->{NAME});
+ } elsif ($arg eq "icon") {
+ shift @a;
+ shift @a;
+
+ my $icon = join (' ', @a);
+
+ return FW_iconPath($icon);
} else {
return "Unknown argument $arg choose one of config:noArg groupWidget";
}
@@ -277,22 +283,34 @@ sub Dashboard_Get($@) {
sub Dashboard_define ($$) {
my ($hash, $def) = @_;
+
+ my @args = split (" ", $def);
+
my $now = time();
my $name = $hash->{NAME};
$hash->{VERSION} = $dashboardversion;
readingsSingleUpdate( $hash, "state", "Initialized", 0 );
RemoveInternalTimer($hash);
- InternalTimer ($now + 5, 'CreateDashboardEntry', $hash, 0);
InternalTimer ($now + 5, 'CheckDashboardAttributUssage', $hash, 0);
my $dashboard_groupListfhem = Dashboard_GetGroupList;
+ my $url = '/dashboard/' . $name;
+
+ $data{FWEXT}{$url}{CONTENTFUNC} = 'Dashboard_CGI';
+ $data{FWEXT}{$url}{LINK} = 'dashboard/' . $name;
+ $data{FWEXT}{$url}{NAME} = $name;
+
return;
}
sub Dashboard_undef ($$) {
my ($hash,$arg) = @_;
-
+
+ # remove dashboard links from left menu
+ my $url = '/dashboard/' . $hash->{NAME};
+ delete $data{FWEXT}{$url};
+
RemoveInternalTimer($hash);
return undef;
@@ -300,12 +318,49 @@ sub Dashboard_undef ($$) {
sub Dashboard_attr($$$) {
my ($cmd, $name, $attrName, $attrVal) = @_;
+
+ # add dynamic attributes
+ if ($cmd eq "set" && $attrName =~ m/dashboard_tab([1-9][0-9]*)groups/) {
+ addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "name");
+ addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "groups");
+ addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "sorting");
+ addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "icon");
+ addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "colcount");
+ addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "rowcentercolwidth");
+ addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "backgroundimage");
+ }
+
return;
}
#############################################################################################
#############################################################################################
+sub Dashboard_CGI($)
+{
+ my ($htmlarg) = @_;
+
+ $htmlarg =~ s/^\///; # eliminate leading /
+ my @params = split(/\//,$htmlarg); # split URL by /
+ my $ret = '';
+ my $name = $params[1];
+
+ FW_pO ' ';
+
+ if ($name && defined($defs{$name})) {
+ $ret = Dashboard_SummaryFN($FW_wname,$name,$FW_room,undef);
+
+ FW_pO $ret;
+ }
+ else {
+ FW_pO 'Dashboard "' . $name . '" not found';
+ }
+
+ FW_pO ' ';
+
+ return 0;
+}
+
sub DashboardAsHtml($)
{
my ($d) = @_;
@@ -335,64 +390,42 @@ sub Dashboard_SummaryFN($$$$)
my $rowtopheight = AttrVal($defs{$d}{NAME}, "dashboard_rowtopheight", 250);
my $rowbottomheight = AttrVal($defs{$d}{NAME}, "dashboard_rowbottomheight", 250);
my $showtabs = AttrVal($defs{$d}{NAME}, "dashboard_showtabs", "tabs-and-buttonbar-at-the-top");
- my $showtooglebuttons = AttrVal($defs{$d}{NAME}, "dashboard_showtooglebuttons", 1);
+ my $showtogglebuttons = AttrVal($defs{$d}{NAME}, "dashboard_showtogglebuttons", 1);
my $showfullsize = AttrVal($defs{$d}{NAME}, "dashboard_showfullsize", 0);
- my $webfrontendfilter = AttrVal($defs{$d}{NAME}, "dashboard_webfrontendfilter", "*");
+ my $flexible = AttrVal($defs{$d}{NAME}, "dashboard_flexible", 0);
my $customcss = AttrVal($defs{$d}{NAME}, "dashboard_customcss", "none");
+ my $backgroundimage = AttrVal($defs{$d}{NAME}, "dashboard_backgroundimage", "");
my $row = AttrVal($defs{$d}{NAME}, "dashboard_row", "center");
my $debug = AttrVal($defs{$d}{NAME}, "dashboard_debug", "0");
my $activetab = AttrVal($defs{$d}{NAME}, "dashboard_activetab", 1);
- my $tabcount = AttrVal($defs{$d}{NAME}, "dashboard_tabcount", 1);
+ my $tabcount = GetTabCount($defs{$d}, 1);
my $dbwidth = AttrVal($defs{$d}{NAME}, "dashboard_width", "100%");
- my @tabnames = (AttrVal($defs{$d}{NAME}, "dashboard_tab1name", "Dashboard-Tab 1"),
- AttrVal($defs{$d}{NAME}, "dashboard_tab2name", "Dashboard-Tab 2"),
- AttrVal($defs{$d}{NAME}, "dashboard_tab3name", "Dashboard-Tab 3"),
- AttrVal($defs{$d}{NAME}, "dashboard_tab4name", "Dashboard-Tab 4"),
- AttrVal($defs{$d}{NAME}, "dashboard_tab5name", "Dashboard-Tab 5"),
- AttrVal($defs{$d}{NAME}, "dashboard_tab6name", "Dashboard-Tab 6"),
- AttrVal($defs{$d}{NAME}, "dashboard_tab7name", "Dashboard-Tab 7"));
- my @tabgroups = (AttrVal($defs{$d}{NAME}, "dashboard_tab1groups", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab2groups", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab3groups", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab4groups", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab5groups", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab6groups", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab7groups", ""));
- my @tabsortings = (AttrVal($defs{$d}{NAME}, "dashboard_tab1sorting", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab2sorting", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab3sorting", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab4sorting", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab5sorting", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab6sorting", ""),
- AttrVal($defs{$d}{NAME}, "dashboard_tab7sorting", ""));
+ my @tabnames = ();
+ my @tabsortings = ();
+
+ if ($showfullsize) {
+ if ($FW_RET =~ m/]*class="([^"]+)"[^>]*>/) {
+ $FW_RET =~ s/style="$1"/style="$1 dashboard_fullsize"/;
+ }
+ else {
+ $FW_RET =~ s/";
- # $ret .= "Set Attribute dashboard_webfrontendfilter, see Details";
- return $ret;
- }
- }
##################################################################################
if ($debug == 1) { $debugfield = "edit" };
@@ -409,7 +442,7 @@ sub Dashboard_SummaryFN($$$$)
#------------------- Check dashboard_sorting on false content ------------------------------------
for (my $i=0;$i<@tabsortings;$i++){
- if (($tabsortings[$i-1] !~ /[0-9]/ || $tabsortings[$i-1] !~ /:/ || $tabsortings[$i-1] !~ /,/ ) && ($tabsortings[$i-1] ne "," && $tabsortings[$i-1] ne "")){
+ if (($tabsortings[$i-1] !~ /[0-9]+/ || $tabsortings[$i-1] !~ /:/ || $tabsortings[$i-1] !~ /,/ ) && ($tabsortings[$i-1] ne "," && $tabsortings[$i-1] ne "")){
Log3 $d, 3, "[".$name." V".$dashboardversion."] Value of attribut dashboard_tab".$i."sorting is wrong. Saved sorting can not be set. Fix Value or delete the Attribute. [".$tabsortings[$i-1]."]";
} else { Log3 $d, 5, "[".$name." V".$dashboardversion."] Sorting OK or Empty: dashboard_tab".$i."sorting "; }
}
@@ -445,11 +478,11 @@ sub Dashboard_SummaryFN($$$$)
$ret .= "$d \n";
$ret .= "
\n";
+ $ret .= " \n";
+
+ return $ret;
+}
+
sub BuildDashboardTopRow($$$$){
my ($t,$id, $dbgroups, $dbsorting) = @_;
my $ret;
@@ -515,6 +611,18 @@ sub BuildDashboardCenterRow($$$$$){
$ret .= "
| ||||
| \n";
$ret .= " \n";
+ my $currentcol = $colcount;
+ my $maxcolindex = $colcount - 1;
+ my $replace = "t" . $t . "c" . $maxcolindex . ",";
+
+ # replace all sortings referencing not existing columns
+ # this does only work if there is not empty column inbetween
+ while (index($dbsorting, "t".$t."c".$currentcol.",") >= 0) {
+ my $search = "t" . $t . "c" . $currentcol . ",";
+ $dbsorting =~ s/$search/$replace/g;
+ $currentcol++;
+ }
+
for (my $i=0;$i<$colcount;$i++){
$ret .= " \n";
$ret .= BuildGroupWidgets($t,$i,$id,$dbgroups,$dbsorting);
@@ -545,29 +653,31 @@ sub BuildGroupWidgets($$$$$) {
my $counter = 0;
my @storedsorting = split(":", $dbsorting);
my @dbgroup = split(",", $dbgroups);
- my $widgetheader = "";
+ my $groupicon = '';
foreach my $singlesorting (@storedsorting) {
- my @groupdata = split(",", $singlesorting);
- if (scalar(@groupdata) > 1) {
- if (index($dbsorting, "t".$tab."c".$column.",".$groupdata[1]) >= 0 && index($dbgroups, $groupdata[1]) >= 0 && $groupdata[1] ne "" ) { #group is set to tab
-
- $widgetheader = $groupdata[1];
+ my @groupdata = split(",", $singlesorting);
+ my $groupMatch = $dbgroups;
+ $groupicon = '';
+ if (scalar(@groupdata) > 1) {
+ if (
+ index($dbsorting, "t".$tab."c".$column.",".$groupdata[1]) >= 0
+ && (
+ index($dbgroups, $groupdata[1]) >= 0
+ || $groupdata[1] =~ $groupMatch
+ )
+ && $groupdata[1] ne ""
+ ) { #group is set to tab
+ my $groupId = $id."t".$tab."c".$column."w".$counter;
foreach my $strdbgroup (@dbgroup) {
- my @groupicon = split(":", trim($strdbgroup));
- if ($groupicon[0] eq $groupdata[1]) {
- if ($#groupicon > 0) { $widgetheader = FW_makeImage($groupicon[1],$groupicon[1],"dashboard_tabicon") . " ".$groupdata[1]; }
+ my @temp= split(":", trim($strdbgroup));
+ if (defined($temp[1]) && $groupdata[1] eq $temp[0]) {
+ $groupicon = $temp[1];
}
}
- $ret .= " \n";
- $ret .= " \n";
- $ret .= " \n";
+ $ret .= BuildGroup( ($groupdata[1],$singlesorting,$groupId,$groupicon) );
+
$counter++;
}
}
@@ -584,7 +694,8 @@ sub BuildGroupList($) {
$grp = trim($grp);
foreach my $g (@dashboardgroups){
my ($gtitle, $iconName) = split(":", trim($g));
- $group{$grp}{$d} = 1 if($gtitle eq $grp);
+ my $titleMatch = "^" . $gtitle . "\$";
+ $group{$grp}{$d} = 1 if($grp =~ $titleMatch);
}
}
}
@@ -601,21 +712,37 @@ sub Dashboard_GetGroupList() {
return $ret;
}
-sub BuildGroup($)
+sub BuildGroup
{
- my ($currentgroup) = @_;
+ my ($currentgroup,$singleSorting,$groupId,$icon) = @_;
my $ret = "";
my $row = 1;
my %extPage = ();
+ my $matchGroup = "^" . $currentgroup . "\$";
+ my $foundDevices = 0;
+ my $replaceGroup = "";
my $rf = ($FW_room ? "&room=$FW_room" : ""); # stay in the room
foreach my $g (keys %group) {
+ next if ($g !~ m/$matchGroup/);
+ $replaceGroup = "," . quotemeta($currentgroup) . ",";
+ $singleSorting =~ s/$replaceGroup/,$g,/;
+ $currentgroup = $g;
+
+ $ret .= " \n";
+ $ret .= " |