iobroker.energiefluss-erweitert
Version:
This ioBroker adapter is the next Version of the energiefluss with the attribute 'erweitert' and allows to display an energyflow animation inside an iframe or HTML DIV.
1 lines • 166 kB
JavaScript
"use strict";function hashCode(e){let t=0;if(0===e.length)return t;for(let o=0;o<e.length;o++){t=(t<<5)-t+e.charCodeAt(o),t&=t}return t>>>0}$.fn.countTo=function(e,t=1e3){const o=String(e).includes(".")?String(e).split(".")[1].length:0;var a=$(this),n=null;const i=parseFloat(a.text()),s=parseFloat(e);return requestAnimationFrame((function e(r){n||(n=r);var l=r-n,c=i+l/t*(s-i);l<t?(a.text(c.toFixed(o)),requestAnimationFrame(e)):a.text(s.toFixed(o))})),this},$.fn.scrollTo=function(e,t,o){return $(this).animate({scrollTop:$(this).scrollTop()-$(this).offset().top+$(e).offset().top+(o||0)},null==t?1e3:t),this},$.expr.pseudos.icontains=function(e,t,o){return e.textContent.toUpperCase().includes(o[3].toUpperCase())},$.fn.appendToWithIndex=function(e,t=0){!e instanceof jQuery&&(e=$(e));let o=e.children().last().index()||0;0===t?$(this).prependTo(e):t>o?$(this).appendTo(e):$(this).insertAfter(e.children().eq(t-1))};const jQueryDialog={open:function(){$(".ui-widget-overlay").hide().fadeIn(600),$(this).parent().focus();var e=$(this).parent(),t=parseInt(e.css("top"));e.css({top:t-60,opacity:0}),e.animate({opacity:1,top:t},{duration:600})},beforeClose:function(){$(".ui-widget-overlay").show().fadeOut(600);var e=$(this).parent();return e.animate({opacity:0,top:parseInt(e.css("top"))-60},{duration:600,queue:!1,complete:function(){$(".ui-dialog, .tmpDiv").remove()}}),!1},classes:{"ui-dialog":"no-close"}};let aceLog,aceCSS,aceOverride;const urlParams=new URLSearchParams(window.location.search),appProperties={instance:Number(urlParams.get("instance"))||0,lowPerformance:urlParams.get("lowPerformance")||!1,theme:urlParams.get("theme")||!1,updateCheck:"https://api.github.com/repos/SKB-CGN/ioBroker.energiefluss-erweitert/tags",updateURL:"https://github.com/SKB-CGN/ioBroker.energiefluss-erweitert/#changelog",namespace:`energiefluss-erweitert.${urlParams.get("instance")||0}`,hostname:window.location.hostname,localMode:!window.location.hostname,socketURL:window.location.hostname?"/":"https://192.168.2.19:8082/",socketPath:"/socket.io",devMode:"true"==urlParams.get("devMode"),colorScheme:window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light",userAgent:navigator.userAgent.indexOf("WebKit")>-1?"Chrome":"Firefox",isMobile:/iPhone|iPad|iPod|Android/i.test(navigator.userAgent),isApple:/Apple Computer/i.test(navigator.vendor),aceEditorTheme:{dark:"clouds_midnight",light:"textmate"}};let manifestElement=document.getElementById("manifestData");manifestElement.setAttribute("href",`/energiefluss-erweitert.0/?serve=manifest&instance=${appProperties.instance}`);const socket=io.connect(appProperties.socketURL,{path:appProperties.socketPath,reconnectionDelay:500,reconnectionAttempts:1/0,upgrade:!0,transports:appProperties.hostname.match(/iobroker\.pro|iobroker\.net/)?void 0:["websocket","polling"]});socket.on("reauthenticate",(function(){let e=(new Date).toLocaleString();console.log(`[Socket] reauthenticate ${e}`)})),socket.on("error",(function(e){let t=(new Date).toLocaleString();console.error(`[Socket] error: ${e} ${t}`)})),socket.on("permissionError",(function(e){let t=(new Date).toLocaleString();console.error(`[Socket] permission error: ${e} ${t}`)})),socket.on("upgrade",(function(e){let t=(new Date).toLocaleString();console.log(`[Socket] connection upgrade at ${t}`)})),socket.on("connect_error",(function(e){let t=(new Date).toLocaleString();console.error("[Socket] connect error: "+e+" "+t),console.log(`Current connection set: ${socket.io.opts.transports}`),socket.io.opts.forceNew=!0,"polling"==socket.io.opts.transports[0]?(socket.io.opts.transports=["websocket","polling"],console.log("[Socket] Connection Error. Trying websocket first!")):(socket.io.opts.transports=["polling","websocket"],console.log("[Socket] Connection Error. Trying polling first!"))})),console.debug(appProperties),console.log("[Config] Using Instance: "+appProperties.namespace);const subscribeObjID=[appProperties.namespace+".configuration",appProperties.namespace+".data","system.adapter."+appProperties.namespace+".alive"];systemLang=navigator.language||navigator.userLanguage,console.log("[Language] Detected System-Languag: "+systemLang);let globalSelectedId,configuration={},displayMode=!1,globalConfigChanged=!1,basicConfig=!1,globalUndoStack=[],globalRedoStack=[],globalAdapterOnline=!1,globalIobObjectsLoaded=!1,globalGalleryLoaded=!1,globalClipboard=[],globalMoving=[],globalError=[],oldRefreshObj={};const clockIntervals={};var filename=location.pathname.substr(location.pathname.lastIndexOf("/")+1);filename.includes("index")||""==filename?displayMode=!0:(jscolor.presets.default={alphaChannel:"auto",format:"any",borderColor:"var(--primary)",borderRadius:10,controlBorderColor:"#538EA3",previewSize:28,previewPosition:"right",required:!1,backgroundColor:"var(--white)",palette:["#00b5dd","#61687a","#ffce4a","#a1d343","#c5902e","#f20e40"]},ace.require("ace/ext/language_tools"));const dataSourceAutocompleteOptions={position:{my:"left top",at:"left bottom",collision:"fit"},source:async function(e,t){globalIobObjectsLoaded||(iobObjects=await loadIobObjects());t($.ui.autocomplete.filter(iobArray,e.term).slice(0,200))},classes:{"ui-autocomplete":"select_overflow"},minLength:3,delay:500,search:function(){globalIobObjectsLoaded||$(this).siblings(".icon_wrapper").find(".ds_search_spinner").show()},response:function(){setTimeout((()=>{$(this).siblings(".icon_wrapper").find(".ds_search_spinner").hide()}),500)}};let iobObjects,iobArray=[],globalUserImages=[];const multiselect_options={columns:1,search:!0,minWidth:"250px",maxWidth:"auto",maxPlaceholderOpts:1,texts:{}};function loadIobObjects(){return console.log("iobObjects not present! Requesting!"),new Promise(((e,t)=>{const o=performance.now();socket.emit("getObjects",(function(t,a){globalIobObjectsLoaded=!0,console.log(`${Object.keys(a).length} Objects loaded in ${performance.now()-o} ms`);let n={};Object.keys(a).sort(((e,t)=>e.toLowerCase().localeCompare(t.toLowerCase()))).forEach((e=>n[e]=a[e])),iobArray=Object.keys(n).filter((e=>"state"==n[e].type)),e(n)}))}))}function sprintf(e){var t=Array.prototype.slice.call(arguments,1),o=0;return e.replace(/%s/g,(function(){return t[o++]}))}function displayLoading(e){$("#loading").fadeIn(600),$("#loading_text").html(e).show(),$(".loading-spinner").show(),$("#loading_text_error").hide()}function displayListener(){const e=(new Date).toLocaleString();socket.emit("subscribe",subscribeObjID),console.log("[Socket] subscribed to: "+subscribeObjID.toString()+" at "+e),socket.on("reconnect",(function(){console.log("[Socket] reconnected at "+e),socket.emit("subscribe",subscribeObjID),$("#loading").fadeOut("fast")})),socket.on("disconnect",(function(){console.log("[Socket] disconnected "+e),displayLoading(translateWord("msg_reconnect"))})),socket.on("stateChange",(function(t,o){setTimeout((function(){if(t==subscribeObjID[0])try{Object.keys(clockIntervals).forEach((e=>{clearTimeout(clockIntervals[e]),console.log("Cleared Clock-Timout for "+e)})),$("#frameContainer").is(":visible")&&closeEditorContainer("frame"),$("#action_change_value").is(":visible")&&$(".ui-dialog-buttonset").children(".red").click(),$("#errorLogContainer").is(":visible")&&closeEditorContainer("errorLog"),displayLoading(translateWord("msg_loading_config")),configuration=JSON.parse(o.val),setLoadedConfig(!0),console.log("Applied new configuration at "+e)}catch(e){console.log("Error while parsing Config in JSON-Object!")}if(t==subscribeObjID[1])try{refreshData(JSON.parse(o.val))}catch(e){console.log("Error while parsing Values in JSON-Object!")}if(t==subscribeObjID[2])if(0==o.val){displayLoading(sprintf(systemDictionary.msg_instance_loading[systemLang],appProperties.instance)),console.log("Adapter instance: "+appProperties.instance+" is not started! "+e),globalAdapterOnline=!1}else if(o.val!=globalAdapterOnline&&1==o.val){console.log("Adapter instance: "+appProperties.instance+" started at "+e),globalAdapterOnline=!0;let t=(Math.random()+1).toString(36).substring(7);window.location.href=`?instance=${appProperties.instance}&hash=${t}&lowPerformance=${appProperties.lowPerformance}&theme=${appProperties.theme}`}}),0)}))}function addBorderFill(e,t,o,a=-90){let n=$("#"+e),i=n.attr("r"),s=Math.PI*(2*i),r=Number(n.attr("height")),l=Number(n.attr("width")),c={id:`border_${e}`,class:"border_fill"};if("rect"==n.prop("tagName"))switch(s=2*n.attr("width")+2*n.attr("height"),a=Number(a)+90){case 90:case 270:if(r!=l){let e=Math.abs(r-l)/2;c.width=r,c.height=l,c.x=r>l?Number(n.attr("x"))-e:Number(n.attr("x"))+e,c.y=r>l?Number(n.attr("y"))+e:Number(n.attr("y"))-e}}let d=n.clone().attr(c).css({fill:"",filter:"",transform:"rotate("+a+"deg)",strokeDashoffset:s,strokeDasharray:s,strokeLinecap:o}).data("border_reverse_value_default",n.css("stroke"));$(d).insertAfter(n),n.css({stroke:t})}function updateBorderFill(e,t,o,a,n="cw"){try{let i,s,r=$("#border_"+e),l=r.attr("r"),c=Math.PI*(2*l);switch("rect"==r.prop("tagName")&&(c=2*r.attr("width")+2*r.attr("height")),a){case"percent":s=100-Math.abs(t);break;case"value":if(!o)throw new Error("No max value for element declared!");s=100-Math.abs(t)/o*100}s<0&&(s=0),s>100&&(s=100),r.data("border_reverse")&&(t<0?(n="cw"==n?"ccw":"cw",i=r.data("border_reverse_value")||r.data("border_reverse_value_default")):i=r.data("border_reverse_value_default")),c="cw"==n?c:-1*c;let d=(s/100*c).toFixed(0);r.css({strokeDashoffset:d,strokeDasharray:c,stroke:i})}catch(t){console.error("Error while updating border fill for ID: "+e+"! "+t)}}function animateGradient(e,t,o){const a="object"==typeof e?e:document.getElementById(e);let n=parseInt(t),i=parseInt(o),s=!1;a&&(s||function e(){s=!0,n<i?n=Math.min(n+1,i):n>i&&(n=Math.max(n-1,i));a.setAttribute("offset",`${n}%`),n!=i?requestAnimationFrame(e):s=!1}())}function updateMultiGradient(e,t,o,a){const n=document.getElementById(`gradient_${e}_fill`),i=n.childNodes,s=parseInt(n.getAttribute("data-value"));let r;try{switch(a){case"percent":r=t;break;case"value":if(!o)throw new Error(`No max value for element with ID ${e} declared!`);r=Math.abs(t)/o*100}}catch(t){console.error("Error while updating gradient for ID: "+e+"! "+t)}if(r=parseInt(r),s!=r){for(const e of i){const t=e.getAttribute("data-defaultOffset");if(null!=t){const o=parseInt(e.getAttribute("offset").replace("%",""));animateGradient(e,o,parseFloat(t)/100*r)}}n.setAttribute("data-value",r)}}function userClock(e,t,o=!1){const a=Object.keys(e).reduce(((t,o)=>("none"!==e[o]&&""!==e[o]&&(t[o]=e[o]),t)),{}),n=document.getElementById(t);let i;const s=new Date;try{i=new Intl.DateTimeFormat(systemLang,a).format(s)}catch(e){console.log("Not a valid date. Waiting for setting-up correctely!",e.message)}return n&&n.innerHTML!=i&&(n.innerHTML=i),o||(clockIntervals[t]=setTimeout(userClock,1e3,e,t)),i}function addErrorToLog(e){globalError.some((t=>JSON.stringify(e)===JSON.stringify(t)))||globalError.push(e),globalError.length>0&&$("#info_error_area").fadeIn("fast")}function openErrorLog(){$("#errorLog-table tbody").empty();globalError.forEach((e=>$("#errorLog-table tbody").append(`<tr><td>${e.id}</td><td>${e.for}</td><td>${e.error}</td><td>${e.function}</td></tr>`))),$("#loading").fadeIn(600),$(".loading-spinner, #loading_text").hide(),$("#errorLogContainer").css({top:"45%",opacity:0,display:"block"}),$("#errorLogContainer").animate({opacity:1,top:"50%"},{duration:600,queue:!1})}async function refreshData(e,t=!1){function o(e,a){if(t)return!1;if(e===a)return!0;if("object"!=typeof e||"object"!=typeof a||null===e||null===a)return!1;const n=Object.keys(e),i=Object.keys(a);if(n.length!==i.length)return!1;for(let t of n)if(!o(e[t],a[t]))return!1;return!0}try{if(o(e.values,oldRefreshObj.values)?appProperties.devMode&&console.debug("[Debug] [Refresh] No changes for 'Values'!"):(appProperties.devMode&&console.debug("[Debug] [Refresh] Changes for 'Values'. Refreshing!",e.values,oldRefreshObj.values),Object.entries(e.values).forEach((t=>{const[o,a]=t;if(a){const t=configuration.elements[o];let n=a;if(Object.hasOwn(e,"override")&&Object.hasOwn(e.override,o)&&Object.hasOwn(e.override[o],"value")){const t=e.override[o].value;t&&"object"==typeof t?addErrorToLog({id:o,for:`${translateWord("lbl_override")}: <b>value</b>`,error:t.error,function:t.function}):n=e.override[o].value}"value"==t.source_display||"auto"==t.source_display?t.counter_animation?isNaN(n)?$(`#${o}_value`).html(generateMultiLineText(`${o}_value`,n,t.pos_x)):($(`#${o}_value`).children().length>0||$(`#${o}_value`).html(generateMultiLineText(`${o}_value`,0,t.pos_x)),$(`#${o}_value_line_0`).countTo(n,configuration.basic.animation_timer)):($(`#${o}_value`).children().length>0||$(`#${o}_value`).html(generateMultiLineText(`${o}_value`,0,t.pos_x)),$(`#${o}_value_line_0`).html(n)):$(`#${o}_value`).html(generateMultiLineText(`${o}_value`,n,t.pos_x)),"auto"==t.calculate_kw&&$(`#${o}_unit`).html(generateMultiLineText(`${o}_unit`," "+e.unit[o],t.pos_x))}})),oldRefreshObj.values=JSON.parse(JSON.stringify(e.values))),displayMode){try{o(e.fillValues,oldRefreshObj.fillValues)?appProperties.devMode&&console.debug("[Debug] [Refresh] No changes for 'Fill-Values'!"):(appProperties.devMode&&console.debug("[Debug] [Refresh] Changes for 'Fill-Values'. Refreshing!",e.fillValues,oldRefreshObj.fillValues),Object.entries(e.fillValues).forEach((t=>{const[o,a]=t,n=configuration.elements[o];if(n&&-1!=n.fill_type&&n.fill_value){let t=n.fill_value;Object.hasOwn(e,"override")&&Object.hasOwn(e.override,o)&&Object.hasOwn(e.override[o],"fillcolor")&&(t=e.override[o].fillcolor),t=t.replace(/[+-]?(?:\d*\.?\d+)(deg|rad|grad|turn)\s*,\s*|to\s+(top|bottom|left|right)(\s+left|\s+right)?\s*,\s*/gi,"-90deg,").toLocaleLowerCase(),t=parseColorString(t);const i=t.includes("gradient")?"gradient":"color",s=document.getElementById(`gradient_${o}_fill`),r=s?s.getAttribute("data-type"):null,l=s?parseInt(s.getAttribute("data-colorHash")):null,c=hashCode(t);if(l==c)"color"==r&&updateSingleGradient(o,a,n.fill_max,n.fill_type),"gradient"==r&&updateMultiGradient(o,a,n.fill_max,n.fill_type);else if("color"==i&&("color"==r?(s.lastChild.setAttribute("stop-color",t),s.setAttribute("data-colorHash",c)):(s&&s.remove(),generateSingleGradient(o,t,n.fill,n.fill_direction),console.log("[Config] Single-Fill-Gradient added for: "+o)),updateSingleGradient(o,a,n.fill_max,n.fill_type)),"gradient"==i){if("gradient"==r){$(s).children(".gradientStop").remove();const e=generateSVGGradient("","",t,!0);$(e).insertBefore(`#gradient_${o}_fill_transparent`),s.setAttribute("data-colorHash",c)}else{generateStyleProperty(o,"fill",t,!0);const e=document.getElementById(`gradient_${o}_fill`),a=n.fill&&!n.fill.match(/(?=(gradient|none))/gi)?n.fill:"rgba(0,0,0,0)";let i=document.createElementNS("http://www.w3.org/2000/svg","stop");i.setAttribute("id",`gradient_${o}_fill_transparent`),i.setAttribute("offset","0%"),i.setAttribute("stop-color",a),e.appendChild(i),e.setAttribute("gradientTransform","rotate("+n.fill_direction+",0.5,0.5)"),console.log("[Config] Multi-Fill-Gradient added for: "+o)}updateMultiGradient(o,a,n.fill_max,n.fill_type)}}})),oldRefreshObj.fillValues=JSON.parse(JSON.stringify(e.fillValues)))}catch(e){console.error("Could not apply Fill-Values. The following error was thrown: "+e)}try{o(e.img_href,oldRefreshObj.img_href)?appProperties.devMode&&console.debug("[Debug] [Refresh] No changes for 'Images'!"):(appProperties.devMode&&console.debug("[Debug] [Refresh] Changes for 'Images'. Refreshing!",e.img_href,oldRefreshObj.img_href),Object.entries(e.img_href).forEach((e=>{const[t,o]=e;"#"==o?$(`#${t}`).fadeOut(600).attr("href","img/bg_trans.png"):$(`#${t}`).attr("href",o).fadeIn(600)})),oldRefreshObj.img_href=JSON.parse(JSON.stringify(e.img_href)))}catch(e){console.error("Could not apply Image-Sources. The following error was thrown: "+e)}try{o(e.borderValues,oldRefreshObj.borderValues)?appProperties.devMode&&console.debug("[Debug] [Refresh] No changes for 'BorderValues'!"):(appProperties.devMode&&console.debug("[Debug] [Refresh] Changes for 'BorderValues'. Refreshing!",e.borderValues,oldRefreshObj.borderValues),Object.entries(e.borderValues).forEach((t=>{const[o,a]=t,n=new RegExp(/[+-]?(?:\d*\.?\d+)(deg|rad|grad|turn)\s*,\s*|to\s+(top|bottom|left|right)(\s+left|\s+right)?\s*,\s*/gi),i=configuration.elements[o];if(-1!=i.border_type&&i.border_value){const t=(e,t)=>{const n=document.getElementById(e);if(n){if(n.style.stroke.includes("url")){const o=document.getElementById(`gradient_${e}_stroke`),a=o?parseInt(o.getAttribute("data-colorHash")):null,n=hashCode(t);"gradient"==l&&a!=n&&generateStyleProperty(e,"stroke",t,!0,"url"),"color"==l&&(o&&o.remove(),$(`#${e}`).css("stroke",t))}else"gradient"==l&&generateStyleProperty(e,"stroke",t,!0,"url"),"color"==l&&$(`#${e}`).css("stroke",t);updateBorderFill(o,a,i.border_max,i.border_type,i.border_direction)}};let s=i.border_value,r=i.color;Object.hasOwn(e,"override")&&Object.hasOwn(e.override,o)&&(Object.hasOwn(e.override[o],"borderfillcolor")&&(r=e.override[o].borderfillcolor),Object.hasOwn(e.override[o],"bordercolor")&&(s=e.override[o].bordercolor)),s=s.replace(n,"-90deg,").toLocaleLowerCase(),r=r.replace(n,"-90deg,").toLocaleLowerCase(),s=parseColorString(s),r=parseColorString(r);const l=s.includes("gradient")?"gradient":"color";0==$(`#border_${o}`).length&&(addBorderFill(o,i.border_value,i.border_style,i.border_start),updateBorderFill(o,a,i.border_max,i.border_type,i.border_direction),console.log("[Config] Border-Fill added for: "+o)),t(`border_${o}`,r),t(o,s)}})),oldRefreshObj.borderValues=JSON.parse(JSON.stringify(e.borderValues)))}catch(e){console.error("Could not apply Border-Values. The following error was thrown: "+e)}try{o(e.animations,oldRefreshObj.animations)?appProperties.devMode&&console.debug("[Debug] [Refresh] No changes for 'Animations'!"):(appProperties.devMode&&console.debug("[Debug] [Refresh] Changes for 'Animations'. Refreshing!",e.animations,oldRefreshObj.animations),Object.entries(e.animations).forEach((([e,t])=>{let o="",a="",n="";const i=document.getElementById(e),s=document.getElementById(e.replace("anim","line")),r=configuration.animations[e]||{};if("dots"===t.type&&(o=t.stroke),"duration"===t.type&&(a=t.duration),"reverse"===t.option&&(n="reverse"),i.style.strokeDasharray=o,i.style.animationDirection=n,configuration.basic.enable_low_performance||"true"===appProperties.lowPerformance||(i.style.animationDuration=a+"ms"),configuration.basic.enable_line_animation)if(t.animation){const t=calculatePathAnimationTime(e);animatePath(e.replace("anim","line")),setTimeout((()=>{i.style.display="inline"}),t/330*1e3)}else i.style.display="none";else i.style.display=t.animation?"inline":"none",r.active_only&&(s.style.display=t.animation?"inline":"none");if(r.active_only&&!t.animation&&(i.style.display="none",configuration.basic.enable_line_animation)){const t=calculatePathAnimationTime(e);s.style.strokeDasharray="100%",s.style.animation=`eraseAnimatedLine ${t/340}s linear forwards`}})),oldRefreshObj.animations=JSON.parse(JSON.stringify(e.animations)))}catch(e){console.error("Could not apply Animations. The following error was thrown: "+e)}try{o(e.css,oldRefreshObj.css)?appProperties.devMode&&console.debug("[Debug] [Refresh] No changes for 'CSS'!"):(appProperties.devMode&&console.debug("[Debug] [Refresh] Changes for 'CSS'. Refreshing!",e.css,oldRefreshObj.css),Object.entries(e.css).forEach((e=>{const[t,o]=e;o.inactPos&&$("#"+t).removeClass(o.inactPos),o.inactNeg&&$("#"+t).removeClass(o.inactNeg),o.actPos&&$("#"+t).addClass(o.actPos),o.actNeg&&$("#"+t).addClass(o.actNeg)})),oldRefreshObj.css=JSON.parse(JSON.stringify(e.css)))}catch(e){console.error("Could not apply Own CSS-Values. The following error was thrown: "+e)}o(e.override,oldRefreshObj.override)?appProperties.devMode&&console.debug("[Debug] [Refresh] No changes for 'Override'!"):(appProperties.devMode&&console.debug("[Debug] [Refresh] Changes for 'Override'. Refreshing!",e.override,oldRefreshObj.override),applyElementOverrides(e.override),oldRefreshObj.override=JSON.parse(JSON.stringify(e.override)))}}catch(e){console.error("An error occured, while refreshing the data! The following Error was thrown: "+e)}}async function applyElementOverrides(e){try{Object.keys(e).length>0&&Object.entries(e).forEach((async e=>{const[t,o]=e;Object.keys(o).length>0&&Object.entries(o).forEach((e=>{const[o,a]=e,n=configuration.elements[t];switch(o.toLowerCase()){case"error":if(console.log("Error found!"),!1===a.status)return void addErrorToLog({id:t,for:`${translateWord("lbl_override")}: <b>Object</b>`,error:a.error,function:a.function});break;case"unit":!1===a.status?addErrorToLog({id:t,for:`${translateWord("lbl_override")}: <b>unit</b>`,error:a.error,function:a.function}):$(`#${t}_unit`).html(generateMultiLineText(`${t}_unit`,a,n.pos_x));break;case"append":$(`#${t}_append`).html(generateMultiLineText(`${t}_append`,a,n.pos_x));break;case"prepend":$(`#${t}_prepend`).html(generateMultiLineText(`${t}_prepend`,a,n.pos_x));break;case"value":case"bordercolor":case"borderfillcolor":case"fillcolor":break;case"img_url":let e=a;e.match(/\//)||(e=appProperties.socketURL+appProperties.namespace+"/userFiles/"+e),$(`#${t}`).attr("href",e);break;case"icon":iconHandler(t,a);break;case"pos_x":case"pos_y":if(n)if("text"==n.type){const e="pos_x"==o.toLocaleLowerCase()?"x":"y";$(`#${t}`).attr(e,a)}else addErrorToLog({id:t,for:`${translateWord("lbl_override")}: <b>pos_x/posy_y</b>`,error:"This property can only be used on text or datasource elements!",function:""});break;default:if(!1===a.status)return void addErrorToLog({id:t,for:`${translateWord("lbl_override")}: <b>CSS</b>`,error:a.error,function:a.function});let i=a;if(i.includes("gradient")){i=generateStyleProperty(t,o,a,!1,"url");const e=new RegExp(/(line_|anim_)/gi);t.match(e)&&gradientForStraightLine(t,t.replace(e,""))}$(`#${t}`).css(o,i)}}))}))}catch(e){console.error("Could not apply override rules. The following error was thrown: "+e)}}async function translateGoogle(e,t){try{$.ajax({minLength:1,url:"http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&dt=t",type:"GET",data:{tl:t,q:e},success:function(e){console.log(e[0][0][0])},error:function(){console.log("Error while translating into "+t)},timeout:3e3})}catch(e){console.log("Error!")}}function loadConfig(){const e=performance.now(),t=setTimeout((()=>{$("#loading_text_error").fadeIn("fast")}),4e3);console.log("[Config] Loading config for instance: "+appProperties.instance),loadAdditionalCSSFile(appProperties.theme),appProperties.isApple&&loadAdditionalCSSFile("webkit"),!appProperties.localMode||displayMode?socket.emit("getStates",subscribeObjID,(function(o,a){if(o)console.log(o),failedMessage(translateWord("failmsg_receiving_data"));else if(a){if(null!=a[subscribeObjID[0]]){console.log("[Config] Trying to load configuration from state!");try{if(configuration=JSON.parse(a[subscribeObjID[0]].val),0==Object.keys(configuration).length)throw new Error("No configuration found in state! Using basic configuration instead!");getBackups("backup_list"),setLoadedConfig()}catch(e){console.log("[Config] Error: No configuration in states found! Using basic configuration! "+e),basicConfig=!0,failedMessage(1==displayMode?translateWord("failmsg_no_config_display_mode"):translateWord("failmsg_no_config")),console.log("[Config] Loading Basic configuration from file!"),$.getJSON("js/basic_config.json",(function(e){configuration=e,configuration?(console.log("[Config] File loaded!"),console.debug(configuration),setLoadedConfig()):failedMessage(translateWord("failmsg_failed_config"))}))}clearTimeout(t)}else sprintf(systemDictionary.msg_instance_loading[systemLang],appProperties.instance),failedMessage(sprintf(systemDictionary.failmsg_instance[systemLang],appProperties.instance));if(null!=a[subscribeObjID[1]])try{if(console.log("[Config] Loading initial Data"),!a[subscribeObjID[1]].val)throw new Error("[Config] No data to display found! Please check, if layout is configured and saved properly!");refreshData(JSON.parse(a[subscribeObjID[1]].val))}catch(e){console.log("An error occured, while loading data! "+e)}globalAdapterOnline=null!=a[subscribeObjID[2]]&&a[subscribeObjID[2]].val}else failedMessage(translateWord("failmsg_no_values"));console.log(`[Config] Configuration loaded in ${performance.now()-e} ms`)})):(getBackups("backup_list"),configuration=localTest,configuration?(clearTimeout(t),console.log("[Config] Loading Local Config"),setLoadedConfig()):(basicConfig=!0,failedMessage(1==displayMode?translateWord("failmsg_no_config_display_mode"):translateWord("failmsg_no_config"))))}function generateStateTree(e,t){const o=performance.now();$(".title.folder, .title.state").off();let a=document,n=a.createElement("div"),i={};n.setAttribute("id","stateRoot"),$("#"+t).append(n);for(const t in e){let o=t.split("."),s="",r="";for(let l=0;l<o.length;l++)if(r=s,s=l>0?s+"."+o[l]:s+o[l],!a.getElementById(s)){let c=a.createElement("div");if(c.setAttribute("id",s),0==l)c.className="root",c.innerHTML=`<div class='title folder'><span class='type folderClosed'></span><span>${o[l]}</span></div>`,n.append(c);else if(c.className="sub","state"==e[t].type&&l==o.length-1)i[s]=e[t];else{let n="";l>1&&(n=Object.hasOwn(e[t],"common")&&"state"!=e[t].type?e[t].common.name:""),c.innerHTML=`<div class='title folder'><span class='type folderClosed'></span><span>${o[l]}</span><span>${n}</span></div>`,a.getElementById(r)&&a.getElementById(r).append(c)}}}for(const t in i){let o=t,n=o.lastIndexOf("."),s=o.slice(0,n),r=o.slice(n+1,o.length);if(a.getElementById(s)){let n=a.createElement("div"),l="",c="";l=Object.hasOwn(e[t],"common")?"object"==typeof e[t].common.name?e[t].common.name[systemLang]:e[t].common.name:"",c=Object.hasOwn(i[t],"common")&&i[t].common.role||"",n.setAttribute("id",o),n.className="sub",n.innerHTML=`<div class='title state'><span class='type file'></span><span>${r}</span><span>${l}</span><span>${i[t].type}</span><span>${c}</span><span>${i[t].common.type}</span></div>`,a.getElementById(s).append(n)}}$(".title.folder").click((function(){$("#"+t).scrollTo($(this).parents(".root"),1e3),$(this).find(".type").first().toggleClass("folderOpen folderClosed"),$(this).siblings().not(".filter_hidden").slideToggle("fast")})),$(".title.state").click((function(){$(".state").removeClass("active"),$(".state").children(".type").removeClass("file-selected"),$(this).toggleClass("active"),$(this).children(".type").addClass("file-selected"),console.log("Active state: "+$(this).parent().attr("id")),$("#select_state").prop("disabled",!1)})),document.querySelector(".stateExplorerFilter").onkeyup=null,document.querySelector(".stateExplorerFilter").onkeyup=async function(){const e=performance.now();let t=$("#stateRoot"),o=new RegExp(this.value.trim().toLowerCase(),"gi");if($(".state").removeClass("active").children(".type").removeClass("file-selected"),$("#select_state").prop("disabled",!0),this.value)setTimeout((function(){t.find(".title").each((function(e,t){$(t).text().match(o)?$(t).parents(".root, .sub").removeClass("filter_hidden").addClass("filter green"):$(t).parent().removeClass("filter green").addClass("filter_hidden")})),t.find(".sub:visible").siblings().each((function(e,t){$(t).hasClass("filter_hidden")?$(t).slideUp():$(t).slideDown()})),console.debug(`Filtered elements in ${performance.now()-e} ms`)}),0);else{t.find(".root, .sub").removeClass("filter filter_hidden green");let e=t.find(".sub:visible").siblings();e.slideDown(),e.children(".folder").children("span.folderOpen").parent().siblings().slideDown()}},$("#stateExplorer_placeholder").hide(),console.log(`StateTree build up in ${performance.now()-o} ms`)}async function openStateTree(e,t=""){globalIobObjectsLoaded||(iobObjects=await loadIobObjects(),generateStateTree(iobObjects,"stateExplorer")),$("#select_state").prop("disabled",!0),$("#"+e).scrollTop(0);let o=$("[id^='"+t+"']").first();$("#"+e).show(),o.length&&(o.children(".title.state").addClass("active"),o.children(".title.state").children(".type").addClass("file-selected"),o.parents(".sub").show(),o.parents(".sub").children(".sub").show(),o.siblings().show(),o.parents(".sub, .root").children("div.title").children(".type").toggleClass("folderOpen folderClosed"),$("#"+e).animate({scrollTop:o.offset().top-$("#stateExplorerContainer").height()/2}),$("#select_state").prop("disabled",!1))}function getElements(e,t){function o(e,t){return e.length<=t?e:e.substr(0,t)+" …"}let a={},n=[],i=[],s=[],r=[],l=[],c=[],d=[],u=[],g=[];Object.entries(configuration.elements).forEach((e=>{const[t,a]=e;switch(a.type){case"text":"datasource"==a.subType?i.push({id:a.id,text:`${o($(`#${t}`).text(),30)} (${-1!=a.source?configuration.datasources[a.source].alias:""} - ID: ${a.id})`}):n.push({id:a.id,text:`${o($(`#${t}`).text(),30)} (ID: ${a.id})`});break;case"circle":s.push({id:a.id,text:`ID ${a.id} (X: ${a.pos_x} Y: ${a.pos_y})`,y:a.pos_y});break;case"rect":r.push({id:a.id,text:`ID ${a.id} (X: ${a.pos_x} Y: ${a.pos_y})`,y:a.pos_y});break;case"icon":l.push({id:a.id,text:`ID ${a.id} (X: ${a.pos_x} Y: ${a.pos_y} - ${a.icon})`,y:a.pos_y});break;case"svg":d.push({id:a.id,text:`ID ${a.id} (X: ${a.pos_x} Y: ${a.pos_y})`,y:a.pos_y});break;case"image":u.push({id:a.id,text:`ID ${a.id} (X: ${a.pos_x} Y: ${a.pos_y})`,y:a.pos_y});break;case"foreignObject":g.push({id:a.id,text:`ID ${a.id} (X: ${a.pos_x} Y: ${a.pos_y})`,y:a.pos_y})}})),Object.entries(configuration.defs).forEach((e=>{const[t,o]=e;let a=o.d.substring(1,o.d.indexOf(" "));c.push({id:`line_${o.id}`,text:`ID line_${o.id} (X: ${a})`,d:a})})),a={opt_elm_circle:s.sort(((e,t)=>parseFloat(e.y)-parseFloat(t.y))),opt_elm_ds:i.sort(((e,t)=>parseFloat(e.id)-parseFloat(t.id))),opt_elm_icons:l.sort(((e,t)=>parseFloat(e.y)-parseFloat(t.y))),opt_elm_svg:d.sort(((e,t)=>parseFloat(e.y)-parseFloat(t.y))),opt_elm_image:u.sort(((e,t)=>parseFloat(e.y)-parseFloat(t.y))),opt_elm_fObj:g.sort(((e,t)=>parseFloat(e.y)-parseFloat(t.y))),opt_elm_lines:c.sort(((e,t)=>parseFloat(e.d)-parseFloat(t.d))),opt_elm_rect:r.sort(((e,t)=>parseFloat(e.y)-parseFloat(t.y))),opt_elm_text:n.sort(((e,t)=>e.text<t.text?-1:e.text>t.text?1:0))};let p=document.createDocumentFragment();for(var f of Object.keys(a)){let e=document.createElement("optgroup");for(var h of(e.label=translateWord(f),Object.keys(a[f]))){let o=new Option(a[f][h].text,a[f][h].id);o.selected=a[f][h].id==t,e.append(o)}p.appendChild(e)}const m=document.getElementById(e);m&&(m.innerHTML="",m.append(p))}function getDataSources(e,t,o=!0){let a,n=document.createDocumentFragment();if(o&&n.append(new Option(translateWord("opt_please_choose"),"-1")),Object.keys(configuration.datasources).length>0){const e=Object.entries(configuration.datasources).sort((([,e],[,t])=>e.alias.toLowerCase()<t.alias.toLowerCase()?-1:e.alias.toLowerCase()>t.alias.toLowerCase()?1:0));for(var i of e){if(a=new Option(`${i[1].alias} (${i[1].source})`,i[0]),"object"==typeof t)for(var s in t)t[s]==i[0]&&(a.selected=!0);else a.selected=i[0]==t;n.appendChild(a)}}else a=new Option(translateWord("no_ds_added"),"-1"),a.disabled=!0,a.title=translateWord("ex_no_ds_added"),n.appendChild(a);const r=document.getElementById(e);r&&(r.innerHTML="",r.append(n))}function checkDatasourcesInUse(e){let t={},o=0;return Object.entries(configuration.elements).forEach((a=>{const[n,i]=a;Array.isArray(i.add)&&-1!==i.add.map((e=>parseInt(e))).indexOf(e)&&(t[o++]={id:i.id,type:translateWord(`lbl_${i.subType?i.subType:i.type}`),reason:translateWord("failmsg_delete_source_as_addition")}),Array.isArray(i.subtract)&&-1!==i.subtract.map((e=>parseInt(e))).indexOf(e)&&(t[o++]={id:i.id,type:translateWord(`lbl_${i.subType?i.subType:i.type}`),reason:translateWord("failmsg_delete_source_as_subtraction")}),i.source==e&&(t[o++]={id:i.id,type:translateWord(`lbl_${i.subType?i.subType:i.type}`),reason:translateWord("failmsg_delete_source_as_source")}),i.source_action==e&&(t[o++]={id:i.id,type:translateWord(`lbl_${i.subType?i.subType:i.type}`),reason:translateWord("failmsg_delete_source_as_source_action")})})),Object.entries(configuration.calculation.consumption).forEach((a=>{const[n,i]=a;"boolean"!=typeof i&&i===e&&(t[o++]={id:translateWord(`lbl_consumption_${n}`).replace("*",""),type:translateWord(`lbl_consumption_${n}`).replace("*",""),reason:translateWord("failmsg_delete_source_as_consumption")}),Array.isArray(i)&&"production"==n&&-1!=i.map((e=>parseInt(e))).indexOf(e)&&(t[o++]={id:translateWord(`lbl_consumption_${n}`).replace("*",""),type:translateWord(`lbl_consumption_${n}`).replace("*",""),reason:translateWord("failmsg_delete_source_as_production")})})),Object.entries(configuration.calculation.battery).forEach((a=>{const[n,i]=a;"boolean"!=typeof i&&i==e&&(t[o++]={id:translateWord(`lbl_battery_${n}`).replace("*",""),type:translateWord(`lbl_battery_${n}`).replace("*",""),reason:translateWord("failmsg_delete_source_as_calculation")})})),Object.entries(configuration.animations).forEach((a=>{const[n,i]=a;i.source==e&&(t[o++]={id:n.replace("anim","line"),type:translateWord("lbl_animation"),reason:translateWord("failmsg_delete_source_as_source")})})),t}function receiveImage(e){return new Promise(((t,o)=>{if(e){let o=new Image;if(e.startsWith("{")){console.debug("[Image] Loading image URL via ioBroker state: "+e);let a=e.substring(1,e.lastIndexOf("}"));socket.emit("getState",a,(function(e,a){a?(o.onload=()=>t(a.val),o.onerror=()=>t(""),null!=a.val&&""!=a.val?o.src=a.val:displayMode?(console.debug('[Image] State is empty! Returning "#"!'),t("#")):(console.debug('[Image] State is empty! Returning "Not found"!'),t("img/icon_not_found.png"))):console.log("[Image] A valid picture URL under the given source could not be found!")}))}else e.match(/\//)||(e=appProperties.socketURL+appProperties.namespace+"/userFiles/"+e,console.debug("Loading image from gallery: "+e)),o.onload=()=>t(e),o.onerror=()=>t("img/tmp_img.png"),o.src=e}else t("img/tmp_img.png");displayMode&&$(".type_image").removeClass("draggable")}))}function updateDataSources(){for(var e of(console.debug("Refreshing Datasources!"),Object.keys(configuration.calculation)))for(var t of Object.keys(configuration.calculation[e]))if("production"===t)getDataSources(`calculation.${e}.${t}`,configuration.calculation[e][t],!1),$(`#calculation\\.${e}\\.${t}`).multiselect(multiselect_options);else"boolean"!=typeof configuration.calculation[e][t]&&getDataSources(`calculation.${e}.${t}`,configuration.calculation[e][t],!0)}function calculatePathAnimationTime(e){const t=document.getElementById(e);if(!t)return 0;const o=t.getAttribute("xlink:href");return document.querySelector(o).getTotalLength()}function animatePath(e){const t=document.getElementById(e),o=calculatePathAnimationTime(e);t.style.display="inline",t.style.strokeDasharray=o,t.style.strokeDashoffset=o,t.style.animation=`drawAnimatedLine ${o/340}s linear forwards`}function setLoadedConfig(e=!1){let t=0;if(startIconObserver(),configuration.basic.enable_icon_proxy?appProperties.hostname.match(/iobroker\.pro|iobroker\.net/)?(console.log("[Config] Using direct load via iconify-API!"),loadAdditionalJSFile("js/iconify.min.js")):(console.log("[Config] Using Icon-Proxy for Icons"),$(".iconify").each((function(){loadIconViaProxy($(this).data("icon"),$(this))}))):(console.log("[Config] Using direct load via iconify-API!"),loadAdditionalJSFile("js/iconify.min.js")),e&&$("#style_user").empty(),$("#style_user").append(configuration.basic.styles),!displayMode){for(var o of(t=100,resizeSVG(),aceCSS=ace.edit("own_css"),aceCSS.session.setMode("ace/mode/css"),aceCSS.setTheme("ace/theme/"+appProperties.aceEditorTheme[appProperties.colorScheme]),aceCSS.setOptions({enableBasicAutocompletion:!0,enableSnippets:!0,enableLiveAutocompletion:!0,enableAutoIndent:!0}),aceCSS.on("change",(function(){configuration.basic.styles=aceCSS.getSession().getValue(),$("#style_user").empty().append(configuration.basic.styles)})),Object.entries(configuration.basic).forEach((e=>{const[t,o]=e;if(o)if("object"==typeof o)for(var a of Object.keys(configuration.basic[t]))$(`#basic\\.${t}\\.${a}`).hasClass("color")?$(`#basic\\.${t}\\.${a}`)[0].jscolor.fromString(configuration.basic[t][a]):$(`#basic\\.${t}\\.${a}`).val(configuration.basic[t][a]);else switch(t){default:switch(typeof o){case"boolean":$(`#basic\\.${t}`).prop("checked",o);break;case"number":case"string":$(`#basic\\.${t}`).val(o)}break;case"enable_grid":$(`#basic\\.${t}`).prop("checked",o),o&&$("#help_grid").fadeIn("fast");break;case"height":$("#basic\\.height\\.slider").val(o),$("#basic\\.height").val(o),resizeSVG();break;case"width":$("#basic\\.width").val(o),$("#basic\\.width\\.slider").val(o),resizeSVG();break;case"background_color":$("#basic\\.background_color")[0].jscolor.fromString(o);break;case"styles":aceCSS.setValue(configuration.basic.styles,-1),aceCSS.resize();break;case"animation_timer":$("#basic\\.animation_timer").val(configuration.basic.animation_timer?configuration.basic.animation_timer:1e3)}})),Object.keys(configuration.animation)))$(`#animation\\.${o}`).val(configuration.animation[o]);for(var o of Object.keys(configuration.animation_configuration))$(`#animation_configuration\\.${o}`).val(configuration.animation_configuration[o]);for(var o of Object.keys(configuration.line))$(`#line\\.${o}`).val(configuration.line[o]);for(var o of Object.keys(configuration.calculation))for(var a of Object.keys(configuration.calculation[o]))switch(a){default:getDataSources(`calculation.${o}.${a}`,configuration.calculation[o][a],!0);break;case"production":getDataSources(`calculation.${o}.${a}`,configuration.calculation[o][a],!1),$(`#calculation\\.${o}\\.${a}`).multiselect(multiselect_options);break;case"charge_prop":case"discharge_prop":case"gridFeed_prop":case"gridConsume_prop":case"batteryCharge_prop":case"batteryDischarge_prop":$(`#calculation\\.${o}\\.${a}`).prop("checked",configuration.calculation[o][a])}for(var o of(configuration.calculation.battery.dod>=0&&null!=configuration.calculation.battery.dod&&configuration.calculation.battery.capacity>=0&&null!=configuration.calculation.battery.capacity&&configuration.calculation.battery.percent>=0&&null!=configuration.calculation.battery.percent&&configuration.calculation.battery.charge>=0&&null!=configuration.calculation.battery.charge&&configuration.calculation.battery.discharge>=0&&null!=configuration.calculation.battery.discharge&&(console.debug("[Calculation] Battery configured!"),$("#calculation\\.battery\\.status").addClass("green").removeClass("red").text(translateWord("txt_calculation_succ"))),0!=configuration.calculation.consumption.production.indexOf(-1)&&configuration.calculation.consumption.production.length>0&&configuration.calculation.consumption.gridFeed>=0&&null!=configuration.calculation.consumption.gridFeed&&configuration.calculation.consumption.gridConsume>=0&&null!=configuration.calculation.consumption.gridConsume&&(console.debug("[Calculation] Consumption configured!"),$("#calculation\\.consumption\\.status").addClass("green").removeClass("red").text(translateWord("txt_calculation_succ"))),Object.keys(configuration.datasources)))addDataSourceRow(o,!0);configuration.basic.enable_ds_autocomplete&&$("#elm_ds_source").autocomplete(dataSourceAutocompleteOptions)}if(Object.hasOwn(configuration,"elements")){$(".placeholders").empty();let i=[];for(var o in configuration.elements)i.push({key:o,position:configuration.elements[o].position||0});i.sort((function(e,t){return e.position-t.position}));for(var n=0;n<i.length;n++)svgElement(configuration.elements[i[n].key],!1);for(var o of Object.keys(configuration.defs))svgElement(configuration.defs[o],!1);for(var o of Object.keys(configuration.lines))svgElement(configuration.lines[o],!1);for(var o of Object.keys(configuration.animations))svgElement(configuration.animations[o],!1);if(updateLineAnimation(),displayMode){if(configuration.basic.background_color&&(console.debug("Setting background color!"),$("#style_user").append(`html,body { background-color: ${configuration.basic.background_color}; }`)),$("#svg_display").attr({viewBox:"0 0 "+configuration.basic.width+" "+configuration.basic.height}),$(".all_elements").removeClass("anim_element no_animation"),$("#config_link").on("click",(function(){window.location.replace("configuration.html?instance="+appProperties.instance)})),$("#info_error_area").hide(),globalError=[],$("#config_link").toggle(configuration.basic.enable_config_icon),configuration.basic.enable_low_performance||"true"===appProperties.lowPerformance){console.log("[Config] Low performance mode activated!");const s=document.querySelectorAll(".type_animation"),r=-136,l=Math.abs(r)/80,c=new Map;function d(){s.forEach((e=>{if("none"===getComputedStyle(e).display)return;const t="reverse"===e.style.animationDirection;let o=c.get(e);o=t?o>=0?r:o:o<=r?0:o,e.style.strokeDashoffset=o,c.set(e,o+(t?l:-l))})),setTimeout(d,20)}s.forEach((e=>{c.set(e,0)})),setTimeout(d,20)}else $(".type_animation").addClass("animation animation_cfg");e?console.log("Applying config without re-adding socket listener!"):displayListener()}basicConfig||displayMode||successMessage(translateWord("succ_msg_loading")),setTimeout((()=>{$("#loading").fadeOut("fast")}),t)}else successMessage(translateWord("succ_msg_loading_basic")),setTimeout((()=>{$("#loading").fadeOut("fast")}),t),$("#config_link > a").attr("href","configuration.html?instance="+appProperties.instance).show()}function updateLineAnimation(){$("#style_animation").empty().append(`.line {stroke-width:${configuration.line.stroke_width}px; stroke:${configuration.line.stroke}; }`).append(`.animation {stroke:${configuration.animation.stroke}; stroke-dasharray:${configuration.animation.stroke_dasharray};`).append(`stroke-width:${configuration.animation.stroke_width}px; stroke-linecap:${configuration.animation.stroke_linecap}; }`).append(`.animation_cfg {animation-duration:${configuration.animation.animation_duration}ms; animation-timing-function:${configuration.animation.animation_timing_function}; }`),displayMode&&$("#style_animation").append(".type_animation {display: none;}")}function linePreview(e){let t="",o=136,a=parseInt($("#animation\\.stroke_width").val()),n=parseInt($("#animation_configuration\\.dots").val()),i=parseInt($("#animation_configuration\\.distance").val()),s=parseInt($("#animation_configuration\\.length").val()),r=parseInt($("#line\\.stroke_width").val()),l=parseInt($("#animation\\.animation_duration").val()),c=$("#animation\\.stroke_linecap").val(),d=$("#animation\\.animation_timing_function").val();for(let e=0;e<n;e++)i>0&&s>0&&(t+=s+" ",e!=n-1&&(t+=i+" ",o-=i),o-=s);n>0&&s>0&&i&&(t+=" "+o),o<0&&$("#"+e).val($("#"+e).val()-1),configuration.animation={stroke_dasharray:t,stroke_width:a,animation_duration:l,stroke_linecap:c,animation_timing_function:d},configuration.animation_configuration={dots:n,distance:i,length:s},configuration.line={stroke_width:r,stroke:"#000000"},updateLineAnimation()}function successMessage(e){const t=2e3+20*e.length,o=$("#message_success");o.html(e),o.stop().fadeIn("middle",(function(){$(this).delay(t).fadeOut("middle",(function(){$(this).html("")}))}))}function failedMessage(e){const t=2e3+20*e.length,o=$("#message_failed");o.html(e),o.stop().fadeIn("middle",(function(){$(this).delay(t).fadeOut("middle",(function(){$(this).html("")}))}))}function resizeSVG(){const e=document.getElementById("svg_config");e.setAttribute("width",configuration.basic.width),e.setAttribute("height",configuration.basic.height),e.setAttribute("viewBox",`0 0 ${configuration.basic.width} ${configuration.basic.height}`)}function lineConnection(e){const t=[];for(const o in configuration.defs){const[,a,n]=o.split("_");a!=e&&n!=e||t.push({path:o,from:a,to:n})}return t}function checkSVGSize(e,t){function o(e,t){const o=getElementCoords(e.id),a=Number("width"===t?o.width:o.height);return("width"===t?o.x:o.y)+("circle"===o.type||"text"===o.type?a/2:a)+o.stroke}function a(e){return Object.values(configuration.elements).reduce(((t,a)=>o(a,e)>o(t,e)?a:t))}const n=a("width"),i=a("height");return{width:e>o(n,"width"),height:t>o(i,"height")}}function checkElementBounds(e,t){const o=configuration.basic,a=Number(e.stroke)/2,n="circle"==e.type||"text"==e.type?t.x-Number(e.width)/2-a:t.x-a,i=n+Number(e.width)+2*a,s="circle"==e.type||"text"==e.type?t.y-Number(e.height)/2-a:t.y-a,r=s+Number(e.height)+2*a;return{x:n>=0&&i<=o.width,y:s>=0&&r<=o.height}}function moveSVGElement(e,t){const o=configuration.elements[e.id],a="circle"==e.type?"cx":"x",n="circle"==e.type?"cy":"y",i=checkElementBounds(e,t).x,s=checkElementBounds(e,t).y;if(i&&($("#"+e.id).attr(a,t.x),o.pos_x=t.x,Object.hasOwn(o,"text")&&o.text.match(/\n/gi)&&$("#"+e.id).children().attr("x",t.x),(Object.hasOwn(o,"prepend")||Object.hasOwn(o,"append")||Object.hasOwn(o,"unit"))&&$(`#${e.id}_prepend, #${e.id}_append, #${e.id}_value, #${e.id}_unit`).children().each((function(){$(this).attr("x")&&$(this).attr("x",t.x)}))),s&&($("#"+e.id).attr(n,t.y),o.pos_y=t.y),appProperties.isApple&&o.degree&&$("#"+e.id).attr("transform",`rotate(${o.degree}, ${o.pos_x}, ${o.pos_y})`),e.connections.length>0)for(var r of e.connections)calculatePath(r.path,r.from,r.to);if(i&&s)return!0}function getMousePosition(e){var t=document.getElementById("svg_config").getScreenCTM();return e.touches&&(e=e.touches[0]),{x:parseInt((e.clientX-t.e)/t.a),y:parseInt((e.clientY-t.f)/t.d)}}function getElementCoords(e,t,o={}){const a=configuration.elements[e];let{width:n=1,height:i=1,radius:s=0,stroke:r=0}={...a,...o},l=Number(a.pos_x),c=Number(a.pos_y),d=0,u=0,g=t?getMousePosition(t):{x:0,y:0},p=i;switch(g.x-=l,g.y-=c,a.type){case"circle":n=2*s,i=n,d=l,u=c;break;case"text":const t=document.getElementById(e),o=t.getBoundingClientRect();let r=4;if(t.classList.contains("type_text")){const e=t.children;e.length>1&&(r+=e.length*a.font_size)}if(t.classList.contains("type_datasource")){const e=t.children[1].children;e.length>1&&(r+=e.length*a.font_size)}n=Math.round(o.width),i=Math.round(o.height)-r,p=i,d=l,u=c}return{id:Number(e),cx:d,cy:u,x:l,y:c,width:n,height:i,radius:s,stroke:r,coordHeight:p,connections:lineConnection(e),offset:g,type:a.type}}function connectorAngle(e){return(e-90)*(Math.PI/180)}function showConnectionPoints(e=!0){const t=$("#connection_points");e?(t.empty(),$(".connector").each((function(){const e=$(this).attr("id"),o={};o[e]={};const a=$(this).prop("tagName").toLowerCase();let n=function(e,t){if("circle"===t){const t=parseInt(e.attr("r"));return{r:t,cx:parseInt(e.attr("cx")),cy:parseInt(e.attr("cy")),width:2*t,height:2*t,x:parseInt(e.attr("cx"))-t,y:parseInt(e.attr("cy"))-t}}if("rect"===t)return{width:parseInt(e.attr("width")),height:parseInt(e.attr("height")),x:parseInt(e.attr("x")),y:parseInt(e.attr("y"))}}($(this),a);"circle"===a?function(e,{cx:t,cy:o,r:a}){const n=["top_left","top_right","right_top","right_bottom","bottom_left","bottom_right","left_bottom","left_top"];[340,20,70,110,200,160,250,290].forEach(((i,s)=>{e[n[s]]={x:t+a*Math.cos(connectorAngle(i)),y:o+a*Math.sin(connectorAngle(i))}}))}(o[e],n):"rect"===a&&function(e,{width:t,height:o,x:a,y:n}){e.top_left={x:a+t/2-20,y:n},e.top_right={x:a+t/2+20,y:n},e.left_top={x:a,y:n+o/2-20},e.left_bottom={x:a,y:n+o/2+20},e.right_top={x:a+t,y:n+o/2-20},e.right_bottom={x:a+t,y:n+o/2+20},e.bottom_left={x:a+t/2-20,y:n+o},e.bottom_right={x:a+t/2+20,y:n+o}}(o[e],n),function(e,{width:t,height:o,x:a,y:n}){e.top={x:a+t/2,y:n},e.left={x:a,y:n+o/2},e.right={x:a+t,y:n+o/2},e.bottom={x:a+t/2,y:n+o}}(o[e],n),function(e,t,o){Object.entries(e).forEach((([e,a])=>{const n=document.createElementNS("http://www.w3.org/2000/svg","circle");n.setAttribute("class","connPoints clickable"),n.setAttribute("cx",a.x),n.setAttribute("cy",a.y),n.setAttribute("r",5),n.setAttribute("data-slot",e),n.setAttribute("data-element",t),o.append(n)}))}(o[e],e,t)}))):t.empty()}function getSlots(e){const t=Math.floor(e.width/2),o=Math.floor(e.height/2),a=Math.floor(e.stroke/2);return{top:{x:e.cx?e.cx:e.x+t,y:e.cy?e.cy-t-a:e.y-a,direction:"vertical"},right:{x:e.cx?e.cx+t+a:e.x+e.width+a,y:e.cy?e.cy:e.y+o,direction:"horizontal"},bottom:{x:e.cx?e.cx:e.x+t,y:e.cy?e.cy+t+a:e.y+e.height+a,direction:"vertical"},left:{x:e.cx?e.cx-t-a:e.x-a,y:e.cy?e.cy:e.y+o,direction:"horizontal"}}}function getSpecialSlots(e,t){const o=Math.floor(e.width/2),a=Math.floor(e.height/2),n=Math.floor(e.stroke/2);let i=getSlots(e);return e.radius>0?(i.top_left={x:e.cx+e.radius*Math.cos(connectorAngle(340)),y:e.cy+e.radius*Math.sin(connectorAngle(340))-n,direction:"vertical"},i.top_right={x:e.cx+e.radius*Math.cos(connectorAngle(20)),y:e.cy+e.radius*Math.sin(connectorAngle(20))-n,direction:"vertical"},i.right_top={x:e.cx+e.radius*Math.cos(connectorAngle(70))+n,y:e.cy+e.radius*Math.sin(connectorAngle(70)),direction:"horizontal"},i.right_bottom={x:e.cx+e.radius*Math.cos(connectorAngle(110))+n,y:e.cy+e.radius*Math.sin(connectorAngle(110)),direction:"horizontal"},i.bottom_left={x:e.cx+e.radius*Math.cos(connectorAngle(200)),y:e.cy+e.radius*Math.sin(connectorAngle(200))+n,direction:"vertical"},i.bottom_right={x:e.cx+e.radius*Math.cos(connectorAngle(160)),y:e.cy+e.radius*Math.sin(connectorAngle(160))+n,direction:"vertical"},i.left_bottom={x:e.cx+e.radius*Math.cos(connectorAngle(250))-n,y:e.cy+e.radius*Math.sin(connectorAngle(250)),direction:"horizontal"},i.left_top={x:e.cx+e.radius*Math.cos(connectorAngle(290))-n,y:e.cy+e.radius*Math.sin(connectorAngle(290)),direction:"horizontal"}):(i.top_left={x:e.x+o-20,y:e.y-n,direction:"vertical"},i.top_right={x:e.x+o+20,y:e.y-n,direction:"vertical"},i.right_top={x:e.x+e.width+n,y:e.y+a-20,direction:"horizontal"},i.right_bottom={x:e.x+e.width+n,y:e.y+a+20,direction:"horizontal"},i.bottom_left={x:e.x+o-20,y:e.y+e.height+n,direction:"vertical"},i.bottom_right={x:e.x+o+20,y:e.y+e.height+n,direction:"vertical"},i.left_top={x:e.x-n,y:e.y+a-20,direction:"horizontal"},i.left_bottom={x:e.x-n,y:e.y+a+20,direction:"horizontal"}),{spec:i[t]}}async function connectElements(e){return new Promise(((t,o)=>{const a=$(".line:not(.faded_out, .preview)");let n,i,s,r;$(".connector").length>=2?($(`