From f7bf132efdfbea30b3e7d9f817608607afab0a8c Mon Sep 17 00:00:00 2001 From: talkabout Date: Sun, 5 Jul 2015 13:12:02 +0000 Subject: [PATCH] Released version 3.0 of the dashboard module with the following changes: - 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. git-svn-id: https://svn.fhem.de/fhem/trunk@8893 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/95_Dashboard.pm | 830 +++++++++++++++++-------------------- fhem/www/pgm2/dashboard.js | 466 +++++++++++++++------ 2 files changed, 708 insertions(+), 588 deletions(-) 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 .= "\n"; $ret .= "':'">',j='':'">',g='
Helper:\n
\n"; - $ret .= " \n"; + $ret .= " \n"; $ret .= " \n"; $ret .= " \n"; $ret .= "
\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"; - $ret .= "\n"; $ret .= "
\n"; - $ret .= "\n"; + $ret .= "
\n"; + $ret .= "\n"; $ret .= "\n"; $ret .= "
\n"; + $ret .= "
\n"; ########################### Dashboard Tab-Liste ############################################## $ret .= "
    \n"; @@ -458,26 +491,9 @@ sub Dashboard_SummaryFN($$$$) ######################################################################################## for (my $t=0;$t<$tabcount;$t++){ - my @tabgroup = split(",", $tabgroups[$t]); #Set temp. position for groups without an stored position - for (my $i=0;$i<@tabgroup;$i++){ - my @stabgroup = split(":", trim($tabgroup[$i])); - if (index($tabsortings[$t],','.trim($stabgroup[0]).',') < 0) {$tabsortings[$t] = $tabsortings[$t]."t".$t."c".GetMaxColumnId($row,$colcount).",".trim($stabgroup[0]).",true,0,0:";} - } - - %group = BuildGroupList($tabgroups[$t]); - $ret .= "
    \n"; - $ret .= "
      \n"; - $ret .= " \n"; - ##################### Top Row (only one Column) ############################################# - if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "top"){ $ret .= BuildDashboardTopRow($t,$id,$tabgroups[$t],$tabsortings[$t]); } - ##################### Center Row (max. 5 Column) ############################################ - if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "center-bottom" || $row eq "center"){ $ret .= BuildDashboardCenterRow($t,$id,$tabgroups[$t],$tabsortings[$t],$colcount);} - ############################# Bottom Row (only one Column) ############################################ - if ($row eq "top-center-bottom" || $row eq "center-bottom" || $row eq "bottom"){ $ret .= BuildDashboardBottomRow($t,$id,$tabgroups[$t],$tabsortings[$t]); } - ############################################################################################# - $ret .= "
      \n"; - $ret .= "
    \n"; - $ret .= "
    \n"; + if ($t == $activetab - 1) { + $ret .= BuildDashboardTab($t, $d); + } } $ret .= "
\n"; @@ -496,6 +512,86 @@ sub Dashboard_SummaryFN($$$$) return $ret; } +sub BuildDashboardTab($$) +{ + my ($t, $d) = @_; + + my $id = $defs{$d}{NR}; + my $colcount = AttrVal($defs{$d}{NAME}, 'dashboard_tab' . ($t + 1) . 'colcount', AttrVal($defs{$d}{NAME}, "dashboard_colcount", 1)); + my $colwidths = AttrVal($defs{$d}{NAME}, 'dashboard_tab' . ($t + 1) . 'rowcentercolwidth', AttrVal($defs{$d}{NAME}, "dashboard_rowcentercolwidth", 100)); + my $backgroundimage = AttrVal($defs{$d}{NAME}, 'dashboard_tab' . ($t + 1) . 'backgroundimage', ""); + $colwidths =~ tr/,/:/; + my $row = AttrVal($defs{$d}{NAME}, "dashboard_row", "center"); + my $tabcount = GetTabCount($defs{$d}, 1); + my @tabgroups = (); + my @tabsortings = (); + + for (my $i = 0; $i < $tabcount; $i++) { + $tabgroups[$i] = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($i + 1) . "groups", ""); + $tabsortings[$i] = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($i + 1) . "sorting", ""); + } + + unless (@tabgroups) { + readingsSingleUpdate( $defs{$d}, "state", "No Groups set", 0 ); + return ""; + } + + my $groups = Dashboard_GetGroupList(); + $groups =~ s/#/ /g; + my @groups = split(',', $groups); + + my @temptabgroup = split(",", $tabgroups[$t]); #Set temp. position for groups without an stored position + my @tabgroup = (); + + foreach my $g (@groups){ + for (my $i=0;$i<@temptabgroup;$i++) { + my @stabgroup = split(":", trim($temptabgroup[$i])); + my $matchGroup = trim($stabgroup[0]); + + # fill groups that are matching the configured groups + if ($g =~ m/$matchGroup/ && $g ne $stabgroup[0]) { + push(@tabgroup, $g); + } + elsif ($g eq $stabgroup[0]) { + push(@tabgroup, $g); + } + } + } + + for (my $i=0;$i<@tabgroup;$i++) { + my @stabgroup = split(":", trim($tabgroup[$i])); + my $matchGroup = "," . trim($stabgroup[0]) . ","; + + if ($tabsortings[$t] !~ m/$matchGroup/) { + $tabsortings[$t] = $tabsortings[$t]."t".$t."c".GetMaxColumnId($row,$colcount).",".trim($stabgroup[0]).",true,0,0:"; + } + } + + %group = BuildGroupList($tabgroups[$t]); + + my $ret = "
\n"; + $ret .= "
    \n"; + $ret .= " \n"; + ##################### Top Row (only one Column) ############################################# + if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "top"){ + $ret .= BuildDashboardTopRow($t,$id,$tabgroups[$t],$tabsortings[$t]); + } + ##################### Center Row (max. 5 Column) ############################################ + if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "center-bottom" || $row eq "center") { + $ret .= BuildDashboardCenterRow($t,$id,$tabgroups[$t],$tabsortings[$t],$colcount); + } + ############################# Bottom Row (only one Column) ############################################ + if ($row eq "top-center-bottom" || $row eq "center-bottom" || $row eq "bottom"){ + $ret .= BuildDashboardBottomRow($t,$id,$tabgroups[$t],$tabsortings[$t]); + } + ############################################################################################# + $ret .= "
    \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 .= "
