diff --git a/fhem/CHANGED b/fhem/CHANGED index 0a504af2a..2dea2a686 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,9 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 95_Dashboard: added new attribute dashboard_tabXdevices which + supports devspec definitions for shown dashboard groups. + Storage of current opened tab and restore when opening dashboard. + Fixed some CSS issues (text alignment, colors ...) - change: SYSMON: warning (userdefined readings), reading for perl version - feature: 38_CO20.pm: added advanced features, retries and timeout (by Markus M.) - feature: 32_yowsup.pm: added support for groups diff --git a/fhem/FHEM/95_Dashboard.pm b/fhem/FHEM/95_Dashboard.pm index cf81458de..fa2913b73 100644 --- a/fhem/FHEM/95_Dashboard.pm +++ b/fhem/FHEM/95_Dashboard.pm @@ -60,6 +60,7 @@ # Optimized icon loading. # Optimized fullscreen view. # Minor improvements in javascript and css. +# 3.10: added attribute dashboard_tabXdevices, which can contain devspec definitions and thus allow to also shown not grouped devices # # 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...) @@ -115,9 +116,7 @@ my %group; my $dashboard_groupListfhem; my $fwjquery = "jquery.min.js"; my $fwjqueryui = "jquery-ui.min.js"; -my $dashboardversion = "3.00"; -my @fhemweb_instances = (); - +my $dashboardversion = "3.10"; ############################################################################################# sub Dashboard_Initialize ($) { @@ -132,11 +131,9 @@ sub Dashboard_Initialize ($) { $hash->{AttrList} = "disable:0,1 ". "dashboard_colcount:1,2,3,4,5 ". "dashboard_debug:0,1 ". - "dashboard_lockstate:dont-use-this-attribut ". #obolet since 04.2014 "dashboard_rowtopheight ". "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_showtogglebuttons:0,1 ". #new attribute vers. 2.00 "dashboard_activetab:1,2,3,4,5,6,7 ". @@ -146,15 +143,16 @@ sub Dashboard_Initialize ($) { "dashboard_rowcentercolwidth ". "dashboard_showfullsize:0,1 ". #new attribute vers. 2.02 - #"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 #new attribute vers. 2.06 "dashboard_customcss " . + #new attribute vers. 3.00 "dashboard_flexible " . #tab-specific attributes "dashboard_tab1name " . "dashboard_tab1groups " . + #new attribute vers. 3.10 + "dashboard_tab1devices " . "dashboard_tab1sorting " . "dashboard_tab1icon " . "dashboard_tab1colcount " . @@ -163,6 +161,8 @@ sub Dashboard_Initialize ($) { # dynamic attributes "dashboard_tab[0-9]+name " . "dashboard_tab[0-9]+groups " . + #new attribute vers. 3.10 + "dashboard_tab[0-9]+devices " . "dashboard_tab[0-9]+sorting " . "dashboard_tab[0-9]+icon " . "dashboard_tab[0-9]+colcount " . @@ -239,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\", \"dashboard_tabcount\": " . GetTabCount($hash, 0); + $res .= " \"icondirs\": \"$iconDirs\", \"dashboard_tabcount\": " . GetTabCount($hash, 0). ", \"dashboard_activetab\": " . GetActiveTab($hash->{NAME}); $res .= ($i != $x) ? ",\n" : "\n"; foreach my $attr (sort keys %$attrdata) { @@ -248,7 +248,10 @@ sub Dashboard_Get($@) { if (@splitattr == 2) { $res .= " \"".Dashboard_Escape($attr)."\": \"".$splitattr[0]."\",\n"; $res .= " \"".Dashboard_Escape($attr)."color\": \"".$splitattr[1]."\""; - } else { $res .= " \"".Dashboard_Escape($attr)."\": \"".$attrdata->{$attr}."\"";} + } elsif ($attr ne "dashboard_activetab") { $res .= " \"".Dashboard_Escape($attr)."\": \"".$attrdata->{$attr}."\"";} + else { + next; + } $res .= ($i != $x) ? ",\n" : "\n"; } $res .= " }\n"; @@ -258,15 +261,15 @@ sub Dashboard_Get($@) { } elsif ($arg eq "groupWidget") { #### Comming Soon ###### # For dynamic load of GroupWidgets from JavaScript - my $dbgroup = ""; + #my $dbgroup = ""; #for (my $p=2;$p<@a;$p++){$dbgroup .= @a[$p]." ";} #For Groupnames with Space - for (my $p=2;$p<@a;$p++){$dbgroup .= $a[$p]." ";} #For Groupnames with Space + #for (my $p=2;$p<@a;$p++){$dbgroup .= $a[$p]." ";} #For Groupnames with Space - $dashboard_groupListfhem = Dashboard_GetGroupList; - %group = BuildGroupList($dashboard_groupListfhem); - $res .= BuildGroupWidgets(1,1,1212,trim($dbgroup),"t1c1,".trim($dbgroup).",true,0,0:"); - return $res; -#For dynamic loading of tabs + #$dashboard_groupListfhem = Dashboard_GetGroupList; + #%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") { @@ -277,7 +280,7 @@ sub Dashboard_Get($@) { return FW_iconPath($icon); } else { - return "Unknown argument $arg choose one of config:noArg groupWidget"; + return "Unknown argument $arg choose one of config:noArg groupWidget tab icon"; } } @@ -293,7 +296,6 @@ sub Dashboard_define ($$) { RemoveInternalTimer($hash); InternalTimer ($now + 5, 'CheckDashboardAttributUssage', $hash, 0); - my $dashboard_groupListfhem = Dashboard_GetGroupList; my $url = '/dashboard/' . $name; @@ -320,8 +322,15 @@ sub Dashboard_attr($$$) { my ($cmd, $name, $attrName, $attrVal) = @_; # add dynamic attributes - if ($cmd eq "set" && $attrName =~ m/dashboard_tab([1-9][0-9]*)groups/) { + if ( + $cmd eq "set" && + ( + $attrName =~ m/dashboard_tab([1-9][0-9]*)groups/ + || $attrName =~ m/dashboard_tab([1-9][0-9]*)devices/ + ) + ) { addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "name"); + addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "devices"); addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "groups"); addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "sorting"); addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "icon"); @@ -358,7 +367,7 @@ sub Dashboard_CGI($) FW_pO $ret; - return 1; + return 0; } sub DashboardAsHtml($) @@ -399,7 +408,7 @@ sub Dashboard_SummaryFN($$$$) 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 $activetab = GetActiveTab($d); my $tabcount = GetTabCount($defs{$d}, 1); my $dbwidth = AttrVal($defs{$d}{NAME}, "dashboard_width", "100%"); my @tabnames = (); @@ -407,7 +416,7 @@ sub Dashboard_SummaryFN($$$$) if ($showfullsize) { if ($FW_RET =~ m/]*class="([^"]+)"[^>]*>/) { - $FW_RET =~ s/style="$1"/style="$1 dashboard_fullsize"/; + $FW_RET =~ s/class="$1"/class="$1 dashboard_fullsize"/; } else { $FW_RET =~ s/\n"; @@ -519,90 +527,89 @@ sub BuildDashboardTab($$) 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 $backgroundimage = AttrVal($defs{$d}{NAME}, 'dashboard_tab' . ($t + 1) . 'backgroundimage', ""); my $row = AttrVal($defs{$d}{NAME}, "dashboard_row", "center"); my $tabcount = GetTabCount($defs{$d}, 1); - my @tabgroups = (); - my @tabsortings = (); + my $tabgroups = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($t + 1) . "groups", ""); + my $tabsortings = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($t + 1) . "sorting", ""); + my $tabdevicegroups = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($t + 1) . "devices", ""); - 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 ); + unless ($tabgroups || $tabdevicegroups) { + readingsSingleUpdate( $defs{$d}, "state", "No Groups or devices set", 0 ); return ""; } - my $groups = Dashboard_GetGroupList(); + my @temptabdevicegroup = split(' ', $tabdevicegroups); + my @tabdevicegroups = (); + + # make sure device groups without a group name are splitted into + # separate groups for every device they are containing + for my $devicegroup (@temptabdevicegroup) { + my @groupparts = split(':', $devicegroup); + + if (@groupparts == 1) { + my @devices = map { $_ . ':' . $_ } devspec2array($groupparts[0]); + push(@tabdevicegroups, @devices); + } + else { + push(@tabdevicegroups, $devicegroup); + } + } + + 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 = (); - my @index = (); - + my @groups = split(',', $groups); + my @temptabgroup = split(",", $tabgroups); + + # resolve group names from regular expressions for (my $i=0;$i<@temptabgroup;$i++) { my @stabgroup = split(":", trim($temptabgroup[$i])); - @index = grep { $groups[$_] eq $stabgroup[0] } (0 .. @groups-1); + my @index = grep { $groups[$_] eq $stabgroup[0] } (0 .. @groups-1); + + if (@index == 0) { + my $matchGroup = '^' . $stabgroup[0] . '$'; + @index = grep { $groups[$_] =~ m/$matchGroup/ } (0 .. @groups-1); + } if (@index > 0) { for (my $j=0; $j<@index;$j++) { my $groupname = @groups[$index[$j]]; + $groupname .= ':' . 'group=' . $groupname; if (@stabgroup > 1) { $groupname .= ':' . $stabgroup[1]; } - push(@tabgroup,$groupname); + push(@tabdevicegroups,$groupname); } } - else { - my $matchGroup = '^' . $stabgroup[0] . '$'; - @index = grep { $groups[$_] =~ m/$matchGroup/ } (0 .. @groups-1); - - if (@index > 0) { - for (my $j=0; $j<@index;$j++) { - my $groupname = @groups[$index[$j]]; - if (@stabgroup > 1) { - $groupname .= ':' . $stabgroup[1]; - } - push(@tabgroup,$groupname); - } - } - } - } - + $tabgroups = join('§§§', @tabdevicegroups); - $tabgroups[$t] = join(',', @tabgroup); - - for (my $i=0;$i<@tabgroup;$i++) { - my @stabgroup = split(":", trim($tabgroup[$i])); + # add sortings for groups not already having a defined sorting + for (my $i=0;$i<@tabdevicegroups;$i++) { + my @stabgroup = split(":", trim($tabdevicegroups[$i])); my $matchGroup = "," . quotemeta(trim($stabgroup[0])) . ","; - if ($tabsortings[$t] !~ m/$matchGroup/) { - $tabsortings[$t] = $tabsortings[$t]."t".$t."c".GetMaxColumnId($row,$colcount).",".trim($stabgroup[0]).",true,0,0:"; + if ($tabsortings !~ m/$matchGroup/) { + $tabsortings = $tabsortings."t".$t."c".GetMaxColumnId($row,$colcount).",".trim($stabgroup[0]).",true,0,0:"; } - } + } - %group = BuildGroupList($tabgroups[$t]); - - my $ret = "
\n"; + 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]); + $ret .= BuildDashboardTopRow($t,$id,$tabgroups,$tabsortings); } ##################### 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); + $ret .= BuildDashboardCenterRow($t,$id,$tabgroups,$tabsortings,$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 .= BuildDashboardBottomRow($t,$id,$tabgroups,$tabsortings); } ############################################################################################# $ret .= "
    \n"; @@ -613,12 +620,12 @@ sub BuildDashboardTab($$) } sub BuildDashboardTopRow($$$$){ - my ($t,$id, $dbgroups, $dbsorting) = @_; + my ($t,$id, $devicegroups, $groupsorting) = @_; my $ret; $ret .= "\n"; $ret .= "
    \n"; $ret .= "
    \n"; - $ret .= BuildGroupWidgets($t,"100",$id,$dbgroups,$dbsorting); + $ret .= BuildGroupWidgets($t,"100",$id,$devicegroups,$groupsorting); $ret .= "
    \n"; $ret .= "
    \n"; $ret .= "\n"; @@ -626,9 +633,9 @@ sub BuildDashboardTopRow($$$$){ } sub BuildDashboardCenterRow($$$$$){ - my ($t,$id, $dbgroups, $dbsorting, $colcount) = @_; - my $ret; - $ret .= "\n"; + my ($t,$id, $devicegroups, $groupsorting, $colcount) = @_; + + my $ret = "\n"; $ret .= "
    \n"; my $currentcol = $colcount; @@ -636,16 +643,16 @@ sub BuildDashboardCenterRow($$$$$){ 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) { + # this does only work if there is no empty column inbetween + while (index($groupsorting, "t".$t."c".$currentcol.",") >= 0) { my $search = "t" . $t . "c" . $currentcol . ","; - $dbsorting =~ s/$search/$replace/g; + $groupsorting =~ s/$search/$replace/g; $currentcol++; } for (my $i=0;$i<$colcount;$i++){ $ret .= "
    \n"; - $ret .= BuildGroupWidgets($t,$i,$id,$dbgroups,$dbsorting); + $ret .= BuildGroupWidgets($t,$i,$id,$devicegroups,$groupsorting); $ret .= "
    \n"; } $ret .= "
    \n"; @@ -654,12 +661,12 @@ sub BuildDashboardCenterRow($$$$$){ } sub BuildDashboardBottomRow($$$$){ - my ($t,$id, $dbgroups, $dbsorting) = @_; + my ($t,$id, $devicegroups, $groupsorting) = @_; my $ret; $ret .= "\n"; $ret .= "
    \n"; $ret .= "
    \n"; - $ret .= BuildGroupWidgets($t,"200",$id,$dbgroups,$dbsorting); + $ret .= BuildGroupWidgets($t,"200",$id,$devicegroups,$groupsorting); $ret .= "
    \n"; $ret .= "
    \n"; $ret .= "\n"; @@ -667,38 +674,36 @@ sub BuildDashboardBottomRow($$$$){ } sub BuildGroupWidgets($$$$$) { - my ($tab,$column,$id,$dbgroups, $dbsorting) = @_; + my ($tab,$column,$id,$devicegroups, $groupsorting) = @_; my $ret = ""; my $counter = 0; - my @storedsorting = split(":", $dbsorting); - my @dbgroup = split(",", $dbgroups); + my %sorting = (); + + foreach (split(":", $groupsorting)) { + my @parts = split (',', $_); + $sorting{$parts[1]} = $_; + } my $groupicon = ''; + + my @devicegroups = split('§§§', $devicegroups); + + foreach my $singlegroup (@devicegroups) { + # make sure that splitting with colon is not destroying the devspec that might + # also contain a colon followed by a filter + my ($groupname, $groupdevices, $groupicon) = split(/:(?!FILTER=)/, $singlegroup); + + # if the device is not stored in the current column, skip it + next if (index($sorting{$groupname}, 't'.$tab.'c'.$column) < 0); + + my $groupId = $id."t".$tab."c".$column."w".$counter; + + $ret .= BuildGroup( ($groupname,$groupdevices,$sorting{$groupname},$groupId,$groupicon) ); + + $counter++; + } - foreach my $singlesorting (@storedsorting) { - my @groupdata = split(",", $singlesorting); - $groupicon = ''; - 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 - my $groupId = $id."t".$tab."c".$column."w".$counter; - foreach my $strdbgroup (@dbgroup) { - my @temp= split(":", trim($strdbgroup)); - if (defined($temp[1]) && $groupdata[1] eq $temp[0]) { - $groupicon = $temp[1]; - } - } - - $ret .= BuildGroup( ($groupdata[1],$singlesorting,$groupId,$groupicon) ); - - $counter++; - } - } - } - return $ret; + return $ret; } sub BuildGroupList($) { @@ -730,34 +735,36 @@ sub Dashboard_GetGroupList() { sub BuildGroup { - my ($currentgroup,$singleSorting,$groupId,$icon) = @_; - my $ret = ""; - my $row = 1; - my %extPage = (); - my $foundDevices = 0; - my $replaceGroup = ""; + my ($groupname,$devices,$sorting,$groupId,$icon) = @_; + my $ret = ""; + my $row = 1; + my %extPage = (); + my $foundDevices = 0; + my $replaceGroup = ""; - my $rf = ($FW_room ? "&room=$FW_room" : ""); # stay in the room + my $rf = ($FW_room ? "&room=$FW_room" : ""); # stay in the room - foreach my $g (keys %group) { - next if ($g ne $currentgroup); - $replaceGroup = "," . quotemeta($currentgroup) . ","; - $singleSorting =~ s/$replaceGroup/,$g,/; - $currentgroup = $g; - - $ret .= "
    \n"; + $ret .= "
    \n"; $ret .= "
    \n"; - $ret .= "
    "; - if ($icon) { - $ret .= FW_makeImage($icon,$icon,"dashboard_group_icon"); - } - $ret .= $currentgroup."
    \n"; - $ret .= "
    \n"; - $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}}) { + if ($groupname && $groupname ne $devices) { + $ret .= "
    "; + if ($icon) { + $ret.= FW_makeImage($icon,$icon,"dashboard_group_icon"); + } + $ret .= $groupname . "
    \n"; + } + $ret .= "
    \n"; + $ret .= "
    "; + + my %seen; + # make sure devices are not contained twice in the list + my @devices = grep { ! $seen{$_} ++ } devspec2array($devices); + + foreach my $d (@devices) { + next if (!defined($defs{$d})); $foundDevices++; + $ret .= sprintf("", ($row&1)?"odd":"even"); my $type = $defs{$d}{TYPE}; @@ -774,7 +781,7 @@ sub BuildGroup my ($allSets, $cmdlist, $txt) = FW_devState($d, $rf, \%extPage); - ############## Customize Result for Special Types ##################### + ############## Customize Result for Special Types ##################### my @txtarray = split(">", $txt); if ($modules{$defs{$d}{TYPE}}{FW_atPageEnd}) { no strict "refs"; @@ -787,12 +794,12 @@ sub BuildGroup $ret .= ">$devret"; use strict "refs"; } else { - $ret .= ""; + $ret .= ""; } ########################################################### ###### Commands, slider, dropdown - if(!$FW_ss && $cmdlist) { + if(!$FW_ss && $cmdlist) { foreach my $cmd (split(":", $cmdlist)) { my $htmlTxt; my @c = split(' ', $cmd); @@ -816,23 +823,21 @@ sub BuildGroup } $ret .= ""; } + $ret .= "
    $txt$txt
    "; - $ret .= "
    \n"; $ret .= "
    \n"; $ret .= "
    \n"; - } - 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
    "; - } - + if (!$foundDevices) { + $ret .= ""; + $ret .= ""; + $ret .= ""; + $ret .= ""; + $ret .= "
    Devices for group not found: $groupname
    Check if the device/group attribute is really set
    Check if the device spec is correctly written
    "; + } - return $ret; + return $ret; } sub GetMaxColumnId($$) { @@ -904,13 +909,34 @@ GetTabCount ($$) my $tabCount = 0; - while (AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'groups', '') ne "") { + while ( + AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'groups', '') ne "" + || AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'devices', '') ne "" + ) { $tabCount++; } return $tabCount ? $tabCount : $defaultTabCount; } +sub +GetActiveTab ($) +{ + my ($d) = @_; + + if (defined($FW_httpheader{Cookie})) { + my %cookie = map({ split('=', $_) } split(/; */, $FW_httpheader{Cookie})); + if (defined($cookie{dashboard_activetab})) { + my $activeTab = $cookie{dashboard_activetab}; + if ($activeTab <= GetTabCount($defs{$d}, 1)) { + return $activeTab; + } + } + } + + return AttrVal($defs{$d}{NAME}, 'dashboard_activetab', 1); +} + 1; =pod @@ -1019,6 +1045,13 @@ GetTabCount ($$) 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"
    + +
  • dashboard_tabXdevices
    + devspec list of devices that should appear in the tab. The format is:
    + GROUPNAME:devspec1,devspec2,...,devspecN:ICONNAME
    + THe icon name is optional. Also the group name is optional. In case of missing group name, the matching devices are not grouped but shown as separate widgets without titles. For further details on the devspec format see:
    + Dev-Spec +

  • 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. @@ -1181,6 +1214,13 @@ GetTabCount ($$) 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_tabXdevices
    + devspec Liste von Geräten, die im Tab angezeigt werden sollen. Das format ist:
    + GROUPNAME:devspec1,devspec2,...,devspecN:ICONNAME
    + Das Icon ist optional. Auch der Gruppenname muss nicht vorhanden sein. Im Falle dass dieser fehlt, werden die gefunden Geräte nicht gruppiert sondern als einzelne Widgets im Tab angezeigt. Für weitere Details bezüglich devspec: + Dev-Spec +

  • 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. diff --git a/fhem/www/pgm2/dashboard.js b/fhem/www/pgm2/dashboard.js index f10b41219..9fc426a40 100644 --- a/fhem/www/pgm2/dashboard.js +++ b/fhem/www/pgm2/dashboard.js @@ -499,39 +499,6 @@ function dashboard_insert_tab(tabIndex, content) { FW_replaceWidgets($("#dashboard_tab" + tabIndex)); dashboard_init_tab(tabIndex); - - // call FHEMWEB specific link replacement - $("#dashboard_tab" + tabIndex + " a").each(function() { FW_replaceLink(this); }); - - restoreOrder(tabIndex); - if (gridSize = is_dashboard_flexible()) { - var $container = $("#dashboard_rowcenter_tab" + tabIndex); - $("#dashboard_tab" + tabIndex + " .dashboard_widget").draggable({ - cursor: 'move', - 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'); - - // call the initialization of reading groups - FW_readingsGroupReadyFn($('#dashboard_tab' + tabIndex)); - - if ((DashboardConfigHash['lockstate'] == "lock") || (dashboard_buttonbar == "hidden")) { - dashboard_setlock(); - } else { - dashboard_unsetlock(); - } - restoreGroupVisibility(tabIndex); } function dashboard_init_tab(tabIndex) { @@ -553,6 +520,39 @@ function dashboard_init_tab(tabIndex) { event.stopImmediatePropagation(); }); } else { $("#dashboard_tab" + tabIndex + " .dashboard_widgetheader").addClass( "dashboard_widgetheader ui-corner-all" );} + + // call FHEMWEB specific link replacement + $("#dashboard_tab" + tabIndex + " a").each(function() { FW_replaceLink(this); }); + + restoreOrder(tabIndex); + if (gridSize = is_dashboard_flexible()) { + var $container = $("#dashboard_rowcenter_tab" + tabIndex); + $("#dashboard_tab" + tabIndex + " .dashboard_widget").draggable({ + cursor: 'move', + 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'); + + // call the initialization of reading groups + FW_readingsGroupReadyFn($('#dashboard_tab' + tabIndex)); + + if ((DashboardConfigHash['lockstate'] == "lock") || (dashboard_buttonbar == "hidden")) { + dashboard_setlock(); + } else { + dashboard_unsetlock(); + } + restoreGroupVisibility(tabIndex); } function restoreGroupVisibility(tabId) { @@ -602,7 +602,6 @@ 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(); @@ -616,16 +615,25 @@ function dashboard_buildDashboard(){ $("#dashboardtabs").tabs({ active: 0, create: function(event, ui) { - $( "#dashboardtabs" ).tabs( "option", "active", DashboardConfigHash['dashboard_activetab']-1);//set active Tab + /*$( "#dashboardtabs" ).tabs( "option", "active", 2);//set active Tab restoreOrder(); - restoreGroupVisibility(0); + restoreGroupVisibility(0);*/ }, activate: function (event, ui) { var tabIndex = ui.newTab.parent().children('li').index(ui.newTab); + $.cookie('dashboard_activetab', tabIndex + 1, {expires : 365}); //restoreOrder(tabIndex); //restoreGroupVisibility(tabIndex); } }); + + var iActiveTab = getTabIndexFromTab($('#dashboardtabs .dashboard_tabpanel')); + + $( "#dashboardtabs" ).tabs( "option", "active", iActiveTab);//set active Tab + dashboard_init_tab(iActiveTab); + restoreOrder(iActiveTab); + restoreGroupVisibility(iActiveTab); + if ($("#dashboard_tabnav").hasClass("dashboard_tabnav_bottom")) { $(".dashboard_tabnav").appendTo(".dashboard_tabs"); } //set Tabs on the Bottom $(".dashboard_tab_hidden").css("display", "none"); //hide Tabs diff --git a/fhem/www/pgm2/dashboard_darkstyle.css b/fhem/www/pgm2/dashboard_darkstyle.css index 6f48be709..1fb907362 100644 --- a/fhem/www/pgm2/dashboard_darkstyle.css +++ b/fhem/www/pgm2/dashboard_darkstyle.css @@ -179,10 +179,6 @@ body.dashboard_fullsize #content { border: none !important; } -.col2 { - text-align: center; -} - .dashboard_widgetheader svg { margin-right: 5px; } diff --git a/fhem/www/pgm2/dashboard_ios7.css b/fhem/www/pgm2/dashboard_ios7.css index 1b3aed9c4..f43cf9963 100644 --- a/fhem/www/pgm2/dashboard_ios7.css +++ b/fhem/www/pgm2/dashboard_ios7.css @@ -43,7 +43,7 @@ svg.dashboard_tabicon { fill:#929292; } #dashboard .dashboard_widgetheader {background: none repeat scroll 0 0 #FFFFFF; /*border: 1px solid #FFFFFF; box-shadow: 5px 5px 5px #000000;*/ margin: 0.2em; padding-bottom: 4px; padding-top: 3px; padding-left: 0.7em; font-weight: normal;} #dashboard .ui-widget .ui-widget {font-size: 1em; font-family: Arial,Helvetica,sans-serif;} -#dashboard .ui-widget-header {background-color: #FFFFFF;/*color: #ffffff;*/} +#dashboard .ui-widget-header {border: none; background: #FFFFFF;/*color: #ffffff;*/} #dashboard .ui-helper-clearfix:before, #dashboard .ui-helper-clearfix:after {content: "";display: table;border-collapse: collapse;} #dashboard .ui-helper-clearfix:after {clear: both;} diff --git a/fhem/www/pgm2/dashboard_style.css b/fhem/www/pgm2/dashboard_style.css index 34022db54..f3c3fa5a4 100644 --- a/fhem/www/pgm2/dashboard_style.css +++ b/fhem/www/pgm2/dashboard_style.css @@ -42,7 +42,7 @@ #dashboard .dashboard_widgetinner .block .block {border: none; box-shadow: none;} #dashboard .dashboard_tabcontent {width: 100%; padding: 0; margin: 0; } #dashboard .dashboard_widget {border-radius: 8px; float: left;} -#dashboard .dashboard_widgethelper {background-color: #D7FFFF; } +#dashboard .dashboard_widgethelper {background-color: #A8A870; } #dashboard .dashboard_widgetheader {background: none repeat scroll 0 0 #F0F0D8; border: 1px solid #808080; margin: 0.2em; padding-bottom: 4px; padding-top: 3px; padding-left: 0.7em; font-weight: normal;} #dashboard .ui-widget .ui-widget {font-size: 1em; font-family: Arial,Helvetica,sans-serif;} @@ -60,6 +60,7 @@ #dashboard .ui-tabs .ui-tabs-nav .ui-tabs-anchor {float: left;padding: .5em .5em;text-decoration: none;} #dashboard .ui-tabs-icon {width: 23px;height: 23px; margin: -8px 2px -6px -3px; padding-right: 2px;/*float: left;vertical-align: top;margin-left: 0.3em;margin-top: 0.5em;*/} #dashboard .dashboard_tabnav_hidden{background-color: #F8F8d5;} +#dashboard .dashboard_tabnav {background: #e9e9c8 !important;} #dashboard .ui-widget-header .ui-state-default {border: 1px solid #278727;background-color: #d5d5b7;font-weight: normal;color: #F0F0dd;} #dashboard .ui-widget-header .ui-state-active{border: 1px solid #278727;background: #F8F8d5;font-weight: normal;color: #278727;} #dashboard .ui-state-default a {color: #F8F8d5;text-decoration: none;} @@ -171,10 +172,6 @@ body.dashboard_fullsize #content { border: none !important; } -.col2 { - text-align: center; -} - .dashboard_widgetheader svg { margin-right: 5px; } diff --git a/fhem/www/pgm2/ios6touchpadstyle.css b/fhem/www/pgm2/ios6touchpadstyle.css index ba072db2a..172872054 100644 --- a/fhem/www/pgm2/ios6touchpadstyle.css +++ b/fhem/www/pgm2/ios6touchpadstyle.css @@ -602,6 +602,10 @@ table.block tr:last-child td { padding-left:10px; font-weight:700 } + +.block > tbody > tr > td:last-child { + padding-right:10px; +} .roomoverview table.block td:first-child { min-width:50px @@ -832,4 +836,4 @@ table.room tr.sel a:hover svg { ::-webkit-scrollbar-thumb:hover { background:#777 -} \ No newline at end of file +}