diff --git a/fhem/CHANGED b/fhem/CHANGED
index f147dc42a..db19c3a74 100644
--- a/fhem/CHANGED
+++ b/fhem/CHANGED
@@ -1,5 +1,6 @@
# 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: FHEMWEB: new style f18
- feature: 98_weekprofile.pm: new set command 'reread_master'
- change: 10_SOMFY: minor changes remvoe debug and add parsestate reading
- bugfix: 74_XiaomiFlowerSens: fix error then use ssh and no connect
diff --git a/fhem/FHEM/00_ZWDongle.pm b/fhem/FHEM/00_ZWDongle.pm
index 23ae8f3c0..2033afcef 100644
--- a/fhem/FHEM/00_ZWDongle.pm
+++ b/fhem/FHEM/00_ZWDongle.pm
@@ -209,7 +209,7 @@ ZWDongle_nlData($)
my %line = (
pos => '['.AttrVal($e, "neighborListPos", "").']',
- class => '"zwBox"',
+ class => '"zwBox col_link col_oddrow"',
neighbors => '['.$nl.']'
);
@@ -229,7 +229,7 @@ ZWDongle_nlData($)
my $pos = AttrVal($d, "neighborListPos", "");
my $nl = (@dn ? '"'.join('","',@dn).'"' : '');
push @ret, "\"$d\":{\"txt\":\"$d\", \"pos\":[$pos],".
- "\"class\":\"zwDongle\",\"neighbors\":[$nl] }";
+ "\"class\":\"zwDongle col_oddrow col_link\",\"neighbors\":[$nl] }";
return "{ \"saveFn\":\"attr {1} neighborListPos {2}\",".
"\"firstObj\":\"$d\",".
"\"el\":{".join(",",@ret)."} }";
diff --git a/fhem/FHEM/98_SVG.pm b/fhem/FHEM/98_SVG.pm
index 67c73ad0f..5af215adb 100644
--- a/fhem/FHEM/98_SVG.pm
+++ b/fhem/FHEM/98_SVG.pm
@@ -1403,7 +1403,7 @@ SVG_render($$$$$$$$$$)
# SVG Header
my $svghdr = 'version="1.1" xmlns="http://www.w3.org/2000/svg" '.
'xmlns:xlink="http://www.w3.org/1999/xlink" '.
- "id='SVGPLOT_$name' $filter";
+ "id='SVGPLOT_$name' $filter data-origin='FHEM'";
if(!$noHeader) {
SVG_pO '';
SVG_pO '';
diff --git a/fhem/www/pgm2/defaultCommon.css b/fhem/www/pgm2/defaultCommon.css
index 9e876cdd5..76bac40a9 100644
--- a/fhem/www/pgm2/defaultCommon.css
+++ b/fhem/www/pgm2/defaultCommon.css
@@ -2,9 +2,9 @@
textarea, .ui-dialog.ui-widget textarea { font-family:Courier; }
-body { font-family:Arial, sans-serif; background-color: #FFFFE7; }
-input { font-family:Arial, sans-serif; font-size:16px;}
-select { font-family:Arial, sans-serif; font-size:16px;}
+body { background-color: #FFFFE7; }
+body,input,select,textarea { font-family:Arial, sans-serif; font-size:16px;}
+input,textarea { border-style:ridge; }
#console { width:100%; top:2em; bottom:0px; position:absolute; overflow-y:auto;}
#errmsg { background-color: #000000; color: #FFFFFF;
@@ -138,9 +138,18 @@ select [value^=l6] { color: olive; }
select [value^=l7] { color: gray; }
select [value^=l8] { color: yellow; }
-svg.zw_nr .zwBox { stroke:#278727; stroke-width:2px; fill:#F0F0D8; }
-svg.zw_nr .zwDongle { stroke:red; stroke-width:2px; fill:#F0F0D8; }
-svg.zw_nr .zwMargin { stroke:#278727; stroke-width:1px; fill:none; }
-svg.zw_nr .zwLine { stroke:#278727; stroke-width:1px; }
-svg.zw_nr .zwArrowHead { fill:#278727; stroke-width:1px; }
+svg.zw_nr .zwBox { stroke-width:2px; }
+svg.zw_nr .zwDongle { stroke:red; stroke-width:2px; }
+svg.zw_nr .zwMargin { stroke-width:1px; fill:none; }
+svg.zw_nr .zwLine { stroke-width:1px; }
+svg.zw_nr .zwArrowHead { stroke-width:1px; }
svg.zw_nr { height:auto; width:auto; margin:0; }
+
+.col_fg { color:#000000; }
+.col_link { color:#278727; stroke:#278727; }
+.col_bg { background: #FFFFE7; fill:#FFFFE7; }
+.col_evenrow { background: #F8F8E0; fill:#F8F8E0; }
+.col_oddrow { background: #F0F0D8; fill:#F0F0D8; }
+.col_header { background: #E0E0C8; fill:#E0E0C8; }
+.col_menu { background: #D7FFFF; fill:#D7FFFF; }
+.col_sel { background: #A0FFFF; fill:#A0FFFF; }
diff --git a/fhem/www/pgm2/f18.js b/fhem/www/pgm2/f18.js
new file mode 100644
index 000000000..f165d952b
--- /dev/null
+++ b/fhem/www/pgm2/f18.js
@@ -0,0 +1,367 @@
+/*
+ - style FW_okDialog
+ - SVG width on mobile
+ - FLOORPLAN
+ - Dashboard
+ */
+
+var f18_attr, f18_aCol, f18_pinOut, f18_sd, f18_isMobile;
+var f18_small = (screen.width < 480 || screen.height < 480);
+// font-awesome: map-pin
+var f18_pinIn='data:image/svg+xml;utf8,';
+
+$(window).resize(f18_resize);
+$(document).ready(function(){
+ f18_sd = $("body").attr("data-styleData");
+ if(f18_sd) {
+ eval("f18_sd="+f18_sd);
+ if(!f18_sd)
+ f18_sd = {};
+ f18_attr = f18_sd.f18;
+ }
+ if(!f18_attr) {
+ f18_attr = { "Pinned.menu":"true" };
+ f18_resetCol();
+ f18_sd.f18 = f18_attr;
+ }
+
+ f18_setCss();
+
+ var icon = FW_root+"/images/default/fhemicon_ios.png";
+ $('head').append(
+ ''+
+ ''+
+ ''+
+ '');
+ if('ontouchstart' in window) $("body").addClass('touch');
+ if(f18_small)
+ $("body").addClass('small');
+
+
+ f18_aCol = getComputedStyle($("a").get(0),null).getPropertyValue('color');
+ f18_pinIn = f18_pinIn.replace('gray', f18_aCol);
+ f18_pinOut = f18_pinIn.replace('/>',' transform="rotate(90,896,896)"/>');
+
+ if(f18_attr.hideLogo) {
+ $("div#menuScrollArea div#logo").css("display", "none");
+ $("#hdr").css("left", f18_small ? "10px":"54px");
+ }
+ f18_menu();
+ f18_tables();
+ f18_svgSetCols();
+});
+
+function
+f18_menu()
+{
+ // font-awesome: bars
+ var bars='data:image/svg+xml;utf8,'
+ .replace('gray', f18_aCol);
+ $("
").prependTo("div#menuScrollArea")
+ .css( {"background-image":"url('"+bars+"')", "cursor":"pointer" })
+ .click(function(){ $("div#menu").toggleClass("visible") });
+
+ $("div#menu").prepend("");
+ f18_addPin("div#menu > div:first", "menu", true, fixMenu, f18_small);
+ setTimeout(function(){ $("div#menu,div#content").addClass("animated"); }, 10);
+
+ function
+ fixMenu(isFixed) {
+ if(isFixed) {
+ $("div#content").css("left", (parseInt($("div#menu").width())+20)+"px");
+ $("div#menu").addClass("visible");
+ $("div#hdr").css("left", "10px");
+ $("div#menuBtn").hide();
+ if(!f18_small)
+ $("div#logo").css("left", "10px");
+ } else {
+ $("div#content").css("left", "10px");
+ $("div#menu").removeClass("visible");
+ if(!f18_small)
+ $("div#logo").css("left", "52px");
+ $("div#menuBtn").show();
+ }
+ f18_resize();
+ }
+}
+
+function
+f18_tables()
+{
+ $("table.roomoverview > tbody > tr > td > .devType:not(:first)")
+ .css("margin-top", "20px");
+ $("table.column tbody tr:not(:first-child) .devType")
+ .css("margin-top", "20px");
+
+ $("#content .devType").each(function(){
+ var el = this, grp = $(el).text();
+ f18_addPin(el, "room."+FW_urlParams.room+".grp."+grp, true,
+ function(isFixed){
+ var ntr = $(el).closest("tr").next("tr");
+ isFixed ? $(ntr).show() : $(ntr).hide();
+ });
+ });
+
+ if(FW_urlParams.detail) {
+ $("div.makeTable > span").each(function(){
+ var el = this, grp = $(el).text();
+ var nel = $(""+grp+"
");
+ $(el).replaceWith(nel);
+ f18_addPin(nel, "detail."+grp, true,
+ function(isFixed){
+ var ntr = $(nel).next("table");
+ isFixed ? $(ntr).show() : $(ntr).hide();
+ });
+ });
+ }
+
+ if(FW_urlParams.cmd == "style%20select") {
+ var row=0;
+
+ function
+ addRow(name, desc, val)
+ {
+ $("table.colors")
+ .append(""+
+ ""+
+ " "+desc+" | "+
+ (val ? ""+val+" | " : '')+
+ "
");
+ }
+
+ function
+ addHider(name, desc, fn)
+ {
+ addRow(name, desc, "");
+ $("table.colors tr."+name+" input")
+ .prop("checked", f18_attr[name])
+ .click(function(){
+ var c = $(this).is(":checked");
+ f18_setAttr(name, c);
+ fn(c);
+ });
+ }
+
+ function
+ addColorChooser(name, desc)
+ {
+ addRow(name, desc, "");
+ FW_replaceWidget("table.colors tr."+name+" div.col2 div.cp", name,
+ ["colorpicker","RGB"], f18_attr.cols[name], name, "rgb", undefined,
+ function(value) {
+ f18_attr.cols[name] = value;
+ f18_setAttr();
+ f18_setCss();
+ });
+ }
+
+
+ $("div#content > table").append("
");
+
+ $("tr.f18").append("f18 special
");
+ $("div.f18colors").css("margin-top", "20px");
+ $("tr.f18").append("");
+
+ loadScript("pgm2/fhemweb_colorpicker.js", addColors);
+
+ function
+ addColors()
+ {
+ $("table.colors")
+ .append(""+
+ " | "+
+ "
");
+ $("table.colors tr.reset a").click(function(){
+ row = 0;
+ $("table.colors").html("");
+ f18_resetCol($(this).text());
+ f18_setCss();
+ f18_setAttr();
+ addColors();
+ });
+ addColorChooser("bg", "Background");
+ addColorChooser("fg", "Foreground");
+ addColorChooser("link", "Link");
+ addColorChooser("evenrow", "Even row");
+ addColorChooser("oddrow", "Odd row");
+ addColorChooser("header", "Header row");
+ addColorChooser("menu", "Menu");
+ addColorChooser("sel", "Menu/Selected");
+ addColorChooser("inpBack", "Input bg");
+ $("table.colors input").attr("size", 8);
+ addRow("empty", " ");
+ addHider("hidePin", "Hide pin", function(c){
+ $("div.pinHeader div.pin").css("display", c ? "none":"block");
+ });
+ addHider("hideLogo", "Hide logo", function(c){
+ $("div#menuScrollArea div#logo").css("display", c ? "none":"block");
+ f18_resize();
+ });
+ }
+ }
+
+ if(FW_urlParams.cmd == "style%20list" ||
+ FW_urlParams.cmd == "style%20select") {
+ $("div.fileList").each(function(){
+ var el = this, grp = $(el).text();
+ f18_addPin(el, "style.list."+grp, true,
+ function(isFixed){
+ var ntr = $(el).next("table");
+ isFixed ? $(ntr).show() : $(ntr).hide();
+ });
+ });
+ }
+}
+
+function
+f18_resize()
+{
+ var w=$(window).width();
+ log("W:"+w+" S:"+screen.width);
+
+ var diff = 0
+ diff += f18_attr.hideLogo ? 0 : 40;
+ diff += f18_attr["Pinned.menu"] ? 0 : 44;
+ $("input.maininput").css("width", (w-(FW_isiOS ? 40 : 30)-diff)+'px');
+ if(f18_small)
+ diff -= 44
+ $("#hdr").css("left",(10+diff)+"px");
+
+}
+
+function
+f18_addPin(el, name, defVal, fn, hidePin)
+{
+ var init = f18_attr["Pinned."+name];
+ if(init == undefined)
+ init = defVal;
+ $("")
+ .appendTo(el)
+ .css("background-image", "url('"+(init ? f18_pinIn : f18_pinOut)+"')");
+ $(el).addClass("col_header pinHeader "+name.replace(/[^A-Z0-9]/ig,'_'));
+ el = $(el).find("div.pin");
+ $(el)
+ .addClass(init ? "pinIn" : "")
+ .css("cursor", "pointer")
+ .css("display", (f18_attr.hidePin || hidePin) ? "none" : "block")
+ .click(function(){
+ var nextVal = !$(el).hasClass("pinIn");
+ $(el).toggleClass("pinIn");
+ $(el).css("background-image","url('"+(nextVal ?f18_pinIn:f18_pinOut)+"')")
+ f18_setAttr("Pinned."+name, nextVal);
+ fn(nextVal);
+ });
+ fn(init);
+}
+
+
+function
+f18_setAttr(name, value)
+{
+ if(name)
+ f18_attr[name]=value;
+ var wn = $("body").attr("data-webName");
+ FW_cmd(FW_root+"?cmd=attr "+wn+" styleData "+
+ encodeURIComponent(JSON.stringify(f18_sd, null, 2))+"&XHR=1");
+}
+
+function
+f18_resetCol(name)
+{
+ var cols = {
+ "default":{ bg: "FFFFE7", fg: "000000", link: "278727",
+ evenrow:"F8F8E0", oddrow:"F0F0D8", header: "E0E0C8",
+ menu: "D7FFFF", sel: "A0FFFF", inpBack:"FFFFFF" },
+ light: { bg: "F8F8F8", fg: "465666", link: "4C9ED9",
+ evenrow:"E8E8E8", oddrow:"F0F0F0", header: "DDDDDD",
+ menu: "EEEEEE", sel: "CAC8CF", inpBack:"FFFFFF" },
+ dark: { bg: "444444", fg: "CCCCCC", link: "FF9900",
+ evenrow:"333333", oddrow:"111111", header: "222222",
+ menu: "111111", sel: "333333", inpBack:"444444" }
+ };
+ f18_attr.cols = name ? cols[name] : cols["default"];
+}
+
+function
+f18_setCss()
+{
+ var cols = f18_attr.cols;
+ var style = "";
+ function bg(c) { return "{ background:#"+c+"; fill:#"+c+"; }\n" }
+ function fg(c) { return "{ color:#"+c+"; }\n" }
+ style += ".col_fg, body, input "+fg(cols.fg);
+ style += ".col_bg, body, #menu, input, option "+bg(cols.bg);
+ style += ".col_fg, body, input { color:#"+cols.fg+"; }\n";
+ style += ".col_link, a, .handle, .fhemlog, input[type=submit], select "+
+ "{color:#"+cols.link+"; stroke:#"+cols.link+";}\n";
+ style += "svg:not([fill]):not(.jssvg) { fill:#"+cols.link+"; }\n";
+ style += ".col_evenrow, table.block,div.block "+bg(cols.evenrow);
+ style += ".col_oddrow,table.block tr.odd,table.block tr.sel "+bg(cols.oddrow);
+ style += ".col_header "+bg(cols.header);
+ style += ".col_menu, table.room "+bg(cols.menu);
+ style += ".col_sel, table.room tr.sel "+bg(cols.sel);
+ style += ".col_inpBack, input "+bg(cols.inpBack);
+ if(cols.bg == "FFFFE7") // default
+ style += "div.pinHeader.menu {background:#"+cols.sel+";}\n";
+
+ style += "div.ui-dialog-titlebar "+bg(cols.header);
+ style += "div.ui-widget-content "+bg(cols.bg);
+ style += "div.ui-widget-content, .ui-button-text "+fg(cols.fg+"!important");
+ style += "div.ui-dialog { border:1px solid #"+cols.link+"; }";
+ style += "button.ui-button { background:#"+cols.oddrow+"!important; "+
+ "border:1px solid #"+cols.link+"!important; }\n";
+
+ $("head style.f18").remove();
+ $("head").append("");
+}
+
+var dbg;
+function
+f18_svgSetCols()
+{
+ $("body embed").each(function(){
+ this.addEventListener('load', function(){
+ var svg = FW_getSVG(this);
+ if(svg.contentType != "image/svg+xml")
+ return;
+ if(!svg || !svg.firstChild || !svg.firstChild.nextSibling)
+ return;
+ svg = svg.firstChild.nextSibling;
+ if(!svg.getAttribute("data-origin"))
+ return;
+
+
+ var style = $(svg).find("> style").first();
+ var sTxt = $(style).text();
+ var cols = f18_attr.cols;
+ sTxt = sTxt.replace(/font-family:Times/, "fill:#"+cols.fg);
+ $(style).text(sTxt);
+
+ function
+ addCol(c, d)
+ {
+ var r="";
+ for(var i1=0; i1<6; i1+=2) {
+ var n = parseInt(c.substr(i1,2), 16);
+ n += d;
+ if(n>255) n = 255;
+ if(n< 0) n = 0;
+ n = n.toString(16);
+ if(n.length < 2)
+ n = "0"+length;
+ r += n;
+ }
+ return r;
+ }
+
+ var stA = $(svg).find("> defs > #gr_bg").children();
+ $(stA[0]).css("stop-color", addCol(cols.bg, 10));
+ $(stA[1]).css("stop-color", addCol(cols.bg, -10));
+
+ }, false);
+ });
+}
diff --git a/fhem/www/pgm2/f18style.css b/fhem/www/pgm2/f18style.css
new file mode 100644
index 000000000..415960a81
--- /dev/null
+++ b/fhem/www/pgm2/f18style.css
@@ -0,0 +1,57 @@
+@import url("defaultCommon.css");
+
+#logo {
+ position:absolute; top:10px; width:32px; height:32px; z-index:10;
+ background-image:url(../images/default/fhemicon.png);
+ background-size: contain; background-repeat: no-repeat;
+}
+#menuBtn { position:absolute; top:10px; left:10px; width:32px; height:32px; }
+#hdr { position:absolute; top:10px; left:94px; }
+#content { position:absolute; top:50px; left:10px; bottom:10px; right:10px; }
+#menu {
+ position: absolute;
+ top:50px; left:-120%;
+ z-index:20;
+ display:inline-block;
+ padding:0 0.5em 0.5em 0;
+}
+#menu.visible { left:10px!important; }
+table.room,table.block.wide,table.fileList {
+ border:0;
+ border-radius:0;
+ border-top:1px solid gray;
+}
+
+#menuScrollArea { display:none; } /* commandref */
+body[fw_id] #menuScrollArea { display:block; } /* not commandref */
+#right { top:10px; left:10px; }
+
+input[type=submit] { border:none; background:none; }
+select { background:none; }
+#menu img.icon { width:18px; height:18px; }/* Firefox assumes 100px bef.load */
+
+table.roomoverview { border-spacing:0; }
+div#menu > table { border-spacing:0; }
+tr.devTypeTr td { padding:0px; }
+tr.column > td { padding-right:10px; }
+
+.animated { transition: all .1s ease-in; }
+a { text-decoration:none; }
+
+div.dist { padding-top:0.3em; }
+button.dist { margin:10px; background:transparent; border:0px; cursor:pointer; }
+
+div.pin { float:right; width:1em; height:1em; }
+div.pinHeader { height:1em; padding:2px; }
+
+body.touch a { font-size: 20px; }
+body.touch #menu { font-size: 20px; } /* for the menuTree icon */
+body.touch div.col1, body.touch #menu table.room div { padding:0.25em 0; }
+
+@media screen and (orientation: portrait) {
+ body.small table.block tr td:nth-child(n+3) { width: 0px; display: none; }
+ body.small #content > table { width: 100%; }
+ body.small #menuBtn { right:10px; left:auto; }
+ body.small #logo { left:10px; }
+ body.small #hdr { left:52px; }
+}
diff --git a/fhem/www/pgm2/zwave_neighborlist.js b/fhem/www/pgm2/zwave_neighborlist.js
index 9cf577f88..91eddd37d 100644
--- a/fhem/www/pgm2/zwave_neighborlist.js
+++ b/fhem/www/pgm2/zwave_neighborlist.js
@@ -81,14 +81,14 @@ zw_draw(fnRet, width, height)
svg += ''+
''+
- ''+
+ ''+
''+
''+
- ''+
+ ''+
''+
'';
- svg += '';
var ld={};
@@ -192,7 +192,7 @@ zw_drawline(ld, h, o, n)
h[n].lines.push(cl);
var fr = zw_calcPos(h[o], h[n]);
var to = zw_calcPos(h[n], h[o]);
- return '