95_Dashboard.pm 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333
  1. # $Id: 95_Dashboard.pm 12251 2016-10-03 09:45:43Z talkabout $
  2. ########################################################################################
  3. #
  4. # 95_Dashboard.pm
  5. #
  6. ########################################################################################
  7. # Released : 20.12.2013 Sascha Hermann
  8. # Version :
  9. # 1.00: Released to testers
  10. # 1.02: Don't show link on Groups with WebLinks. Hide GroupToogle Button (new Attribut dashboard_showtogglebuttons).
  11. # Set the Columnheight (new Attribur dashboard_colheight).
  12. # 1.03: Dashboard Entry over the Room-List, set the Room "Dashboard" to hiddenroom. Build weblink independently.
  13. # Dashboard Row on Top and Bottom (no separately columns). Detail Button
  14. # to jump into define Detailview. Don't show link on Groups with SVG and readingsGroup.
  15. # 1.04: Sort the Groupentrys (@gemx). Hide Room Dashboard.
  16. # 1.05: Fix dashboard_row center
  17. # 1.10: Released Version 1.10. Rename Module from 95_FWViews to 95_Dashboard. Rename view_* Attributes to
  18. # dashboard_*. Rename fhemweb_FWViews.js to dashboard.js. Cleanup CSS. Reduce single png-Images to one File only.
  19. # Fix duplicated run of JS Script. Dashboard STAT show "Missing File" Information if installation is wrong.
  20. # 1.11: use jquery.min and jquery-ui.min. add dashboard_debug attribute. Check dashboard_sorting value plausibility.
  21. # Change default Values. First Release to FHEM SVN.
  22. # 1.12: Add Germyn command_ref Text. Add Default Values to command_ref (@cotecmania). Fix identification of an existing
  23. # Dashboard-Weblink (Message *_weblink already defined, delete it first on rereadcfg). Remove white space from
  24. # both ends of a group in dashboard_groups. Fix dashboard_sorting check. Wrong added hiddenroom to FHEMWEB
  25. # Browsersession fixed. Buttonbar can now placed on top or bottom of the Dashboard (@cotecmania).
  26. # Dashboard is always edited out the Room Dashboard (@justme1968)
  27. # Fix Dashboard Entry over the Room-List after 01_FHEMWEB.pm changes
  28. # 2.00: First Changes vor Dashboard Tabs. Change while saving positioning. Alterd max/min Group positioning.
  29. # Many changes in Dasboard.js. Replaced the attributes dashboard_groups, dashboard_colheight and dashboard_sorting
  30. # Many new Attributes vor Tabs, Dashboard sizing. Set of mimimal attributes (helpful for beginners).
  31. # Provisionally the columns widths are dependent on the total width of the Dashboard.
  32. # 2.01: attibute dashboard_colwidth replace with dashboard_rowcentercolwidth. rowcentercolwidth can now be defined per
  33. # column. Delete Groups Attribut with Value 1. Dashboard can hide FHEMWEB Roomliste and Header => Fullscreenmode
  34. # 2.02: Tabs can set on top, bottom or hidden. Fix "variable $tabgroups masks earlier" Errorlog.
  35. # 2.03: dashboard_showfullsize only in DashboardRoom. Tabs can show Icons (new Attributes). Fix showhelper Bug on lock/unlock.
  36. # The error that after a trigger action the curren tab is changed to the "old" activetab tab has been fixed. dashboard_activetab
  37. # is stored after tab change
  38. # 2.04: change view of readingroups. Attribute dashboard_groups removed. New Attribute dashboard_webfrontendfilter to define
  39. # separate Dashboards per FHEMWEB Instance.
  40. # 2.05: bugfix, changes in dashboard.js, groups can show Icons (group:icon@color,group:icon@color ...). "Back"-Button in Fullsize-Mode.
  41. # Dashboard near top in Fullsize-Mode. dashboard_activetab store the active Tab, not the last active tab.
  42. # 2.06: Attribute dashboard_colheight removed. Change Groupcontent sorting in compliance by alias and sortby.
  43. # Custom CSS over new Attribute dashboard_customcss. Fix Bug that affect new groups.
  44. # 2.07: Fix GroupWidget-Error with readingGroups in hiddenroom
  45. # 2.08: Fix dashboard_webfrontendfilter Error-Message. Internal changes. Attribute dashboard_colwidth and dashboard_sorting removed.
  46. # 2.09: dashboard_showfullsize not applied in room "all" resp. "Everything". First small implementation over Dashboard_DetailFN.
  47. # 2.10: Internal Changes. Lock/Unlock now only in Detail view. Attribut dashboard_lockstate are obsolet.
  48. # 2.11: Attribute dashboard_showhelper ist obolet. Erase tabs-at-the-top-buttonbar-hidden and tabs-on-the-bottom-buttonbar-hidden values
  49. # from Attribute dashboard_showtabs. Change Buttonbar Style. Clear CSS and Dashboard.js.
  50. # 2.12: Update Docu. CSS Class Changes. Insert Configdialog for Tabs. Change handling of parameters in both directions.
  51. # 2.13: Changed View of readingsHistory. Fix Linebrake in unlock state. Bugfix Display Group with similar group names.
  52. # 3.00: Tabs are loading via ajax (asynchronous).
  53. # Removed attribute "dashboard_tabcount". The number of tabs is determined automatically based on the gorup definitions.
  54. # Group names now also support regular expressions.
  55. # Dashboard is not limited to 1 for every FHEMWEB instance.
  56. # Dashboard link in left menu has the same name as the dashboard definition in fhem.cfg.
  57. # dashboard_webfrontendfilter has been removed. To hide a dashboard put its name into the FHEMWEB instance's hiddenroom attribute.
  58. # Flexible mode to be able to position groups absolutely on the dashboard screen.
  59. # The number of columns can be defined per tab (additionally to the global definition)
  60. # Optimized icon loading.
  61. # Optimized fullscreen view.
  62. # Minor improvements in javascript and css.
  63. # 3.10: added attribute dashboard_tabXdevices, which can contain devspec definitions and thus allow to also shown not grouped devices
  64. #
  65. # Known Bugs/Todos:
  66. # 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...)
  67. # BUG: Variabler abstand wird nicht gesichert
  68. # BUG: Überlappen Gruppen andere? ->Zindex oberer reihe > als darunter liegenden
  69. #
  70. # Log 1, "[DASHBOARD simple debug] '".$g."' ";
  71. ########################################################################################
  72. #
  73. # This program is free software: you can redistribute it and/or modify
  74. # it under the terms of the GNU General Public License as published by
  75. # the Free Software Foundation, either version 3 of the License, or
  76. # (at your option) any later version.
  77. #
  78. # This program is distributed in the hope that it will be useful,
  79. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  80. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  81. # GNU General Public License for more details.
  82. #
  83. # You should have received a copy of the GNU General Public License
  84. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  85. #
  86. ########################################################################################
  87. # Helpfull Links:
  88. # http://jquery.10927.n7.nabble.com/saving-portlet-state-td125831.html
  89. # http://jsfiddle.net/w7ZvQ/
  90. # http://jsfiddle.net/adamboduch/e6zdX/1/
  91. # http://www.innovativephp.com/jquery-resizable-practical-examples-and-demos/
  92. # http://jsfiddle.net/raulfernandez/mAuxn/
  93. # http://jsfiddle.net/zeTP8/
  94. package main;
  95. use strict;
  96. use warnings;
  97. use vars qw(%FW_icons); # List of icons
  98. use vars qw($FW_dir); # base directory for web server
  99. use vars qw($FW_icondir); # icon base directory
  100. use vars qw($FW_room); # currently selected room
  101. use vars qw(%defs); # FHEM device/button definitions
  102. #use vars qw(%FW_groups); # List of Groups
  103. use vars qw($FW_wname); # Web instance
  104. use vars qw(%FW_types); # device types
  105. use vars qw($FW_ss); # is smallscreen, needed by 97_GROUP/95_VIEW
  106. #########################
  107. # Forward declaration
  108. sub Dashboard_GetGroupList();
  109. #########################
  110. # Global variables
  111. my %group;
  112. my $dashboard_groupListfhem;
  113. my $fwjquery = "jquery.min.js";
  114. my $fwjqueryui = "jquery-ui.min.js";
  115. my $dashboardversion = "3.10";
  116. #############################################################################################
  117. sub Dashboard_Initialize ($) {
  118. my ($hash) = @_;
  119. $hash->{DefFn} = "Dashboard_define";
  120. $hash->{SetFn} = "Dashboard_Set";
  121. $hash->{GetFn} = "Dashboard_Get";
  122. $hash->{UndefFn} = "Dashboard_undef";
  123. $hash->{FW_detailFn} = "Dashboard_DetailFN";
  124. $hash->{AttrFn} = "Dashboard_attr";
  125. $hash->{AttrList} = "disable:0,1 ".
  126. "dashboard_colcount:1,2,3,4,5 ".
  127. "dashboard_debug:0,1 ".
  128. "dashboard_rowtopheight ".
  129. "dashboard_rowbottomheight ".
  130. "dashboard_row:top,center,bottom,top-center,center-bottom,top-center-bottom ".
  131. "dashboard_showtogglebuttons:0,1 ".
  132. #new attribute vers. 2.00
  133. "dashboard_activetab:1,2,3,4,5,6,7 ".
  134. "dashboard_width ".
  135. "dashboard_rowcenterheight ".
  136. #new attribute vers. 2.01
  137. "dashboard_rowcentercolwidth ".
  138. "dashboard_showfullsize:0,1 ".
  139. #new attribute vers. 2.02
  140. "dashboard_showtabs:tabs-and-buttonbar-at-the-top,tabs-and-buttonbar-on-the-bottom,tabs-and-buttonbar-hidden ".
  141. #new attribute vers. 2.06
  142. "dashboard_customcss " .
  143. #new attribute vers. 3.00
  144. "dashboard_flexible " .
  145. #tab-specific attributes
  146. "dashboard_tab1name " .
  147. "dashboard_tab1groups " .
  148. #new attribute vers. 3.10
  149. "dashboard_tab1devices " .
  150. "dashboard_tab1sorting " .
  151. "dashboard_tab1icon " .
  152. "dashboard_tab1colcount " .
  153. "dashboard_tab1rowcentercolwidth " .
  154. "dashboard_tab1backgroundimage " .
  155. # dynamic attributes
  156. "dashboard_tab[0-9]+name " .
  157. "dashboard_tab[0-9]+groups " .
  158. #new attribute vers. 3.10
  159. "dashboard_tab[0-9]+devices " .
  160. "dashboard_tab[0-9]+sorting " .
  161. "dashboard_tab[0-9]+icon " .
  162. "dashboard_tab[0-9]+colcount " .
  163. "dashboard_tab[0-9]+rowcentercolwidth " .
  164. "dashboard_tab[0-9]+backgroundimage " .
  165. "dashboard_backgroundimage";
  166. $data{FWEXT}{jquery}{SCRIPT} = "/pgm2/".$fwjquery if (!$data{FWEXT}{jquery}{SCRIPT});
  167. $data{FWEXT}{jqueryui}{SCRIPT} = "/pgm2/".$fwjqueryui if (!$data{FWEXT}{jqueryui}{SCRIPT});
  168. $data{FWEXT}{z_dashboard}{SCRIPT} = "/pgm2/dashboard.js" if (!$data{FWEXT}{z_dashboard});
  169. $data{FWEXT}{x_dashboard}{SCRIPT} = "/pgm2/svg.js" if (!$data{FWEXT}{x_dashboard});
  170. return undef;
  171. }
  172. sub Dashboard_DetailFN() {
  173. my ($name, $d, $room, $pageHash) = @_;
  174. my $hash = $defs{$name};
  175. my $ret = "";
  176. $ret .= "<table class=\"block wide\" id=\"dashboardtoolbar\" style=\"width:100%\">\n";
  177. $ret .= "<tr><td>Helper:\n<div>\n";
  178. $ret .= " <a href=\"$FW_ME/dashboard/" . $d . "\"><button type=\"button\">Return to Dashboard</button></a>\n";
  179. $ret .= " <a href=\"$FW_ME?cmd=shutdown restart\"><button type=\"button\">Restart FHEM</button></a>\n";
  180. $ret .= " <a href=\"$FW_ME?cmd=save\"><button type=\"button\">Save config</button></a>\n";
  181. $ret .= " </div>\n";
  182. $ret .= "</td></tr>\n";
  183. $ret .= "</table>\n";
  184. return $ret;
  185. }
  186. sub Dashboard_Set($@) {
  187. my ( $hash, $name, $cmd, @args ) = @_;
  188. if ( $cmd eq "lock" ) {
  189. readingsSingleUpdate( $hash, "lockstate", "lock", 0 );
  190. return;
  191. } elsif ( $cmd eq "unlock" ) {
  192. readingsSingleUpdate( $hash, "lockstate", "unlock", 0 );
  193. return;
  194. }else {
  195. return "Unknown argument " . $cmd . ", choose one of lock:noArg unlock:noArg";
  196. }
  197. }
  198. sub Dashboard_Escape($) {
  199. my $a = shift;
  200. return "null" if(!defined($a));
  201. my %esc = ("\n" => '\n', "\r" => '\r', "\t" => '\t', "\f" => '\f', "\b" => '\b', "\"" => '\"', "\\" => '\\\\', "\'" => '\\\'', );
  202. $a =~ s/([\x22\x5c\n\r\t\f\b])/$esc{$1}/eg;
  203. return $a;
  204. }
  205. sub Dashboard_Get($@) {
  206. my ($hash, @a) = @_;
  207. my $res = "";
  208. my $arg = (defined($a[1]) ? $a[1] : "");
  209. my $arg2 = (defined($a[2]) ? $a[2] : "");
  210. if ($arg eq "config") {
  211. my $name = $hash->{NAME};
  212. my $attrdata = $attr{$name};
  213. if ($attrdata) {
  214. my $x = keys %$attrdata;
  215. my $i = 0;
  216. my @splitattr;
  217. $res .= "{\n";
  218. $res .= " \"CONFIG\": {\n";
  219. $res .= " \"name\": \"$name\",\n";
  220. $res .= " \"lockstate\": \"".ReadingsVal($name,"lockstate","unlock")."\",\n";
  221. my @iconFolders = split(":", AttrVal($FW_wname, "iconPath", "$FW_sp:default:fhemSVG:openautomation"));
  222. my $iconDirs = "";
  223. foreach my $idir (@iconFolders) {$iconDirs .= "$attr{global}{modpath}/www/images/".$idir.",";}
  224. $res .= " \"icondirs\": \"$iconDirs\", \"dashboard_tabcount\": " . GetTabCount($hash, 0). ", \"dashboard_activetab\": " . GetActiveTab($hash->{NAME});
  225. $res .= ($i != $x) ? ",\n" : "\n";
  226. foreach my $attr (sort keys %$attrdata) {
  227. $i++;
  228. @splitattr = split("@", $attrdata->{$attr});
  229. if (@splitattr == 2) {
  230. $res .= " \"".Dashboard_Escape($attr)."\": \"".$splitattr[0]."\",\n";
  231. $res .= " \"".Dashboard_Escape($attr)."color\": \"".$splitattr[1]."\"";
  232. } elsif ($attr ne "dashboard_activetab") { $res .= " \"".Dashboard_Escape($attr)."\": \"".$attrdata->{$attr}."\"";}
  233. else {
  234. next;
  235. }
  236. $res .= ($i != $x) ? ",\n" : "\n";
  237. }
  238. $res .= " }\n";
  239. $res .= "}\n";
  240. return $res;
  241. }
  242. } elsif ($arg eq "groupWidget") {
  243. #### Comming Soon ######
  244. # For dynamic load of GroupWidgets from JavaScript
  245. #my $dbgroup = "";
  246. #for (my $p=2;$p<@a;$p++){$dbgroup .= @a[$p]." ";} #For Groupnames with Space
  247. #for (my $p=2;$p<@a;$p++){$dbgroup .= $a[$p]." ";} #For Groupnames with Space
  248. #$dashboard_groupListfhem = Dashboard_GetGroupList;
  249. #%group = BuildGroupList($dashboard_groupListfhem);
  250. #$res .= BuildGroupWidgets(1,1,1212,trim($dbgroup),"t1c1,".trim($dbgroup).",true,0,0:");
  251. #return $res;
  252. #For dynamic loading of tabs
  253. } elsif ($arg eq "tab" && $arg2 =~ /^\d+$/) {
  254. return BuildDashboardTab($arg2, $hash->{NAME});
  255. } elsif ($arg eq "icon") {
  256. shift @a;
  257. shift @a;
  258. my $icon = join (' ', @a);
  259. return FW_iconPath($icon);
  260. } else {
  261. return "Unknown argument $arg choose one of config:noArg groupWidget tab icon";
  262. }
  263. }
  264. sub Dashboard_define ($$) {
  265. my ($hash, $def) = @_;
  266. my @args = split (" ", $def);
  267. my $now = time();
  268. my $name = $hash->{NAME};
  269. $hash->{VERSION} = $dashboardversion;
  270. readingsSingleUpdate( $hash, "state", "Initialized", 0 );
  271. RemoveInternalTimer($hash);
  272. InternalTimer ($now + 5, 'CheckDashboardAttributUssage', $hash, 0);
  273. my $url = '/dashboard/' . $name;
  274. $data{FWEXT}{$url}{CONTENTFUNC} = 'Dashboard_CGI';
  275. $data{FWEXT}{$url}{LINK} = 'dashboard/' . $name;
  276. $data{FWEXT}{$url}{NAME} = $name;
  277. return;
  278. }
  279. sub Dashboard_undef ($$) {
  280. my ($hash,$arg) = @_;
  281. # remove dashboard links from left menu
  282. my $url = '/dashboard/' . $hash->{NAME};
  283. delete $data{FWEXT}{$url};
  284. RemoveInternalTimer($hash);
  285. return undef;
  286. }
  287. sub Dashboard_attr($$$) {
  288. my ($cmd, $name, $attrName, $attrVal) = @_;
  289. # add dynamic attributes
  290. if (
  291. $cmd eq "set" &&
  292. (
  293. $attrName =~ m/dashboard_tab([1-9][0-9]*)groups/
  294. || $attrName =~ m/dashboard_tab([1-9][0-9]*)devices/
  295. )
  296. ) {
  297. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "name");
  298. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "devices");
  299. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "groups");
  300. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "sorting");
  301. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "icon");
  302. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "colcount");
  303. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "rowcentercolwidth");
  304. addToDevAttrList($name, "dashboard_tab" . ($1 + 1) . "backgroundimage");
  305. }
  306. # if an alias is set to the dashboard, replace the name shown in the left navigation
  307. # by this alias
  308. if (
  309. $cmd eq "set"
  310. && $attrName =~ m/alias/
  311. ) {
  312. my $url = '/dashboard/' . $name;
  313. $data{FWEXT}{$url}{NAME} = $attrVal;
  314. }
  315. return;
  316. }
  317. #############################################################################################
  318. #############################################################################################
  319. sub Dashboard_CGI($)
  320. {
  321. my ($htmlarg) = @_;
  322. $htmlarg =~ s/^\///; # eliminate leading /
  323. my @params = split(/\//,$htmlarg); # split URL by /
  324. my $ret = '';
  325. my $name = $params[1];
  326. $ret = '<div id="content">';
  327. if ($name && defined($defs{$name})) {
  328. my $showfullsize = AttrVal($defs{$name}{NAME}, "dashboard_showfullsize", 0);
  329. if ($showfullsize) {
  330. if ($FW_RET =~ m/<body[^>]*class="([^"]+)"[^>]*>/) {
  331. $FW_RET =~ s/class="$1"/class="$1 dashboard_fullsize"/;
  332. }
  333. else {
  334. $FW_RET =~ s/<body/<body class="dashboard_fullsize"/;
  335. }
  336. }
  337. $ret .= Dashboard_SummaryFN($FW_wname,$name,$FW_room,undef);
  338. }
  339. else {
  340. $ret .= 'Dashboard "' . $name . '" not found';
  341. }
  342. $ret .= '</div>';
  343. FW_pO $ret;
  344. # empty room to make sure no room actions are taken by the framework
  345. $FW_room = '';
  346. return 0;
  347. }
  348. sub DashboardAsHtml($)
  349. {
  350. my ($d) = @_;
  351. Dashboard_SummaryFN($FW_wname,$d,$FW_room,undef);
  352. }
  353. sub Dashboard_SummaryFN($$$$)
  354. {
  355. my ($FW_wname, $d, $room, $pageHash) = @_;
  356. my $ret = "";
  357. my $showbuttonbar = "hidden";
  358. my $debugfield = "hidden";
  359. my $h = $defs{$d};
  360. my $name = $defs{$d}{NAME};
  361. my $id = $defs{$d}{NR};
  362. ######################### Read Dashboard Attributes and set Default-Values ####################################
  363. my $lockstate = ($defs{$d}->{READINGS}{lockstate}{VAL}) ? $defs{$d}->{READINGS}{lockstate}{VAL} : "unlock";
  364. my $showhelper = ($lockstate eq "unlock") ? 1 : 0;
  365. my $disable = AttrVal($defs{$d}{NAME}, "disable", 0);
  366. my $colcount = AttrVal($defs{$d}{NAME}, "dashboard_colcount", 1);
  367. my $colwidth = AttrVal($defs{$d}{NAME}, "dashboard_rowcentercolwidth", 100);
  368. my $colheight = AttrVal($defs{$d}{NAME}, "dashboard_rowcenterheight", 400);
  369. my $rowtopheight = AttrVal($defs{$d}{NAME}, "dashboard_rowtopheight", 250);
  370. my $rowbottomheight = AttrVal($defs{$d}{NAME}, "dashboard_rowbottomheight", 250);
  371. my $showtabs = AttrVal($defs{$d}{NAME}, "dashboard_showtabs", "tabs-and-buttonbar-at-the-top");
  372. my $showtogglebuttons = AttrVal($defs{$d}{NAME}, "dashboard_showtogglebuttons", 1);
  373. my $showfullsize = AttrVal($defs{$d}{NAME}, "dashboard_showfullsize", 0);
  374. my $flexible = AttrVal($defs{$d}{NAME}, "dashboard_flexible", 0);
  375. my $customcss = AttrVal($defs{$d}{NAME}, "dashboard_customcss", "none");
  376. my $backgroundimage = AttrVal($defs{$d}{NAME}, "dashboard_backgroundimage", "");
  377. my $row = AttrVal($defs{$d}{NAME}, "dashboard_row", "center");
  378. my $debug = AttrVal($defs{$d}{NAME}, "dashboard_debug", "0");
  379. my $activetab = GetActiveTab($d);
  380. my $tabcount = GetTabCount($defs{$d}, 1);
  381. my $dbwidth = AttrVal($defs{$d}{NAME}, "dashboard_width", "100%");
  382. my @tabnames = ();
  383. my @tabsortings = ();
  384. for (my $i = 0; $i < $tabcount; $i++) {
  385. $tabnames[$i] = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($i + 1) . "name", "Dashboard-Tab " . ($i + 1));
  386. $tabsortings[$i] = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($i + 1) . "sorting", "");
  387. }
  388. #############################################################################################
  389. if ($disable == 1) {
  390. readingsSingleUpdate( $defs{$d}, "state", "Disabled", 0 );
  391. return "";
  392. }
  393. ##################################################################################
  394. if ($debug == 1) { $debugfield = "edit" };
  395. if ($showtabs eq "tabs-and-buttonbar-at-the-top") { $showbuttonbar = "top"; }
  396. if ($showtabs eq "tabs-and-buttonbar-on-the-bottom") { $showbuttonbar = "bottom"; }
  397. if ($showbuttonbar eq "hidden") { $lockstate = "lock" };
  398. if ($activetab > $tabcount) { $activetab = $tabcount; }
  399. $colwidth =~ tr/,/:/;
  400. if (not ($colheight =~ /^\d+$/)) { $colheight = 400 };
  401. if (not ($rowtopheight =~ /^\d+$/)) { $rowtopheight = 50 };
  402. if (not ($rowbottomheight =~ /^\d+$/)) { $rowbottomheight = 50 };
  403. #------------------- Check dashboard_sorting on false content ------------------------------------
  404. for (my $i=0;$i<@tabsortings;$i++){
  405. if (($tabsortings[$i-1] !~ /[0-9]+/ || $tabsortings[$i-1] !~ /:/ || $tabsortings[$i-1] !~ /,/ ) && ($tabsortings[$i-1] ne "," && $tabsortings[$i-1] ne "")){
  406. 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]."]";
  407. } else { Log3 $d, 5, "[".$name." V".$dashboardversion."] Sorting OK or Empty: dashboard_tab".$i."sorting "; }
  408. }
  409. #-------------------------------------------------------------------------------------------------
  410. if ($room ne "all") {
  411. ################################
  412. ################################
  413. ############################ Set FHEM url to avoid hardcoding it in javascript ############################
  414. $ret .= "<script type='text/javascript'>var fhemUrl = '" . $FW_ME . "';</script>";
  415. $ret .= "<div id=\"tabEdit\" class=\"dashboard-dialog-content dashboard-widget-content\" title=\"Dashboard-Tab\" style=\"display:none;\">\n";
  416. $ret .= " <div id=\"dashboard-dialog-tabs\" class=\"dashboard dashboard_tabs\">\n";
  417. $ret .= " <ul class=\"dashboard dashboard_tabnav\">\n";
  418. $ret .= " <li class=\"dashboard dashboard_tab\"><a href=\"#tabs-1\">Current Tab</a></li>\n";
  419. $ret .= " <li class=\"dashboard dashboard_tab\"><a href=\"#tabs-2\">Common</a></li>\n";
  420. $ret .= " </ul>\n";
  421. $ret .= " <div id=\"tabs-1\" class=\"dashboard_tabcontent\">\n";
  422. $ret .= " <table>\n";
  423. $ret .= " <tr colspan=\"2\"><td><div id=\"tabID\"></div></td></tr>\n";
  424. $ret .= " <tr><td>Tabtitle:</td><td colspan=\"2\"><input id=\"tabTitle\" type=\"text\" size=\"25\"></td></tr>";
  425. $ret .= " <tr><td>Tabicon:</td><td><input id=\"tabIcon\" type=\"text\" size=\"10\"></td><td><input id=\"tabIconColor\" type=\"text\" size=\"7\"></td></tr>";
  426. # the method FW_multipleSelect seems not to be available any more in fhem
  427. #$ret .= " <tr><td>Groups:</td><td colspan=\"2\"><input id=\"tabGroups\" type=\"text\" size=\"25\" onfocus=\"FW_multipleSelect(this)\" allvals=\"multiple,$dashboard_groupListfhem\" readonly=\"readonly\"></td></tr>";
  428. $ret .= " <tr><td>Groups:</td><td colspan=\"2\"><input id=\"tabGroups\" type=\"text\" size=\"25\"></td></tr>";
  429. $ret .= " <tr><td></td><td colspan=\"2\"><input type=\"checkbox\" id=\"tabActiveTab\" value=\"\"><label for=\"tabActiveTab\">This Tab is currently selected</label></td></tr>";
  430. $ret .= " </table>\n";
  431. $ret .= " </div>\n";
  432. $ret .= " <div id=\"tabs-2\" class=\"dashboard_tabcontent\">\n";
  433. $ret .= "Comming soon";
  434. $ret .= " </div>\n";
  435. $ret .= " </div>\n";
  436. $ret .= "</div>\n";
  437. $ret .= "<div id=\"dashboard_define\" style=\"display: none;\">$d</div>\n";
  438. $ret .= "<table class=\"roomoverview dashboard\" id=\"dashboard\">\n";
  439. $ret .= "<tr style=\"height: 0px;\"><td><div class=\"dashboardhidden\">\n";
  440. $ret .= "<input type=\"$debugfield\" size=\"100%\" id=\"dashboard_attr\" value=\"$name,$dbwidth,$showhelper,$lockstate,$showbuttonbar,$colheight,$showtogglebuttons,$colcount,$rowtopheight,$rowbottomheight,$tabcount,$activetab,$colwidth,$showfullsize,$customcss,$flexible\">\n";
  441. $ret .= "<input type=\"$debugfield\" size=\"100%\" id=\"dashboard_jsdebug\" value=\"\">\n";
  442. $ret .= "</div></td></tr>\n";
  443. $ret .= "<tr><td><div id=\"dashboardtabs\" class=\"dashboard dashboard_tabs\" style=\"background: " . ($backgroundimage ? "url(/fhem/images/" . FW_iconPath($backgroundimage) . ")" : "") . " no-repeat !important;\">\n";
  444. ########################### Dashboard Tab-Liste ##############################################
  445. $ret .= " <ul id=\"dashboard_tabnav\" class=\"dashboard dashboard_tabnav dashboard_tabnav_".$showbuttonbar."\">\n";
  446. for (my $i=0;$i<$tabcount;$i++){$ret .= " <li class=\"dashboard dashboard_tab dashboard_tab_".$showbuttonbar."\"><a href=\"#dashboard_tab".$i."\">".trim($tabnames[$i])."</a></li>";}
  447. $ret .= " </ul>\n";
  448. ########################################################################################
  449. for (my $t=0;$t<$tabcount;$t++){
  450. if ($t == $activetab - 1) {
  451. $ret .= BuildDashboardTab($t, $d);
  452. }
  453. }
  454. $ret .= "</div></td></tr>\n";
  455. $ret .= "</table>\n";
  456. } else {
  457. $ret .= "<table>";
  458. $ret .= "<tr><td><div class=\"devType\">".$defs{$d}{TYPE}."</div></td></tr>";
  459. $ret .= "<tr><td><table id=\"TYPE_".$defs{$d}{TYPE}."\" class=\"block wide\">";
  460. $ret .= "<tbody><tr>";
  461. $ret .= "<td><div><a href=\"$FW_ME?detail=$d\">$d</a></div></td>";
  462. $ret .= "<td><div>".$defs{$d}{STATE}."</div></td>";
  463. $ret .= "</tr></tbody>";
  464. $ret .= "</table></td></tr>";
  465. $ret .= "</table>";
  466. }
  467. return $ret;
  468. }
  469. sub BuildDashboardTab($$)
  470. {
  471. my ($t, $d) = @_;
  472. my $id = $defs{$d}{NR};
  473. my $colcount = AttrVal($defs{$d}{NAME}, 'dashboard_tab' . ($t + 1) . 'colcount', AttrVal($defs{$d}{NAME}, "dashboard_colcount", 1));
  474. my $colwidths = AttrVal($defs{$d}{NAME}, 'dashboard_tab' . ($t + 1) . 'rowcentercolwidth', AttrVal($defs{$d}{NAME}, "dashboard_rowcentercolwidth", 100));
  475. $colwidths =~ tr/,/:/;
  476. my $backgroundimage = AttrVal($defs{$d}{NAME}, 'dashboard_tab' . ($t + 1) . 'backgroundimage', "");
  477. my $row = AttrVal($defs{$d}{NAME}, "dashboard_row", "center");
  478. my $tabcount = GetTabCount($defs{$d}, 1);
  479. my $tabgroups = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($t + 1) . "groups", "");
  480. my $tabsortings = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($t + 1) . "sorting", "");
  481. my $tabdevicegroups = AttrVal($defs{$d}{NAME}, "dashboard_tab" . ($t + 1) . "devices", "");
  482. unless ($tabgroups || $tabdevicegroups) {
  483. readingsSingleUpdate( $defs{$d}, "state", "No Groups or devices set", 0 );
  484. return "";
  485. }
  486. my @temptabdevicegroup = split(' ', $tabdevicegroups);
  487. my @tabdevicegroups = ();
  488. # make sure device groups without a group name are splitted into
  489. # separate groups for every device they are containing
  490. for my $devicegroup (@temptabdevicegroup) {
  491. my @groupparts = split(':', $devicegroup);
  492. if (@groupparts == 1) {
  493. my @devices = map { $_ . '$$$' . $_ } devspec2array($groupparts[0]);
  494. push(@tabdevicegroups, @devices);
  495. }
  496. else {
  497. push(@tabdevicegroups, $devicegroup);
  498. }
  499. }
  500. my $groups = Dashboard_GetGroupList();
  501. $groups =~ s/#/ /g;
  502. my @groups = split(',', $groups);
  503. my @temptabgroup = split(",", $tabgroups);
  504. # resolve group names from regular expressions
  505. for (my $i=0;$i<@temptabgroup;$i++) {
  506. my @stabgroup = split(":", trim($temptabgroup[$i]));
  507. my @index = grep { $groups[$_] eq $stabgroup[0] } (0 .. @groups-1);
  508. if (@index == 0) {
  509. my $matchGroup = '^' . $stabgroup[0] . '$';
  510. @index = grep { $groups[$_] =~ m/$matchGroup/ } (0 .. @groups-1);
  511. }
  512. if (@index > 0) {
  513. for (my $j=0; $j<@index;$j++) {
  514. my $groupname = @groups[$index[$j]];
  515. $groupname .= '$$$' . 'a:group=' . $groupname;
  516. if (@stabgroup > 1) {
  517. $groupname .= '$$$' . $stabgroup[1];
  518. }
  519. push(@tabdevicegroups,$groupname);
  520. }
  521. }
  522. }
  523. $tabgroups = join('§§§', @tabdevicegroups);
  524. # add sortings for groups not already having a defined sorting
  525. for (my $i=0;$i<@tabdevicegroups;$i++) {
  526. my @stabgroup = split(/\$\$\$/, trim($tabdevicegroups[$i]));
  527. my $matchGroup = "," . quotemeta(trim($stabgroup[0])) . ",";
  528. if ($tabsortings !~ m/$matchGroup/) {
  529. $tabsortings = $tabsortings."t".$t."c".GetMaxColumnId($row,$colcount).",".trim($stabgroup[0]).",true,0,0:";
  530. }
  531. }
  532. my $ret = " <div id=\"dashboard_tab".$t."\" data-tabwidgets=\"".$tabsortings."\" data-tabcolwidths=\"".$colwidths."\" class=\"dashboard dashboard_tabpanel\" style=\"background: " . ($backgroundimage ? "url(/fhem/images/" . FW_iconPath($backgroundimage) . ")" : "none") . " no-repeat !important;\">\n";
  533. $ret .= " <ul class=\"dashboard_tabcontent\">\n";
  534. $ret .= " <table class=\"dashboard_tabcontent\">\n";
  535. ##################### Top Row (only one Column) #############################################
  536. if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "top"){
  537. $ret .= BuildDashboardTopRow($t,$id,$tabgroups,$tabsortings);
  538. }
  539. ##################### Center Row (max. 5 Column) ############################################
  540. if ($row eq "top-center-bottom" || $row eq "top-center" || $row eq "center-bottom" || $row eq "center") {
  541. $ret .= BuildDashboardCenterRow($t,$id,$tabgroups,$tabsortings,$colcount);
  542. }
  543. ############################# Bottom Row (only one Column) ############################################
  544. if ($row eq "top-center-bottom" || $row eq "center-bottom" || $row eq "bottom"){
  545. $ret .= BuildDashboardBottomRow($t,$id,$tabgroups,$tabsortings);
  546. }
  547. #############################################################################################
  548. $ret .= " </table>\n";
  549. $ret .= " </ul>\n";
  550. $ret .= " </div>\n";
  551. return $ret;
  552. }
  553. sub BuildDashboardTopRow($$$$){
  554. my ($t,$id, $devicegroups, $groupsorting) = @_;
  555. my $ret;
  556. $ret .= "<tr><td class=\"dashboard_row\">\n";
  557. $ret .= "<div id=\"dashboard_rowtop_tab".$t."\" class=\"dashboard dashboard_rowtop\">\n";
  558. $ret .= " <div class=\"dashboard ui-row dashboard_row dashboard_column\" id=\"dashboard_tab".$t."column100\">\n";
  559. $ret .= BuildGroupWidgets($t,"100",$id,$devicegroups,$groupsorting);
  560. $ret .= " </div>\n";
  561. $ret .= "</div>\n";
  562. $ret .= "</td></tr>\n";
  563. return $ret;
  564. }
  565. sub BuildDashboardCenterRow($$$$$){
  566. my ($t,$id, $devicegroups, $groupsorting, $colcount) = @_;
  567. my $ret = "<tr><td class=\"dashboard_row\">\n";
  568. $ret .= "<div id=\"dashboard_rowcenter_tab".$t."\" class=\"dashboard dashboard_rowcenter\">\n";
  569. my $currentcol = $colcount;
  570. my $maxcolindex = $colcount - 1;
  571. my $replace = "t" . $t . "c" . $maxcolindex . ",";
  572. # replace all sortings referencing not existing columns
  573. # this does only work if there is no empty column inbetween
  574. while (index($groupsorting, "t".$t."c".$currentcol.",") >= 0) {
  575. my $search = "t" . $t . "c" . $currentcol . ",";
  576. $groupsorting =~ s/$search/$replace/g;
  577. $currentcol++;
  578. }
  579. for (my $i=0;$i<$colcount;$i++){
  580. $ret .= " <div class=\"dashboard ui-row dashboard_row dashboard_column\" id=\"dashboard_tab".$t."column".$i."\">\n";
  581. $ret .= BuildGroupWidgets($t,$i,$id,$devicegroups,$groupsorting);
  582. $ret .= " </div>\n";
  583. }
  584. $ret .= "</div>\n";
  585. $ret .= "</td></tr>\n";
  586. return $ret;
  587. }
  588. sub BuildDashboardBottomRow($$$$){
  589. my ($t,$id, $devicegroups, $groupsorting) = @_;
  590. my $ret;
  591. $ret .= "<tr><td class=\"dashboard_row\">\n";
  592. $ret .= "<div id=\"dashboard_rowbottom_tab".$t."\" class=\"dashboard dashboard_rowbottom\">\n";
  593. $ret .= " <div class=\"dashboard ui-row dashboard_row dashboard_column\" id=\"dashboard_tab".$t."column200\">\n";
  594. $ret .= BuildGroupWidgets($t,"200",$id,$devicegroups,$groupsorting);
  595. $ret .= " </div>\n";
  596. $ret .= "</div>\n";
  597. $ret .= "</td></tr>\n";
  598. return $ret;
  599. }
  600. sub BuildGroupWidgets($$$$$) {
  601. my ($tab,$column,$id,$devicegroups, $groupsorting) = @_;
  602. my $ret = "";
  603. my $counter = 0;
  604. my %sorting = ();
  605. my %groups = ();
  606. my @groupnames = ();
  607. foreach (split(":", $groupsorting)) {
  608. my @parts = split (',', $_);
  609. $sorting{$parts[1]} = $_;
  610. # add group names to a list to have the correct order afterwards in the foreach loop
  611. # store the group names in the right order to use them in the foreach loop
  612. push(@groupnames, $parts[1]);
  613. }
  614. my @devicegroups = split('§§§', $devicegroups);
  615. # sort the devices into a hash to be able to access them via group name
  616. foreach my $singlegroup (@devicegroups) {
  617. # make sure that splitting with colon is not destroying the devspec that might
  618. # also contain a colon followed by a filter
  619. my ($groupname, $groupdevices, $groupicon) = split(/\$\$\$/, $singlegroup);
  620. my @values = ($groupdevices, $groupicon);
  621. $groups{$groupname} = \@values;
  622. }
  623. my $groupicon = '';
  624. foreach my $groupname (@groupnames) {
  625. next if (!defined($groups{$groupname}));
  626. my ($groupdevices, $groupicon) = @{$groups{$groupname}};
  627. # if the device is not stored in the current column, skip it
  628. next if (index($sorting{$groupname}, 't'.$tab.'c'.$column) < 0);
  629. my $groupId = $id."t".$tab."c".$column."w".$counter;
  630. $ret .= BuildGroup( ($groupname,$groupdevices,$sorting{$groupname},$groupId,$groupicon) );
  631. $counter++;
  632. }
  633. return $ret;
  634. }
  635. sub BuildGroupList($) {
  636. my @dashboardgroups = split(",", $_[0]); #array for all groups to build an widget
  637. my %group = ();
  638. foreach my $d (sort keys %defs) {
  639. foreach my $grp (split(",", AttrVal($d, "group", ""))) {
  640. $grp = trim($grp);
  641. foreach my $g (@dashboardgroups){
  642. my ($gtitle, $iconName) = split(":", trim($g));
  643. my $titleMatch = "^" . quotemeta($gtitle) . "\$";
  644. $group{$grp}{$d} = 1 if($grp =~ $titleMatch);
  645. }
  646. }
  647. }
  648. return %group;
  649. }
  650. sub Dashboard_GetGroupList() {
  651. my %allGroups = ();
  652. foreach my $d (keys %defs ) {
  653. next if(IsIgnored($d));
  654. foreach my $g (split(",", AttrVal($d, "group", ""))) { $allGroups{$g}{$d} = 1; }
  655. }
  656. my $ret = join(",", sort map { $_ =~ s/ /#/g ;$_} keys %allGroups);
  657. return $ret;
  658. }
  659. sub BuildGroup
  660. {
  661. my ($groupname,$devices,$sorting,$groupId,$icon) = @_;
  662. my $ret = "";
  663. my $row = 1;
  664. my %extPage = ();
  665. my $foundDevices = 0;
  666. my $replaceGroup = "";
  667. my $rf = ($FW_room ? "&amp;room=$FW_room" : ""); # stay in the room
  668. $ret .= " <div class=\"dashboard dashboard_widget ui-widget\" data-groupwidget=\"".$sorting."\" id=\"".$groupId."\">\n";
  669. $ret .= " <div class=\"dashboard_widgetinner\">\n";
  670. if ($groupname && $groupname ne $devices) {
  671. $ret .= " <div class=\"dashboard_widgetheader ui-widget-header dashboard_group_header\">";
  672. if ($icon) {
  673. $ret.= FW_makeImage($icon,$icon,"dashboard_group_icon");
  674. }
  675. $ret .= $groupname . "</div>\n";
  676. }
  677. $ret .= " <div data-userheight=\"\" class=\"dashboard_content\">\n";
  678. $ret .= "<table class=\"dashboard block wide\" id=\"TYPE_$groupname\">";
  679. my %seen;
  680. # make sure devices are not contained twice in the list
  681. my @devices = grep { ! $seen{$_} ++ } devspec2array($devices);
  682. # sort the devices in alphabetical order by sortby, alias, name
  683. @devices = sort {
  684. lc(AttrVal($a,'sortby',AttrVal($a,'alias',$a))) cmp lc(AttrVal($b,'sortby',AttrVal($b,'alias',$b)))
  685. } @devices;
  686. foreach my $d (@devices) {
  687. next if (!defined($defs{$d}));
  688. $foundDevices++;
  689. $ret .= sprintf("<tr class=\"%s\">", ($row&1)?"odd":"even");
  690. my $type = $defs{$d}{TYPE};
  691. my $devName = AttrVal($d, "alias", $d);
  692. my $icon = AttrVal($d, "icon", "");
  693. $icon = FW_makeImage($icon,$icon,"icon dashboard_groupicon") . "&nbsp;" if($icon);
  694. if (!$modules{$defs{$d}{TYPE}}{FW_atPageEnd}) { # Don't show Link for "atEnd"-devices
  695. $ret .= FW_pH "detail=$d", "$icon$devName", 1, "col1", 1;
  696. }
  697. $row++;
  698. $extPage{group} = $groupname;
  699. my ($allSets, $cmdlist, $txt) = FW_devState($d, $rf, \%extPage);
  700. $allSets = FW_widgetOverride($d, $allSets);
  701. ############## Customize Result for Special Types #####################
  702. my @txtarray = split(">", $txt);
  703. if ($modules{$defs{$d}{TYPE}}{FW_atPageEnd}) {
  704. no strict "refs";
  705. my $devret = &{$modules{$defs{$d}{TYPE}}{FW_summaryFn}}($FW_wname, $d,
  706. $FW_room, \%extPage);
  707. $ret .= "<td class=\"dashboard_dev_container\"";
  708. if ($devret !~ /informId/i) {
  709. $ret .= " informId=\"$d\"";
  710. }
  711. $ret .= ">$devret</td>";
  712. use strict "refs";
  713. } else {
  714. $ret .= "<td informId=\"$d\">$txt</td>";
  715. }
  716. ###########################################################
  717. ###### Commands, slider, dropdown
  718. my $smallscreenCommands = AttrVal($FW_wname, "smallscreenCommands", "");
  719. if((!$FW_ss || $smallscreenCommands) && $cmdlist) {
  720. my @a = split("[: ]", AttrVal($d, "cmdIcon", ""));
  721. my %cmdIcon = @a;
  722. foreach my $cmd (split(":", $cmdlist)) {
  723. my $htmlTxt;
  724. my @c = split(' ', $cmd);
  725. if(int(@c) && $allSets && $allSets =~ m/\b$c[0]:([^ ]*)/) {
  726. my $values = $1;
  727. foreach my $fn (sort keys %{$data{webCmdFn}}) {
  728. no strict "refs";
  729. $htmlTxt = &{$data{webCmdFn}{$fn}}($FW_wname,
  730. $d, $FW_room, $cmd, $values);
  731. use strict "refs";
  732. last if(defined($htmlTxt));
  733. }
  734. }
  735. if($htmlTxt) {
  736. # add colspan to avoid squeezed table cells
  737. $htmlTxt =~ s/<td>/<td colspan="10">/;
  738. $ret .= $htmlTxt;
  739. } else {
  740. my $nCmd = $cmdIcon{$cmd} ?
  741. FW_makeImage($cmdIcon{$cmd},$cmd,"webCmd") : $cmd;
  742. $ret .= FW_pH "cmd.$d=set $d $cmd$rf", $nCmd, 1, "col3", 1;
  743. }
  744. }
  745. }
  746. $ret .= "</tr>";
  747. }
  748. $ret .= "</table>";
  749. $ret .= " </div>\n";
  750. $ret .= " </div>\n";
  751. $ret .= " </div>\n";
  752. if (!$foundDevices) {
  753. $ret .= "<table class=\"block wide\" id=\"TYPE_unknowngroup\">";
  754. $ret .= "<tr class=\"odd\"><td class=\"changed\">Devices for group not found: $groupname</td></tr>";
  755. $ret .= "<tr class=\"even\"><td class=\"changed\">Check if the device/group attribute is really set</td></tr>";
  756. $ret .= "<tr class=\"odd\"><td class=\"changed\">Check if the device spec is correctly written</td></tr>";
  757. $ret .= "</table>";
  758. }
  759. return $ret;
  760. }
  761. sub GetMaxColumnId($$) {
  762. my ($row, $colcount) = @_;
  763. my $maxcolid = "0";
  764. if (index($row,"bottom") > 0) { $maxcolid = "200"; }
  765. elsif (index($row,"center") > 0) { $maxcolid = $colcount-1; }
  766. elsif (index($row,"top") > 0) { $maxcolid = "100"; }
  767. return $maxcolid;
  768. }
  769. sub CheckDashboardEntry($) {
  770. my ($hash) = @_;
  771. my $now = time();
  772. my $timeToExec = $now + 5;
  773. RemoveInternalTimer($hash);
  774. InternalTimer ($timeToExec, 'CheckDashboardAttributUssage', $hash, 0);
  775. }
  776. sub CheckDashboardAttributUssage($) { # replaces old disused attributes and their values | set minimal attributes
  777. my ($hash) = @_;
  778. my $d = $hash->{NAME};
  779. my $detailnote = "";
  780. # --------- Set minimal Attributes in the hope to make it easier for beginners --------------------
  781. my $tab1groups = AttrVal($defs{$d}{NAME}, "dashboard_tab1groups", "<noGroup>");
  782. if ($tab1groups eq "<noGroup>") { FW_fC("attr ".$d." dashboard_tab1groups Set Your Groups - See Attribute dashboard_tab1groups-"); }
  783. # -------------------------------------------------------------------------------------------------
  784. # ---------------- Delete empty Groups entries ----------------------------------------------------------
  785. my $tabgroups = AttrVal($defs{$d}{NAME}, "dashboard_tab1groups", "999");
  786. if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab1groups"); }
  787. $tabgroups = AttrVal($defs{$d}{NAME}, "dashboard_tab2groups", "999");
  788. if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab2groups"); }
  789. $tabgroups = AttrVal($defs{$d}{NAME}, "dashboard_tab3groups", "999");
  790. if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab3groups"); }
  791. $tabgroups = AttrVal($defs{$d}{NAME}, "dashboard_tab4groups", "999");
  792. if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab4groups"); }
  793. $tabgroups = AttrVal($defs{$d}{NAME}, "dashboard_tab5groups", "999");
  794. if ($tabgroups eq "1" ) { FW_fC("deleteattr ".$d." dashboard_tab5groups"); }
  795. # -------------------------------------------------------------------------------------------------
  796. my $lockstate = AttrVal($defs{$d}{NAME}, "dashboard_lockstate", ""); # outdates 04.2014
  797. if ($lockstate ne "") {
  798. { FW_fC("deleteattr ".$d." dashboard_lockstate"); }
  799. Log3 $hash, 3, "[".$hash->{NAME}. " V".$dashboardversion."]"." Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [dashboard_lockstate]";
  800. }
  801. my $showhelper = AttrVal($defs{$d}{NAME}, "dashboard_showhelper", ""); # outdates 04.2014
  802. if ($showhelper ne "") {
  803. { FW_fC("deleteattr ".$d." dashboard_showhelper"); }
  804. Log3 $hash, 3, "[".$hash->{NAME}. " V".$dashboardversion."]"." Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [dashboard_showhelper]";
  805. }
  806. my $showtabs = AttrVal($defs{$d}{NAME}, "dashboard_showtabs", ""); # delete values 04.2014
  807. if ($showtabs eq "tabs-at-the-top-buttonbar-hidden") {
  808. { FW_fC("set ".$d." dashboard_showtabs tabs-and-buttonbar-at-the-top"); }
  809. Log3 $hash, 3, "[".$hash->{NAME}. " V".$dashboardversion."]"." Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [tabs-at-the-top-buttonbar-hidden]";
  810. }
  811. if ($showtabs eq "tabs-on-the-bottom-buttonbar-hidden") {
  812. { FW_fC("set ".$d." dashboard_showtabs tabs-and-buttonbar-on-the-bottom"); }
  813. Log3 $hash, 3, "[".$hash->{NAME}. " V".$dashboardversion."]"." Using an outdated no longer used Attribute or Value. This has been corrected. Don't forget to save config. [tabs-on-the-bottom-buttonbar-hidden]";
  814. }
  815. }
  816. sub
  817. GetTabCount ($$)
  818. {
  819. my ($hash, $defaultTabCount) = @_;
  820. my $tabCount = 0;
  821. while (
  822. AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'groups', '') ne ""
  823. || AttrVal($hash->{NAME}, 'dashboard_tab' . ($tabCount + 1) . 'devices', '') ne ""
  824. ) {
  825. $tabCount++;
  826. }
  827. return $tabCount ? $tabCount : $defaultTabCount;
  828. }
  829. sub
  830. GetActiveTab ($)
  831. {
  832. my ($d) = @_;
  833. if (defined($FW_httpheader{Cookie})) {
  834. my %cookie = map({ split('=', $_) } split(/; */, $FW_httpheader{Cookie}));
  835. if (defined($cookie{dashboard_activetab})) {
  836. my $activeTab = $cookie{dashboard_activetab};
  837. if ($activeTab <= GetTabCount($defs{$d}, 1)) {
  838. return $activeTab;
  839. }
  840. }
  841. }
  842. return AttrVal($defs{$d}{NAME}, 'dashboard_activetab', 1);
  843. }
  844. 1;
  845. =pod
  846. =item summary Dashboard for showing multiple devices sorted in tabs
  847. =item summary_DE Dashboard zur Anzeige mehrerer Geräte in verschiedenen Tabs
  848. =begin html
  849. <a name="Dashboard"></a>
  850. <h3>Dashboard</h3>
  851. <ul>
  852. Creates a Dashboard in any group can be arranged. The positioning may depend the Groups and column width are made<br>
  853. arbitrarily by drag'n drop. Also, the width and height of a Group can be increased beyond the minimum size.<br>
  854. <br>
  855. <a name="Dashboarddefine"></a>
  856. <b>Define</b>
  857. <ul>
  858. <code>define &lt;name&gt; Dashboard</code>
  859. <br><br>
  860. Example:<br>
  861. <ul>
  862. <code>define anyViews Dashboard</code>
  863. </ul><br>
  864. <b>Bestpractice beginner configuration</b>
  865. <br><br>
  866. <code>
  867. define anyViews Dashboard<br>
  868. attr anyViews dashboard_colcount 2<br>
  869. attr anyviews dashboard_rowcentercolwidth 30,70<br>
  870. attr anyViews dashboard_tab1groups &lt;Group1&gt;,&lt;Group2&gt;,&lt;Group3&gt;<br>
  871. </code>
  872. </ul>
  873. <br>
  874. <a name="Dashboardset"></a>
  875. <b>Set</b>
  876. <ul>
  877. <code>set &lt;name&gt; lock</code><br><br>
  878. locks the Dashboard so that no position changes can be made<br>
  879. <code>set &lt;name&gt; unlock</code><br><br>
  880. unlock the Dashboard<br>
  881. </ul>
  882. <br>
  883. <a name="Dashboardget"></a>
  884. <b>Get</b> <ul>N/A</ul><br>
  885. <a name="Dashboardattr"></a>
  886. <b>Attributes</b>
  887. <ul>
  888. <a name="dashboard_tabcount"></a>
  889. <li>dashboard_tabcount<br>
  890. Returns the number of displayed tabs. (Does not need to be set any more. It is read automatically from the configured tabs)
  891. Default: 1
  892. </li><br>
  893. <a name="dashboard_activetab"></a>
  894. <li>dashboard_activetab<br>
  895. Specifies which tab is activated. Can be set manually, but is also set by the switch "Set" to the currently active tab.
  896. Default: 1
  897. </li><br>
  898. <a name="dashboard_tabXname"></a>
  899. <li>dashboard_tabXname<br>
  900. Title of Tab at position X.
  901. </li><br>
  902. <a name="dashboard_tabXsorting"></a>
  903. <li>dashboard_tabXsorting<br>
  904. Contains the position of each group in Tab X. Value is written by the "Set" button. It is not recommended to take manual changes.
  905. </li><br>
  906. <a name="dashboard_row"></a>
  907. <li>dashboard_row<br>
  908. To select which rows are displayed. top only; center only; bottom only; top and center; center and bottom; top,center and bottom.<br>
  909. Default: center
  910. </li><br>
  911. <a name="dashboard_width"></a>
  912. <li>dashboard_width<br>
  913. To determine the Dashboardwidth. The value can be specified, or an absolute width value (eg 1200) in pixels in% (eg 80%).<br>
  914. Default: 100%
  915. </li><br>
  916. <a name="dashboard_rowcenterheight"></a>
  917. <li>dashboard_rowcenterheight<br>
  918. Height of the center row in which the groups may be positioned. <br>
  919. Default: 400
  920. </li><br>
  921. <a name="dashboard_rowcentercolwidth"></a>
  922. <li>dashboard_rowcentercolwidth<br>
  923. About this attribute, the width of each column of the middle Dashboardrow can be set. It can be stored for each column a separate value.
  924. The values ​​must be separated by a comma (no spaces). Each value determines the column width in%! The first value specifies the width of the first column,
  925. the second value of the width of the second column, etc. Is the sum of the width greater than 100 it is reduced.
  926. If more columns defined as widths the missing widths are determined by the difference to 100. However, are less columns are defined as the values ​​of
  927. ignores the excess values​​.<br>
  928. Default: 100
  929. </li><br>
  930. <a name="dashboard_rowtopheight"></a>
  931. <li>dashboard_rowtopheight<br>
  932. Height of the top row in which the groups may be positioned. <br>
  933. Default: 250
  934. </li><br>
  935. <a name="dashboard_rowbottomheight"></a>
  936. <li>"dashboard_rowbottomheight<br>
  937. Height of the bottom row in which the groups may be positioned.<br>
  938. Default: 250
  939. </li><br>
  940. <a name="dashboard_tabXgroups"></a>
  941. <li>dashboard_tabXgroups<br>
  942. Comma-separated list of the names of the groups to be displayed in Tab X.<br>
  943. Each group can be given an icon for this purpose the group name, the following must be completed ":&lt;icon&gt;@&lt;color&gt;"<br>
  944. Example: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow<br/>
  945. Additionally a group can contain a regular expression to show all groups matching a criteria.
  946. Example: .*Light.* to show all groups that contain the string "Light"
  947. </li><br>
  948. <a name="dashboard_tabXdevices"></a>
  949. <li>dashboard_tabXdevices<br>
  950. devspec list of devices that should appear in the tab. The format is:<br/>
  951. GROUPNAME:devspec1,devspec2,...,devspecN:ICONNAME</br/>
  952. 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:<br/>
  953. <a href="#devspec">Dev-Spec</a>
  954. </li><br>
  955. <a name="dashboard_tabXicon"></a>
  956. <li>dashboard_tabXicon<br>
  957. 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.
  958. </li><br>
  959. <a name="dashboard_colcount"></a>
  960. <li>dashboard_colcount<br>
  961. Number of columns in which the groups can be displayed. Nevertheless, it is possible to have multiple groups <br>
  962. to be positioned in a column next to each other. This is depend on the width of columns and groups. <br>
  963. Default: 1
  964. </li><br>
  965. <a name="dashboard_tabXcolcount"></a>
  966. <li>dashboard_tabXcolcount<br>
  967. Number of columns for a specific tab in which the groups can be displayed. Nevertheless, it is possible to have multiple groups <br>
  968. to be positioned in a column next to each other. This depends on the width of columns and groups. <br>
  969. Default: <dashboard_colcount>
  970. </li><br>
  971. <a name="dashboard_tabXbackgroundimage"></a>
  972. <li>dashboard_tabXbackgroundimage<br>
  973. 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.
  974. Standard:
  975. </li><br>
  976. <a name="dashboard_flexible"></a>
  977. <li>dashboard_flexible<br>
  978. 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.<br/>
  979. The value for this parameter also defines the grid, in which the position "snaps in".
  980. Default: 0
  981. </li><br>
  982. <a name="dashboard_showfullsize"></a>
  983. <li>dashboard_showfullsize<br>
  984. Hide FHEMWEB Roomliste (complete left side) and Page Header if Value is 1.<br>
  985. Default: 0
  986. </li><br>
  987. <a name="dashboard_showtabs"></a>
  988. <li>dashboard_showtabs<br>
  989. Displays the Tabs/Buttonbar on top or bottom, or hides them. If the Buttonbar is hidden lockstate is "lock" is used.<br>
  990. Default: tabs-and-buttonbar-at-the-top
  991. </li><br>
  992. <a name="dashboard_showtogglebuttons"></a>
  993. <li>dashboard_showtogglebuttons<br>
  994. Displays a Toogle Button on each Group do collapse.<br>
  995. Default: 0
  996. </li><br>
  997. <a name="dashboard_backgroundimage"></a>
  998. <li>dashboard_backgroundimage<br>
  999. Displays a background image for the complete dashboard. The image is not stretched in any way so the size should match/extend the
  1000. dashboard height/width.
  1001. Default:
  1002. </li><br>
  1003. <a name="dashboard_debug"></a>
  1004. <li>dashboard_debug<br>
  1005. Show Hiddenfields. Only for Maintainer's use.<br>
  1006. Default: 0
  1007. </li><br>
  1008. </ul>
  1009. </ul>
  1010. =end html
  1011. =begin html_DE
  1012. <a name="Dashboard"></a>
  1013. <h3>Dashboard</h3>
  1014. <ul>
  1015. Erstellt eine Übersicht in der Gruppen angeordnet werden können. Dabei können die Gruppen mit Drag'n Drop frei positioniert<br>
  1016. und in mehreren Spalten angeordnet werden. Auch kann die Breite und Höhe einer Gruppe über die Mindestgröße hinaus gezogen werden. <br>
  1017. <br>
  1018. <a name="Dashboarddefine"></a>
  1019. <b>Define</b>
  1020. <ul>
  1021. <code>define &lt;name&gt; Dashboard</code>
  1022. <br><br>
  1023. Beispiel:<br>
  1024. <ul>
  1025. <code>define anyViews Dashboard</code>
  1026. </ul><br>
  1027. <b>Bestpractice Anfängerkonfiguration</b>
  1028. <br><br>
  1029. <code>
  1030. define anyViews Dashboard<br>
  1031. attr anyViews dashboard_colcount 2<br>
  1032. attr anyViews dashboard_rowcentercolwidth 30,70<br>
  1033. attr anyViews dashboard_tab1groups &lt;Group1&gt;,&lt;Group2&gt;,&lt;Group3&gt;<br>
  1034. </code>
  1035. </ul>
  1036. <br>
  1037. <a name="Dashboardset"></a>
  1038. <b>Set</b>
  1039. <ul>
  1040. <code>set &lt;name&gt; lock</code><br><br>
  1041. Sperrt das Dashboard so das keine Positionsänderungen vorgenommen werden können<br>
  1042. <code>set &lt;name&gt; unlock</code><br><br>
  1043. Entsperrt das Dashboard<br>
  1044. </ul>
  1045. <br>
  1046. <a name="Dashboardget"></a>
  1047. <b>Get</b> <ul>N/A</ul><br>
  1048. <a name="Dashboardattr"></a>
  1049. <b>Attributes</b>
  1050. <ul>
  1051. <a name="dashboard_tabcount"></a>
  1052. <li>dashboard_tabcount<br>
  1053. Gibt die Anzahl der angezeigten Tabs an. (Dieser Parameter is veraletet, die Anzahl der Tabs wird aus der Dashboard-Konfiguration gelesen)
  1054. Standard: 1
  1055. </li><br>
  1056. <a name="dashboard_activetab"></a>
  1057. <li>dashboard_activetab<br>
  1058. Gibt an welches Tab aktiviert ist. Kann manuell gesetzt werden, wird aber auch durch den Schalter "Set" auf das gerade aktive Tab gesetzt.
  1059. Standard: 1
  1060. </li><br>
  1061. <a name="dashboard_tabXname"></a>
  1062. <li>dashboard_tabXname<br>
  1063. Titel des X. Tab.
  1064. </li><br>
  1065. <a name="dashboard_tabXsorting"></a>
  1066. <li>dashboard_tabXsorting<br>
  1067. 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
  1068. </li><br>
  1069. <a name="dashboard_row"></a>
  1070. <li>dashboard_row<br>
  1071. Auswahl welche Zeilen angezeigt werden sollen. top (nur Oben), center (nur Mitte), bottom (nur Unten) und den Kombinationen daraus.<br>
  1072. Standard: center
  1073. </li><br>
  1074. <a name="dashboard_width"></a>
  1075. <li>dashboard_width<br>
  1076. Zum bestimmen der Dashboardbreite. Der Wert kann in % (z.B. 80%) angegeben werden oder als absolute Breite (z.B. 1200) in Pixel.<br>
  1077. Standard: 100%
  1078. </li><br>
  1079. <a name="dashboard_rowcenterheight"></a>
  1080. <li>dashboard_rowcenterheight<br>
  1081. Höhe der mittleren Zeile, in der die Gruppen angeordnet werden. <br>
  1082. Standard: 400
  1083. </li><br>
  1084. <a name="dashboard_rowcentercolwidth"></a>
  1085. <li>dashboard_rowcentercolwidth<br>
  1086. Über dieses Attribut wird die Breite der einzelnen Spalten der mittleren Dashboardreihe festgelegt. Dabei kann je Spalte ein separater Wert hinterlegt werden.
  1087. Die Werte sind durch ein Komma (ohne Leerzeichen) zu trennen. Jeder Wert bestimmt die Spaltenbreite in %! Der erste Wert gibt die Breite der ersten Spalte an,
  1088. der zweite Wert die Breite der zweiten Spalte usw. Ist die Summe der Breite größer als 100 werden die Spaltenbreiten reduziert.
  1089. Sind mehr Spalten als Breiten definiert werden die fehlenden Breiten um die Differenz zu 100 festgelegt. Sind hingegen weniger Spalten als Werte definiert werden
  1090. die überschüssigen Werte ignoriert.<br>
  1091. Standard: 100
  1092. </li><br>
  1093. <a name="dashboard_rowtopheight"></a>
  1094. <li>dashboard_rowtopheight<br>
  1095. Höhe der oberen Zeile, in der die Gruppen angeordnet werden. <br>
  1096. Standard: 250
  1097. </li><br>
  1098. <a name="dashboard_rowbottomheight"></a>
  1099. <li>"dashboard_rowbottomheight<br>
  1100. Höhe der unteren Zeile, in der die Gruppen angeordnet werden.<br>
  1101. Standard: 250
  1102. </li><br>
  1103. <a name="dashboard_tabXgroups"></a>
  1104. <li>dashboard_tab1groups<br>
  1105. Durch Komma getrennte Liste mit den Namen der Gruppen, die im Tab 1 angezeigt werden. Falsche Gruppennamen werden hervorgehoben.<br>
  1106. Jede Gruppe kann zusätzlich ein Icon anzeigen, dazu muss der Gruppen name um ":&lt;icon&gt;@&lt;farbe&gt;"ergänzt werden<br>
  1107. Beispiel: Light:Icon_Fisch@blue,AVIcon_Fisch@red,Single Lights:Icon_Fisch@yellow<br/>
  1108. Der Gruppenname kann ebenfalls einen regulären Ausdruck beinhalten, um alle Gruppen anzuzeigen, die darauf passen.<br/>
  1109. Beispiel: .*Licht.* zeigt alle Gruppen an, die das Wort "Licht" im Namen haben.
  1110. </li><br>
  1111. <a name="dashboard_tabXdevices"></a>
  1112. <li>dashboard_tabXdevices<br>
  1113. devspec Liste von Geräten, die im Tab angezeigt werden sollen. Das format ist:<br/>
  1114. GROUPNAME:devspec1,devspec2,...,devspecN:ICONNAME</br/>
  1115. 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:
  1116. <a href="#devspec">Dev-Spec</a>
  1117. </li><br>
  1118. <a name="dashboard_tabXicon"></a>
  1119. <li>dashboard_tabXicon<br>
  1120. 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.
  1121. </li><br>
  1122. <a name="dashboard_colcount"></a>
  1123. <li>dashboard_colcount<br>
  1124. Die Anzahl der Spalten in der Gruppen dargestellt werden können. Dennoch ist es möglich, mehrere Gruppen <br>
  1125. in einer Spalte nebeneinander zu positionieren. Dies ist abhängig von der Breite der Spalten und Gruppen. <br>
  1126. Gilt nur für die mittlere Spalte! <br>
  1127. Standard: 1
  1128. </li><br>
  1129. <a name="dashboard_tabXcolcount"></a>
  1130. <li>dashboard_tabXcolcount<br>
  1131. Die Anzahl der Spalten im Tab X in der Gruppen dargestellt werden können. Dennoch ist es möglich, mehrere Gruppen <br>
  1132. in einer Spalte nebeneinander zu positionieren. Dies ist abhängig von der Breite der Spalten und Gruppen. <br>
  1133. Gilt nur für die mittlere Spalte! <br>
  1134. Standard: <dashboard_colcount>
  1135. </li><br>
  1136. <a name="dashboard_tabXbackgroundimage"></a>
  1137. <li>dashboard_tabXbackgroundimage<br>
  1138. 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.
  1139. Standard:
  1140. </li><br>
  1141. <a name="dashboard_flexible"></a>
  1142. <li>dashboard_flexible<br>
  1143. 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".
  1144. Standard: 0
  1145. </li><br>
  1146. <a name="dashboard_showfullsize"></a>
  1147. <li>dashboard_showfullsize<br>
  1148. Blendet die FHEMWEB Raumliste (kompleter linker Bereich der Seite) und den oberen Bereich von FHEMWEB aus wenn der Wert auf 1 gesetzt ist.<br>
  1149. Default: 0
  1150. </li><br>
  1151. <a name="dashboard_showtabs"></a>
  1152. <li>dashboard_showtabs<br>
  1153. Zeigt die Tabs/Schalterleiste des Dashboards oben oder unten an, oder blendet diese aus. Wenn die Schalterleiste ausgeblendet wird ist das Dashboard gespert.<br>
  1154. Standard: tabs-and-buttonbar-at-the-top
  1155. </li><br>
  1156. <a name="dashboard_showtogglebuttons"></a>
  1157. <li>dashboard_showtogglebuttons<br>
  1158. Zeigt eine Schaltfläche in jeder Gruppe mit der man diese auf- und zuklappen kann.<br>
  1159. Standard: 0
  1160. </li><br>
  1161. <a name="dashboard_backgroundimage"></a>
  1162. <li>dashboard_backgroundimage<br>
  1163. Zeig in Hintergrundbild im Dashboard an. Das Bild wird nicht gestreckt, es sollte daher auf die Größe des Dashboards passen oder diese überschreiten.
  1164. Default:
  1165. </li><br>
  1166. <a name="dashboard_debug"></a>
  1167. <li>dashboard_debug<br>
  1168. Zeigt Debug-Felder an. Sollte nicht gesetzt werden!<br>
  1169. Standard: 0
  1170. </li><br>
  1171. </ul>
  1172. </ul>
  1173. =end html_DE
  1174. =cut