From 59d29a2a495abe0a73bc8cee20e9ea1d86d52a9c Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Fri, 6 Jul 2018 20:49:43 +0000 Subject: [PATCH] f18.js: change positioning from relative to absolute, add resize git-svn-id: https://svn.fhem.de/fhem/trunk@16954 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/www/pgm2/f18.js | 267 +++++++++++++++++++++++++++++++++---------- 1 file changed, 205 insertions(+), 62 deletions(-) diff --git a/fhem/www/pgm2/f18.js b/fhem/www/pgm2/f18.js index aaf054dd5..23f493a7f 100644 --- a/fhem/www/pgm2/f18.js +++ b/fhem/www/pgm2/f18.js @@ -1,8 +1,9 @@ "use strict"; FW_version["f18.js"] = "$Id$"; -// TODO: absPos,hierMenu+Pin,menuBorder,SVGcolors,floorplan -var f18_attr={}, f18_sd, f18_icon={}, f18_hasPos, f18_room; +// TODO: hierMenu+Pin,SVGcolors,floorplan +// Known bugs: AbsSize is wrong for ColorSlider +var f18_attr={}, f18_sd, f18_icon={}, f18_room, f18_grid=20; var f18_small = (screen.width < 480 || screen.height < 480); $(window).resize(f18_resize); @@ -31,15 +32,16 @@ $(document).ready(function(){ if(typeof f18_attr.savePinChanges == "undefined") f18_attr.savePinChanges = true; - f18_setCss('init'); + f18_setCss('init'); - var icon = FW_root+"/images/default/fhemicon_ios.png"; + var icon = FW_root+"/images/default/fhemicon_ios.png"; $('head').append( ''+ ''+ ''+ ''); - if('ontouchstart' in window) $("body").addClass('touch'); + if('ontouchstart' in window) + $("body").addClass('touch'); if(f18_small) { $("body").addClass('small'); f18_attr["Pinned.menu"] = false; @@ -53,12 +55,18 @@ $(document).ready(function(){ f18_icon.pinOut = f18_icon.pinIn .replace('/>',' transform="rotate(90,896,896)"/>'); + // Needed for moving this label + var szc = $("[data-name=svgZoomControl]"); + if($(szc).length) + $(szc).before("
"); + f18_setFixedInput(); f18_menu(); f18_tables(); f18_svgSetCols(); if(typeof svgCallback != "undefined") svgCallback.f18 = f18_svgSetCols; + $("[data-name]").each(function(){ f18_setPos(this) }); }); function @@ -108,18 +116,8 @@ f18_tables() var ntr = $(el).closest("tr").next("tr"); isFixed ? $(ntr).show() : $(ntr).hide(); }); - f18_setPos(el); - if(f18_getAttr("showDragger")) - f18_addDragger(el); }); - $("div.SVGlabel").each(function(){ - f18_setPos(this); - if(f18_getAttr("showDragger")) - f18_addDragger(this); - }); - - if(FW_urlParams.detail) { $("div.makeTable > span").each(function(){ var el = this, grp = $(el).text(); @@ -133,15 +131,15 @@ f18_tables() }); } - if(FW_urlParams.cmd == "style%20select") - f18_special(); if(FW_urlParams.cmd == "style%20list" || - FW_urlParams.cmd == "style%20select") + FW_urlParams.cmd == "style%20select") $("div.fileList").each(function(){ f18_addPinToStyleDiv(this) }); - if(f18_hasPos || f18_getAttr("showDragger")) - $("div.pinHeader:not(.menu) div.pin").hide(); + if(FW_urlParams.cmd == "style%20select") + f18_special(); + else if(f18_getAttr("showDragger")) + $("[data-name]").each(function(){ f18_addDragger(this) }); } function @@ -184,7 +182,8 @@ f18_special() .click(function(){ var c = $(this).is(":checked"); setAttr(name, c, inRoom); - fn(c); + if(fn) + fn(c); }); }; @@ -199,7 +198,7 @@ f18_special() }); }; -// call drawspecial after got the roomlist... + // call drawspecial after got the roomlist... var f18_drawSpecial = function() { var roomHash={}; @@ -223,15 +222,24 @@ f18_special() addHider("rightMenu", false, "MenuBtn right
on SmallScreen", function(c){ $("body").toggleClass("rightMenu"); }); - addHider("savePinChanges", false, "Save pin changes", function(){}); + addHider("savePinChanges", false, "Save pin changes"); addHider("showDragger", false, "Dragging active", function(c){ if(c) { - $("div.fileList").each(function(){ f18_addDragger(this) }); - $("div.pinHeader:not(.menu) div.pin").hide(); + if($(".ui-draggable").length) { + $(".ui-draggable").draggable("enable"); + $(".dragMove,.dragSize,.dragReset").show(); + } else { + $("div.fileList").each(function(){ f18_addDragger(this) }); + } } else { - $("div.pinHeader div.dragger").remove(); + $(".dragMove,.dragSize,.dragReset").hide(); + $(".ui-draggable").draggable("disable"); } }); + addHider("snapToGrid", false, "Snap to grid", function(c){ + $(".ui-draggable").draggable("option", "grid", + c ? [f18_grid,f18_grid] : [1,1]); + }); addRow("editStyle", "Additional CSS"); $(appendTo+" tr.ar_editStyle a").click(function(){ @@ -346,15 +354,15 @@ f18_special() addHider("hideLogo", true, "Hide logo", f18_menu); addHider("hideInput", true, "Hide input", f18_menu); addHider("hidePin", true, "Hide pin", function(c){ - if(f18_hasPos || f18_getAttr("showDragger")) - $("div.pinHeader.menu div.pin").css("display", c ? "none":"block"); - else - $("div.pinHeader div.pin").css("display", c ? "none":"block"); + $("div.pinHeader div.pin").css("display", c ? "none":"block"); }); addHider("fixedInput", true, "Fixed input", f18_setFixedInput); $("div.f18colors").css("margin-top", "20px"); - $("tr.f18 div.fileList").each(function(e){f18_addPinToStyleDiv(this)}); + $("tr.f18 div.fileList").each(function(e){ f18_addPinToStyleDiv(this) }); + if(f18_getAttr("showDragger")) + $("div.fileList").each(function(){ f18_addDragger(this) }); + $("[data-name]").each(function(){ f18_setPos(this) }); }; loadScript("pgm2/fhemweb_colorpicker.js", f18_drawSpecial); } @@ -377,11 +385,6 @@ f18_addPinToStyleDiv(el) var ntr = $(el).next("table"); isFixed ? $(ntr).show() : $(ntr).hide(); }); - if(f18_getAttr("showDragger")) - f18_addDragger(el); - f18_setPos(el); - if(f18_hasPos || f18_getAttr("showDragger")) - $("div.pinHeader:not(.menu) div.pin").hide(); } @@ -433,64 +436,202 @@ f18_addPin(el, name, defVal, fn, hidePin) fn(init); } +// el is the drag-handle, return the corresponding SVG/table etc +function +f18_compEl(el) +{ + return $(el).hasClass("fileList") ? $(el).next("table") : + $(el).hasClass("SVGlabel") ? $(el).prev(".SVGplot") : + $(el).closest("tr").next().find(">td>table").first(); +} + function f18_addDragger(el) { if(f18_small) return; - var comp = $(el).hasClass("fileList") ? $(el).next("table") : - $(el).hasClass("SVGlabel") ? $(el).prev(".SVGplot") : - $(el).closest("tr").next().find(">td>table").first(); + if($(el).find(".dragger").length) + return; + + var comp = f18_compEl(el); + if($(comp).length == 0) + return; + f18_convertToAbs(); + var ep = $(el).position(); + var cp = $(comp).position(); + var padding = $(el).css("padding").replace("px","")*2; // kind of a hack + + var grid = [1,1]; + if(f18_getAttr("snapToGrid")) + grid = [f18_grid, f18_grid]; + + function + save() + { + var nep = $(el).position(); + f18_setAttr("Pos."+$(el).attr("data-name"), { + left:nep.left, top:nep.top, + width:$(comp).width(), height:$(comp).height(), + oTop:cp.top-ep.top, oLeft:cp.left-ep.left + }); + } + + ///////////////////////////////////// + // Position $("
") .appendTo(el) .css({"cursor":"pointer", "background-image":"url('"+f18_icon.arrows+"')"}) $(el).draggable({ drag:function(evt,ui){ - $(comp).css({ left:ui.position.left, top:ui.position.top}); - }, - start:function(evt,ui){ - $(comp).css({ position:"relative", - left:0, top:0, right:"auto", bottom:"auto" }); - }, - stop:function(evt,ui){ - f18_setAttr("Pos."+$(el).attr("data-name"), ui.position); + $(comp).css({ left:ui.position.left+cp.left-ep.left, + top: ui.position.top +cp.top -ep.top }); }, + stop:save, grid:grid }); + ///////////////////////////////////// + // Size + var off = 20; + if(!$(el).hasClass("SVGlabel")) { + $("
") + .appendTo(el) + .css({ cursor:"pointer", "background-image":"url('"+f18_icon.arrows+"')", + position:"absolute", width:"16px", height:"16px", + top:$(comp).height()+2, left:$(comp).width()-off, "z-index":1 }) + .draggable({ + drag:function(evt,ui){ + $(el).css( { width:ui.position.left+off-padding }); + $(comp).css({ width:ui.position.left+off, + height:ui.position.top }); + }, + stop:save, grid:grid + }); + } + + + ///////////////////////////////////// + // Reset _all_ elements on this page $("
") .appendTo(el) .css({"cursor":"pointer", "background-image":"url('"+f18_icon.ban+"')"}) + .click(function(){ - $(el) .css({ left:0, top:0 }); - $(comp).css({ left:0, top:0 }); - delete(f18_attr["Pos."+$(el).attr("data-name")]); + function + delStyle(e) + { + var style = $(e).attr("style"); + $(e).attr("style", style.replace(/position:.*;/,"")); // hack + } + + $("[data-name]").each(function(){ + var el = this; + var name = $(el).attr("data-name"); + if(!f18_getAttr("Pos."+name)) + return; + delete(f18_attr["Pos."+$(el).attr("data-name")]); + delStyle(el); + delStyle(f18_compEl(el)); + $(el).draggable('disable'); + $(el).find(".dragMove,.dragSize,.dragReset").hide(); + }); f18_setAttr(); }); } +function +f18_applyGrid(pos) +{ + if(!f18_getAttr("snapToGrid")) + return; + pos.left = Math.floor((pos.left + f18_grid-1)/f18_grid)*f18_grid; + pos.top = Math.floor((pos.top + f18_grid-1)/f18_grid)*f18_grid; + pos.width = Math.floor((pos.width + f18_grid-1)/f18_grid)*f18_grid; + pos.height = Math.floor((pos.height+ f18_grid-1)/f18_grid)*f18_grid; +} + +////////////////////////// +// We use absolute positioning for all elements, if a user positioned +// an item, relative (the default one) else. +function +f18_convertToAbs() +{ + // Need two loops, else the sizes/positions are wrong + var sz = {}; + $("[data-name]").each(function(){ + var el = this; + var name = $(el).attr("data-name"); + if(f18_getAttr("Pos."+name)) + return; + var comp = f18_compEl(el); + if($(comp).length == 0) + return; + sz[name] = { ep:$(el).position(), cp:$(comp).position(), + w:$(comp).width(), h:$(comp).height() }; + }); + + var needSave=false; + $("[data-name]").each(function(){ + var el = this; + var name = $(el).attr("data-name"); + if(!name || !sz[name]) + return; + needSave = true; + + var comp = f18_compEl(el); + var ep=sz[name].ep, cp=sz[name].cp, w=sz[name].w, h=sz[name].h; + var pos = { + left:ep.left, top:ep.top, width:w, height:h, + oTop:cp.top-ep.top, oLeft:cp.left-ep.left + }; + f18_doSetPos(el, comp, pos); + f18_setAttr("Pos."+name, pos, true); + }); + + if(needSave) + f18_setAttr(); +} + function f18_setPos(el) { if(f18_small) return; - var name = $(el).attr("data-name"); - var pos = f18_attr["Pos."+name]; - if(!pos) + var comp = f18_compEl(el); + if($(comp).length == 0) return; - f18_hasPos = true; - var comp = $(el).hasClass("fileList") ? $(el).next("table") : - $(el).hasClass("SVGlabel") ? $(el).prev(".SVGplot") : - $(el).closest("tr").next().find(">td>table").first(); - $(el).css({ position:"relative", - left:pos.left, top:pos.top, right:"auto", bottom:"auto" }); - $(comp).css({ position:"relative", - left:pos.left, top:pos.top, right:"auto", bottom:"auto" }); + var name = $(el).attr("data-name"); + var pos = f18_getAttr("Pos."+name); + if(!pos || !pos.width) + return; + + f18_doSetPos(el, comp, pos); + + // correct position + var ds = $(el).find(".dragSize"); + if($(ds).length) + $(ds).css({ top:pos.height+2, left:pos.width-20 }); } +function +f18_doSetPos(el, comp, pos) +{ + f18_applyGrid(pos); + $(el).css({ position:"absolute", left:pos.left, top:pos.top }); + if(!$(el).hasClass("SVGlabel")) { + var padding = $(el).css("padding").replace("px","")*2; // kind of a hack + $(el).css({ width:pos.width-padding }); + } + $(comp).css({ position:"absolute", + left:pos.left+pos.oLeft, top:pos.top+pos.oTop, + width:pos.width, height:pos.height }); + +} + + function f18_getAttr(attrName) { @@ -503,7 +644,7 @@ f18_getAttr(attrName) } function -f18_setAttr(name, value) +f18_setAttr(name, value, dontSave) { if(name) f18_attr[name]=value; @@ -511,6 +652,8 @@ f18_setAttr(name, value) delete f18_attr[name]; if(name && name.indexOf("Pinned.") == 0 && !f18_attr.savePinChanges) return; + if(dontSave) + return; var wn = $("body").attr("data-webName"); FW_cmd(FW_root+"?cmd=attr "+wn+" styleData "+