');
$("body").append(div);
$(div).dialog({
dialogClass:"no-close", modal:true, width:"auto", closeOnEscape:true,
maxWidth:$(window).width()*0.9, maxHeight:$(window).height()*0.9,
buttons: [
{text:"Rename", click:function(){
var nn = $(div).find("input").val();
if(!nn.match(/^[a-z0-9._]*$/i))
return FW_okDialog("Illegal characters in the new name");
location.href=addcsrf(FW_root+"?cmd=rename "+dev+" "+nn+"&detail="+nn);
}},
{text:"Cancel", click:doClose} ],
close: doClose
});
function
doClose()
{
$(this).dialog("close"); $(div).remove();
}
}
// Show the webCmd list in a dialog if: smallScreen & hiddenroom=detail & room
function
FW_smallScreenCommands()
{
if($("div#menu select").length == 0 || // not SmallScreen
$("div#content").attr("room") == undefined || // not room Overview
$("div#content div.col1 a").length > 0) // no hiddenroom=detail
return;
$("div#content div.col1").each(function(){
var tr = $(this).closest("tr");
if($(tr).find("> td").length <= 2)
return;
$(this).html("
");
if(row++ == 0) {
$(t).find("tr:last").append($(this).find("a").html());
} else {
$(this).attr("data-orig", 1);
this.orig=$(this).parent();
$(t).find("tr:last").append($(this).detach());
}
});
FW_okDialog(t, this, function(){
$("#FW_okDialog [data-orig]").each(function(){
$(this).detach().appendTo(this.orig);
});
});
});
});
}
if(window.jQuery) {
$(document).ready(FW_jqueryReadyFn);
} else {
// FLOORPLAN compatibility
loadScript("pgm2/jquery.min.js", function() {
loadScript("pgm2/jquery-ui.min.js", function() {
FW_jqueryReadyFn();
}, true);
}, true);
}
// FLOORPLAN compatibility
function
FW_delayedStart()
{
setTimeout("FW_longpoll()", 100);
}
var FW_logStack=[];
function
log(txt)
{
var d = new Date();
var ms = ("000"+(d.getMilliseconds()%1000));
ms = ms.substr(ms.length-3,3);
var lTxt = d.toTimeString().substring(0,8)+"."+ms+" "+txt;
if(typeof window.console != "undefined")
console.log(lTxt);
if(FW_jsLog==1 && FW_longpollType == "websocket") {
FW_logStack.push(txt);
if(FW_pollConn && FW_pollConn.readyState == FW_pollConn.OPEN) {
while(FW_logStack.length) {
txt = '{Log 1, "jsLog: '+FW_logStack.shift().replace(/"/g, "'")+'"}';
console.log(txt);
FW_pollConn.send(txt);
}
}
}
}
function
addcsrf(arg)
{
if(typeof FW_csrfToken != "undefined") {
arg = arg.replace(/&fwcsrf=[^&]*/,'');
arg += '&fwcsrf='+encodeURIComponent(FW_csrfToken);
}
return arg;
}
function
FW_csrfRefresh(callback)
{
log("FW_csrfRefresh, last was "+(FW_csrfOk ? "ok":"bad"));
if(!FW_csrfOk) // avoid endless loop
return;
$.ajax({
url:location.pathname+"?XHR=1",
success: function(data, textStatus, request){
FW_csrfToken = request.getResponseHeader('x-fhem-csrftoken');
FW_csrfOk = false;
if(callback)
callback();
}
});
}
var FW_cmdStack=[];
function
FW_cmd(arg, callback, rep)
{
if(arg.length < 120)
log("FW_cmd:"+arg);
else
log("FW_cmd:"+arg.substr(0,120)+"...");
$.ajax({
url:addcsrf(arg)+'&fw_id='+$("body").attr('fw_id'),
headers: { "cache-control": "no-cache" },
dataType: "text",
method:'POST',
success: function(data, textStatus, req){
FW_csrfOk = true;
if(callback)
callback(req.responseText);
else if(req.responseText)
FW_errmsg(req.responseText, 5000);
var todo = FW_cmdStack.shift();
if(todo) {
log("FW_cmd retry #"+todo.rep);
FW_cmd(todo.arg, todo.callback, todo.rep);
}
},
error:function(xhr, status, err) {
// iOS 13+ is not queueing requests, have to do it myself. Forum #116962
if(xhr.status == 0 && xhr.readyState == 0 && (!rep || rep < 10)) {
FW_cmdStack.push({ arg:arg, callback:callback, rep:(rep?rep+1:1)});
} else if(xhr.status == 400 && typeof FW_csrfToken != "undefined") {
FW_csrfToken = "";
FW_csrfRefresh(function(){FW_cmd(arg, callback)});
} else {
log("FW_cmd error: "+status+"/"+JSON.stringify(xhr));
}
}
});
}
function
FW_errmsg(txt, timeout)
{
log("ERRMSG:"+txt+"<");
var errmsg = document.getElementById("errmsg");
if(!errmsg) {
if(txt == "")
return;
errmsg = document.createElement('div');
errmsg.setAttribute("id","errmsg");
document.body.appendChild(errmsg);
}
if(txt == "") {
document.body.removeChild(errmsg);
return;
}
errmsg.innerHTML = txt;
if(timeout)
setTimeout("FW_errmsg('')", timeout);
}
function
FW_okDialog(txt, parent, removeFn)
{
$("#FW_okDialog").remove();
var div = $("
");
$(div).html(txt);
$("body").append(div);
var oldPos = $("body").scrollTop();
$(div).dialog({
dialogClass:"no-close", modal:true, width:"auto", closeOnEscape:true,
maxWidth:$(window).width()*0.9, maxHeight:$(window).height()*0.9,
buttons: [{text:"OK", click:function(){
$(this).dialog("close");
if(removeFn)
removeFn();
$(div).remove();
}}]
});
FW_replaceWidgets(div);
$(div).find("a").each(function(){FW_replaceLink(this);}); //Forum #33766
if(parent)
$(div).dialog( "option", "position", {
my: "left top", at: "right bottom",
of: parent, collision: "flipfit"
});
setTimeout(function(){$("body").scrollTop(oldPos);}, 1); // Not ideal.
}
function
FW_menu(evt, el, arr, dis, fn, embedEl)
{
if(!embedEl)
evt.stopPropagation();
if($("#fwmenu").length) {
delfwmenu();
return;
}
var html = '';
$("body").append(html);
function
delfwmenu()
{
$("ul#fwmenu").remove();
$('html').unbind('click.fwmenu');
}
var wt = $(window).scrollTop();
$("#fwmenu")
.menu({
select: function(e,ui) { // changes the scrollTop();
e.stopPropagation();
fn($(e.currentTarget).find("[row]").attr("row"));
delfwmenu();
setTimeout(function(){ $(window).scrollTop(wt) }, 1); // Bug in select?
}
});
var off = $(el).offset();
if(embedEl) {
var embOff = $(embedEl).offset();
off.top += embOff.top;
off.left += embOff.left;
}
var dH = $("#fwmenu").height(), dW = $("#fwmenu").width(),
wH = $(window).height(), wW = $(window).width();
var ey = off.top+dH+20, ex = off.left+dW;
if(ex>wW && ey>wH) { off.top -= dH; off.left -= (dW+16);
} else if(ey > wH) { off.top -= dH; off.left += 20;
} else if(ex > wW) { off.left -= (dW+16);
} else { off.top += 20;
}
$("#fwmenu").css(off);
$('html').bind('click.fwmenu', function() { delfwmenu(); });
}
function
FW_getLink(el)
{
var attr = $(el).attr("href");
if(!attr) {
attr = $(el).attr("onclick"); // Tablet/smallScreen version
if(!attr)
return "";
attr = attr.replace(/^location.href='/,'');
attr = attr.replace(/'$/,'');
}
return attr;
}
function
FW_replaceLink(el)
{
var attr = FW_getLink(el);
if(!attr)
return;
var ma = attr.match(/^(.*\?)(cmd[^=]*=.*)$/);
if(ma == null || ma.length == 0 || !ma[2].match(/=(save|set)/)) {
ma = attr.match(new RegExp("^"+FW_root)); // Avoid "Connection lost" @iOS
if(ma) {
$(el).click(function(e) {
// Open link in window/tab, Forum #39154
if(e.shiftKey || e.ctrlKey || e.metaKey || e.button == 1)
return;
e.preventDefault();
FW_leaving = 1;
if($(el).attr("target") == "_blank") {
window.open(attr, '_blank').focus();
} else {
location.href = attr;
}
});
}
return;
}
$(el).removeAttr("href");
$(el).removeAttr("onclick");
$(el).click(function() {
attr = attr.replace(/&.*$/,''); // remove unnecessary params, forum: #97351
FW_cmd(attr+"&XHR=1", function(txt){
if(!txt)
return;
if(ma[2].match(/=set/)) // Forum #38875
FW_okDialog('
'+txt+'', el);
else
FW_errmsg(txt, 5000);
});
});
$(el).css("cursor", "pointer");
}
function
FW_htmlQuote(text)
{
return text.replace(/&/g, '&') // Same as in 01_FHEMWEB
.replace(//g, '>');
}
function
FW_inlineModify() // Do not generate a new HTML page upon pressing modify
{
var cm;
if( typeof AddCodeMirror == 'function' ) {
// init codemirror for FW_style edit textarea
AddCodeMirror($('textarea[name="data"]'));
}
$('#DEFa').click(function(){
var old = $('#edit').css('display');
$('#edit').css('display', old=='none' ? 'block' : 'none');
$('#disp').css('display', old=='none' ? 'none' : 'block');
if( typeof AddCodeMirror == 'function' ) {
var s=document.getElementById("edit").getElementsByTagName("textarea");
AddCodeMirror(s[0], function(pcm) {cm = pcm;});
}
});
var hr = $("body").attr("data-hiddenroom");
if(!hr || !hr.match(/\binput\b/)) {
$("table.internals div.dname").each(function(){
if($(this).text() == "NAME") {
var dev = $(this).attr("data-name");
var a=$("NAME ");
$(this).html(a);
a.click(function(){ FW_renameDevice(dev) });
}
});
}
// Set and attr
$("div input.psc[type=submit]:not(.get)").click(function(e){
e.preventDefault();
var frm = $(this).closest("form");
var newDef = typeof cm !== 'undefined' ?
cm.getValue() : frm.find("textarea").val();
var cmd = $(this).attr("name")+"="+$(this).attr("value")+" "+newDef;
var isDef = true, reloadIfOk = false;
if(newDef == undefined || $(this).attr("value").indexOf("modify") != 0) {
isDef = false;
var div = $(this).closest("div.makeSelect");
var devName = $(div).attr("dev"),
cmd = $(div).attr("cmd");
var sel = frm.find("select");
var arg = $(sel).val();
var ifid = (devName+"-"+arg).replace(/([^_a-z0-9])/gi,
function(m){ return "\\"+m });
if($(".dval[informid="+ifid+"]").length == 0) {// No reading with this name
if(cmd == "attr" || (cmd == "set" && arg == "attrTemplate")) {
reloadIfOk = true;
} else {
$(this).unbind('click').click();// No element found to replace, reload
return;
}
}
// Make it similar to submit: values joined by ,
var nd=frm.find("[name^=val]").map(function(){return $(this).val()}).get();
newDef = nd.length ? nd.join(",") : frm.find("input:text").val();
cmd = $(this).attr("name")+"="+cmd+" "+devName+" "+arg+" "+newDef;
}
FW_cmd(FW_root+"?"+encodeURIComponent(cmd)+"&XHR=1", function(resp){
if(!resp && reloadIfOk) {
var hr = location.href+"";
location.href = hr+ // retain fw_id
(hr.match(/fw_id=\d+/) ? "" : '&fw_id='+$("body").attr('fw_id'));
}
if(resp) {
if(!resp.match(/^[\s\S]*<\/html>/ ) ) {
resp = FW_htmlQuote(resp);
if(resp.indexOf("\n") >= 0)
resp = ''+resp+' ';
}
return FW_okDialog(resp);
}
if(isDef) {
newDef = FW_htmlQuote(newDef);
if(newDef.indexOf("\n") >= 0)
newDef = ''+newDef+' ';
$("div#disp").html(newDef).css("display", "");
$("div#edit").css("display", "none");
}
});
});
}
function
FW_removeLink(el)
{
$(el).unbind("click");
$(el).attr("href", "#"); // Desktop: show underlined Text
$(el).removeAttr("onclick"); // smallscreen style
}
// Fill the "detLink" line with life
function
FW_detLink()
{
if(FW_isiOS || FW_os == "osx") { // our copy fails here
$("#detLink a[href*=forumCopy]").parent().remove();
$("#detLink option[data-cmd^=forumCopy]").remove();
}
$("#detLink a").each(function(){
var m = FW_getLink(this).match(/cmd=([^&]*)/);
if(!m) // delete is already processed
return;
FW_removeLink(this);
$(this).click(function(){doDetCmd(m[1])});
});
$("#detLink select#moreCmds").change(function(){
doDetCmd($(this).find("option:selected").attr("data-cmd"));
});
function
doDetCmd(fCmd)
{
if(!fCmd)
return;
var m = fCmd.match(/^([^ ]+) (.*)$/);
if(!m)
return;
var cmd=m[1], dev=m[2];
if(cmd == "devSpecHelp") {
if($("#devSpecHelp").length) {
$("#devSpecHelp").remove();
return;
}
FW_getHelp(dev, function(data){
$("#content").append('
');
$("#devSpecHelp").html(data);
var off = $("#devSpecHelp").position().top-20;
$('body, html').animate({scrollTop:off}, 500);
});
} else if(cmd == "forumCopy") {
FW_cmd(FW_root+"?cmd=list -r -i "+dev+"&XHR=1", function(data) {
var ta = document.createElement("textarea"), at="";
if(data.length > 50*1000) {
data = data.substr(0,50*1000)+
"\n# ... truncated to 50k, original length "+data.length;
at = " Text truncated to 50k due to forum restrictions.";
}
ta.value = '[code]'+data+'[/code]';
document.body.appendChild(ta);
ta.select();
if(document.execCommand('copy'))
FW_okDialog('"forum ready" definition copied to the clipboard.'+at);
else
FW_okDialog('Could not copy');
document.body.removeChild(ta);
});
} else if(cmd == "delete") {
FW_delete("delete "+dev);
} else if(cmd == "rawDef") {
if($("#rawDef").length) {
$("#rawDef").remove();
return;
}
var textAreaStyle = typeof AddCodeMirror == 'function'?'opacity:0':'';
$("#content").append(''+
''+
'Execute commands '+
' Dump "Probably associated with" too '+
' '+
' With internals '+
'
');
var cmVar;
function
fillData(opt)
{
var s = $('#rawDef textarea');
FW_cmd(FW_root+"?cmd=list "+opt+" "+dev+"&XHR=1", function(data) {
var re = new RegExp("^define", "gm");
data = data.replace(re, "defmod");
s.val(data);
var off = $("#rawDef").position().top-20;
$('body, html').animate({scrollTop:off}, 500);
$("#rawDef button").hide();
var propertychange = function() {
var nData = $("#rawDef textarea").val();
if(nData != data &&
!$("body").attr("data-hiddenroom").match(/\binput\b/))
$("#rawDef button").show();
else
$("#rawDef button").hide();
};
s.bind('input propertychange', propertychange);
if(cmVar) {
cmVar.setValue(data);
} else if(typeof AddCodeMirror == 'function') {
AddCodeMirror(s, function(cm) {
cmVar = cm;
cm.on("change", function() {
s.val(cm.getValue());
propertychange();
})
});
}
});
}
fillData("-r");
$("#rawDef input").click(function(){
fillData(
($("input.paw").is(":checked") ? "-R" : "-r")+
($("input.int").is(":checked") ? " -i" : ""));
});
$("#rawDef button").click(function(){
FW_execRawDef($("#rawDef textarea").val());
});
} else {
location.href = addcsrf(FW_root+"?cmd="+cmd+" "+dev);
}
}
}
function
FW_execRawDef(data)
{
var arr = data.split("\n"), str="", i1=-1;
function
doNext()
{
if(++i1 >= arr.length) {
if($("#FW_okDialog").length) // F2F remote cmd execution
return;
return FW_okDialog("Executed everything, no errors found.");
}
str += arr[i1];
if(arr[i1].charAt(arr[i1].length-1) === "\\") {
str += "\n";
return doNext();
}
if(str != "") {
str = str.replace(/\\\n/g, "\n");
FW_cmd(FW_root+"?cmd="+encodeURIComponent(str)+"&XHR=1",
function(r){
if(r)
return FW_okDialog(''+r+' ');
str = "";
doNext();
});
} else {
doNext();
}
}
doNext();
}
var FW_arrowDown="", FW_arrowRight="";
function
FW_treeMenu()
{
var a = $("a").get(0);
var col = 'rgb(39, 135, 38)';
if(window.getComputedStyle && a)
col = getComputedStyle(a,null).getPropertyValue('color');
FW_arrowRight = 'data:image/svg+xml;utf8, '
.replace('gray', col);
FW_arrowDown =FW_arrowRight.replace('/>',' transform="rotate(90,896,896)"/>');
var fnd;
$("div#menu table.room").each(function(){ // one loop per Block
var t = this, ma = {};
$(t).find("td > div > a > span").each(function(e){
var span = this, spanTxt = $(span).text().replace(/,/g,'');
var ta = spanTxt.split("->");
if(ta.length <= 1)
return;
fnd = true;
var nxt="", lst="", tr=$(span).closest("tr");
for(var i1=0; i1"+ta[i1];
if(!ma[nxt]) {
$(tr).before("");
}
ma[nxt] = true;
lst = nxt;
}
$(span).html(ta[ta.length-1]);
$(tr).attr("data-mTree", nxt)
.addClass("menuTree level"+(ta.length-1));
});
});
if(fnd) {
$("head").append(
"");
var t = $("div#menu table.room");
$(t).find("tr[data-mTree]").not(".level0").hide();
$(t).find("tr.menuTree").click(function(){treeClick(this)});
$(t).find("tr.menuTree > td > div > div")
.css("background-image", "url('"+FW_arrowRight+"')");
var selRoom = $("div#content").attr("room");
if(selRoom) {
var ta = selRoom.split("->"), nxt="";
for(var i1=0; i1"+ta[i1]);
treeClick($(t).find("tr.menuTree[data-nxt="+nxt+"]"));
}
}
}
function
treeClick(el)
{
var tgt = FW_escapeSelector($(el).attr("data-nxt"));
if($(el).hasClass("closed")) {
$(el).closest("table").find("tr[data-mTree="+tgt+"]").show();
$(el).find("div>div").css("background-image", "url('"+FW_arrowDown+"')");
} else {
$(el).closest("table").find("tr[data-mTree^="+tgt+"]")
.hide().filter('[data-nxt]').addClass("closed").removeClass("open");
$(el).find("div>div").css("background-image", "url('"+FW_arrowRight+"')");
}
$(el).toggleClass("closed");
$(el).toggleClass("open");
};
}
function
FW_escapeSelector(s)
{
if(typeof s != 'string')
return s;
return s.replace(/[ .#\[\]>,]/g, function(r) { return '\\'+r });
}
/*************** LONGPOLL START **************/
var FW_pollConn;
var FW_longpollOffset = 0;
var FW_leaving;
var FW_lastDataTime=0;
function
FW_doUpdate(evt)
{
var errstr = "Connection lost, trying a reconnect every 5 seconds.";
var input="";
var retryTime = 5000;
var now = new Date()/1000;
// d: array
// d[0]: informid
// d[1]: if the informid Widget has setValueFn, arg for this
// d[2]: else replace the html with this
function
setValue(d) // is Callable from eval below
{
$("[informId='"+d[0]+"']").each(function(){
if(this.setValueFn) { // change the select/etc value
this.setValueFn(d[1].replace(/\n/g, '\u2424'));
} else {
if(d[2].match(/\n/) && !d[2].match(/<.*>/)) // format multiline
d[2] = ''+d[2]+' ';
var ma = /^([\s\S]*)<\/html>/.exec(d[2]);
if(!d[0].match("-")) { // not a reading
$(this).html(d[2]);
FW_replaceWidgets($(this));
} else if(ma) {
$(this).html(ma[1]);
FW_replaceWidgets($(this));
} else {
$(this).text(d[2]);
}
if(d[0].match(/-ts$/)) // timestamps
$(this).addClass('changed');
$(this).find("a").each(function() { FW_replaceLink(this) });
}
});
}
// iOS closes HTTP after 60s idle, websocket after 240s idle
if(now-FW_lastDataTime > 59) {
errstr="";
retryTime = 100;
}
FW_lastDataTime = now;
// Websocket starts with Android 4.4, and IE10
if(typeof WebSocket == "function" && evt && evt.target instanceof WebSocket) {
if(evt.type == 'close' && !FW_leaving) {
FW_errmsg(errstr, retryTime-100);
if(FW_pollConn) // Race-condition(?) # 112181
FW_pollConn.close();
FW_pollConn = undefined;
setTimeout(FW_longpoll, retryTime);
return;
}
input = evt.data;
FW_longpollOffset = 0;
} else if(FW_pollConn != undefined) {
if(FW_pollConn.readyState == 4 && !FW_leaving) {
if(FW_pollConn.status == "400") {
location.reload();
return;
}
FW_errmsg(errstr, retryTime-100);
setTimeout(FW_longpoll, retryTime);
return;
}
if(FW_pollConn.readyState != 3)
return;
input = FW_pollConn.responseText;
}
var devs = new Array();
if(!input || input.length <= FW_longpollOffset)
return;
FW_serverLastMsg = (new Date()).getTime()/1000;
for(;;) {
var nOff = input.indexOf("\n", FW_longpollOffset);
if(nOff < 0)
break;
var l = input.substr(FW_longpollOffset, nOff-FW_longpollOffset);
FW_longpollOffset = nOff+1;
if(l != '[""]') // jsLog answer
log("Rcvd: "+(l.length>132 ? l.substring(0,132)+"...("+l.length+")":l));
if(!l.length)
continue;
if(l.indexOf("<")== 0) { // HTML returned by proxy, if FHEM behind is dead
FW_closeConn();
FW_errmsg(errstr, retryTime-100);
setTimeout(FW_longpoll, retryTime);
return;
}
var d = JSON.parse(l);
if(d.length != 3)
continue;
if( d[0].match(/^#FHEMWEB:/) ) {
try {
eval(d[1]);
} catch(e) {
if($("body").attr("data-confirmJSError") != 0)
FW_okDialog("#FHEMWEB notification: "+d[1]+" "+e);
}
} else {
setValue(d);
}
// updateLine is deprecated, use setValueFn
for(var w in FW_widgets)
if(FW_widgets[w].updateLine && !FW_widgets[w].second)
FW_widgets[w].updateLine(d);
devs.push(d);
}
// used for SVG to avoid double-reloads
for(var w in FW_widgets)
if(FW_widgets[w].updateDevs && !FW_widgets[w].second)
FW_widgets[w].updateDevs(devs);
// reset the connection to avoid memory problems
if(FW_longpollOffset > 1024*1024 && FW_longpollOffset==input.length)
FW_longpoll();
}
function
FW_closeConn()
{
FW_leaving = 1;
if(!FW_pollConn)
return;
if(typeof FW_pollConn.close == "function")
FW_pollConn.close();
else if(typeof FW_pollConn.abort == "function")
FW_pollConn.abort();
FW_pollConn = undefined;
}
function
FW_longpoll()
{
FW_closeConn();
FW_leaving = 0;
FW_longpollOffset = 0;
// Build the notify filter for the backend
var filter = $("body").attr("longpollfilter");
filter = filter ? decodeURIComponent(filter) : "";
var retry;
if(filter == "") {
$("embed").each(function() { // wait for all embeds to be there
if(retry)
return;
var ed = FW_getSVG(this);
if(!retry && ed == undefined && filter != ".*" && --embedLoadRetry > 0) {
retry = 1;
setTimeout(FW_longpoll, 100);
return;
}
if(ed && $(ed).find("svg[flog]").attr("flog"))
filter=".*";
});
if(retry)
return;
}
if(filter == "") {
if(FW_urlParams.room)
filter="room="+FW_urlParams.room
.replace(/[[\]().+*?]/g, function(r){return '\\'+r});
if(FW_urlParams.detail) filter=FW_urlParams.detail;
}
if($("#floorplan").length>0) //floorplan special
filter += ";iconPath="+$("body").attr("name");
if(filter == "") {
var content = document.getElementById("content");
if(content) {
var room = content.getAttribute("room");
if(room)
filter="room="+room
.replace(/[[\]().+*?]/g, function(r){return '\\'+r});
}
}
// use devspec directly if room is dynamic (#devspec=)
filter = filter.replace( 'room=#devspec=', '' );
filter = filter.replace( 'room=%23devspec%3d', '' );
var iP = $("body").attr("iconPath");
if(iP != null)
filter = filter +";iconPath="+iP;
var since = "null";
if(FW_serverGenerated)
since = FW_serverLastMsg + (FW_serverGenerated-FW_serverFirstMsg);
var inform = encodeURIComponent("type=status;filter="+filter+
";since="+since+";fmt=JSON"); // 128651
var query = "?XHR=1"+
"&inform="+inform+
'&fw_id='+$("body").attr('fw_id')+
"×tamp="+new Date().getTime();
var loc = (""+location).replace(/\?.*/,"");
if(typeof WebSocket == "function" && FW_longpollType == "websocket") {
FW_pollConn = new WebSocket(loc.replace(/[#&?].*/,'')
.replace(/^http/i, "ws")+query);
FW_pollConn.onclose =
FW_pollConn.onerror =
FW_pollConn.onmessage = FW_doUpdate;
} else {
FW_pollConn = new XMLHttpRequest();
FW_pollConn.open("GET", location.pathname+query, true);
if(FW_pollConn.overrideMimeType) // Win 8.1, #66004
FW_pollConn.overrideMimeType("application/json");
FW_pollConn.onreadystatechange = FW_doUpdate;
FW_pollConn.send(null);
}
log("Inform-channel opened ("+(FW_longpollType==1 ? "HTTP":FW_longpollType)+
") with filter "+filter);
}
/*************** LONGPOLL END **************/
/*************** WIDGETS START **************/
/*************** "Double" select in detail window ****/
function
FW_detailSelect(selEl, mayMissing)
{
if(selEl.target)
selEl = selEl.target;
var selVal = $(selEl).val();
var div = $(selEl).closest("div.makeSelect");
if(!div.attr("list")) // hiddenRoom=input
return;
var argAndPar, fnd,
listArr = $(div).attr("list").split(" "),
devName = $(div).attr("dev"),
cmd = $(div).attr("cmd");
if(selVal != null && selVal != undefined) {
for(var i1=0; i1 2) {
var re = aap.shift();
aap = [re, aap.join(":")];
}
argAndPar = aap;
fnd = true;
}
} catch(e){
log("Problem building regexp from "+listArr[i1]);
}
}
}
var vArr = [];
if(!fnd && !mayMissing)
return;
if(fnd && argAndPar[1])
vArr = argAndPar[1].split(",");
FW_replaceWidget($(selEl).next(), devName, vArr,undefined,selVal,
undefined, undefined, undefined,
function(newEl) {
if(cmd == "attr")
FW_queryValue('{AttrVal("'+devName+'","'+selVal+'","")}', newEl);
if(cmd == "set")
FW_queryValue('{ReadingsVal("'+devName+'","'+selVal+'","")}', newEl);
});
}
// elName: HTML-Element-id
// devName: FHEM-Device name
// vArr: all parameters split by ,
// current: the value of the current attribute
// set: "cmd" attribute first value
// params: "cmd" attribute other values, split by space
// cmd: function to call, if value changes
function
FW_callCreateFn(elName, devName, vArr, currVal, set, params, cmd, finishFn)
{
for(var wn in FW_widgets) {
if(FW_widgets[wn].createFn && !FW_widgets[wn].second) {
var newEl = FW_widgets[wn].createFn(elName, devName, vArr,
currVal, set, params, cmd);
if(newEl)
return finishFn(wn, newEl);
}
}
var v0 = vArr[0].split("-")[0];
if(v0.indexOf("uzsu") == 0)
v0 = "uzsu";
if(FW_availableJs[v0]) {
loadScript("pgm2/fhemweb_"+v0+".js", function() {
if(!FW_widgets[vArr[0]]) {
log("ERROR: fhemweb_"+vArr[v0]+".js does not fill FW_widgets");
return;
}
if(FW_widgets[vArr[0]].createFn)
var newEl = FW_widgets[vArr[0]].createFn(elName, devName, vArr,
currVal, set, params, cmd);
finishFn(vArr[0], newEl);
});
} else {
finishFn();
}
}
function
FW_replaceWidget(oldEl,devName,vArr,currVal,reading,set,params,cmd,readyFn)
{
var elName = $(oldEl).attr("name");
if(!elName)
elName = $(oldEl).find("[name]").attr("name");
if(vArr.length == 0) { // No parameters, input field
var newEl = FW_createTextField(elName, devName, ["textField"], currVal,
set, params, cmd);
finishFn("textField", newEl);
} else {
return FW_callCreateFn(elName, devName, vArr, currVal, set,
params, cmd, finishFn);
}
function
finishFn(wn, newEl)
{
if(!newEl) {
vArr.unshift("select");
newEl = FW_createSelect(elName,devName,vArr,currVal,set,params,cmd);
wn = "select";
}
if(!newEl) { // Simple link
newEl = $('');
$(newEl).click(function(arg) { cmd(params[0]) });
$(oldEl).replaceWith(newEl);
if(readyFn)
return readyFn(newEl);
return;
}
$(newEl).addClass(wn+"_widget");
if( $(newEl).find("[informId]").length==0 && !$(newEl).attr("informId") ) {
if(reading) {
var a = $(oldEl).closest("form").find("input[type=submit][value=attr]");
$(newEl).attr("informId", devName+(a.length?"-a-":"-")+reading);
}
var addTitle = $("body").attr("data-addHtmlTitle");
if(reading != "state" && addTitle==1)
$(newEl).attr("title", reading);
}
$(oldEl).replaceWith(newEl);
if(newEl.activateFn) // CSS is not applied if newEl is not in the document
newEl.activateFn();
if(readyFn)
readyFn(newEl);
}
}
function
FW_queryValue(cmd, el)
{
log("FW_queryValue:"+cmd);
var query = location.pathname+"?cmd="+encodeURIComponent(cmd)+"&XHR=1";
query = addcsrf(query);
var qConn = new XMLHttpRequest();
qConn.onreadystatechange = function() {
if(qConn.readyState != 4)
return;
var qResp = qConn.responseText.replace(/\n$/, '');
qResp = qResp.replace(/\n/g, '\u2424');
if(el.setValueFn)
el.setValueFn(qResp);
qConn.abort();
}
qConn.open("GET", query, true);
qConn.send(null);
}
/*************** TEXTFIELD **************/
function
FW_createTextField(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr.length > 2 ||
(vArr[0] != "textField" &&
vArr[0] != "textFieldNL" &&
vArr[0] != "textField-long" &&
vArr[0] != "textFieldNL-long") ||
(params && params.length))
return undefined;
var is_long = (vArr[0].indexOf("long") > 0);
var newEl = $("").get(0);
if(set && set != "state" && vArr[0].indexOf("NL") < 0)
$(newEl).append(set+":");
$(newEl).append('
');
var inp = $(newEl).find("input").get(0);
if(elName)
$(inp).attr('name', elName);
if(currVal != undefined)
$(inp).val(currVal);
if(vArr.length == 2 && !is_long)
$(inp).attr("placeholder", vArr[1]);
function addBlur() { if(cmd) $(inp).blur(function() { cmd($(inp).val()) }); };
newEl.setValueFn = function(arg){ $(inp).val(arg) };
addBlur();
var myFunc = function(){
$(inp).unbind("blur");
$('body').append(
'
'+
''+
'
');
var txt = $(inp).val();
txt = txt.replace(/\u2424/g, '\n');
$("#td_longText").val(txt);
var cm;
if(typeof AddCodeMirror == 'function') {
AddCodeMirror($("#td_longText"), function(pcm) {cm = pcm;});
}
var sz = vArr[1] ? parseInt(vArr[1]) : 75;
$('#editdlg').dialog(
{ modal:true, closeOnEscape:true,
width:$(window).width()*(sz/100),
height:$(window).height()*(sz/100),
close:function(){ $('#editdlg').remove(); },
buttons:[
{ text:"Cancel", click:function(){
$(this).dialog('close');
addBlur();
}},
{ text:"OK", click:function(){
if(cm)
$("#td_longText").val(cm.getValue());
var res=$("#td_longText").val();
res = res.replace(/\n/g, '\u2424' );
$(this).dialog('close');
$(inp).val(res);
addBlur();
}}]
});
};
if(is_long)
$(newEl).click(myFunc);
return newEl;
}
/*************** select **************/
function
FW_createSelect(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr.length < 2 || vArr[0] != "select" || (params && params.length))
return undefined;
var newEl = document.createElement('select');
var vHash = {};
for(var j=1; j < vArr.length; j++) {
var o = document.createElement('option');
if(!vArr[j].match(/[0-9a-f]{1,4};/i)) // how to reproduce?
o.text = o.value = vArr[j].replace(/#/g," ");
vHash[o.value] = 1;
newEl.options[j-1] = o;
}
if(elName)
$(newEl).attr('name', elName);
if(cmd)
$(newEl).change(function(arg) { cmd($(newEl).val()) });
newEl.setValueFn = function(arg) {
if(!vHash[arg] && typeof(arg) != "undefined")
arg = (arg+"").replace(/ /g,"."); // #124505, replaceAll is Chrome 84+
if(vHash[arg])
$(newEl).val(arg);
};
newEl.setValueFn(currVal);
return newEl;
}
/*************** selectNumbers **************/
// Syntax: selectnumbers,
,,,,lin|log10
function
FW_createSelectNumbers(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr.length < 6 || vArr[0] != "selectnumbers" || (params && params.length))
return undefined;
var min = parseFloat(vArr[1]);
var stp = parseFloat(vArr[2]);
var max = parseFloat(vArr[3]);
var dp = parseFloat(vArr[4]); // decimal points
var fun = vArr[5]; // function
if(currVal != undefined)
currVal = currVal.replace(/[^\d.\-]/g, "");
currVal = (currVal==undefined || currVal=="") ? min : parseFloat(currVal);
if(max==min)
return undefined;
if(!(fun == "lin" || fun == "log10"))
return undefined;
if(currVal < min)
currVal = min;
if(currVal > max)
currVal = max;
var newEl = document.createElement('select');
var vHash = {};
var k = 0;
var v = 0;
if (fun == "lin") {
for(var j=min; j <= max; j+=stp) {
var o = document.createElement('option');
o.text = o.value = j.toFixed(dp);
vHash[o.text] = 1;
newEl.options[k] = o;
k++;
}
} else if (fun == "log10") {
if(min <= 0 || max <= 0)
return undefined;
for(var j=Math.log10(min); j <= Math.log10(max)+stp; j+=stp) {
var o = document.createElement('option');
var w = Math.pow(10, j)
if (w > max)
w = max;
if (v == w.toFixed(dp))
continue;
v = w.toFixed(dp);
o.text = o.value = v;
vHash[v] = 1;
newEl.options[k] = o;
k++;
}
}
if(typeof(currVal) != "undefined")
$(newEl).val(currVal.toFixed(dp));
if(elName)
$(newEl).attr('name', elName);
if(cmd)
$(newEl).change(function(arg) { cmd($(newEl).val()) });
newEl.setValueFn = function(arg) {
arg = parseFloat(arg).toFixed(dp);
if(vHash[arg])
$(newEl).val(arg);
};
return newEl;
}
/*************** noArg **************/
function
FW_createNoArg(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr.length != 1 || vArr[0] != "noArg" || (params && params.length))
return undefined;
var newEl = $('').get(0);
if(elName)
$(newEl).append('
');
return(newEl);
}
/*************** slider **************/
function
FW_createSlider(elName, devName, vArr, currVal, set, params, cmd)
{
// min, step, max, float
if(vArr.length < 4 || vArr.length > 5 || vArr[0] != "slider" ||
(params && params.length))
return undefined;
var min = parseFloat(vArr[1]);
var stp = parseFloat(vArr[2]);
var max = parseFloat(vArr[3]);
var flt = (vArr.length == 5 && vArr[4] == "1");
var dp = 0; // decimal points for float
if(flt) {
var s = ""+stp;
if(s.indexOf(".") >= 0)
dp = s.substr(s.indexOf(".")+1).length;
}
if(currVal != undefined)
currVal = currVal.replace(/[^\d.\-]/g, "");
currVal = (currVal==undefined || currVal=="") ? min : parseFloat(currVal);
if(max==min)
return undefined;
if(currVal < min || currVal > max)
currVal = min;
var newEl = $('
').get(0);
var slider = $('
').get(0);
$(newEl).append(slider);
var sh = $('
'+currVal+'
').get(0);
$(slider).append(sh);
if(elName)
$(newEl).append('
');
var lastX=-1, offX=0, maxX=0, val=currVal;
newEl.activateFn = function() {
if(currVal < min || currVal > max)
return;
if(!slider.offsetWidth)
return setTimeout(newEl.activateFn, 1);
maxX = slider.offsetWidth-sh.offsetWidth;
offX = (currVal-min)*maxX/(max-min);
var strVal = (flt ? currVal.toFixed(dp) : ""+parseInt(currVal));
sh.innerHTML = strVal;
sh.setAttribute('style', 'left:'+offX+'px;');
if(elName)
slider.nextSibling.setAttribute('value', strVal);
}
$(newEl).keydown(function(e){
if(e.keyCode == 37) currVal -= stp;
else if(e.keyCode == 39) currVal += stp;
else return;
if(currVal < min) currVal = min;
if(currVal > max) currVal = max;
offX = (currVal-min)*maxX/(max-min);
var strVal = (flt ? currVal.toFixed(dp) : ""+parseInt(currVal));
sh.innerHTML = strVal;
sh.setAttribute('style', 'left:'+offX+'px;');
if(cmd)
cmd(strVal);
if(elName)
slider.nextSibling.setAttribute('value', strVal);
});
function
touchFn(e, fn)
{
e.preventDefault(); // Prevents Safari from scrolling!
if(e.touches == null || e.touches.length == 0)
return;
e.clientX = e.touches[0].clientX;
fn(e);
}
function
mouseDown(e)
{
var oldFn1 = document.onmousemove, oldFn2 = document.onmouseup,
oldFn3 = document.ontouchmove, oldFn4 = document.ontouchend;
e.stopPropagation(); // Dashboard fix
lastX = e.clientX; // Does not work on IE8
function
mouseMove(e)
{
e.stopPropagation(); // Dashboard fix
if(maxX == 0) // Forum #35846
maxX = slider.offsetWidth-sh.offsetWidth;
var diff = e.clientX-lastX; lastX = e.clientX;
offX += diff;
if(offX < 0) offX = 0;
if(offX > maxX) offX = maxX;
val = offX/maxX * (max-min);
val = flt ? (Math.floor(val/stp)*stp+min).toFixed(dp) :
(Math.floor(Math.floor(val/stp)*stp)+min);
sh.innerHTML = val;
sh.setAttribute('style', 'left:'+offX+'px;');
}
document.onmousemove = mouseMove;
document.ontouchmove = function(e) { touchFn(e, mouseMove); }
document.onmouseup = document.ontouchend = function(e)
{
e.stopPropagation(); // Dashboard fix
document.onmousemove = oldFn1; document.onmouseup = oldFn2;
document.ontouchmove = oldFn3; document.ontouchend = oldFn4;
if(cmd)
cmd(val);
if(elName)
slider.nextSibling.setAttribute('value', val);
};
};
sh.onselectstart = function() { return false; }
sh.onmousedown = mouseDown;
sh.ontouchstart = function(e) { touchFn(e, mouseDown); }
newEl.setValueFn = function(arg) {
var res = arg.match(/-?[\d.]+/); // extract first number
currVal = (res ? parseFloat(res[0]) : min);
if(currVal < min || currVal > max)
currVal = min;
newEl.activateFn();
};
return newEl;
}
/*************** TIME **************/
function
FW_createTime(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr.length != 1 || vArr[0] != "time" || (params && params.length))
return undefined;
var open="-", closed="+";
var newEl = document.createElement('div');
$(newEl).append('
');
$(newEl).append('
');
var inp = $(newEl).find("[type=text]");
var btn = $(newEl).find("[type=button]");
currVal = (currVal ? currVal : "12:00")
.replace(/[^\d]*(\d\d):(\d\d).*/g,"$1:$2");
$(inp).val(currVal)
if(elName)
$(inp).attr("name", elName);
var hh, mm; // the slider elements
newEl.setValueFn = function(arg) {
arg = arg.replace(/[^\d]*(\d\d):(\d\d).*/g,"$1:$2");
$(inp).val(arg);
var hhmm = arg.split(":");
if(hhmm.length == 2 && hh && mm) {
hh.setValueFn(hhmm[0]);
mm.setValueFn(hhmm[1]);
}
};
$(btn).click(function(){ // Open/Close the slider view
var v = $(inp).val();
if($(btn).val() == open) {
$(btn).val(closed);
$(newEl).find(".timeSlider").remove();
hh = mm = undefined;
if(cmd)
cmd(v);
return;
}
$(btn).val(open);
if(v.indexOf(":") < 0) {
v = "12:00";
$(inp).val(v);
}
var hhmm = v.split(":");
function
tSet(idx, arg)
{
if((""+arg).length < 2)
arg = '0'+arg;
hhmm[idx] = arg;
$(inp).val(hhmm.join(":"));
}
$(newEl).append('
');
var ts = $(newEl).find(".timeSlider");
hh = FW_createSlider(undefined, devName+"HH", ["slider", 0, 1, 23],
hhmm[0], undefined, params, function(arg) { tSet(0, arg) });
mm = FW_createSlider(undefined, devName+"MM", ["slider", 0, 5, 55],
hhmm[1], undefined, params, function(arg) { tSet(1, arg) });
$(ts).append("
"); $(ts).append(hh); hh.activateFn();
$(ts).append("
"); $(ts).append(mm); mm.activateFn();
});
return newEl;
}
/*************** MULTIPLE **************/
function
FW_createMultiple(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr.length < 2 || (vArr[0]!="multiple" && vArr[0]!="multiple-strict") ||
(params && params.length))
return undefined;
var newEl = $('
').get(0);
if(currVal)
$(newEl).val(currVal);
if(elName)
$(newEl).attr("name", elName);
newEl.setValueFn = function(arg){ $(newEl).val(arg) };
for(var i1=1; i1
'+ // funny stuff for ios6 style, forum #23561
''+
' '+'
'+
''+v+' ';
delete(selObj[v]);
}
var selArr=[];
for(var i1 in selObj)
selArr.push(i1);
var strict = (vArr[0] == "multiple-strict");
$('body').append(
''+
'
'+(!strict ? '
' : '')+
'
');
$('#multidlg').dialog(
{ modal:true, closeOnEscape:false, maxHeight:$(window).height()*3/4,
buttons:[
{ text:"Cancel", click:function(){ $('#multidlg').remove(); }},
{ text:"OK", click:function(){
var res=[];
if($("#md_freeText").val())
res.push($("#md_freeText").val());
$("#multidlg table input").each(function(){
if($(this).prop("checked"))
res.push($(this).attr("name"));
});
$('#multidlg').remove();
$(newEl).val(res.join(","));
if(cmd)
cmd(res.join(","));
}}]});
});
return newEl;
}
function
FW_createBitfield(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr[0] != "bitfield")
return undefined;
if(elName)
elName = elName.replace(/[^A-Z0-9_]/ig, '_');
var lName = Math.random().toString(36).substr(2);
var fieldSize = (vArr.length > 1 ? parseInt(vArr[1]) : 8);
var bitMask = (vArr.length > 2 ? parseInt(vArr[2]) : 4294967295);
var html = '';
var newEl = $(html).get(0);
newEl.activateFn = function() {
var bm = bitMask;
for(var i1=1; i1<=fieldSize; i1++) {
$('#'+lName+'_bitfield input[value='+i1+']')
.prop("disabled", (bm%2 == 0));
bm = parseInt(bm/2);
}
$("#"+lName+"_bitfield input").change(function(){
var total = 0;
$("#"+lName+"_bitfield input").each(function(){
if($(this).is(":checked")) {
var sv = parseInt($(this).attr("value"))-1, thisVal=1;
while(sv) { thisVal *= 2; sv--; } // << works on signed 32bit values
total += thisVal;
}
});
if(cmd)
cmd(total);
if(elName)
$("[name="+elName+"]").val(total);
});
}
newEl.setValueFn = function(arg) {
var total = parseInt(arg);
for(var i1=1; i1<=fieldSize; i1++) {
$('#'+lName+'_bitfield input[value='+i1+']')
.prop("checked", (total%2 == 1));
total = parseInt(total/2);
}
};
return newEl;
}
// List of widgets, each one is prepended with its vArr.length
// widgetList,4,select,f1,f2,f3,1,textField,3,select,s1,s2
// No autoloading for subwidgets!
function
FW_createWidgetList(elName, devName, vArr, currVal, set, params, cmd)
{
if(vArr[0] != "widgetList")
return undefined;
var newEl = $('').get(0);
function
setCmd()
{
cmd($(newEl).find("[name^=val]")
.map( function(){return $(this).val()} )
.get()
.join(","));
}
if(!elName)
elName = "val."+Math.random().toString(36).substr(2);
for(var i1=1; i1= 0)
attr = $(this).attr("attr");
});
var ua={};
if(attr && attr != "") {
try {
ua=JSON.parse(attr);
} catch(e){
FW_errmsg(sname+" Parameter "+e,5000);
}
}
return ua;
}
/*************** SCRIPT LOAD FUNCTIONS END **************/
function
print_call_stack() {
var stack = new Error().stack;
console.log("PRINTING CALL STACK");
console.log( stack );
}
function
FW_getSVG(emb)
{
if(emb.contentDocument)
return emb.contentDocument;
if(typeof emb.getSVGDocument == "function") {
try {
return emb.getSVGDocument();
} catch(err) {
// dom not loaded -> fall through -> retry;
}
}
return undefined;
}
function
FW_checkNotifydev(reName)
{
var internals={};
$("table.internals tr td div.dname").each(function(){
internals[$(this).html()] = this;
});
if(!internals[reName] || internals.NOTIFYDEV)
return;
$(internals[reName])
.html(reName+" (!) ")
.css("cursor","pointer")
.click(function(){
var val = $(internals[reName]).closest("tr").find("div[informid]").text();
FW_okDialog("Could not optimize the regexp:How I tried (notifyRegexpCheck): ");
FW_cmd(FW_root+'?cmd={notifyRegexpCheck("'+val+'")}&XHR=1',
function(res){
$("#FW_okDialog pre").html(res);
});
});
}
function
FW_rescueClient(pid, key)
{
var html='';
if(!pid || pid == "0") {
html += '
Key (send it to the rescuer): '+
(key ? '
'+key+'
' : 'Not found, generate one first');
html += '
';
}
var buttons = [];
if(key) {
if(pid && pid != "0") {
html += "
There is a connection with pid "+pid+"
";
buttons.push({
text:"Terminate connection",
click:function(){
FW_cmd(FW_root+
"?cmd=set "+$("body").attr("data-webname")+
" rescueTerminate&XHR=1");
setTimeout(function(){ location.reload() }, 1000);
}});
} else {
html += "Address (rescuer will tell you host and port)
";
html += "
";
buttons.push({
text:"Start connection",
click:function(){
FW_cmd(FW_root+
"?cmd=set "+$("body").attr("data-webname")+" rescueStart "+
$("#rescueDialog input").val()+"&XHR=1");
setTimeout(function(){ location.reload() }, 1000);
}});
}
}
buttons.push({ text:"Cancel", click:function(){ $(this).dialog('close')} });
$('body').append(html);
$('#rescueDialog').dialog({
modal:true, closeOnEscape:true, width:"auto",
close:function(){ $('#rescueDialog').remove(); },
buttons:buttons
});
}
/*
=pod
=begin html
noArg - show no input field.
time - show a JavaScript driven timepicker.
Example: attr FS20dev widgetOverride on-till:time
textField[,placeholder] - show an input field.
Example: attr WEB widgetOverride room:textField
textFieldNL[,placeholder] - show the input field and hide the label.
textField-long[,sizePct] - show an input-field, but upon
clicking on the input field open a textArea.
sizePct specifies the size of the dialog relative to the screen, in
percent. Default is 75
textFieldNL-long[,sizePct] - the behaviour is the same
as :textField-long, but no label is displayed.
slider,<min>,<step>,<max>[,1] - show
a JavaScript driven slider. The optional ,1 at the end
avoids the rounding of floating-point numbers.
multiple,<val1>,<val2>,..." - present a
multiple-value-selector with an additional textfield. The result is
comman separated.
multiple-strict,<val1>,<val2>,... - like :multiple, but
without the textfield.
selectnumbers,<min>,<step>,<max>,<number of
digits after decimal point>,lin|log10" - display a select widget
generated with values from min to max with step.
lin generates a constantly increasing series. log10 generates an
exponentially increasing series to base 10, step is related to the
exponent, e.g. 0.0625.
select,<val1>,<val2>,... - show a dropdown with all values.
NOTE : this is also the fallback, if no modifier is found.
bitfield,<size><mask> - show a table of checkboxes (8 per
line) to set single bits. Default for size is 8 and for mask 2^32-1
widgetList,... - show a list of widgets. The arguments are concatenated,
and separated be the length of the following argument list.
Example: widgetList,3,select,opt1,opt2,1,textField
Note: the values will be sent to FHEM as a comma separated list, and only
preloaded widgets can be referenced.
=end html
=begin html_DE
noArg - es wird kein weiteres Eingabefeld angezeigt.
time - zeigt ein Zeitauswahlmenü.
Beispiel: attr FS20dev widgetOverride on-till:time
textField[,placeholder] - zeigt ein Eingabefeld.
Beispiel: attr WEB widgetOverride room:textField
textFieldNL[,placeholder] - Eingabefeld ohne Label.
textField-long[,sizePct] - ist wie textField, aber beim Click im
Eingabefeld wird ein Dialog mit einer HTML textarea wird
geöffnet. sizePct ist die relative Größe des Dialogs,
die Voreinstellung ist 75.
textFieldNL-long[,sizePct] - wi textField-long, aber kein Label wir
angezeigt.
slider,<min>,<step>,<max>[,1] - zeigt einen
Schieberegler. Das optionale 1 (isFloat) vermeidet eine Rundung der
Fliesskommazahlen.
multiple,<val1>,<val2>,... - zeigt eine Mehrfachauswahl mit
einem zusätzlichen Eingabefeld. Das Ergebnis ist Komma
separiert.
multiple-strict,<val1>,<val2>,... - ist wie :multiple,
bloß ohne Eingabefeld.
selectnumbers,<min>,<step>,<max>,<number of
digits after decimal point>,lin|log10" zeigt ein HTML-select mit einer
Zahlenreihe vom Wert min bis Wert max mit Schritten von step
angezeigt.
Die Angabe lin erzeugt eine konstant ansteigende Reihe. Die Angabe
log10 erzeugt eine exponentiell ansteigende Reihe zur Basis 10,
step bezieht sich auf den Exponenten, z.B. 0.0625.
select,<val1>,<val2>,... - zeigt ein HTML select mit allen
Werten. Achtung : so ein Widget wird auch dann angezeigt, falls
kein passender Modifier gefunden wurde.
bitfield,<size>,<mask> - zeigt eine Tabelle von
Kontrollkästchen (8 pro Zeile), um einzelne Bits setzen zu koennen.
Die Voreinstellung fuer size ist 8 und fuer mask 2^32-1.
widgetList,... - zeigt eine Liste von Widgets. Die Argumente aller
widgets sind durch die Längenangabe der jeweiligen Argumentliste
getrennt.
Beispiel: widgetList,3,select,opt1,opt2,1,textField
Achtung: die Werte werden Komma separiert zu FHEM gesendet, und es
können nur bereits geladene widgets definiert werden.
=end html_DE
=cut
*/