".$widgetheader."
\n"; - $ret .= "
\n"; - $ret .= BuildGroup($groupdata[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 .= "
\n"; + $ret .= "
"; + if ($icon) { + $ret .= FW_makeImage($icon,$icon,"dashboard_group_icon"); + } + $ret .= $currentgroup."
\n"; + $ret .= "
\n"; - next if ($g ne $currentgroup); $ret .= ""; foreach my $d (sort { lc(AttrVal($a,"sortby",AttrVal($a,"alias",$a))) cmp lc(AttrVal($b,"sortby",AttrVal($b,"alias",$b))) } keys %{$group{$g}}) { + $foundDevices++; $ret .= sprintf("", ($row&1)?"odd":"even"); my $type = $defs{$d}{TYPE}; @@ -624,7 +751,7 @@ sub BuildGroup($) $icon = FW_makeImage($icon,$icon,"icon dashboard_groupicon") . " " if($icon); - if ($type ne "weblink" && $type ne "SVG" && $type ne "readingsGroup" && $type ne "readingsHistory") { # Don't show Link by weblink, svg and readingsGroup + if (!$modules{$defs{$d}{TYPE}}{FW_atPageEnd}) { # Don't show Link for "atEnd"-devices $ret .= FW_pH "detail=$d", "$icon$devName", 1, "col1", 1; } @@ -634,20 +761,19 @@ sub BuildGroup($) ############## Customize Result for Special Types ##################### my @txtarray = split(">", $txt); - if (($type eq "readingsGroup" || $type eq "readingsHistory") && $txtarray[0] eq " -1) {$storeinfo = 0; } - if ($storeinfo == 3) { $txtreturn .= $txtarray[$i].">"; } - if ($storeinfo == 2 && index($txtarray[$i]," -1 ) { $storeinfo = $storeinfo+1;} - if ($storeinfo == 1 && index($txtarray[$i]," -1 ) { $linkreturn = $txtarray[$i].">"; } - if (index($txtarray[$i]," -1) {$storeinfo = $storeinfo+1; } - } - $ret .= ""; - } else { $ret .= ""; } + if ($modules{$defs{$d}{TYPE}}{FW_atPageEnd}) { + no strict "refs"; + my $devret = &{$modules{$defs{$d}{TYPE}}{FW_summaryFn}}($FW_wname, $d, + $FW_room, \%extPage); + $ret .= ""; + } ########################################################### ###### Commands, slider, dropdown @@ -665,6 +791,8 @@ sub BuildGroup($) } } if($htmlTxt) { + # add colspan to avoid squeezed table cells + $htmlTxt =~ s/"; } $ret .= "
$txtreturn$txt$txt//; $ret .= $htmlTxt; } else { $ret .= FW_pH "cmd.$d=set $d $cmd$rf", $cmd, 1, "col3", 1; @@ -674,14 +802,21 @@ sub BuildGroup($) $ret .= "
"; + + $ret .= "
\n"; + $ret .= "
\n"; + $ret .= "
\n"; } - if ($ret eq "") { + if (!$foundDevices) { $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= "
Unknown Group: $currentgroup
Check if the group attribute is really set
Check if the groupname is correct written
"; } + + + return $ret; } @@ -701,7 +836,6 @@ sub CheckDashboardEntry($) { my $timeToExec = $now + 5; RemoveInternalTimer($hash); - InternalTimer ($timeToExec, 'CreateDashboardEntry', $hash, 0); InternalTimer ($timeToExec, 'CheckDashboardAttributUssage', $hash, 0); } @@ -711,8 +845,6 @@ sub CheckDashboardAttributUssage($) { # replaces old disused attributes and thei my $detailnote = ""; # --------- Set minimal Attributes in the hope to make it easier for beginners -------------------- - my $tabcount = AttrVal($defs{$d}{NAME}, "dashboard_tabcount", "0"); - if ($tabcount eq "0") { FW_fC("attr ".$d." dashboard_tabcount 1"); } my $tab1groups = AttrVal($defs{$d}{NAME}, "dashboard_tab1groups", ""); if ($tab1groups eq "") { FW_fC("attr ".$d." dashboard_tab1groups Set Your Groups - See Attribute dashboard_tab1groups-"); } # ------------------------------------------------------------------------------------------------- @@ -750,27 +882,18 @@ sub CheckDashboardAttributUssage($) { # replaces old disused attributes and thei } } -sub CreateDashboardEntry($) { - my ($hash) = @_; +sub +GetTabCount ($$) +{ + my ($hash, $defaultTabCount) = @_; - my $h = $hash->{NAME}; - if (!defined $defs{$h."_weblink"}) { - FW_fC("define ".$h."_weblink weblink htmlCode {DashboardAsHtml(\"".$h."\")}"); - Log3 $hash, 3, "[".$hash->{NAME}. " V".$dashboardversion."]"." Weblink dosen't exists. Created weblink ".$h."_weblink. Don't forget to save config."; - } - FW_fC("attr ".$h."_weblink room ".$dashboardhiddenroom); + my $tabCount = 0; - foreach my $dn (sort keys %defs) { - if ($defs{$dn}{TYPE} eq "FHEMWEB" && $defs{$dn}{NAME} !~ /FHEMWEB:/) { - my $hr = AttrVal($defs{$dn}{NAME}, "hiddenroom", ""); - if (index($hr,$dashboardhiddenroom) == -1){ - if ($hr eq "") {FW_fC("attr ".$defs{$dn}{NAME}." hiddenroom ".$dashboardhiddenroom);} - else {FW_fC("attr ".$defs{$dn}{NAME}." hiddenroom ".$hr.",".$dashboardhiddenroom);} - Log3 $hash, 3, "[".$hash->{NAME}. " V".$dashboardversion."]"." Added hiddenroom '".$dashboardhiddenroom."' to ".$defs{$dn}{NAME}.". Don't forget to save config."; - } - } + while (AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'groups', '') ne "") { + $tabCount++; } - + + return $tabCount ? $tabCount : $defaultTabCount; } 1; @@ -800,7 +923,7 @@ sub CreateDashboardEntry($) { define anyViews Dashboard
attr anyViews dashboard_colcount 2
- attr anyViews dashboard_rowcentercolwidth 30,70
+ attr anyviews dashboard_rowcentercolwidth 30,70
attr anyViews dashboard_tab1groups <Group1>,<Group2>,<Group3>
@@ -823,7 +946,7 @@ sub CreateDashboardEntry($) {
  • dashboard_tabcount
    - Returns the number of displayed tabs. + Returns the number of displayed tabs. (Does not need to be set any more. It is read automatically from the configured tabs) Default: 1

  • @@ -831,80 +954,15 @@ sub CreateDashboardEntry($) { Specifies which tab is activated. Can be set manually, but is also set by the switch "Set" to the currently active tab. Default: 1
    - -
  • dashboard_tab1name
    - Title of Tab 1. - Default: Dashboard-Tab 1 + +
  • dashboard_tabXname
    + Title of Tab at position X.

  • - -
  • dashboard_tab2name
    - Title of Tab 2. - Default: Dashboard-Tab 2 -

  • - -
  • dashboard_tab3name
    - Title of Tab 3. - Default: Dashboard-Tab 3 -

  • - -
  • dashboard_tab4name
    - Title of Tab 4. - Default: Dashboard-Tab 4 -

  • - -
  • dashboard_tab5name
    - Title of Tab 5. - Default: Dashboard-Tab 5 -

  • - -
  • dashboard_tab6name
    - Title of Tab 6. - Default: Dashboard-Tab 6 + +
  • dashboard_tabXsorting
    + Contains the position of each group in Tab X. Value is written by the "Set" button. It is not recommended to take manual changes.

  • - -
  • dashboard_tab7name
    - Title of Tab 7. - Default: Dashboard-Tab 7 -

  • - -
  • dashboard_webfrontendfilter
    - If this attribute not set, or value is * the dashboard is displayed on all configured FHEMWEB instances.
    - Set the Name of an FHEMWEB instance (eg WEB) to the Dashboard appears only in this.
    - There may be several valid instances are separated by comma eg WEB,WEBtablet.
    - This makes it possible to define an additional dashboard that only Show on Tablet (which of course an own instance FHEMWEB use).
    - Default: * -
    - It should NEVER two ore more active dashboards in a FHEMWEB instance! -

  • - -
  • dashboard_tab1sorting
    - Contains the position of each group in Tab 1. Value is written by the "Set" button. It is not recommended to take manual changes. -

  • - -
  • dashboard_tab2sorting
    - Contains the position of each group in Tab 2. Value is written by the "Set" button. It is not recommended to take manual changes. -

  • - -
  • dashboard_tab3sorting
    - Contains the position of each group in Tab 3. Value is written by the "Set" button. It is not recommended to take manual changes. -

  • - -
  • dashboard_tab4sorting
    - Contains the position of each group in Tab 4. Value is written by the "Set" button. It is not recommended to take manual changes. -

  • - -
  • dashboard_tab5sorting
    - Contains the position of each group in Tab 5. Value is written by the "Set" button. It is not recommended to take manual changes. -

  • - -
  • dashboard_tab6sorting
    - Contains the position of each group in Tab 6. Value is written by the "Set" button. It is not recommended to take manual changes. -

  • - -
  • dashboard_tab7sorting
    - Contains the position of each group in Tab 7. Value is written by the "Set" button. It is not recommended to take manual changes. -

  • - +
  • dashboard_row
    To select which rows are displayed. top only; center only; bottom only; top and center; center and bottom; top,center and bottom.
    Default: center @@ -938,82 +996,41 @@ sub CreateDashboardEntry($) { Height of the bottom row in which the groups may be positioned.
    Default: 250

  • - -
  • dashboard_tab1groups
    - Comma-separated list of the names of the groups to be displayed in Tab 1.
    + +
  • dashboard_tabXgroups
    + Comma-separated list of the names of the groups to be displayed in Tab X.
    Each group can be given an icon for this purpose the group name, the following must be completed ":<icon>@<color>"
    - Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow + Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow
    + Additionally a group can contain a regular expression to show all groups matching a criteria. + Example: .*Light.* to show all groups that contain the string "Light"

  • - -
  • 2
    - Comma-separated list of the names of the groups to be displayed in Tab 2.
    - Each group can be given an icon for this purpose the group name, the following must be completed ":<icon>@<color>"
    - Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

  • - -
  • dashboard_tab3groups
    - Comma-separated list of the names of the groups to be displayed in Tab 3.
    - Each group can be given an icon for this purpose the group name, the following must be completed ":<icon>@<color>"
    - Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

  • - -
  • dashboard_tab4groups
    - Comma-separated list of the names of the groups to be displayed in Tab 4.
    - Each group can be given an icon for this purpose the group name, the following must be completed ":<icon>@<color>"
    - Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

  • - -
  • dashboard_tab5groups
    - Comma-separated list of the names of the groups to be displayed in Tab 5.
    - Each group can be given an icon for this purpose the group name, the following must be completed ":<icon>@<color>"
    - Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

  • - -
  • dashboard_tab6groups
    - Comma-separated list of the names of the groups to be displayed in Tab 6.
    - Each group can be given an icon for this purpose the group name, the following must be completed ":<icon>@<color>"
    - Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

  • - -
  • dashboard_tab7groups
    - Comma-separated list of the names of the groups to be displayed in Tab 7.
    - Each group can be given an icon for this purpose the group name, the following must be completed ":<icon>@<color>"
    - Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

  • - -
  • dashboard_tab1icon
    - Set the icon for a Tab. There must exist an icon with the name ico.png in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image. + +
  • dashboard_tabXicon
    + Set the icon for a Tab. There must exist an icon with the name ico.(png|svg) in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image.

  • - -
  • dashboard_tab2icon
    - Set the icon for a Tab. There must exist an icon with the name ico.png in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image. -

  • - -
  • dashboard_tab3icon
    - Set the icon for a Tab. There must exist an icon with the name ico.png in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image. -

  • - -
  • dashboard_tab4icon
    - Set the icon for a Tab. There must exist an icon with the name ico.png in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image. -

  • - -
  • dashboard_tab5icon
    - Set the icon for a Tab. There must exist an icon with the name ico.png in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image. -

  • - -
  • dashboard_tab6icon
    - Set the icon for a Tab. There must exist an icon with the name ico.png in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image. -

  • - -
  • dashboard_tab7icon
    - Set the icon for a Tab. There must exist an icon with the name ico.png in the modpath directory. If the image is referencing an SVG icon, then you can use the @colorname suffix to color the image. -

  • dashboard_colcount
    Number of columns in which the groups can be displayed. Nevertheless, it is possible to have multiple groups
    - to be positioned in a column next to each other. This is dependent on the width of columns and groups.
    + to be positioned in a column next to each other. This is depend on the width of columns and groups.
    Default: 1

  • + +
  • dashboard_tabXcolcount
    + Number of columns for a specific tab in which the groups can be displayed. Nevertheless, it is possible to have multiple groups
    + to be positioned in a column next to each other. This depends on the width of columns and groups.
    + Default: +

  • + +
  • dashboard_tabXbackgroundimage
    + Shows a background image for the X tab. The image is not stretched in any way, it should therefore match the tab size or extend it. + Standard: +

  • + +
  • dashboard_flexible
    + If set to a value > 0, the widgets are not positioned in columns any more but can be moved freely to any position in the tab.
    + The value for this parameter also defines the grid, in which the position "snaps in". + Default: 0 +

  • dashboard_showfullsize
    Hide FHEMWEB Roomliste (complete left side) and Page Header if Value is 1.
    @@ -1024,11 +1041,17 @@ sub CreateDashboardEntry($) { Displays the Tabs/Buttonbar on top or bottom, or hides them. If the Buttonbar is hidden lockstate is "lock" is used.
    Default: tabs-and-buttonbar-at-the-top

  • - -
  • dashboard_showtooglebuttons
    + +
  • dashboard_showtogglebuttons
    Displays a Toogle Button on each Group do collapse.
    Default: 0

  • + +
  • dashboard_backgroundimage
    + Displays a background image for the complete dashboard. The image is not stretched in any way so the size should match/extend the + dashboard height/width. + Default: +

  • dashboard_debug
    Show Hiddenfields. Only for Maintainer's use.
    @@ -1085,7 +1108,7 @@ sub CreateDashboardEntry($) {
    • dashboard_tabcount
      - Gibt die Anzahl der angezeigten Tabs an. + Gibt die Anzahl der angezeigten Tabs an. (Dieser Parameter is veraletet, die Anzahl der Tabs wird aus der Dashboard-Konfiguration gelesen) Standard: 1

    • @@ -1093,79 +1116,14 @@ sub CreateDashboardEntry($) { Gibt an welches Tab aktiviert ist. Kann manuell gesetzt werden, wird aber auch durch den Schalter "Set" auf das gerade aktive Tab gesetzt. Standard: 1
      - -
    • dashboard_tab1name
      - Titel des 1. Tab. - Standard: Dashboard-Tab 1 + +
    • dashboard_tabXname
      + Titel des X. Tab.

    • - -
    • dashboard_tab2name
      - Titel des 2. Tab. - Standard: Dashboard-Tab 2 -

    • - -
    • dashboard_tab3name
      - Titel des 3. Tab. - Standard: Dashboard-Tab 3 -

    • - -
    • dashboard_tab4name
      - Titel des 4. Tab. - Standard: Dashboard-Tab 4 -

    • - -
    • dashboard_tab5name
      - Titel des 5. Tab. - Standard: Dashboard-Tab 5 + +
    • dashboard_tabXsorting
      + Enthält die Poistionierung jeder Gruppe im Tab X. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern

    • - -
    • dashboard_tab6name
      - Titel des 6. Tab. - Standard: Dashboard-Tab 6 -

    • - -
    • dashboard_tab7name
      - Titel des 7. Tab. - Standard: Dashboard-Tab 7 -

    • - -
    • dashboard_webfrontendfilter
      - Ist dieses Attribut nicht gesetzt, oder hat den Wert * wird das Dashboard auf allen konfigurierten FHEMWEB Instanzen angezeigt.
      - Wird dem Attribut der Name einer FHEMWEB Instanz (z.B. WEB) zugewiesen so wird das Dashboard nur in dieser Instanz angezeigt.
      - Es können auch mehrere Instanzen durch Komma getrennt angegeben werden, z.B. WEB,WEBtablet. Dadurch ist es möglich ein
      - zusätzliches Dashboard zu definieren und dieses nur z.B. auf Tablet anzeigen zulassen (die natürlich eine eigenen FHEMWEB Instanz verwenden).
      - Standard: *
      -
      - Es dürfen NIE zwei Dashboards in einer FHEMWEB instanz aktiv sein! -

    • - -
    • dashboard_tab1sorting
      - Enthält die Poistionierung jeder Gruppe im Tab 1. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern -

    • - -
    • dashboard_tab2sorting
      - Enthält die Poistionierung jeder Gruppe im Tab 2. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern -

    • - -
    • dashboard_tab3sorting
      - Enthält die Poistionierung jeder Gruppe im Tab 3. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern -

    • - -
    • dashboard_tab4sorting
      - Enthält die Poistionierung jeder Gruppe im Tab 4. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern -

    • - -
    • dashboard_tab5sorting
      - Enthält die Poistionierung jeder Gruppe im Tab 5. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern -

    • - -
    • dashboard_tab6sorting
      - Enthält die Poistionierung jeder Gruppe im Tab 6. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern -

    • - -
    • dashboard_tab7sorting
      - Enthält die Poistionierung jeder Gruppe im Tab 7. Der Wert wird mit der Schaltfläche "Set" geschrieben. Es wird nicht empfohlen dieses Attribut manuelle zu ändern -

    • dashboard_row
      Auswahl welche Zeilen angezeigt werden sollen. top (nur Oben), center (nur Mitte), bottom (nur Unten) und den Kombinationen daraus.
      @@ -1200,76 +1158,18 @@ sub CreateDashboardEntry($) { Höhe der unteren Zeile, in der die Gruppen angeordnet werden.
      Standard: 250

    • - +
    • dashboard_tab1groups
      Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 1 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.
      Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt werden
      - Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow + Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow
      + Der Gruppenname kann ebenfalls einen regulären Ausdruck beinhalten, um alle Gruppen anzuzeigen, die darauf passen.
      + Beispiel: .*Licht.* zeigt alle Gruppen an, die das Wort "Licht" im Namen haben.

    • - -
    • dashboard_tab2groups
      - Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 2 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.
      - Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt werden
      - Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

    • - -
    • dashboard_tab3groups
      - Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 3 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.
      - Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt werden
      - Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

    • - -
    • dashboard_tab4groups
      - Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 4 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.
      - Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt werden
      - Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

    • - -
    • dashboard_tab5groups
      - Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 5 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.
      - Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt werden
      - Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

    • - -
    • dashboard_tab6groups
      - Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 6 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.
      - Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt werden
      - Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

    • - -
    • dashboard_tab7groups
      - Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 7 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.
      - Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":<icon>@<farbe>"ergänzt werden
      - Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow -

    • - -
    • dashboard_tab1icon
      + +
    • dashboard_tabXicon
      Zeigt am Tab ein Icon an. Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden.

    • - -
    • dashboard_tab2icon
      - Zeigt am Tab ein Icon an. Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden. -

    • - -
    • dashboard_tab3icon
      - Zeigt am Tab ein Icon an. Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden. -

    • - -
    • dashboard_tab4icon
      - Zeigt am Tab ein Icon an. Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden. -

    • - -
    • dashboard_tab5icon
      - Zeigt am Tab ein Icon an. Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden. -

    • - -
    • dashboard_tab6icon
      - Zeigt am Tab ein Icon an. Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden. -

    • - -
    • dashboard_tab7icon
      - Zeigt am Tab ein Icon an. Es muss sich dabei um ein exisitereindes Icon mit modpath Verzeichnis handeln. Handelt es sich um ein SVG Icon kann der Suffix @colorname für die Farbe des Icons angegeben werden. -

    • dashboard_colcount
      Die Anzahl der Spalten in der Gruppen dargestellt werden können. Dennoch ist es möglich, mehrere Gruppen
      @@ -1277,6 +1177,23 @@ sub CreateDashboardEntry($) { Gilt nur für die mittlere Spalte!
      Standard: 1

    • + +
    • dashboard_tabXcolcount
      + Die Anzahl der Spalten im Tab X in der Gruppen dargestellt werden können. Dennoch ist es möglich, mehrere Gruppen
      + in einer Spalte nebeneinander zu positionieren. Dies ist abhängig von der Breite der Spalten und Gruppen.
      + Gilt nur für die mittlere Spalte!
      + Standard: +

    • + +
    • dashboard_tabXbackgroundimage
      + Zeigt ein Hintergrundbild für den X-ten Tab an. Das Bild wird nicht gestreckt, es sollte also auf die Größe des Tabs passen oder diese überschreiten. + Standard: +

    • + +
    • dashboard_flexible
      + Hat dieser Parameter einen Wert > 0, dann können die Widgets in den Tabs frei positioniert werden und hängen nicht mehr an den Spalten fest. Der Wert gibt ebenfalls das Raster an, in dem die Positionierung "zu schnappt". + Standard: 0 +

    • dashboard_showfullsize
      Blendet die FHEMWEB Raumliste (kompleter linker Bereich der Seite) und den oberen Bereich von FHEMWEB aus wenn der Wert auf 1 gesetzt ist.
      @@ -1287,11 +1204,16 @@ sub CreateDashboardEntry($) { Zeigt die Tabs/Schalterleiste des Dashboards oben oder unten an, oder blendet diese aus. Wenn die Schalterleiste ausgeblendet wird ist das Dashboard gespert.
      Standard: tabs-and-buttonbar-at-the-top

    • - -
    • dashboard_showtooglebuttons
      + +
    • dashboard_showtogglebuttons
      Zeigt eine Schaltfläche in jeder Gruppe mit der man diese auf- und zuklappen kann.
      Standard: 0

    • + +
    • dashboard_backgroundimage
      + Zeig in Hintergrundbild im Dashboard an. Das Bild wird nicht gestreckt, es sollte daher auf die Größe des Dashboards passen oder diese überschreiten. + Default: +

    • dashboard_debug
      Zeigt Debug-Felder an. Sollte nicht gesetzt werden!
      diff --git a/fhem/www/pgm2/dashboard.js b/fhem/www/pgm2/dashboard.js index 8b181dc08..a5b37009d 100644 --- a/fhem/www/pgm2/dashboard.js +++ b/fhem/www/pgm2/dashboard.js @@ -24,12 +24,15 @@ var DashboardConfigHash = {}; var dashboard_buttonbar = "top"; +var DashboardDraggable = true; +var fhemUrl = '/fhem'; /* evol.colorpicker 2.2 (c) 2014 Olivier Giulieri http://www.codeproject.com/Articles/452401/ColorPicker-a-jQuery-UI-Widget*/ !function(a){var b=0,c=!a.support.cssFloat,d=c?"-ie":"",e=c?!1:/mozilla/.test(navigator.userAgent.toLowerCase())&&!/webkit/.test(navigator.userAgent.toLowerCase()),f=[],g=["ffffff","000000","eeece1","1f497d","4f81bd","c0504d","9bbb59","8064a2","4bacc6","f79646"],h=["f2f2f2","7f7f7f","ddd9c3","c6d9f0","dbe5f1","f2dcdb","ebf1dd","e5e0ec","dbeef3","fdeada","d8d8d8","595959","c4bd97","8db3e2","b8cce4","e5b9b7","d7e3bc","ccc1d9","b7dde8","fbd5b5","bfbfbf","3f3f3f","938953","548dd4","95b3d7","d99694","c3d69b","b2a2c7","92cddc","fac08f","a5a5a5","262626","494429","17365d","366092","953734","76923c","5f497a","31859b","e36c09","7f7f7f","0c0c0c","1d1b10","0f243e","244061","632423","4f6128","3f3151","205867","974806"],i=["c00000","ff0000","ffc000","ffff00","92d050","00b050","00b0f0","0070c0","002060","7030a0"],j=[["003366","336699","3366cc","003399","000099","0000cc","000066"],["006666","006699","0099cc","0066cc","0033cc","0000ff","3333ff","333399"],["669999","009999","33cccc","00ccff","0099ff","0066ff","3366ff","3333cc","666699"],["339966","00cc99","00ffcc","00ffff","33ccff","3399ff","6699ff","6666ff","6600ff","6600cc"],["339933","00cc66","00ff99","66ffcc","66ffff","66ccff","99ccff","9999ff","9966ff","9933ff","9900ff"],["006600","00cc00","00ff00","66ff99","99ffcc","ccffff","ccccff","cc99ff","cc66ff","cc33ff","cc00ff","9900cc"],["003300","009933","33cc33","66ff66","99ff99","ccffcc","ffffff","ffccff","ff99ff","ff66ff","ff00ff","cc00cc","660066"],["333300","009900","66ff33","99ff66","ccff99","ffffcc","ffcccc","ff99cc","ff66cc","ff33cc","cc0099","993399"],["336600","669900","99ff33","ccff66","ffff99","ffcc99","ff9999","ff6699","ff3399","cc3399","990099"],["666633","99cc00","ccff33","ffff66","ffcc66","ff9966","ff6666","ff0066","d60094","993366"],["a58800","cccc00","ffff00","ffcc00","ff9933","ff6600","ff0033","cc0066","660033"],["996633","cc9900","ff9900","cc6600","ff3300","ff0000","cc0000","990033"],["663300","996600","cc3300","993300","990000","800000","993333"]],k=function(a){var b=a.toString(16);return 1==b.length&&(b="0"+b),b},l=function(a){return k(Number(a))},m=function(a){var b=k(a);return b+b+b},n=function(a){if(a.length>10){var b=1+a.indexOf("("),c=a.indexOf(")"),d=a.substring(b,c).split(",");return["#",l(d[0]),l(d[1]),l(d[2])].join("")}return a};a.widget("evol.colorpicker",{version:"2.2",options:{color:null,showOn:"both",displayIndicator:!0,history:!0,strings:"Theme Colors,Standard Colors,More Colors,Less Colors,Back to Palette,History,No history yet."},_create:function(){this._paletteIdx=1,this._id="evo-cp"+b++,this._enabled=!0;var f=this;switch(this.element.get(0).tagName){case"INPUT":var g=this.options.color,h=this.element;if(this._isPopup=!0,this._palette=null,null!==g)h.val(g);else{var i=h.val();""!==i&&(g=this.options.color=i)}h.addClass("colorPicker "+this._id).wrap('
      ').after('
      ").on("keyup onpaste",function(){var b=a(this).val();b!=f.options.color&&f._setValue(b,!0)});var j=this.options.showOn;("both"===j||"focus"===j)&&h.on("focus",function(){f.showPalette()}),("both"===j||"button"===j)&&h.next().on("click",function(a){a.stopPropagation(),f.showPalette()});break;default:this._isPopup=!1,this._palette=this.element.html(this._paletteHTML()).attr("aria-haspopup","true"),this._bindColors()}null!==g&&this.options.history&&this._add2History(g)},_paletteHTML:function(){var a=[],b=this._paletteIdx=Math.abs(this._paletteIdx),c=this.options,e=c.strings.split(",");return a.push('
      "),a.push("",this["_paletteHTML"+b](),""),a.push('
      ',e[1+b],""),c.history&&a.push('',e[5],""),a.push("
      "),c.displayIndicator&&a.push(this._colorIndHTML(this.options.color,"left"),this._colorIndHTML("","right")),a.push("
      "),a.join("")},_colorIndHTML:function(a){var b=[];return b.push('
      "+a+"":"/>"),b.push("
"),b.join("")},_paletteHTML1:function(){var a=[],b=this.options.strings.split(","),e='
';a.push('',j,b[0],"");for(var k=0;10>k;k++)a.push(e,g[k],f);for(a.push(""),c||a.push(''),a.push(''),k=0;10>k;k++)a.push(e,h[k],f);for(var l=1;4>l;l++)for(a.push(''),k=0;10>k;k++)a.push(e,h[10*l+k],f);for(a.push(''),k=40;50>k;k++)a.push(e,h[k],f);for(a.push("",j,b[1],""),k=0;10>k;k++)a.push(e,i[k],f);return a.push("
"),a.join("")},_paletteHTML2:function(){var a,b=[],e='
',h="
";b.push('
');for(var i=0,k=j.length;k>i;i++){b.push(g);var l=j[i];for(a=0,iMax=l.length;iMax>a;a++)b.push(e,l[a],f);b.push(h)}b.push('
');var n=[];for(b.push(g),a=255;a>10;a-=10)b.push(e,m(a),f),a-=10,n.push(e,m(a),f);return b.push(h,g,n.join(""),h),b.push("
"),b.join("")},_switchPalette:function(b){if(this._enabled){var c,d,e,g=this.options.strings.split(",");if(a(b).hasClass("evo-hist")){var h=['
',g[5],"
",'
'];if(0===f.length)h.push("

 ",g[6],"

");else for(var i=f.length-1;i>-1;i--)h.push('
');h.push("
"),c=-this._paletteIdx,d=h.join(""),e=g[4]}else this._paletteIdx<0?(c=-this._paletteIdx,this._palette.find(".evo-hist").show()):c=2==this._paletteIdx?1:2,d=this["_paletteHTML"+c](),e=g[c+1],this._paletteIdx=c;this._paletteIdx=c;var j=this._palette.find(".evo-more").prev().html(d).end().children().eq(0).html(e);0>c&&j.next().hide()}},showPalette:function(){if(this._enabled&&(a(".colorPicker").not("."+this._id).colorpicker("hidePalette"),null===this._palette)){this._palette=this.element.next().after(this._paletteHTML()).next().on("click",function(a){a.stopPropagation()}),this._bindColors();var b=this;a(document.body).on("click."+this._id,function(a){a.target!=b.element.get(0)&&b.hidePalette()})}return this},hidePalette:function(){if(this._isPopup&&this._palette){a(document.body).off("click."+this._id);var b=this;this._palette.off("mouseover click","td").fadeOut(function(){b._palette.remove(),b._palette=b._cTxt=null}).find(".evo-more a").off("click")}return this},_bindColors:function(){var b=this._palette.find("div.evo-color"),c=this.options.history?"td,.evo-cHist div":"td";this._cTxt1=b.eq(0).children().eq(0),this._cTxt2=b.eq(1).children().eq(0);var d=this;this._palette.on("click",c,function(){if(d._enabled){var b=n(a(this).attr("style").substring(17));d._setValue(b)}}).on("mouseover",c,function(){if(d._enabled){var b=n(a(this).attr("style").substring(17));d.options.displayIndicator&&d._setColorInd(b,2),d.element.trigger("mouseover.color",b)}}).find(".evo-more a").on("click",function(){d._switchPalette(this)})},val:function(a){return"undefined"==typeof a?this.options.color:(this._setValue(a),this)},_setValue:function(a,b){a=a.replace(/ /g,""),this.options.color=a,this._isPopup?(b||this.hidePalette(),this.element.val(a).next().attr("style","background-color:"+a)):this._setColorInd(a,1),this.options.history&&this._paletteIdx>0&&this._add2History(a),this.element.trigger("change.color",a)},_setColorInd:function(a,b){this["_cTxt"+b].attr("style","background-color:"+a).next().html(a)},_setOption:function(a,b){"color"==a?this._setValue(b,!0):this.options[a]=b},_add2History:function(a){for(var b=f.length,c=0;b>c;c++)if(a==f[c])return;b>27&&f.shift(),f.push(a)},enable:function(){var a=this.element;return this._isPopup?a.removeAttr("disabled"):a.css({opacity:"1","pointer-events":"auto"}),"focus"!==this.options.showOn&&this.element.next().addClass("evo-pointer"),a.removeAttr("aria-disabled"),this._enabled=!0,this},disable:function(){var a=this.element;return this._isPopup?a.attr("disabled","disabled"):(this.hidePalette(),a.css({opacity:"0.3","pointer-events":"none"})),"focus"!==this.options.showOn&&this.element.next().removeClass("evo-pointer"),a.attr("aria-disabled","true"),this._enabled=!1,this},isDisabled:function(){return!this._enabled},destroy:function(){a(document.body).off("click."+this._id),this._palette&&(this._palette.off("mouseover click","td").find(".evo-more a").off("click"),this._isPopup&&this._palette.remove(),this._palette=this._cTxt=null),this._isPopup&&this.element.next().off("click").remove().end().off("focus").unwrap(),this.element.removeClass("colorPicker "+this.id).empty(),a.Widget.prototype.destroy.call(this)}})}(jQuery); +!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){function n(e){return u.raw?e:encodeURIComponent(e)}function o(e){return u.raw?e:decodeURIComponent(e)}function i(e){return n(u.json?JSON.stringify(e):String(e))}function t(e){0===e.indexOf('"')&&(e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return e=decodeURIComponent(e.replace(c," ")),u.json?JSON.parse(e):e}catch(n){}}function r(n,o){var i=u.raw?n:t(n);return e.isFunction(o)?o(i):i}var c=/\+/g,u=e.cookie=function(t,c,s){if(arguments.length>1&&!e.isFunction(c)){if(s=e.extend({},u.defaults,s),"number"==typeof s.expires){var a=s.expires,d=s.expires=new Date;d.setMilliseconds(d.getMilliseconds()+864e5*a)}return document.cookie=[n(t),"=",i(c),s.expires?"; expires="+s.expires.toUTCString():"",s.path?"; path="+s.path:"",s.domain?"; domain="+s.domain:"",s.secure?"; secure":""].join("")}for(var f=t?void 0:{},p=document.cookie?document.cookie.split("; "):[],l=0,m=p.length;m>l;l++){var x=p[l].split("="),g=o(x.shift()),j=x.join("=");if(t===g){f=r(j,c);break}t||void 0===(j=r(j))||(f[g]=j)}return f};u.defaults={},e.removeCookie=function(n,o){return e.cookie(n,"",e.extend({},o,{expires:-1})),!e.cookie(n)}}); //Only use for debugging function showdebugMessage(msg){ @@ -49,23 +52,42 @@ function dashboard_loadsvgIcon(svgIcon, svgColor, destObj) { //search Icon in ev for (var i = 0; i < groupdata.length; i++) { if (groupdata[i] != "") { if (!svgIcon.match('.svg')) {svgIcon = svgIcon+'.svg';} - groupdata[i] = groupdata[i].replace('.',''); - groupdata[i] = groupdata[i].replace('/opt/fhem',''); - dashboard_showsvgIcon(document.location.pathname.replace(/\/+$/, '')+groupdata[i]+"/"+svgIcon, svgColor, destObj); - } + groupdata[i] = groupdata[i].replace('.',''); + groupdata[i] = groupdata[i].replace('/opt/fhem',''); + dashboard_showsvgIcon( + fhemUrl+groupdata[i]+"/"+svgIcon, svgColor, destObj + ); + } } } function dashboard_showsvgIcon(svgIcon, svgColor, destObj) { - $.get(svgIcon, null, function(data) { - var svgNode = $("svg", data); - svgNode.attr('class','ui-tabs-icon'); - svgNode.find('g').attr({ fill : svgColor}); - svgNode.find('g').removeAttr('style'); - svgNode.find('g path').removeAttr('style'); - var docNode = document.adoptNode(svgNode[0]); - var pageNode = $(destObj); - pageNode.html(docNode); - }, 'xml'); + $.ajax({ + type: "GET", + contentType: "application/json", + data: "{}", + url: svgIcon + "&XHR=1", + dataType: "text", + success: function(data) { + if (data) { + $.get(fhemUrl + '/images/' + data, null, function(data) { + var svgNode = $("svg", data); + svgNode.attr('class','ui-tabs-icon'); + svgNode.find('g').attr({ fill : svgColor}); + svgNode.find('g').removeAttr('style'); + svgNode.find('g path').removeAttr('style'); + var docNode = document.adoptNode(svgNode[0]); + var pageNode = $(destObj); + pageNode.html(docNode); + if (gridSize = is_dashboard_flexible()) { + // update containment for draggable to avoid issues with async loaded icons and tab list height + var $container = $(".dashboard_rowcenter"); + $(".dashboard_widget").draggable('option', 'containment', [$container.offset().left,$container.offset().top]); + } + }, 'xml'); + } + } + }); + return; } //------------------------------------------------------------------------------------------------------ @@ -83,7 +105,9 @@ function dashboard_getData(jsonurl, get, dType, cb) {//get Dashboard config if (get.indexOf('groupWidget') != -1) { dashboard_test2(data); } - if (cb) cb(); + if (cb) { + cb(data); + } return; } }); @@ -92,18 +116,14 @@ function dashboard_getData(jsonurl, get, dType, cb) {//get Dashboard config // Write the Attribute Value //------------------------------------------------------------------------------------------------------ function dashboard_setAttribute(Attr, Val) {//set Dashboard Attribute - var location = document.location.pathname; - if (location.substr(location.length-1,1) == '/') {location = location.substr(0,location.length-1);} - var url = document.location.protocol+"//"+document.location.host+location; + var url = document.location.protocol+"//"+document.location.host+fhemUrl; FW_cmd(url+'?XHR=1&cmd.'+DashboardConfigHash['name']+'=attr '+DashboardConfigHash['name']+' '+Attr+' '+Val); } //------------------------------------------------------------------------------------------------------ // Delete the Attribute //------------------------------------------------------------------------------------------------------ function dashboard_delAttribute(Attr) {//delete Dashboard Attribute - var location = document.location.pathname; - if (location.substr(location.length-1,1) == '/') {location = location.substr(0,location.length-1);} - var url = document.location.protocol+"//"+document.location.host+location; + var url = document.location.protocol+"//"+document.location.host+fhemUrl; FW_cmd(url+'?XHR=1&cmd.'+DashboardConfigHash['name']+'=deleteattr '+DashboardConfigHash['name']+' '+Attr); } //------------------------------------------------------------------------------------------------------ @@ -117,7 +137,7 @@ function dashboard_delAttribute(Attr) {//delete Dashboard Attribute var groupdata = (DashboardConfigHash['dashboard_tab2groups'].split(",")); for (var i = 0; i < groupdata.length; i++) { //alert(groupdata[i]); - dashboard_getData(document.location.pathname+"?cmd=get "+$('#dashboard_define').text(), "groupWidget "+groupdata[i], "html"); + dashboard_getData(fhemUrl+"?cmd=get "+$('#dashboard_define').text(), "groupWidget "+groupdata[i], "html"); } } @@ -130,35 +150,35 @@ $('#dashboard_tab1column0').append(data); //------------------------------------------------------------------------------------------------------ function saveOrder() { var EndSaveResult = ""; - var ActiveTab = $("#dashboardtabs .ui-tabs-panel:visible").attr("id").substring(14,13); + var ActiveTab = getTabIndexFromTab($("#dashboardtabs .ui-tabs-panel:visible")); //------------------- Build new Position string ---------------------- - $(".dashboard_column").each(function(index, value){ - var colid = value.id; + $("#dashboard_tab" + ActiveTab + " .dashboard_widget").each(function (index, value) { var SaveResult = ""; - var neworder = $('#' + colid).sortable("toArray"); - for ( var i = 0, n = neworder.length; i < n; i++ ) { - var tab = $('#' + neworder[i]).parent().attr("id").substring(14,13); - var column = $('#' + neworder[i]).parent().attr("id").substring(20); - if (ActiveTab == tab) { - var groupdata = ($('#' + neworder[i]).data("groupwidget").split(",")); //get curren Group-Configuration - if (groupdata[1] != ''){ - groupdata[0] = "t"+tab+"c"+$('#' + neworder[i]).parent().attr("id").substring(20); - groupdata[2] = true; //ever collapsed - //groupdata[2] = $('#' + neworder[i]).find('.dashboard_content').is(':visible'); - groupdata[3] = $('#' + neworder[i]).outerWidth(); - - if (groupdata[4] == 0) {groupdata[4] = $('#' + neworder[i]).outerHeight();} - if (groupdata[2] == true) { - groupdata[4] = $('#' + neworder[i]).outerHeight(); - $('#' + neworder[i]).find(".dashboard_content").data("userheight", $('#' + neworder[i]).outerHeight()); - } - $(neworder[i]).data("groupwidget",groupdata); //store in current Widget - SaveResult = SaveResult+groupdata+":"; - } + var $widget = $(value); + var column = $widget.parent().attr("id").replace(new RegExp('dashboard_tab' + ActiveTab + 'column'), ''); + var groupdata = ($widget.data("groupwidget").split(",")); //get curren Group-Configuration + if (groupdata[1] != ''){ + groupdata[0] = "t"+ActiveTab+"c"+column; + groupdata[2] = true; //ever collapsed + groupdata[3] = $widget.outerWidth(); + + if (this.style.height) { + if (groupdata[4] == 0) {groupdata[4] = $widget.outerHeight();} + if (groupdata[2] == true) { + groupdata[4] = $widget.outerHeight(); + $widget.find(".dashboard_content").data("userheight", $widget.outerHeight()); + } } - } + // store positions relative to the center row + groupdata[5] = Math.round($widget.offset().left - $('#dashboard_rowcenter_tab' + ActiveTab).offset().left); + groupdata[6] = Math.round($widget.offset().top - $('#dashboard_rowcenter_tab' + ActiveTab).offset().top); + + $widget.data("groupwidget",groupdata.join(',')); //store in current Widget + SaveResult = SaveResult+groupdata.join(',')+":"; + } if (SaveResult != ""){ EndSaveResult = EndSaveResult + SaveResult; } //NewResult: ,,,,,,,,: widgetmaxwidth) {width = widgetmaxwidth}; //width is =< columnwith + if (!is_flexible) { + var widgetmaxwidth = $(this).parent().width(); + if (width == 0) { + width = $(this).find(".dashboard_content").children().outerWidth()+10; + } + } $(this).outerWidth(width); //--------------------------------------------------------------------------------------------------------------- //-------------------------------- Height of an Group. | Min. Height if need --------------------------- - if (height == 0) { height = $(this).outerHeight();} - if ($(this).outerHeight() > height) {$(this).outerHeight(height); } //set heigh only if > group min. height - //--------------------------------------------------------------------------------------------------------------- + if (!is_flexible && height > 0) { + $(this).outerHeight(height); //set heigh only if > group min. height + } + //--------------------------------------------------------------------------------------------------------------- + //-------------------------------- Corrent height for inner div. ------------------------------------- + var innerHeight = $(this).children('.dashboard_widgetinner').outerHeight(); + if (this.style.height && $(this).outerHeight() < innerHeight) { + $(this).css('height', innerHeight + 'px'); + } + //--------------------------------------------------------------------------------------------------------------- + //-------------------------------- position of a Group. -------------------------------------------------------- + if (is_flexible) { + if (!left) left = 0; + if (!top) top = 0; + $(this).css('position', 'absolute').css('left', left + 'px').css('top', top + 'px'); + } + //--------------------------------------------------------------------------------------------------------------- $(this).find(".dashboard_content").data("userheight", height-5); if (DashboardConfigHash['lockstate'] == "unlock") { $(this).addClass("dashboard_widgethelper"); } else { $(this).removeClass("dashboard_widgethelper"); }//Show Widget-Helper Frame @@ -246,15 +304,39 @@ function GetColWidth(ColCount, ColWidth){ return aColWidth; } +function is_dashboard_flexible() { + var params = dashboard_get_params(); + return parseInt(params[15]); +} + +function dashboard_get_params() { + if (!dashboard_get_params.dashboard_params) { + dashboard_get_params.dashboard_params = (document.getElementById("dashboard_attr").value).split(","); //get current Configuration + } + return dashboard_get_params.dashboard_params; +} + function dashboard_setlock(){ - $( ".dashboard_column" ).sortable( "option", "disabled", true ); + if(is_dashboard_flexible()) { + $( ".dashboard_widget" ).draggable( "option", "disabled", true ); + } + else { + $( ".dashboard_column" ).sortable( "option", "disabled", true ); + } $( ".dashboard_widget" ).removeClass("dashboard_widgethelper"); - if ($( ".dashboard_widget" ).hasClass("ui-resizable")) { $( ".dashboard_widget" ).resizable("destroy"); }; + if ($( ".dashboard_widget" ).hasClass("ui-resizable")) { + $( ".dashboard_widget" ).resizable("destroy"); + }; $( ".dashboard_column" ).removeClass("dashboard_columnhelper"); } function dashboard_unsetlock(){ - $( ".dashboard_column" ).sortable( "option", "disabled", false ); + if(is_dashboard_flexible()) { + $( ".dashboard_widget" ).draggable( "option", "disabled", false ); + } + else { + $( ".dashboard_column" ).sortable( "option", "disabled", false ); + } if (DashboardConfigHash['lockstate'] == "unlock") { $( ".dashboard_widget" ).addClass("dashboard_widgethelper"); } else { $( ".dashboard_widget" ).removeClass("dashboard_widgethelper"); }//Show Widget-Helper Frame if (DashboardConfigHash['lockstate'] == "unlock") { $( ".dashboard_column" ).addClass("dashboard_columnhelper"); } else { $( ".dashboard_column" ).removeClass("dashboard_columnhelper"); }//Show Widget-Helper Frame dashboard_modifyWidget(); @@ -265,7 +347,7 @@ function dashboard_setposition(){ for (var i = 0, n = DashboardConfigHash['dashboard_tabcount']; i < n; i++ ) { if ($("#dashboard_tab"+i).data("tabwidgets") != null) { var j = i+1; - FW_cmd(document.location.pathname+'?XHR=1&cmd.'+DashboardConfigHash['name']+'=attr '+DashboardConfigHash['name']+' dashboard_tab'+j+'sorting '+$("#dashboard_tab"+i).data("tabwidgets")); + FW_cmd(fhemUrl+'?XHR=1&cmd.'+DashboardConfigHash['name']+'=attr '+DashboardConfigHash['name']+' dashboard_tab'+j+'sorting '+$("#dashboard_tab"+i).data("tabwidgets")); } } $("#setPosition").button({disabled: true}); @@ -274,19 +356,24 @@ function dashboard_setposition(){ // Set only over Dashborad-Dialog or fhem Attribute //var activeTab = ($( "#dashboardtabs" ).tabs( "option", "active" ))+1; //if (DashboardConfigHash['dashboard_activetab'] != activeTab){ - // FW_cmd(document.location.pathname+'?XHR=1&cmd.'+DashboardConfigHash['name']+'=attr '+DashboardConfigHash['name']+' dashboard_activetab '+activeTab); + // FW_cmd(fhemUrl+'?XHR=1&cmd.'+DashboardConfigHash['name']+'=attr '+DashboardConfigHash['name']+' dashboard_activetab '+activeTab); //} //--------------------------------------------------------------------- } function dashboard_modifyWidget(){ - $( ".dashboard_widget" ).resizable({ - 'grid': 5, - start: function(e, ui) { - var params = (document.getElementById("dashboard_attr").value).split(","); //get current Configuration + makeResizable('.dashboard_widget'); +} + +function makeResizable (sSelector) { + var grid = is_dashboard_flexible(); + $( sSelector ).resizable({ + start: function(e, ui) { + if (!is_dashboard_flexible()) { + var params = dashboard_get_params(); var groupdata = $(this).data("groupwidget").split(","); //get the position string from the data - var TabId = $(this).parent().attr("id").substring(14,13); - var ColumnId = $(this).parent().attr("id").substring(20); + var TabId = getTabIndexFromTab($(this).parent()); + var ColumnId = $(this).parent().attr("id").replace(new RegExp('dashboard_tab' + TabId + 'column'), ''); var widgetmaxwidth = $(this).parent().width(); if (ColumnId == "100") { var widgetmaxheight = params[8]; } @@ -296,15 +383,17 @@ function dashboard_modifyWidget(){ maxWidthOffset = widgetmaxwidth; $(this).resizable("option","maxWidth",widgetmaxwidth-5); $(this).resizable("option","maxHeight",widgetmaxheight); - }, - resize: function(e, ui) { - if ($(this).find(".dashboard_widgetheader").outerWidth() < $(this).find(".dashboard_content").children().outerWidth()) {$(this).resizable("option","minWidth", $(this).find(".dashboard_content").children().outerWidth()+5 ); } - if ($(this).find(".dashboard_widget").outerHeight() < $(this).find(".dashboard_widgetinner").outerHeight()) { $(this).resizable("option","minHeight", $(this).find(".dashboard_widgetinner").outerHeight()); } - }, - stop: function() { - saveOrder(); - } - }); + } + }, + resize: function(e, ui) { + if ($(this).find(".dashboard_widgetheader").outerWidth() < $(this).find(".dashboard_content").children().outerWidth()) {$(this).resizable("option","minWidth", $(this).find(".dashboard_content").children().outerWidth()+5 ); } + if ($(this).find(".dashboard_widget").outerHeight() < $(this).find(".dashboard_widgetinner").outerHeight()) { $(this).resizable("option","minHeight", $(this).find(".dashboard_widgetinner").outerHeight()); } + }, + stop: function() { + saveOrder(); + }, + grid: grid ? [grid,grid] : false + }); } function dashboard_openModal(tabid) { @@ -337,9 +426,11 @@ function dashboard_openModal(tabid) { if ($('#tabActiveTab').is(':checked')) {dashboard_setAttribute('dashboard_activetab', tabid+1); } setTimeout(dashboard_reloadpage, 1500); $(this).dialog("close"); + $(this).dialog("destroy"); }, "Cancel": function() { $(this).dialog("close"); + $(this).dialog("destroy"); } }, create: function( event, ui ) { @@ -357,7 +448,7 @@ function adddashboardButton(position, text, id, hint) { function dashboard_buildButtons() { adddashboardButton("top", "", "defineDetails", "Show Details"); - $("#defineDetails").click(function () {location.href=document.location.pathname+'?detail='+DashboardConfigHash['name'];}); + $("#defineDetails").click(function () {location.href=fhemUrl+'?detail='+DashboardConfigHash['name'];}); if (DashboardConfigHash['lockstate'] != "lock"){ adddashboardButton("top", "", "setPosition", "Set Position"); @@ -369,71 +460,145 @@ function dashboard_buildButtons() { } if (DashboardConfigHash['dashboard_showfullsize'] == 1) { adddashboardButton("top", "", "goBack", "Back"); - $("#goBack").click(function () {location.href=document.location.pathname;}); + //$("body").addClass("hideMenu"); + $("#goBack").click(function () {location.href=fhemUrl;}); } //adddashboardButton("top", "", "testButton", "TEST"); //$("#testButton").click(function () {dashboard_test()}); + + $(".dashboard_tab").click(function () { + var tabIndex = $(this).parent().children('li').index(this); + dashboard_load_tab(tabIndex); + }); } -function dashboard_buildDashboard(){ - var params = (document.getElementById("dashboard_attr").value).split(","); //get current Configuration //TEMPORÄR - dashboard_buttonbar = params[4]; +function dashboard_load_tab(tabIndex) { + // in case the tab is already loaded, do nothing + if ($('#dashboard_tab' + tabIndex).length) { + return; + } - - if (DashboardConfigHash['dashboard_showfullsize'] == 1){ //disable roomlist and header - $("#menuScrollArea").remove(); - $("#hdr").remove(); - $(".roomoverview:first").remove(); - $("br:first").remove(); - $("#content").css({position: 'inherit'}); - } - - $(".dashboard_column").sortable({ - connectWith: ['.dashboard_column', '.ui-row'], + dashboard_getData( + fhemUrl+"?cmd=get "+$('#dashboard_define').text(), + "tab " + tabIndex, + "html", + function (tabIndex, data) { + dashboard_insert_tab(tabIndex, data); + }.bind(null, tabIndex) + ); +} + +function dashboard_insert_tab(tabIndex, content) { + $('#dashboardtabs').append(content); + $("#dashboardtabs").tabs('refresh'); + FW_replaceWidgets($("#dashboard_tab" + tabIndex)); + dashboard_init_tab(tabIndex); + $("#dashboard_tab" + tabIndex + " a").each(function() { FW_replaceLink(this); }); + restoreOrder(tabIndex); + restoreGroupVisibility(tabIndex); + if (gridSize = is_dashboard_flexible()) { + var $container = $("#dashboard_rowcenter_tab" + tabIndex); + $("#dashboard_tab" + tabIndex + " .dashboard_widget").draggable({ cursor: 'move', - stop: function() { saveOrder(); } - }); + grid: [gridSize,gridSize], + containment: [$container.offset().left,$container.offset().top], + stop: function() { saveOrder(); } + }); + } + else { + $("#dashboard_tab" + tabIndex + " .dashboard_column").sortable({ + connectWith: ['.dashboard_column', '.ui-row'], + cursor: 'move', + tolerance: 'pointer', + stop: function() { saveOrder(); } + }); + } + makeResizable('.dashboard_widget'); + if ((DashboardConfigHash['lockstate'] == "lock") || (dashboard_buttonbar == "hidden")) { + dashboard_setlock(); + } else { + dashboard_unsetlock(); + } +} - if (DashboardConfigHash['dashboard_showtooglebuttons'] == 1){ //ToogleButton show/hide - $(".dashboard_widget") +function dashboard_init_tab(tabIndex) { + if (DashboardConfigHash['dashboard_showtogglebuttons'] == 1){ //ToggleButton show/hide + $("#dashboard_tab" + tabIndex + " .dashboard_widget") .addClass( "dashboard_widget ui-corner-all" ) .find(".dashboard_widgetheader") .addClass( "dashboard_widgetheader ui-corner-all" ) .prepend('') .end(); - $(".dashboard_widgetheader .dashboard_button_icon").click(function(event) { + $("#dashboard_tab" + tabIndex + " .dashboard_widgetheader .dashboard_button_icon").click(function(event) { if ($(this).hasClass("dashboard_button_iconplus")) { - $(this).removeClass( "dashboard_button_iconplus" ); - $(this).addClass( "dashboard_button_iconminus" ); - $(this).parents(".dashboard_widget:first").find(".dashboard_content").show(); - var newHeigth = $(this).parents(".dashboard_widget:first").find(".dashboard_content").data("userheight"); - - $(this).parent().removeClass("dashboard_widgetmin"); - $(this).parent().addClass("dashboard_widgetmax"); - - //-------- set heigh only if > group min. height ------------- - if ($(this).parents(".dashboard_widgetinner").outerHeight() > newHeigth) { - $(this).parents(".dashboard_widget:first").outerHeight($(this).parents(".dashboard_widgetinner").outerHeight()+10); - } else { $(this).parents(".dashboard_widget:first").outerHeight(newHeigth);} - //------------------------------------------------------------ + showGroupForButton(this); } else { - $(this).removeClass( "dashboard_button_iconminus" ); - $(this).addClass( "dashboard_button_iconplus" ); - var currHeigth = Math.round($(this).parents(".dashboard_widget:first").height()); - $(this).parents(".dashboard_widget:first").find(".dashboard_content").data("userheight", currHeigth); - $(this).parents(".dashboard_widget:first").find(".dashboard_content").hide(); - var newHeigth = $(this).parents(".dashboard_widget:first").find(".dashboard_widgetinner").height()+5; - $(this).parents(".dashboard_widget:first").height(newHeigth); - - $(this).parent().removeClass("dashboard_widgetmax"); - $(this).parent().addClass("dashboard_widgetmin"); + hideGroupForButton(this); } saveOrder(); event.stopImmediatePropagation(); }); - } else { $(".dashboard_widgetheader").addClass( "dashboard_widgetheader ui-corner-all" );} + } else { $("#dashboard_tab" + tabIndex + " .dashboard_widgetheader").addClass( "dashboard_widgetheader ui-corner-all" );} +} + +function restoreGroupVisibility(tabId) { + $("#dashboard_tab" + tabId + ' .dashboard_button_icon').each(function(index, button) { + var $parentElement = $(button).parents(".dashboard_widget:first"); + var id = $parentElement.attr('id'); + if ($.cookie(id + '_hidden')) { + hideGroupForButton(button); + } + }); +} + +function hideGroupForButton(button) { + $(button).removeClass( "dashboard_button_iconminus" ); + $(button).addClass( "dashboard_button_iconplus" ); + var $parentElement = $(button).parents(".dashboard_widget:first"); + var currHeight = Math.round($parentElement.height()); + $parentElement.find(".dashboard_content").data("userheight", currHeight); + $parentElement.find(".dashboard_content").hide(); + var newHeight = $parentElement.find(".dashboard_widgetinner").height()+5; + $parentElement.height(newHeight); + + $(button).parent().removeClass("dashboard_widgetmax"); + $(button).parent().addClass("dashboard_widgetmin"); + $.cookie($parentElement.attr('id') + '_hidden', '1'); +} + +function showGroupForButton(button) { + $(button).removeClass( "dashboard_button_iconplus" ); + var $parentElement = $(button).parents(".dashboard_widget:first"); + $(button).addClass( "dashboard_button_iconminus" ); + $parentElement.find(".dashboard_content").show(); + var newHeigth = $parentElement.find(".dashboard_content").data("userheight"); + + $(button).parent().removeClass("dashboard_widgetmin"); + $(button).parent().addClass("dashboard_widgetmax"); + + //-------- set heigh only if > group min. height ------------- + if ($(button).parents(".dashboard_widgetinner").outerHeight() > newHeigth) { + $parentElement.outerHeight($(button).parents(".dashboard_widgetinner").outerHeight()+10); + } else { $parentElement.outerHeight(newHeigth);} + //------------------------------------------------------------ + $.removeCookie($parentElement.attr('id') + '_hidden'); +} + +function dashboard_buildDashboard(){ + var params = dashboard_get_params(); + dashboard_buttonbar = params[4]; + + dashboard_init_tab(0); + + if (DashboardConfigHash['dashboard_showfullsize'] == 1){ //disable roomlist and header + //$("#menuScrollArea").remove(); + //$("#hdr").remove(); + //$(".roomoverview:first").remove(); + //$("br:first").remove(); + //$("#content").css({position: 'inherit', 'overflow' : 'visible', 'float' : 'none', 'width' : '100%', 'height' : '100%', 'padding' : '0px', 'border' : 'none'}); + } //--------------------------------- Dashboard Tabs ------------------------------------------------------------------------------ $("#dashboardtabs").tabs({ @@ -441,9 +606,12 @@ function dashboard_buildDashboard(){ create: function(event, ui) { $( "#dashboardtabs" ).tabs( "option", "active", DashboardConfigHash['dashboard_activetab']-1);//set active Tab restoreOrder(); + restoreGroupVisibility(0); }, activate: function (event, ui) { - restoreOrder(); + var tabIndex = ui.newTab.parent().children('li').index(ui.newTab); + //restoreOrder(tabIndex); + //restoreGroupVisibility(tabIndex); } }); if ($("#dashboard_tabnav").hasClass("dashboard_tabnav_bottom")) { $(".dashboard_tabnav").appendTo(".dashboard_tabs"); } //set Tabs on the Bottom @@ -451,14 +619,42 @@ function dashboard_buildDashboard(){ //---------------------- Dashboard Tab Icons --------------------------------------------------- for ( var i = 0, n = $('#dashboardtabs >ul >li').size(); i < n; i++ ) { - if (DashboardConfigHash['dashboard_tab'+(i+1)+'icon']) { - if (DashboardConfigHash['dashboard_tab'+(i+1)+'iconcolor']) {var svgColor = DashboardConfigHash['dashboard_tab'+(i+1)+'iconcolor'];} else {svgColor = "#FFFFFF";} + if (DashboardConfigHash['dashboard_tab'+(i+1)+'icon']) { + if (DashboardConfigHash['dashboard_tab'+(i+1)+'iconcolor']) { + var svgColor = DashboardConfigHash['dashboard_tab'+(i+1)+'iconcolor']; + } else { + svgColor = "#FFFFFF"; + } + $('#dashboardtabs ul:first li:eq('+i+')').children().prepend(''); - dashboard_loadsvgIcon(DashboardConfigHash['dashboard_tab'+(i+1)+'icon'], svgColor, "#dashboard_tab"+(i+1)+"icon"); + //dashboard_loadsvgIcon(DashboardConfigHash['dashboard_tab'+(i+1)+'icon'], svgColor, "#dashboard_tab"+(i+1)+"icon"); + dashboard_showsvgIcon ( + fhemUrl + '?cmd=get ' + $('#dashboard_define').text() + ' icon ' + DashboardConfigHash['dashboard_tab'+(i+1)+'icon'], + svgColor, "#dashboard_tab"+(i+1)+"icon" + ); } } //----------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------------------------------------------- + + if (gridSize = is_dashboard_flexible()) { + var $container = $(".dashboard_rowcenter"); + $(".dashboard_widget").draggable({ + cursor: 'move', + grid: [gridSize,gridSize], + containment: [$container.offset().left,$container.offset().top], + stop: function() { saveOrder(); } + }); + } + else { + $(".dashboard_column").sortable({ + connectWith: ['.dashboard_column', '.ui-row'], + cursor: 'move', + tolerance: 'pointer', + stop: function() { saveOrder(); } + }); + } + dashboard_modifyWidget(); if (dashboard_buttonbar != "hidden") dashboard_buildButtons(); if ((DashboardConfigHash['lockstate'] == "lock") || (dashboard_buttonbar == "hidden")) {dashboard_setlock();} else {dashboard_unsetlock();} @@ -466,11 +662,13 @@ function dashboard_buildDashboard(){ } $(document).ready( function () { + svg_init(); var dbattr = document.getElementById("dashboard_attr"); if (dbattr) { $("body").attr("longpollfilter", ".*") //need for longpoll //--------------------------------- Attribute des Dashboards ------------------------------------------------------------------ - dashboard_getData(document.location.pathname+"?cmd=get "+$('#dashboard_define').text(), "config", "json", dashboard_buildDashboard); + dashboard_getData(fhemUrl + "?cmd=get "+$('#dashboard_define').text(), "config", "json", dashboard_buildDashboard); //---------------------------------------------------------------------------------------------------------------------------- + $(window).off('resize'); } -}); \ No newline at end of file +});