diff --git a/apps/app_analyse_plots.html b/apps/app_analyse_plots.html new file mode 100644 index 000000000..4847472c0 --- /dev/null +++ b/apps/app_analyse_plots.html @@ -0,0 +1,464 @@ +/** +* ----------------------------------------------------------------------------- +* @package smartVISU +* @author Wolfram v. Hülsen +* @copyright 2012 - 2024 +* @license GPL [http://www.gnu.de] +* @version 1.0 +* +* @title Plot Analyser +* @category visu +* @icon icons/ws/measure_power_meter.svg +* @color #b00 +* @description Analyse plots with flexible configuration of series parameters +* @description_de Analysieren von Plots mit flexibler Eingabe von Parametern +* +* ----------------------------------------------------------------------------- +*/ + + +{% extends "apps.html" %} + +{% block sidebar %} + +
Y {{ lang('plot_analyser', 'Axis') }} 1 | Y {{ lang('plot_analyser', 'Axis') }} 2 | Y {{ lang('plot_analyser', 'Axis') }} 3 | Y {{ lang('plot_analyser', 'Axis') }} 4 | +|
{{ lang('plot_analyser', 'Axis') }} {{ lang('plot_analyser', 'active') }} | + | |||
Y min | + | |||
Y max | + | |||
Y {{ lang('plot_analyser', 'Axis') }} Position | ++ | + | + | + |
Y {{ lang('plot_analyser', 'Axis') }} {{ lang('plot_analyser', 'scale') }} | ++ | + | + | + |
Y {{ lang('plot_analyser', 'Axis') }} {{ lang('plot_analyser', 'Unit') }} | + |
This tool should help you to create widgets for your smartvisu-Web-Interface. -It will assist you with autocompletes for widgets, items, icons, and colors. -After you have selected a widget (like basic.symbol...) you will get a tooltip for this kind of widget. The actual parameter is highlighted in red and all the available details will be shown in the tooltip-window. -For icons and colors you will see a preview in the tooltip-window. -After completing the wiget you can render it in a new window. The widget in the rendered window is fully working, except there is an error in the created widget, you will get a TWIG-Error. +
This tool should help you to create widgets for your smartvisu-Web-Interface. It will assist you with autocompletes for widgets, items, icons and colors. The autocomplete mode can be selected.
+Just start entering a widget name in the editor or press CTRL-Space to open the widget autocomplete. After you have selected a widget (like basic.symbol...) and enter the opening bracket you will get a tooltip for this widget.
+The actual parameter is highlighted in red and all the available details will be shown in the tooltip-window. For icons and colors you will see a preview in the tooltip-window. Autocompletes will insert the parameters with quotes.
+If no autocomplete is present or you do not use it make sure to enter the quotes manually.
+After completing the wiget you can render it in a new window. The widget in the rendered window is fully working. If there is a syntax error in the created widget, you will get a TWIG-Error.
The final widget including the brackets "{{" + "}}" will be stored on rendering to the clipboard.
You can paste the widget-code directly to your html-file.
Right now you can render multiple widgets, you have to separate the different widgets
-by a <br>
-TAG
You can render multiple widgets by separating them by a <br>
-TAG
-plot.period('', ['licht.og.terrasse.screens.warm.dimmen', 'licht.og.terrasse.screens.kalt.dimmen', 'licht.og.terrasse.decke.dimmen'], 'max', '1w', 'now', '0', '110', '1000', ['Screens warm', 'Screens kalt', 'Decke'], ['#daa', '#aad', '#955'], ['stair', 'stair', 'stair'], ['Uhrzeit', 'Helligkeit'], 'advanced', '', '', '', '', '', { yAxis: [ { tickInterval: 40 } ], legend: {align: 'right', verticalAlign: 'top', y: 50, layout: 'vertical'}, chart: { marginRight: 110} })
+plot.period('', ['licht.og.terrasse.screens.warm.dimmen', 'licht.og.terrasse.screens.kalt.dimmen', 'licht.og.terrasse.decke.dimmen'], 'max', '1w', 'now', '0', '110', '1000', ['Screens warm', 'Screens kalt', 'Decke'], ['#daa', '#aad', '#955'], ['stair', 'stair', 'stair'], ['Uhrzeit', 'Helligkeit'], 'advanced', '', '', '', '', '', { yAxis: [ { tickInterval: 40 } ], legend: {align: 'right', verticalAlign: 'top', y: 50, layout: 'vertical'}, chart: { marginRight: 110} })
<br>
basic.stateswitch('','OG.Bad.Licht','midi','','light_ceiling_light','Licht Bad','','','','','')
<br>
quad.dimmer('Lueftungsstufe1', 'Lüftungsstufe', 'Haustechnik.Lueftung', 'Haustechnik.Lueftung.stufe', 0, 100, 5, icon.ventilation(), icon.ventilation('','','Haustechnik.Lueftung.stufe'), '', '', '', 0, 100, '', '', '', '', '', '', '', '', '', '', '', '', '', ['switch', 'value_popup'])
-
-Change-Log
-2021.05.01 - Version 1.2.0
-
-- added support for all valid values of widget-types from twig-docu
-- some optical changes
-- added widget specific colours to autocomplete dict for colors (for example 'hidden','blank' for basic.print)
-
-2021.01.18 - Version 1.1.0
-
-- changed handling for "render in new window" - if there is no Window a new one will be opened, else the opened window would be refreshed, also if there is a twig error
-- more fixes for "nasty", "nested" widgets
-- some optical changes
-
-2020.11.08 - Version 1.0.0
-
-- added support for multi-widget creation (widgets have to be separated by <br>-TAG)
-- fixed problem for "nasty", "nested" widgets
-- added check for all brackets closed before rendering
-
-2020.05.15 - Version 1.0.0
-
-- added switching for autoclose quotes
-- added filter for item-autocomplete based on item data-type
-- added checkbox to open agiain new window for the preview
-- added data-types to items in basic-widgets (basic.html)
-- added alert when receiving "strange" widget-informations (most based on README.html-Files in /dropins/widgets-folder)
-
-2020.05.03 - Version 1.0.0
-
-- added autocomplete dict for parameters with the following names "type", "mode", "style", "colormodel", "orientation", "valueType"
-
-2020.05.02 - Version 1.0.0
-
-- set filter to *svg while collectin icons in /icon/ws/ ( There is a stylesheet in the folder)
-- until no widget is selected the Widget-only dict is acive
-- added Close-Button to the Tooltip-Window
-- added closeBrackets feature for CodeMirror and solved problem with CSS
-- added direct copy of the final widget to the clipboard when rendering the widget
-
-2020.05.01 - Version 1.0.0
-
-- added support for nested widgets like
{{ basic.symbol('', 'bath.light.switch', '', icon.light('','','bath.light.value') ) }}
-
-- added bracket-matching
-- added autoswitch to dict depending on parameter -> type / you can switch to a dict using the Hot-Keys
-- removed deprecated widgets from widget generator
-
-2020.04.26 - Version 1.0.0
-
-- added search in autocompletes with wildcard (a word with 3 chars will match all entries in the acitve dict like
*your_chars*
-- added Hot-Key 'CTRL+Space' to activate the autocomplete-hint without entering a search key
-- added preview in tooltip for colors and icons
-
-2020.04.25 - launch of Version 1.0.0
-
-- Beta Version for tests distributed
-
-Requirements
-actual smartvisu-Version - you can find it here
Hot-Keys
@@ -150,12 +87,8 @@ Hot-Keys
-STRG+0
-switch OFF autocomplete-Dict
-
-
STRG+1
-switch ON autocomplete-Dict
+only Items in autocomplete-Dict
STRG+2
@@ -178,14 +111,6 @@ Hot-Keys
autocomplete-Dict is OFF
-STRG+7
-switch ON/OFF autocomplete for Ouotes (1) - take some time to build the autocomplete
-
-
-STRG+8
-only Items in autocomplete-Dict
-
-
STRG+9
switch ON/OFF Wildcard search in autocomplete dict
@@ -203,8 +128,6 @@ Hot-Keys
-(1) when autocomplete for quotes is on - the autocomplete dict will return all values without quotes
- when autocomplete for quotes is off - the autocomplete dictionary will return all values with quotes
Known Issues
It is possible to render the new widget into the iframe on the actual page.
@@ -215,8 +138,7 @@
Known Issues
Logic to create masteritem.json from shNG
Only needed for smarthomeNG <= v1.7.2. As of v1.8 the smartvisu plugin writes the file as default.
-
-#!/usr/bin/env python3
+#!/usr/bin/env python3
# create_master_item.py
import json
from lib.item import Items
diff --git a/lib/widget_assistant/README_DE.html b/lib/widget_assistant/README_DE.html
new file mode 100644
index 000000000..a672ceebc
--- /dev/null
+++ b/lib/widget_assistant/README_DE.html
@@ -0,0 +1,156 @@
+
+
+smartvisu - Widget Assistant
+Inhalt
+
+- Funktionsweise
+- Hot-Keys
+- Bekannte Probleme
+- Logik zum Erstellen der masteritem.json in shNG
+- Skript zum Erstellen der masteritem.json in FHEM
+
+
+Funktionsweise
+Dieses Tool hilft bei der Erstellung von Widgets für Ihre Visualisierung mit smartVISU.
+Es unterstützt mit Autovervollständigung vorhandener und im Kontext zulässiger Widgets, Items, Icons und Farben. Der Modus der Autovervollständigung kann ausgewählt werden.
+Beginnen Sie einfach im Editor mit der Eingabe eines Widget-Namens oder öffnen Sie die Liste mit CTRL-Leerzeichen. Nachdem Sie ein Widget ausgewählt haben (z.B. basic.symbol...) und die erste Klammer eintippen,
+wird ein Fenster mit Erläuterungen (Tooltip) für dieses Widget angezeigt. Der jeweils zu bearbeitende Parameter wird in roter Schrift angezeigt und alle dazu verfügbaren Details werden darunter gelistet.
+Für Icons und Farben wird eine Vorschau im Tooltip angezeigt. Alle Parameter müssen mit Anführungszeichen eingegeben werden, wobei die Autovervollständigung die Parameter automatisch in Anführungszeichen setzt.
+Nachdem das Widget vollständig eingegeben ist, können Sie es entweder auf dieser Seite, oder in einem neuen Fenster (empfohlen) anzeigen lassen und live testen. Das Widget ist voll funktionsfähig.
+Es wird lediglich ein Twig-Error angezeigt, wenn ein Fehler in der Syntax ist. Zudem wird der eingegebene Widget Code einschließlich der Klammern "{{" + "}}" in die Zwischenablage
+kopiert und kann direkt in Ihre Visu-Seiten eingefügt werden.
+Man kann mehrere Widgets gleichezitig rendern, indem man sie mit einem <br>
-TAG trennt.
+Beispiel:
+plot.period('', ['licht.og.terrasse.screens.warm.dimmen', 'licht.og.terrasse.screens.kalt.dimmen', 'licht.og.terrasse.decke.dimmen'], 'max', '1w', 'now', '0', '110', '1000', ['Screens warm', 'Screens kalt', 'Decke'], ['#daa', '#aad', '#955'], ['stair', 'stair', 'stair'], ['Uhrzeit', 'Helligkeit'], 'advanced', '', '', '', '', '', { yAxis: [ { tickInterval: 40 } ], legend: {align: 'right', verticalAlign: 'top', y: 50, layout: 'vertical'}, chart: { marginRight: 110} })
+<br>
+basic.stateswitch('','OG.Bad.Licht','midi','','light_ceiling_light','Licht Bad','','','','','')
+<br>
+quad.dimmer('Lueftungsstufe1', 'Lüftungsstufe', 'Haustechnik.Lueftung', 'Haustechnik.Lueftung.stufe', 0, 100, 5, icon.ventilation(), icon.ventilation('','','Haustechnik.Lueftung.stufe'), '', '', '', 0, 100, '', '', '', '', '', '', '', '', '', '', '', '', '', ['switch', 'value_popup'])
+
+
+Hot-Keys
+
+
+
+Kurzbefehl
+Funktion
+
+
+
+
+STRG+1
+Autovervollständigung nur für Items
+
+
+STRG+2
+Autovervollständigung nur für Widgets
+
+
+STRG+3
+Autovervollständigung nur für Icons
+
+
+STRG+4
+Autovervollständigung für alles
+
+
+STRG+5
+Autovervollständigung nur für Farben
+
+
+STRG+6
+Autovervollständigung AUS
+
+
+STRG+9
+Platzhaltersuche für Autovervollständigung ein/ausschalten
+
+
+STRG+Space
+öffnet die aktuelle Liste zur Autovervollständigung
+
+
+STRG+F
+Ausdruck im Code suchen
+
+
+STRG+SHIFT+R
+Ausdruck im Code ersetzen - ENTER wechselt zum Ersatz-Ausdruck
+
+
+
+
+Bekannte Probleme
+Man kann das neue Widget in den iframe auf der aktuellen Seite rendern. Dies wird jedoch die geladene index.php zerstören, so dass Probleme in der weiteren Navigation in smartVISU entstehen.
+Derzeit gibt es dafür nur die Lösung, die Seite neu zu laden (CTRL+F5 / CTRL + Shift + R).
+
+Logik zum Erstellen der masteritem.json in shNG
+Wird nur für shNG Versionen <= v1.7.2 benötigt. Ab v1.8 erstellt das smartvisu plugin die Datei standardmäßig.
+#!/usr/bin/env python3
+# create_master_item.py
+import json
+from lib.item import Items
+items = Items.get_instance()
+items_sorted = sorted(items.return_items(), key=lambda k: str.lower(k['_path']), reverse=False)
+item_list = []
+for item in items_sorted:
+ item_list.append(item._path + "|" + item._type )
+f = open("/var/www/html/smartvisu/pages/YOUR_PAGES/masteritem.json", "w")
+f.write(json.dumps(item_list))
+f.close()
+
+
+Skript zum Erstellen der masteritem.json in FHEM
+Ein Skript ist im fronthem / smartVISU Forum verfügbar
+https://forum.fhem.de/index.php/topic,118508.msg1135044.html#msg1135044
+
diff --git a/lib/widget_assistant/tmpl_assistant_1.html b/lib/widget_assistant/tmpl_assistant_1.html
index 621aa4509..a832ec95c 100644
--- a/lib/widget_assistant/tmpl_assistant_1.html
+++ b/lib/widget_assistant/tmpl_assistant_1.html
@@ -9,20 +9,6 @@
{% extends "base.html" %}
-{% import "@widgets/lib.html" as lib %}
-{% import "@widgets/basic.html" as basic %}
-{% import "@widgets/calendar.html" as calendar %}
-{% import "@widgets/clock.html" as clock %}
-{% import "@widgets/device.html" as device %}
-{% import "@widgets/icon.html" as icon %}
-{% import "@widgets/multimedia.html" as multimedia %}
-{% import "@widgets/phone.html" as phone %}
-{% import "@widgets/plot.html" as plot %}
-{% import "@widgets/popup.html" as popup %}
-{% import "@widgets/status.html" as status %}
-{% import "@widgets/weather.html" as weather %}
-{% import "@widgets/quad.html" as quad %}
-
{% block content %}
diff --git a/lib/widget_assistant/tmpl_assistant_2.html b/lib/widget_assistant/tmpl_assistant_2.html
index 02f9e8275..9f60fa8b3 100644
--- a/lib/widget_assistant/tmpl_assistant_2.html
+++ b/lib/widget_assistant/tmpl_assistant_2.html
@@ -9,20 +9,6 @@
{% extends "base.html" %}
-{% import "@widgets/lib.html" as lib %}
-{% import "@widgets/basic.html" as basic %}
-{% import "@widgets/calendar.html" as calendar %}
-{% import "@widgets/clock.html" as clock %}
-{% import "@widgets/device.html" as device %}
-{% import "@widgets/icon.html" as icon %}
-{% import "@widgets/multimedia.html" as multimedia %}
-{% import "@widgets/phone.html" as phone %}
-{% import "@widgets/plot.html" as plot %}
-{% import "@widgets/popup.html" as popup %}
-{% import "@widgets/status.html" as status %}
-{% import "@widgets/weather.html" as weather %}
-{% import "@widgets/quad.html" as quad %}
-
{% block content %}
diff --git a/lib/widget_assistant/widget_assistant.js b/lib/widget_assistant/widget_assistant.js
index a4ab1fbed..6629607cf 100644
--- a/lib/widget_assistant/widget_assistant.js
+++ b/lib/widget_assistant/widget_assistant.js
@@ -8,7 +8,7 @@
// in einem Popup angezeigt.
//
//
-// (c) Andre Kohler - 2020
+// (c) Andre Kohler 2020 - 2024
// license GPL [http://www.gnu.de]
//
@@ -84,42 +84,42 @@ function removeBalancedBrackets(text)
{
lastpos = BraceArray.pop()
txt2Replace = newText.substr(lastpos,i-lastpos+1)
- console.log(txt2Replace)
+ // console.log(txt2Replace)
replaceLength = txt2Replace.length
newText = newText.replace(txt2Replace, "")
i = i - replaceLength
Laenge = Laenge - replaceLength
- console.log(newText+"\n")
+ // console.log(newText+"\n")
continue
}
if (newText.substr(i,1) == "]" && SquareArray.length >0)
{
lastpos = SquareArray.pop()
txt2Replace = newText.substr(lastpos,i-lastpos+1)
- console.log(txt2Replace)
+ // console.log(txt2Replace)
replaceLength = txt2Replace.length
newText = newText.replace(txt2Replace, "")
i = i - replaceLength
Laenge = Laenge - replaceLength
- console.log(newText+"\n")
+ // console.log(newText+"\n")
continue
}
if (newText.substr(i,1) == "}" && CurlyArray.length >0)
{
lastpos = CurlyArray.pop()
txt2Replace = newText.substr(lastpos,i-lastpos+1)
- console.log(txt2Replace)
+ // console.log(txt2Replace)
replaceLength = txt2Replace.length
newText = newText.replace(txt2Replace, "")
i = i - replaceLength
Laenge = Laenge - replaceLength
- console.log(newText+"\n")
+ // console.log(newText+"\n")
continue
}
}
- console.log("\n"+"BraceCount : "+BraceArray.length)
- console.log("SquareCount : "+SquareArray.length)
- console.log("CurlyCount : "+CurlyArray.length)
+ // console.log("\n"+"BraceCount : "+BraceArray.length)
+ // console.log("SquareCount : "+SquareArray.length)
+ // console.log("CurlyCount : "+CurlyArray.length)
if (BraceArray.length == 0 && SquareArray == 0 && CurlyArray.length == 0)
{ allBracketsClosed = true }
else
@@ -189,7 +189,7 @@ function ChangeDict(selectedDict,myKey,displayKey,sl_SendNoChange)
last_Param = actParam
- console.log('Change Dict')
+ // console.log('Change Dict')
switch (selectedDict)
{
case 1:
@@ -594,7 +594,7 @@ function TooltipChecker(cm)
CursorPos = cm.getCursor()
actLine = CursorPos.line
actColumn = CursorPos.ch
- console.log('Line : ' + actLine+ ' Column : '+actColumn)
+ // console.log('Line : ' + actLine+ ' Column : '+actColumn)
txtCode = widgetCodeMirror.getValue()
realLength = txtCode.length
@@ -662,7 +662,7 @@ function TooltipChecker(cm)
{
try
{
- console.log('nothing to do for Preview of colors/icons in tooltip')
+ // console.log('nothing to do for Preview of colors/icons in tooltip')
myIcon =""
myIconVisible = "hidden"
myActColor = ""
@@ -772,7 +772,7 @@ function TooltipChecker(cm)
displayKey = ''
for (type in myWidgetJson[actWidgetName]['param'][actParam]['valid_values'])
{
- console.log("Type : " + myWidgetJson[actWidgetName]['param'][actParam]['valid_values'][type])
+ // console.log("Type : " + myWidgetJson[actWidgetName]['param'][actParam]['valid_values'][type])
myType = myWidgetJson[actWidgetName]['param'][actParam]['valid_values'][type]
myRegex = myRegex + '\\| Item.*'+myType+'|'
displayKey = displayKey + " " +myType +' |'
@@ -786,7 +786,7 @@ function TooltipChecker(cm)
if (actParam != last_Param && myWidgetJson[actWidgetName]['param'][actParam].hasOwnProperty("type"))
{
- console.log("found Parameter Type")
+ // console.log("found Parameter Type")
switch (true)
{
@@ -863,9 +863,9 @@ function TooltipChecker(cm)
myToolTipHdl.innerHTML +='deprecated :'+ myWidgetJson[actWidgetName]['deprecated']+'
'
}
myToolTipHdl.innerHTML += myToolMacro.replace('%param%',newParam)
- myToolTipHdl.innerHTML +='
Description
'+ myDescription
+ myToolTipHdl.innerHTML +='
'+ sv_lang['widgetassi']['description'] +'
'+ myDescription
paramKey = ("00" + CommaCount).slice(-2);
- myToolTipHdl.innerHTML +='
aktueller Parameter : '+actParam+'
'
+ myToolTipHdl.innerHTML +='
'+ sv_lang['widgetassi']['actual'] +'Parameter: '+actParam+'
'
// Display all the parameters
for (param in myWidgetJson[actWidgetName]['param'][actParam])
{
@@ -914,7 +914,7 @@ function registerAutocompleteHelper(name, curDict) {
var start = cur.ch,
end = start;
- console.log('Autocomplete called - autocompleteHint')
+ // console.log('Autocomplete called - autocompleteHint')
var charexp = /[\w\.\'\"$]+/;
while (end < curLine.length && charexp.test(curLine.charAt(end))) ++end;
while (start && charexp.test(curLine.charAt(start - 1))) --start;
@@ -1038,7 +1038,7 @@ function add_2_Dict(add2Dict,widget2check)
myDisplayText = myValue + " "
myCompleteDict.push({ text: ""+myValue+"", displayText: myDisplayText.substr(0,18)+" | " + myParamType+"@"+myWidget });
myCompleteDictwithQuotes.push({ text: "'"+myValue+"'", displayText: myDisplayText.substr(0,18)+" | " + myParamType+"@"+myWidget });
- console.log("added spec. Parameter to dict :" + myValue+" | " + myParamType+"@"+myWidget )
+ // console.log("added spec. Parameter to dict :" + myValue+" | " + myParamType+"@"+myWidget )
}
}
@@ -1060,7 +1060,7 @@ function CheckValidValues()
{
if(myWidgetJson[myWidget]['param'][actParam]['type'] != 'item')
{
- console.log(myWidget + '-> Param : '+actParam + '-> valid_values :' + myWidgetJson[myWidget]['param'][actParam]['valid_values']+'|')
+ // console.log(myWidget + '-> Param : '+actParam + '-> valid_values :' + myWidgetJson[myWidget]['param'][actParam]['valid_values']+'|')
myParamType = actParam
add_2_Dict(true,myWidget)
@@ -1071,9 +1071,9 @@ function CheckValidValues()
}
}
-//************************************************************************
-//function to change Dict to Auto-close quotes
-//***********************************************************************
+/*******************************************************************************************
+* function to change Dict to Auto-close quotes - deactivated after improvement of autoclose
+********************************************************************************************
function changeCloseBrackets(byKey)
{
quotestate = document.getElementById("switch_quotes").checked
@@ -1117,3 +1117,4 @@ function changeCloseBrackets(byKey)
}
console.log("changeCloseBrackets")
}
+*/
\ No newline at end of file
diff --git a/pages/_template/rooms_menu.html b/pages/_template/rooms_menu.html
index c4373c386..5a6c64d33 100644
--- a/pages/_template/rooms_menu.html
+++ b/pages/_template/rooms_menu.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2023
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -19,9 +19,11 @@
{{ lib.svgimg ('', 'scene_sleeping_alternat.svg', 'icon0', '') }}Sleeping
-
-
+
+
+ /** place to insert widgets on the right end of the menu button */
+
/**
@@ -30,9 +32,9 @@
*
*
* Sleeping
+*
*
*
-*
*
*/
diff --git a/pages/base/apps.html b/pages/base/apps.html
index b81d9bcdc..b715e9153 100644
--- a/pages/base/apps.html
+++ b/pages/base/apps.html
@@ -1,8 +1,8 @@
/**
* -----------------------------------------------------------------------------
* @package smartVISU
-* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @author Martin Gleiß, Wolfram v. Hülsen
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -14,6 +14,7 @@
{% if page=='apps' %}
+ {% set language = lang('baselang') %}
{% for file in dir('apps', 'app_(.+?).html') %}
{% set app = docu('apps/app_'~file.name~'.html') %}
@@ -27,7 +28,11 @@
{{ app.title|e }}
- {{ app.description }}
+ {% if attribute(app, 'description_' ~ language) is defined %}
+ {{ attribute(app, 'description_'~language ) }}
+ {% else %}
+ {{ app.description }}
+ {% endif %}
{% if app.info or app.link %}
@@ -35,7 +40,12 @@ {{ app.title|e }}
{% endif %}
{% if app.info %}
- {{ app.info }}
+ {% if attribute(app, 'info_' ~ language) is defined %}
+ {{ attribute(app, 'info_'~language ) }}
+ {% else %}
+ {{ app.info }}
+ {% endif %}
+
{% endif %}
{% if app.link %}
{{ app.link|e }}
@@ -46,9 +56,9 @@ {{ app.title|e }}
{% endif %}
{% if app.author %}
- Author: {{ app.author }}
+ {{ lang('templatechecker', 'author')|capitalize }}: {{ app.author }}
{% endif %}
- File: {{ file.file }}
+ {{ lang('templatechecker', 'file')|capitalize }}: {{ file.file }}
{% if app.version %}
Version: {{ app.version }}
{% endif %}
diff --git a/pages/base/base.css b/pages/base/base.css
index 868851738..4673307d6 100644
--- a/pages/base/base.css
+++ b/pages/base/base.css
@@ -250,7 +250,8 @@ a:hover {
.ui-listview .ui-li-has-thumb > svg:first-child,
.ui-listview .ui-li-has-thumb>.ui-btn>svg:first-child,
-.ui-listview .ui-btn>svg.icon
+.ui-listview .ui-btn>svg.icon,
+.ui-listview .ui-btn>img.icon
{
position: absolute;
left: 0;
@@ -259,6 +260,11 @@ a:hover {
max-width: 5em;
}
+.ui-listview [data-widget].ui-btn>svg.icon,
+.ui-listview [data-widget] .ui-btn>svg.icon {
+ position: unset;
+}
+
.ui-listview .ui-li-has-thumb > img:first-child,
.ui-listview .ui-li-has-thumb > .ui-btn > img:first-child,
.ui-listview .ui-li-has-thumb .ui-li-thumb,
@@ -278,6 +284,7 @@ a:hover {
.ui-li-aside {
font-size: 0.8em; /* 0.875em; */
right: .6em !important;
+ z-index: 3;
}
.ui-li-aside .icon {
@@ -1192,7 +1199,7 @@ input.ui-slider-input.ui-slider-no-input[data-orientation='semicircle'] {
-webkit-border-radius: 0.1em 0.1em 0.3em 0.3em;
border-radius: 0.1em 0.1em 0.3em 0.3em;
opacity: 0.85;
- filter: alpha(opacity=85);
+ filter: alpha(opacity=85); /* IE7+ command for opacity */
}
/**
@@ -1272,17 +1279,31 @@ input.ui-slider-input.ui-slider-no-input[data-orientation='semicircle'] {
}
.dimmer .switch,
-.dimmer-left .switch {
+.dimmer-left .switch,
+.dimmer-left .ui-midi,
+.dimmer-left .ui-mini,
+.dimmer-left .ui-micro {
float: left;
padding-left: 0;
margin-right: 12px;
}
-.dimmer-right .switch {
+.dimmer-right .switch,
+.dimmer-right .ui-midi,
+.dimmer-right .ui-mini,
+.dimmer-right .ui-micro {
float: right;
padding-right: 0;
margin-left: 12px;
}
+.dimmer-left .ui-btn.ui-midi,
+.dimmer-right .ui-btn.ui-midi {
+ margin-top: -5px;
+}
+.dimmer-left .ui-btn.ui-micro,
+.dimmer-right .ui-btn.ui-micro {
+ margin-top: 10px;
+}
.dimmer .icon,
.dimmer-left .icon,
@@ -1292,11 +1313,7 @@ input.ui-slider-input.ui-slider-no-input[data-orientation='semicircle'] {
}
.dimmer p,
-.dimmer-left p {
- margin: 0;
- padding: 0 0 5px 15px;
-}
-
+.dimmer-left p,
.dimmer-right p {
margin: 0;
padding: 0 0 5px 15px;
@@ -1305,11 +1322,35 @@ input.ui-slider-input.ui-slider-no-input[data-orientation='semicircle'] {
.dimmer .ui-slider,
.dimmer-left .ui-slider {
margin-left: 45px;
-
}
+
.dimmer-right .ui-slider {
margin-right: 45px;
}
+.dimmer-left.dimmer-midi .ui-slider {
+ margin-left: 64px;
+}
+.dimmer-right.dimmer-midi .ui-slider {
+ margin-right: 64px;
+}
+.dimmer-left.dimmer-mini .ui-slider {
+ margin-left: 48px;
+}
+.dimmer-right.dimmer-mini .ui-slider {
+ margin-right: 48px;
+}
+.dimmer-left.dimmer-micro .ui-slider {
+ margin-left: 38px;
+}
+.dimmer-right.dimmer-micro .ui-slider {
+ margin-right: 38px;
+}
+.dimmer-notext .ui-slider {
+ margin-top: 4px;
+}
+.dimmer-notext.dimmer-micro .ui-slider {
+ margin-top: 8px;
+}
.codepad {
display: inline-block;
@@ -1558,7 +1599,7 @@ div.ui-slider-switch{
width: 350px !important;
}
@media screen and (max-width: 625px){
- .uzsuRowExpert, .uzsuRowHoliday, .uzsuRowCondition, .uzsuRowDelayedExec, .uzsuCellExpert, .uzsuRowSeriesLine{
+ .uzsuRowExpert, .uzsuRowHoliday, .uzsuRowCondition, .uzsuRowDelayedExec, .uzsuCellExpert, .uzsuRowSeriesLine, .uzsuCellSeries {
display: none;
}
}
@@ -1609,7 +1650,10 @@ div.ui-slider-switch{
.uzsuCell [data-tip]:after {
left: -190px;
}
-.highcharts-root .uzsu-event-sunrise {
+/**
+ * ---------- UZSU Graph ------------------------------------------------
+ */
+ .highcharts-root .uzsu-event-sunrise {
fill: #ffffff;
stroke: rgba(255, 255, 255, 0.5);
}
@@ -1629,6 +1673,16 @@ div.ui-slider-switch{
fill: #808080;
stroke: #808080;
}
+.uzsu-all-inactive.uzsu-general-once .uzsu-active-toggler {
+ fill: #FF8080;
+ stroke: #FF8080;
+}
+[data-widget="device.uzsugraph"] .highcharts-navigator,
+[data-widget="device.uzsugraph"] .highcharts-navigator-series,
+[data-widget="device.uzsugraph"] .highcharts-navigator-xaxis,
+[data-widget="device.uzsugraph"] .highcharts-navigator-yaxis {
+ display: none;
+}
/**
* --- W i d g e t s : M U L T I M E D I A ----------------------------------
@@ -1742,10 +1796,6 @@ div.ui-slider-switch{
.plot.plot-highstock {
height: 315px;
}
-.plot.plot-highstock {
- height: 315px;
-}
-
.block .ui-fixed .plot,
.block .set-1 .plot {
min-height: 14.5em;
diff --git a/pages/base/config.html b/pages/base/config.html
index 1a78f1a69..34a3ab1f2 100644
--- a/pages/base/config.html
+++ b/pages/base/config.html
@@ -41,7 +41,7 @@ {{ lang('configuration_page', 'configuration', 'label') }}
{% set cfg_data = read_config(source) %}
/** if configured driver is not available and has been changed to 'offline' by root.html, show the active driver (which should be 'offline') */
- {% if cfg_data['driver'] is defined and cfg_data['driver'] != config_driver %}
+ {% if cfg_data['driver'] is defined and not isfile('driver/io_' ~ cfg_data['driver'] ~ '.js') %}
{% set cfg_data = cfg_data | merge({'driver': config_driver }) %}
{% endif %}
@@ -181,8 +181,9 @@ {{ lang('configuration_page', 'options', 'lab
{{ lang('configuration_page', 'functions', 'label') }}
{{ forms.config_flip(source, values, 'updatecheck') }}
- {{ forms.config_flip(source, values, 'driver_loopback') }}
{{ forms.config_flip(source, values, 'collapsible_reset') }}
+ {{ forms.config_flip(source, values, 'driver_loopback') }}
+ {{ forms.config_flip(source, values, 'driver_signalBusy') }}
diff --git a/pages/base/configure.php b/pages/base/configure.php
index c395a7b19..857c9600f 100755
--- a/pages/base/configure.php
+++ b/pages/base/configure.php
@@ -3,7 +3,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Stefan Widmer
- * @copyright 2016
+ * @copyright 2016 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -55,7 +55,7 @@
$sources = array('all');
if(isset($_GET['source']))
$sources = $_GET['source'];
- if(!is_array($sources)) $sources = array($sources);
+ if(!\is_array($sources)) $sources = array($sources);
$result = array();
foreach($sources as $source) {
diff --git a/pages/base/credits.html b/pages/base/credits.html
index 25a75d984..b744f2839 100644
--- a/pages/base/credits.html
+++ b/pages/base/credits.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -14,11 +14,10 @@
Credits
- Thanks to all our supporters! Don't hesitate to contact me, if you have wishes or problems!
+ Thanks to all our supporters!
Special thanks to
-
@@ -36,7 +35,7 @@ Special thanks to
The jQuery Foundation for
jQuery mobile
Touch-Optimized Web Framework for Smartphones & Tablets
- Licensed under the MIT
+ Licensed under the MIT License
@@ -47,7 +46,7 @@ Special thanks to
Fabien Potencier for the
TWIG template engine
The flexible, fast, and secure template engine for PHP
- Released under the new BSD license
+ Released under the BSD license
@@ -113,12 +112,38 @@ Special thanks to
-
+
+
+
+ Jonathan Goode and team for the PHP ICS Parser
+ Licensed under the MIT license
+
+
+
+
Marijn Haverbeke and team for codemirror
Licensed under the MIT license
+
+
+
+
+
+
+ Soundar for the jQuery roundslider plugin
+ Licensed under the MIT license
+
+
+
+
+
+
+
+ Kamran Ahmed for the jQuery toast plugin
+ Licensed under the MIT license
+
{% endblock %}
diff --git a/pages/base/menu.html b/pages/base/menu.html
index 746673669..b185ff3f8 100644
--- a/pages/base/menu.html
+++ b/pages/base/menu.html
@@ -1,8 +1,8 @@
/**
* -----------------------------------------------------------------------------
* @package smartVISU
-* @author Martin Gleiss, Wolfram v. Hülsen
-* @copyright 2012 - 2023
+* @author Martin Gleiß, Wolfram v. Hülsen
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -23,7 +23,7 @@
{% else%}
-
+
{% endif %}
diff --git a/pages/base/pics/scale_pallets.png b/pages/base/pics/scale_pellets.png
similarity index 100%
rename from pages/base/pics/scale_pallets.png
rename to pages/base/pics/scale_pellets.png
diff --git a/pages/base/quad.css b/pages/base/quad.css
index a874443c4..c12372a4b 100755
--- a/pages/base/quad.css
+++ b/pages/base/quad.css
@@ -2,12 +2,11 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
- * @copyright 2012
- * @license GPL
+ * @copyright 2012 - 2024
+ * @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
-
@CHARSET "UTF-8";
.quad *, *:before, *:after {
box-sizing: border-box;
@@ -261,10 +260,10 @@
height: 65px;
}
-.quad_tiles .ui-ri-aside img.icon {
+.quad_tiles .ui-ri-aside img.icon,
+.quad_tiles .ui-ri-aside svg.icon {
height: 24px;
width: 24px;
-
}
.quad_tiles .ui-btn {
@@ -280,10 +279,12 @@
left: 7px;
right: 0px;
position: absolute;
+ z-index:3;
}
.quad_tiles .ui-li-aside {
top: 0 !important;
+ z-index:3;
}
.quad_list a {
@@ -293,7 +294,6 @@
.quad_list .ui-li-static {
display: table-row;
-
}
.quad_list li {
@@ -306,28 +306,20 @@
.quad_list .ui-li-divider {
padding: 0 0 0 10px;
}
+
.quad_list .ui-li-static.ui-li {
padding: 0;
}
+
.quad_list li:nth-child(odd) {
/**background-color: #1d1d1d;*/
}
+
.quad_list li:nth-child(even) {
/**background-color: #212121;*/
}
-.quad_list img.icon {
- height: 32px;
- width: 32px;
- margin-top: -4px;
-}
-.quad_list svg.icon {
- height: 32px;
- width: 32px;
- margin-top: -4px;
-}
-
-.quad_list svg.fx-icon {
+.quad_list img.icon, .quad_list svg.icon, .quad_list svg.fx-icon {
height: 32px;
width: 32px;
margin-top: -4px;
@@ -419,8 +411,7 @@
min-width: 300px;
}
-.quad_rtr-popup
-{
+.quad_rtr-popup {
height: 180px;
min-width: 320px;
text-align: center;
@@ -523,7 +514,7 @@
margin: 15px 0 10px 0;
}
-//NOTIFYBADGE
+/* NOTIFYBADGE */
/* make sure the element has position: relative */
[data-notifications] {
position: relative;
@@ -540,7 +531,7 @@
display: inline-block;
height:1.5rem;
left: 15px;
-// top: 15px;
+/* top: 15px; */
width:1.5rem;
text-align: center;
line-height: 1.5rem;;
@@ -586,12 +577,10 @@
.quad_list .column_symbol{
height: 37px !important;
-
}
.quad_list .column_pos{
width: 130px !important;
-
}
.quad_list div.column_plot, div.column_stateengine, div.column_uzsu, div.column_move_up, div.column_move_down, div.column_stop, div.column_mute {
@@ -655,13 +644,11 @@ div.quad_cover-popup img {
margin: 5px 0 8px 0;
}
-
-.column_value_slider, .column_pos_slider, .column_song_position, .column_volume_slider
-{
+.column_value_slider, .column_pos_slider, .column_song_position, .column_volume_slider {
vertical-align: middle;
}
-.docu_text{
+.docu_text {
margin-top: 20px;
margin-bottom: 10px;
}
diff --git a/pages/base/root.html b/pages/base/root.html
index 338c60743..6d805d481 100755
--- a/pages/base/root.html
+++ b/pages/base/root.html
@@ -54,7 +54,6 @@
'lib/weather/jdigiweather.css',
'pages/base/base.css',
'pages/base/quad.css',
- icon0 ~ 'jquery.mobile.icons.min.css',
design_css,
'pages/' ~ config_pages ~ '/visu.css'
] %}
@@ -232,18 +231,24 @@
io.run();
});
- // Activate the info field in top right corner
+ // Do some actions on page show
$(document).on('pagecontainershow', function () {
+ // Activate the info field in top right corner
notify.display();
- {% if driver_error_msg is not empty %}
+ // show warning if driver error has been detected
+ {% if driver_error_msg is not empty %}
if(io.socketErrorNotification == null || !notify.exists(io.socketErrorNotification))
io.socketErrorNotification = notify.message('warning', 'Backend Driver', "{{ driver_error_msg }}");
- {% endif %}
- // workaround for jQM theme bug - part II
+ {% endif %}
+
+ /* workaround for jQM theme bug in Firefox - obsolete after fix in Firefox
$(this).find('.ui-collapsible-heading').each(function(){
var headerClass = 'ui-page-theme-'+ $(this).closest('div').attr('data-theme');
$(this).addClass(headerClass);
});
+ */
+
+ // reset all collapsibles in menu to original state
{% if config_collapsible_reset %}
$(sv.activePage).find('.secondary [data-collapsed="false"] .ui-collapsible-heading-collapsed').parents().first().collapsible('expand');
{% endif%}
@@ -259,12 +264,36 @@
}
//DEBUG: console.log('anchor clicked', event.target);
});
+
+ // detect link target with anchor and scroll to it, e.g href="index.php?page=myPage&anchor=myAnchor"
+ $(document).on('click', 'a[href*="&anchor="]', function (event) {
+ event.preventDefault();
+ if (event.target.href !== undefined)
+ var targetURI = event.target.href;
+ else
+ targetURI = $(event.target).parents('a.ui-link').first()[0].href;
+
+ var anchorPos = targetURI.indexOf('&anchor');
+ var anchor = targetURI.substring(anchorPos+8);
+ var target = targetURI.substring(0, anchorPos);
+ var targetOffset = $(sv.activePage).find('.ui-content').offset().top;
- // scroll to anchor after page is called w/ anchor link e.g href="index.php?page=myPage&anchor=myAnchor"
+ if (location.href.indexOf(target) == 0){
+ $.mobile.silentScroll($(sv.activePage).find('#'+ anchor).offset().top - targetOffset);
+ //DEBUG: console.log('same page link clicked: '+ anchor)
+ }
+ else {
+ $(':mobile-pagecontainer').pagecontainer('change', target);
+ window.anchorTarget = anchor
+ //DEBUG: console.log('new page link clicked: '+ anchor)
+ }
+ });
$(document).on('pagecontainerchange', function () {
- var searchAnchor = location.search.indexOf('anchor');
- if (searchAnchor > 0) {
- $.mobile.silentScroll($('#'+location.search.substring(searchAnchor+7)).offset().top);
+ if (window.anchorTarget != null) {
+ //DEBUG: console.log ('click on new page anchor target "'+ window.anchorTarget + '" detected');
+ var targetOffset = $(sv.activePage).find('.ui-content').offset().top;
+ $.mobile.silentScroll($(sv.activePage).find('#'+ window.anchorTarget).offset().top - targetOffset);
+ window.anchorTarget = null;
}
});
diff --git a/pages/base/smarthomeNG.html b/pages/base/smarthomeNG.html
index 90bb328cd..00eeef755 100644
--- a/pages/base/smarthomeNG.html
+++ b/pages/base/smarthomeNG.html
@@ -1,8 +1,8 @@
/**
* -----------------------------------------------------------------------------
* @package smartVISU
-* @author Martin Gleiss
-* @copyright 2012 - 2015
+* @author Martin Gleiß
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -46,11 +46,11 @@ memory ({{ basic.print('memorynow', 'env.core.memory', 'kB', 'VAR / 1024') }
- system start: {{ basic.print('systemstart', 'env.system.start', 'short') }},
- SmartHomeNG start: {{ basic.print('corestart', 'env.core.start', 'short') }}
+ System Start: {{ basic.print('systemstart', 'env.system.start', 'short') }},
+ SmartHomeNG Start: {{ basic.print('corestart', 'env.core.start', 'short') }}
{{ lib.connection() }}
- Location
+ {{ lang('system', 'location')|capitalize }}
{{ basic.print('sunrise', 'env.location.sunrise', 'time') }}
@@ -60,7 +60,7 @@ Location
{{ basic.print('moonrise', 'env.location.moonrise', 'time') }}
{{ basic.print('moonset', 'env.location.moonset', 'time') }},
- moonphase: {{ basic.print('moonphase', 'env.location.moonphase') }}, moonlight: {{ basic.print('moonlight', 'env.location.moonlight', '%') }}
+ {{ lang('system', 'moonphase') }}: {{ basic.print('moonphase', 'env.location.moonphase') }}, {{ lang('system', 'moonlight') }}: {{ basic.print('moonlight', 'env.location.moonlight', '%') }}
diff --git a/pages/base/system_menu.html b/pages/base/system_menu.html
index 6c109b02f..48b80b239 100644
--- a/pages/base/system_menu.html
+++ b/pages/base/system_menu.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Wolfram v. Hülsen, ramann
-* @copyright 2021 - 2023
+* @copyright 2021 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -10,19 +10,19 @@
- - System
+ - {{ lang('system', 'system') }}
-
{{ lib.svgimg ('', 'message_service.svg', 'icon0', '') }}
-
Configuration
+ {{ lang('system', 'config') }}
-
{{ lib.svgimg ('', 'control_clear.svg', 'icon0', '') }}
-
Template checker
+ {{ lang('system', 'templatechecker') }}
@@ -46,16 +46,16 @@ SmartHomeNG
-
{{ lib.svgimg ('', 'edit_save.svg', 'icon0', '') }}
-
Backup config
+ {{ lang('system', 'backup') }}
- - Help
+ - {{ lang('system', 'help') }}
-
{{ lib.svgimg ('', 'edit_copy.svg', 'icon0', '') }}
-
Documentation
+ {{ lang('system', 'docu') }}
@@ -63,7 +63,7 @@ Documentation
-
{{ lib.svgimg ('', 'message_help.svg', 'icon0', '') }}
-
Kurzanleitung (German)
+ Kurzanleitung (Deutsch)
{% endif %}
@@ -71,14 +71,21 @@ Kurzanleitung (German)
-
{{ lib.svgimg ('', 'time_manual_mode.svg', 'icon0', '') }}
-
Support on knx-user-forum
+ {{ lang('system', 'forum') }}
-
{{ lib.svgimg ('', 'logo_GitHub.svg', 'icon0', '') }}
-
Source & Issues on GitHub
+ {{ lang('system', 'github') }}
+
+
+
+ -
+
+ {{ lib.svgimg ('', 'edit_favorites', 'icon0', '') }}
+
{{ lang('system', 'newstuff') }}
diff --git a/pages/base/templatechecker.html b/pages/base/templatechecker.html
index 4c9e80c93..682e25017 100644
--- a/pages/base/templatechecker.html
+++ b/pages/base/templatechecker.html
@@ -1,15 +1,13 @@
/**
* -----------------------------------------------------------------------------
* @package smartVISU
-* @author Thomas Ernst
-* @copyright 2016
+* @author Thomas Ernst, Wolfram v. Hülsen
+* @copyright 2016 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
-
{% extends "system.html" %}
-
{% import "@widgets/forms.html" as forms %}
{% block content %}
@@ -17,42 +15,43 @@
+
Template Checker
+{{ lang('templatechecker', 'system') }}:
+
+
+ 'config.ini' {{ lang('templatechecker', 'file') }}
+
+
+ 'temp' {{ lang('templatechecker', 'directory') }}
+
+
+ php version
+
+
+ php {{ lang('templatechecker', 'extension') }} 'mbstring'
+
+
+ newer version
+
+
+{{ lang('templatechecker', 'pages') }}:
-System checks:
-
-
- 'config.ini' file
-
-
- 'temp' directory
-
-
- php version
-
-
- php extension 'mbstring'
-
-
- newer version
-
-
- Masteritem file
-
-
-Files in template directory:
+{{ lang('templatechecker', 'filelist') }}:
{% endblock %}
diff --git a/pages/base/widget_assistant.html b/pages/base/widget_assistant.html
index 20ad4d476..330589292 100644
--- a/pages/base/widget_assistant.html
+++ b/pages/base/widget_assistant.html
@@ -60,10 +60,10 @@
}
.CodeMirror-line{
text-align: left;
- padding-left: 20px;!important
+ padding-left: 20px !important;
}
.CodeMirror pre {
- padding-left: 30px; !important
+ padding-left: 30px !important;
}
.CodeMirror-wrap pre {
@@ -107,100 +107,83 @@
{% set actPage = config_pages %}
-
-
-
-
+
+
+
-
-
+
+
+
+
+
-
-
-
-
-
-
- Widget - Assistant
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Items loaded
-
-
- Colors loaded
-
-
- Icons loaded
-
- Widgets loaded
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+ Widget Editor
+
+
+
+
+
+
+
+
+
+
+
+ Items {{ lang('templatechecker', 'loaded') }}
+ {{ lang('widgetassi', 'colors') }} {{ lang('templatechecker', 'loaded') }}
+ Icons {{ lang('templatechecker', 'loaded') }}
+ Widgets {{ lang('templatechecker', 'loaded') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% set readme = lang('baselang') != 'de' ? 'lib/widget_assistant/README.html' : 'lib/widget_assistant/README_DE.html' %}
- Widget-Preview
+ {{ lang('widgetassi', 'waDocu') }}
-
@@ -243,10 +226,11 @@ Widget-Preview
actDictMode = 2
ChangeDict(6)
},
- "Ctrl-7": function(cm) {
- changeCloseBrackets(true)
+ /** "Ctrl-7": function(cm) {
+ changeCloseBrackets(true)
},
- "Ctrl-9": function(cm) {
+ */
+ "Ctrl-9": function(cm) {
ChangeSearch()
},
diff --git a/pages/docu/basic/widget_basic.icon.html b/pages/docu/basic/widget_basic.icon.html
index 078f52c00..0aec953ec 100644
--- a/pages/docu/basic/widget_basic.icon.html
+++ b/pages/docu/basic/widget_basic.icon.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -52,7 +52,7 @@ Examples
{{ basic.icon(icon.light('','','bath.light.value'), 'rgb', ['bath.color.r', 'bath.color.g', 'bath.color.b']) }}
- New in v3.0: icon sizes may be altered
+ Icon sizes may be altered:
{% filter trim|escape|nl2br %}{% verbatim %}
{{ basic.icon('light_light', 'rgb', ['bath.color.r', 'bath.color.g', 'bath.color.b'], 'micro') }}
diff --git a/pages/docu/basic/widget_basic.offset.html b/pages/docu/basic/widget_basic.offset.html
index 4292aff50..28a53a214 100644
--- a/pages/docu/basic/widget_basic.offset.html
+++ b/pages/docu/basic/widget_basic.offset.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -34,7 +34,7 @@ Examples
{{ basic.offset('', 'bath.rtr.set', -0.5, 'minus', '', 'micro') }}
- New in v3.2: limits can be added
+ Limits can be applied as min / max values for the item:
diff --git a/pages/docu/basic/widget_basic.print.html b/pages/docu/basic/widget_basic.print.html
index d9a8a3ba3..b35f2c0f2 100755
--- a/pages/docu/basic/widget_basic.print.html
+++ b/pages/docu/basic/widget_basic.print.html
@@ -56,7 +56,19 @@ Colors
{{ basic.print('', 'bath.light.value', '', '', '', '#f00') }}
{{ basic.print('', 'bath.light.value', '', '', [100,200], ['green', '', 'icon1']) }}
-
+ Usage as Tooltip
+ By giving any other widget an id and referencing this in the parameter href, a dynamic tooltip can be created on that widget by passing the value 'tooltip' to the parameter "rel". Some widgets need to be wrapped in a span containing the id.
+ Hover with the mouse over the flipswitch to see the effect. (Note: Will not work on Android devices wich do not support hover effects)
+
+ {% filter trim|escape|nl2br %}{% verbatim %}
+ {{ basic.flip('', 'bath.light.switch') }}
+ {{ basic.print('', 'bath.light.switch', 'text', 'VAR=="1"?"Schaltuhr ist an":"Schalter ist aus"','','','myFlip1','tooltip') }} {% endverbatim %}{% endfilter %}
+
+
+ {{ basic.flip('myFlip1', 'bath.light.switch') }}
+ {{ basic.print('', 'bath.light.switch', 'text', 'VAR=="1"?"Schalter ist an":"Schalter ist aus"','','','myFlip1','tooltip') }}
+
+
Advanced Scripting
basic.print can also be used for some "hacks".
This example shows how to update the color of a widget text based on the value of ANOTHER item. Click on the heater icon and change the temperature. The temperature print will turn red if the heater is off and green if it is on.
diff --git a/pages/docu/basic/widget_basic.select.html b/pages/docu/basic/widget_basic.select.html
index 92a11a37c..e3505bc50 100644
--- a/pages/docu/basic/widget_basic.select.html
+++ b/pages/docu/basic/widget_basic.select.html
@@ -26,7 +26,6 @@ Example
-
@@ -46,18 +45,20 @@ Example
-
-
- New
- List items can be used as dynamic option lists for the menu type. If a list item "itemvals" is given it overrides the other value parameters given in the macro call.
- Optional texts can be defined by a second item "itemtxts". If this is not defined the option values will be used as texts.
-
- {% filter trim|escape|nl2br %}{% verbatim %}
- {{ basic.select('', 'bath.multistate', '', '', '', '', '', '', 'bath.list1', 'bath.list2') }}
- {% endverbatim %}{% endfilter %}
-
+
-
+ Dynamic Select Values
+ List items can be used as dynamic option lists for the menu type. If a list item is given in the parameter "itemvals" it overrides the other value parameters given in the macro call.
+ Optional texts can be defined by a second item in the parameter "itemtxts". If this is not defined the option values will be used as texts.
+
+ {% filter trim|escape|nl2br %}{% verbatim %}
+ {{ basic.select('', 'bath.multistate', '', '', '', '', '', '', 'bath.list1', 'bath.list2') }}
+ {% endverbatim %}{% endfilter %}
+
+ Activity Indicator
+ The parameter "indictor" can be used to show different icons / colors / animations while the widget is waiting for the item update by the backend. For the grouped switches the options are
+ the same as in basic.stateswitch. In "menu" mode the widget displays activity with a blinking select menu, only.
+
{% endblock %}
diff --git a/pages/docu/basic/widget_basic.slider.html b/pages/docu/basic/widget_basic.slider.html
index 30e2401a5..61a11fa5a 100644
--- a/pages/docu/basic/widget_basic.slider.html
+++ b/pages/docu/basic/widget_basic.slider.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -15,7 +15,7 @@
Examples
See the various scaling options in the following examples.
- Silent mode (new in v3.1)
+ Silent mode
Per default, sliders send their values constantly during operation. There is also a silent mode
which limits value output to the end of the sliding phase. See the difference by moving different sliders.
The bottom slider is switched to silent mode while the others send their values live.
diff --git a/pages/docu/basic/widget_basic.stateswitch.html b/pages/docu/basic/widget_basic.stateswitch.html
index 7585ab493..10d67f2f9 100644
--- a/pages/docu/basic/widget_basic.stateswitch.html
+++ b/pages/docu/basic/widget_basic.stateswitch.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author WIDMER Stefan
-* @copyright 2017
+* @copyright 2017 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -71,7 +71,7 @@ Long press
{{ basic.stateswitch('', 'bath.light.switch', '', '', '', '', ['green', '#f00'], '', 'bath.multistate', '+6', 5) }}
- New in v3.2: Long press opening popup
+ Long press opening popup
{% filter trim|escape|nl2br %}{% verbatim %}
{{ basic.stateswitch('', 'bath.light.scene', '', 0, 'status_available', '', '', '', '#pop1') }}
@@ -92,7 +92,7 @@ This is a Popup
Styling
- New in v3.3: 6 classes 'icon0' to 'icon5' are available for coloring the icons. Pass them in the "color" parameter.
+ 6 classes 'icon0' to 'icon5' are available for coloring the icons. Pass them in the "color" parameter.
Dynamic icons can be used by calling the icon.* widgets in the icon parameters:
diff --git a/pages/docu/basic/widget_basic.symbol.html b/pages/docu/basic/widget_basic.symbol.html
index 256180373..9ee512c3d 100644
--- a/pages/docu/basic/widget_basic.symbol.html
+++ b/pages/docu/basic/widget_basic.symbol.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -141,7 +141,7 @@ Examples
{{ basic.symbol('', 'bath.light.value', ['low','medium','high'], ['control_1','control_2','control_3'], [85,170], '>') }}
- New in v3.0: size of symbols may be altered. As from v3.1 buttons are also provided and an additional text can be displayed on the
+ The size of symbols may be altered and button styles are provided. An additional text can be displayed on the
button(flip the switch to "on" )
{{ basic.flip('', 'bath.light.switch') }}
diff --git a/pages/docu/basic/widget_basic.tank.html b/pages/docu/basic/widget_basic.tank.html
index 5d19a29ec..f5f9c402f 100644
--- a/pages/docu/basic/widget_basic.tank.html
+++ b/pages/docu/basic/widget_basic.tank.html
@@ -21,8 +21,8 @@ Examples
{{ basic.tank('tank3', 'bath.value', 0, 255, 5, 'cylinder', '#f90' ) }}
{{ basic.tank('tank4', 'bath.value', 0, 255, 5, 'water') }}
{{ basic.tank('tank5', 'bath.value', 0, 255, 5, 'water', '#0c0') }}
- {{ basic.tank('tank6', 'bath.value', 0, 255, 5, 'pallets') }}
-
+ {{ basic.tank('tank6', 'bath.value', 0, 255, 5, 'pellets') }}
+ {{ basic.tank('tank7', 'bath.value', 0, 255, 5, 'cylinder', ['#c00','#cc0','#0c0','#cc0','#c00'], [80,100,155,200]) }}
{% endverbatim %}{% endfilter %}
@@ -32,7 +32,8 @@ Examples
{{ basic.slider('slider1', 'bath.value', 0, 255, 5) }}
- From left to right: 'none', 'cylinder', 'cylinder' orange, 'water', 'water' green, 'pallets'
+ From left to right: 'none', 'cylinder', 'cylinder' orange, 'water', 'water' green, 'pellets', 'cylinder'
+ The last one will have different colors depending on the value <80: red, 80-99: yellow, 100-154: green, 155-199: yellow, >=200: red
{{ basic.tank('tank1', 'bath.value') }}
@@ -40,7 +41,8 @@ Examples
{{ basic.tank('tank3', 'bath.value', 0, 255, 5, 'cylinder', '#f90' ) }}
{{ basic.tank('tank4', 'bath.value', 0, 255, 5, 'water') }}
{{ basic.tank('tank5', 'bath.value', 0, 255, 5, 'water', '#0c0') }}
- {{ basic.tank('tank6', 'bath.value', 0, 255, 5, 'pallets') }}
+ {{ basic.tank('tank6', 'bath.value', 0, 255, 5, 'pellets') }}
+ {{ basic.tank('tank7', 'bath.value', 0, 255, 5, 'cylinder', ['#c00','#cc0','#0c0','#cc0','#c00'], [80,100,155,200]) }}
diff --git a/pages/docu/basic/widget_basic.trigger.html b/pages/docu/basic/widget_basic.trigger.html
index 00e140442..99949b484 100644
--- a/pages/docu/basic/widget_basic.trigger.html
+++ b/pages/docu/basic/widget_basic.trigger.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -13,7 +13,7 @@
{% block example %}
This widget triggers a logic on the backend given by the parameter 'name'. The default function will show a button for manual triggering.
- NEW: with the parameter 'event' set to 'page', the logic is being triggered automatically during page create (button is hidden) while 'both' enables both triggenring methods.
+ With the parameter 'event' set to 'page', the logic is being triggered automatically during page create (button is hidden) while 'both' enables both triggenring methods.
Examples
diff --git a/pages/docu/calendar/widget_calendar.list.html b/pages/docu/calendar/widget_calendar.list.html
index b171665ed..a7807ead0 100644
--- a/pages/docu/calendar/widget_calendar.list.html
+++ b/pages/docu/calendar/widget_calendar.list.html
@@ -37,4 +37,22 @@ Examples
{{ calendar.list('', '', 3, ['#993399','green'], '', ['Personal','Waste'], 'l') }}
+ You can specify your own icons and colors for calendar events in the language file , e.g. .dropins/lang/mylang.ini in the section "[calendar_event_format]".
+
+
+ blue bin[icon] = message_garbage
+ blue bin[color] = #0000FF
+
+
+ Attention: calendar.list searches for the specified keywords and applies icon and color to the event if it's title contains a keyword. With the above example it will display the same for "buy blue binoculars"
+ and "blue bin". Specify the more specific keywords in sequence behind the more general ones in order to optimize pattern matching.
+
+ A default icon and color can be defined using "default_img_list". If no default is defined a transparent image "trans.png" will be displayed.
+
+
+ default_img_list[icon] = message_achtung
+ default_img_list[color] = "rgb(32, 178, 170)"
+
+
+
{% endblock %}
diff --git a/pages/docu/calendar/widget_calendar.waste.html b/pages/docu/calendar/widget_calendar.waste.html
index fbdc1c715..1cf4fd08d 100644
--- a/pages/docu/calendar/widget_calendar.waste.html
+++ b/pages/docu/calendar/widget_calendar.waste.html
@@ -27,5 +27,24 @@ Examples
+
+ You can specify your own icons and colors for calendar events in the language file , e.g. .dropins/lang/mylang.ini in the section "[calendar_event_format]".
+ If the icon is defined as "message_garbage" the widget converts it to "message_garbage_2" which is the roll-out garbage container.
+
+
+ blue bin[icon] = message_garbage
+ blue bin[color] = #0000FF
+
+
+ Attention: calendar.waste searches for the specified keywords and applies icon and color to the event if it's title starts with a keyword. With the above example it will display the same for "blue binoculars"
+ and "blue bin". Specify the more specific keywords in sequence behind the more general ones in order to optimize pattern matching.
+
+ A default icon and color can be defined using "default_img_waste". If no default is defined a transparent image "trans.png" will be displayed.
+
+
+ default_img_waste[icon] = message_achtung
+ default_img_waste[color] = "rgb(32, 178, 170)"
+
+
{% endblock %}
diff --git a/pages/docu/clock/widget_clock.countdown.html b/pages/docu/clock/widget_clock.countdown.html
index b7373ba21..da2648cb4 100644
--- a/pages/docu/clock/widget_clock.countdown.html
+++ b/pages/docu/clock/widget_clock.countdown.html
@@ -12,7 +12,7 @@
{% block example %}
diff --git a/pages/docu/device/widget_device.uzsuicon.html b/pages/docu/device/widget_device.uzsuicon.html
index 425f7764a..975d2652e 100755
--- a/pages/docu/device/widget_device.uzsuicon.html
+++ b/pages/docu/device/widget_device.uzsuicon.html
@@ -2,7 +2,7 @@
* -----------------------------------------------------------------------------
* @package smartVISU
* @author Martin Gleiß
-* @copyright 2012 - 2015
+* @copyright 2012 - 2024
* @license GPL [http://www.gnu.de]
* -----------------------------------------------------------------------------
*/
@@ -14,7 +14,7 @@
diff --git a/pages/docu/device/widget_device.uzsutable.html b/pages/docu/device/widget_device.uzsutable.html
index 2cc4c0c01..9526c4ecf 100644
--- a/pages/docu/device/widget_device.uzsutable.html
+++ b/pages/docu/device/widget_device.uzsutable.html
@@ -11,9 +11,9 @@
{% block example %}
{% endmacro %}
diff --git a/widgets/plot.html b/widgets/plot.html
index 050115369..881067e03 100644
--- a/widgets/plot.html
+++ b/widgets/plot.html
@@ -74,7 +74,7 @@
*
* @param {id=} unique id for this widget. Add the string "plotpopup" to activate on-demand plot data loading, i.e. plot data are not loaded during page creation but when the popup containing the plot is opened. (optional)
* @param {item[?](bool,num,list)} series of item(s); multiple items in array form: [ item1 , item2 ]
-* @param {text[?](avg,sum,min,max,minmax,minmaxavg,raw,on)=avg} the aggregation mode (optional, default 'avg')
+* @param {mode[?]=avg} the aggregation mode (optional, default 'avg')
May be a single mode or an array with separate mode per item.
Available modes depend on backend, common ones are 'avg', 'sum', 'min', 'max', 'minmax', 'minmaxavg', 'on', 'raw'. See backend's documentation for further information.
* @param {duration=1h} the minimum time (x-axis): '1h', '2h'... (duration-format) Value is interpreted as timestamp if no unit is given (e.g. 1629109298731).
@@ -90,10 +90,10 @@
* @param {text[?](line,linestack,stair,spline,area,areastair,areaspline,areastack,column,columnstack)=line} type of each serie: 'line', 'linestack', 'stair', 'spline', 'area', 'areastair', 'areaspline', 'areastack','column', 'columnstack'; multiples in array form (optional, default 'line')
* @param {text[?]=} title for the x-axis and y-axes in array form: [title_x-axis, title_y-axis1, title_y-axis2, ...] (optional)
* @param {duration(advanced,day)=} minimal time range while zooming or 'advanced' or 'day' (optional, duration-format)
- By passing 'advanced' a seaparate range selector is shown and data grouping for large amount of data is enabled
+ By passing 'advanced' a separate range selector is shown and data grouping for large amount of data is enabled
By passing 'day', the plot is shown from 0:00 until 24:00 on the day starting after tmin. Set tmin to '24h' or '1d' for today, '48h' or '2d' for yesterday and so on. tmax must be 'now' or at least 48 hours less than tmin.
-* @param {value[]=} assignment of the series to the y-axes; multiples in array form (optional)
-* @param {value[]=} y-axes setup for left '0' and right '1' hand in array form (optional)
+* @param {value[?]=} assignment of the series to the y-axes; multiples in array form (optional)
+* @param {value[?]=} y-axes setup for left '0' and right '1' hand in array form (optional)
* @param {color[?]=} y-axes color; multiples in array form (optional)
* @param {text[?](linear,logarithmic,boolean)=linear} y-axes type, one of 'linear', 'logarithmic' or 'boolean'; multiples in array form (optional, default 'linear')
* @param {format[?]=} unit(s) for the y-axis. Either a unit of the language file, an individual format string (PHP sprintf like) or a simple string as suffix. Multiples in array form. (optional)
@@ -108,51 +108,60 @@
*/
{% macro period(id, item, mode, tmin, tmax, ymin, ymax, count, label, color, exposure, axis, zoom, assign, opposite, ycolor, ytype, unit, chartoptions, stacking, stacks, export, source) %}
- {% if (not export is empty) and export > 0 %}
-
-
- {% if export == 2 %}
-
- {% endif %}
- {% endif %}
- {% set source = source|default('database') %}
- {% set tmax = (tmax|default('now')|lower=='0h' or tmax==0 or tmax is empty) ? 'now' : tmax %}
- {% set tmin = tmin|default('1h') %}
-
- {% set mode = (mode is iterable ? mode : [mode|default('avg')]) %}
- {% set count = (count is iterable ? count : [count|default(100)]) %}
- {% set unit = (unit is iterable ? unit : [unit|default('')]) %}
- {% set units = [] %}
- {% for uniti in unit %}
- {% set units = units|merge([uniti|replace({',' : ';'})]) %} /** hide comma before implode/explode to allow format strings, e.g. %01,02f% */
- {% endfor %}
- {% set stacking = (stacking is iterable ? stacking : [stacking|default('normal')]) %}
- {% set stacks = (stacks is iterable ? stacks : [stacks|default('0')]) %}
- {% set item = (item is iterable ? item : [item]) %}
- {% set seriesitems = [] %}
- {% for itemi in item %}
- {% if mode|length < loop.index %}
- {% set mode = mode|merge([mode|last]) %}
- {% endif %}
- {% set modei = mode[loop.index0] %}
-
- {% if count|length < loop.index %}
- {% set count = count|merge([count|last]) %}
- {% endif %}
- {% set counti = count[loop.index0] %}
-
- {% if source == 'database' %}
- {% if modei == 'minmax' %}
- {% set seriesitems = seriesitems|merge([ implode(itemi, ['min', tmin, tmax, counti]), implode(itemi, ['max', tmin, tmax, counti]) ]) %}
- {% elseif modei == 'minmaxavg' %}
- {% set seriesitems = seriesitems|merge([ implode(itemi, ['min', tmin, tmax, counti]), implode(itemi, ['max', tmin, tmax, counti]), implode(itemi, ['avg', tmin, tmax, counti]) ]) %}
- {% else %}
- {% set seriesitems = seriesitems|merge([implode(itemi, [modei, tmin, tmax, counti])]) %}
- {% endif %}
- {% else %}
- {% set seriesitems = seriesitems|merge([itemi]) %}
- {% endif %}
- {% endfor %}
+ {%- if (not export is empty) and export > 0 -%}
+ {%- if once('plotimageexport') -%}
+
+
+ {%- endif -%}
+ {%- if export == 2 -%}
+ {%- if once('plotdataexport') -%}
+
+ {%- endif -%}
+ {%- endif -%}
+ {%- endif -%}
+
+ {%- set source = source|default('database') -%}
+ {%- set tmax = (tmax|default('now')|lower=='0h' or tmax==0 or tmax is empty) ? 'now' : tmax -%}
+ {%- set tmin = tmin|default('1h') -%}
+
+ {%- set mode = (mode is iterable ? mode : [mode|default('avg')]) -%}
+ {%- set count = (count is iterable ? count : [count|default(100)]) -%}
+ {%- set unit = (unit is iterable ? unit : [unit|default('')]) -%}
+ {%- set units = [] -%}
+ {%- for uniti in unit -%}
+ {%- set units = units|merge([uniti|replace({',' : ';'})]) -%} /** hide comma before implode/explode to allow format strings, e.g. %01,02f% */
+ {%- endfor -%}
+ {%- set stacking = (stacking is iterable ? stacking : [stacking|default('normal')]) -%}
+ {%- set stacks = (stacks is iterable ? stacks : [stacks|default('0')]) -%}
+ {%- set item = (item is iterable ? item : [item]) -%}
+ {%- set seriesitems = [] -%}
+ {%- for itemi in item -%}
+ {%- if mode|length < loop.index -%}
+ {%- set mode = mode|merge([mode|last]) -%}
+ {%- endif -%}
+ {%- set modei = mode[loop.index0] -%}
+
+ {%- if count|length < loop.index -%}
+ {%- set count = count|merge([count|last]) -%}
+ {%- endif -%}
+ {%- set counti = count[loop.index0] -%}
+ {%- if mode == 'raw' or counti >= 5000 -%}
+ {%- if once('plotboost') -%}
+
+ {%- endif -%}
+ {%- endif -%}
+ {%- if source == 'database' -%}
+ {%- if modei == 'minmax' -%}
+ {%- set seriesitems = seriesitems|merge([ implode(itemi, ['min', tmin, tmax, counti]), implode(itemi, ['max', tmin, tmax, counti]) ]) -%}
+ {%- elseif modei == 'minmaxavg' -%}
+ {%- set seriesitems = seriesitems|merge([ implode(itemi, ['min', tmin, tmax, counti]), implode(itemi, ['max', tmin, tmax, counti]), implode(itemi, ['avg', tmin, tmax, counti]) ]) -%}
+ {%- else -%}
+ {%- set seriesitems = seriesitems|merge([implode(itemi, [modei, tmin, tmax, counti])]) -%}
+ {%- endif -%}
+ {%- else -%}
+ {%- set seriesitems = seriesitems|merge([itemi]) -%}
+ {%- endif -%}
+ {%- endfor -%}
+ class="plot{% if zoom == 'advanced' %} plot-highstock{% endif %}">
+
{% endmacro %}
@@ -232,9 +242,9 @@
/**
* Plots a chart of time series data
*
-* @param {id=} unique id for this widget (optional)
-* @param {item(bool,num,list)} series of item(s); multiple items in array form: [ item1 , item2 ]
-* @param {text(avg,sum,min,max,raw,on)=avg} the aggregation mode (optional, default 'avg')
+* @param {id=} unique id for this widget (optional). Will be used as label / curve name in the tooltip, as well.
+* @param {item(bool,num,list)} single item to plot
+* @param {mode=avg} the aggregation mode (optional, default 'avg')
Available modes depend on backend, common ones are 'avg', 'sum', 'min', 'max', 'minmax', 'minmaxavg', 'on', 'raw'. See backend's documentation for further information.
* @param {duration=1h} the minimum time (x-axis): '1h', '2h'... (duration-format) Value is interpreted as timestamp if no unit is given (e.g. 1629109298731).
* @param {duration=now} the maximum time (x-axis): '', '1h', '2h'... (duration-format, default: now). Value is interpreted as timestamp if no unit is given (e.g. 1629109298731).
@@ -243,21 +253,27 @@
* @param {value=100} the number of datapoints in the series (optional, default 100)
* @param {value=120} width of the chart in px (optional, default = 120 px)
* @param {value=20} height of the chart in px (optional, default = 20 px)
-* @param {text[?](line,stair,spline,area,areastair,areaspline,column)=line} type of each serie: 'line', 'stair', 'spline', 'area', 'areastair', 'areaspline', 'column' (optional, default 'line')
-* @param {format[?]=} unit(s) for the y-axis. Either a unit of the language file, an individual format string (PHP sprintf like) or a simple string as suffix. Multiples in array form. (optional)
-* @param {text[?]=} object with additional options for Highcharts, see https://api.highcharts.com/ (optional)
-* @param {text(database,item)=database} source of the data. If set to 'item', data must be provided in a list item (optional, default=database)
+* @param {text(line,stair,spline,area,areastair,areaspline,column)=line} type of each serie: 'line', 'stair', 'spline', 'area', 'areastair', 'areaspline', 'column' (optional, default 'line')
+* @param {format=} unit for the y-axis. Either a unit of the language file, an individual format string (PHP sprintf like) or a simple string as suffix. (optional)
+* @param {text(database,item)=database} source of the data. If set to 'item', data must be provided in a list item (optional, default=database)
+* @param {text=} URL to use as link or id of a widget to add a tooltip (optional)
+* @param {text=} use 'tooltip' in combination with a widget id as href in order to attach a tooltip to that widget. Any other text will interpret href as link to a popup (optional)
*
-* @see misc/fundamentals#Array-Form
* @see misc/fundamentals#Duration-Format
*/
-{% macro sparkline(id, item, mode, tmin, tmax, ymin, ymax, count, width, height, exposure, unit, source) %}
+{% macro sparkline(id, item, mode, tmin, tmax, ymin, ymax, count, width, height, exposure, unit, source, href, rel) %}
{% set source = source|default('database') %}
{% set tmax = (tmax|default('now')|lower=='0h' or tmax==0 or tmax is empty) ? 'now' : tmax %}
{% set tmin = tmin|default('1h') %}
{% set mode = mode|default('avg') %}
{% set count = count|default(100) %}
+ {%- if mode == 'raw' or count >= 5000 -%}
+ {%- if once('plotboost') -%}
+
+ {%- endif -%}
+ {%- endif -%}
+ /** there is no way to measure the series length from here like in plot.period. So we can't import boost.js on demand for big series. Load it explicitely on the visu page if needed. */
{% set width = width|default(120) %}
{% set height = height|default(20) %}
{% set unit = unit|default('') %}
@@ -267,17 +283,19 @@
{% else %}
{% set seriesitem = item %}
{% endif %}
+ {% set label = id|default(' ') %}
{% set chartoptions = {chart:{backgroundColor: null, borderWidth: 0, margin: [2, 0, 2, 0], width: width, height: height, style: {overflow: 'visible'}, skipClone: true}, title: {text: ''},credits: {enabled: false},
xAxis: [{labels: {enabled: false}, title: {text: null}, startOnTick: false, endOnTick: false, tickPositions: [], type: 'datetime'}],
yAxis: [{endOnTick: false, startOnTick: false, labels: {enabled: false}, title: {text: null}, tickPositions: [0]}],
legend: {enabled: false}, tooltip: {hideDelay: 0, outside: true, shared: true},
plotOptions: {series: {animation: false, lineWidth: 1, shadow: false, states: {hover: {lineWidth: 1}}, marker: {radius: 1, states: {hover: {radius: 2}}}, fillOpacity: 0.25}}} %}
-
+ {% if href is not empty %}{% endif %}
+ {% if href is not empty %}{% endif %}
{% endmacro %}
@@ -378,20 +396,24 @@
*/
{% macro xyplot(id, item, xitem, yitem, xmin, xmax, ymin, ymax, label, xylabel, color, exposure, axis, zoom, assign, opposite, ycolor, ytype, unit, chartoptions, stacking, stacks, export) %}
- {% if (not export is empty) and export > 0 %}
-
-
- {% if export == 2 %}
-
- {% endif %}
- {% endif %}
- {% set unit = (unit is iterable ? unit : [unit|default('')]) %}
- {% set units = [] %}
- {% for uniti in unit %}
- {% set units = units|merge([uniti|replace({',' : ';'})]) %} /** hide comma before implode/explode to allow format strings, e.g. %01,02f% */
- {% endfor %}
- {% set stacking = (stacking is iterable ? stacking : [stacking|default('normal')]) %}
- {% set stacks = (stacks is iterable ? stacks : [stacks|default('0')]) %}
+ {%- if (not export is empty) and export > 0 -%}
+ {%- if once('plotimageexport') -%}
+
+
+ {%- endif -%}
+ {%- if export == 2 -%}
+ {%- if once('plotdataexport') -%}
+
+ {%- endif -%}
+ {%- endif -%}
+ {%- endif -%}
+ {%- set unit = (unit is iterable ? unit : [unit|default('')]) -%}
+ {%- set units = [] -%}
+ {%- for uniti in unit -%}
+ {%- set units = units|merge([uniti|replace({',' : ';'})]) -%} /** hide comma before implode/explode to allow format strings, e.g. %01,02f% */
+ {%- endfor -%}
+ {%- set stacking = (stacking is iterable ? stacking : [stacking|default('normal')]) -%}
+ {%- set stacks = (stacks is iterable ? stacks : [stacks|default('0')]) -%}
= 1){
+ chartOptions.xAxis[i].type = 'datetime';
+ chartOptions.xAxis[i].ordinal = false;
+ }
+ }
+ chartOptions.navigator.xAxis.min = chartOptions.xAxis[0].min;
+ chartOptions.navigator.xAxis.max = chartOptions.xAxis[0].max;
+
+ // register zoom events for multiple x axes
+ if (this.options.chartOptions.xAxis.length > 1){
+ var xAxesCount = this.options.chartOptions.xAxis.length;
+ chartOptions.xAxis[0].events = {
+ setExtremes: function(event){
+ for (var i= 1; i< xAxesCount; i++){
+ that.element.highcharts().xAxis[i].setExtremes(event.min + chartOptions.xAxis[i].min - chartOptions.xAxis[0].min , event.max + chartOptions.xAxis[i].max - chartOptions.xAxis[0].max);
+ }
+ }
+ }
+ }
+ }
+
Highcharts.stockChart(this.element[0], chartOptions);
}
else {
@@ -506,17 +541,18 @@ $.widget("sv.plot_period", $.sv.widget, {
// window.servertimeoffset should be available now
if (window.servertimeoffset != undefined && window.servertimeoffset != 0 && this.options.servertime == 'yes')
chart.time.update({timezoneOffset: parseInt(-Number(sv.serverTimezone.offset)/60 + window.servertimeoffset/60000) });
+ var actualDate = new Date();
if (this.options.chartOptions && this.options.chartOptions.xAxis != undefined && typeof this.options.chartOptions.xAxis == 'object' && this.options.chartOptions.xAxis[0].min && this.options.chartOptions.xAxis[0].max){
- for (var i = 0; i < this.options.chartOptions.xAxis.length; i++){
- var xMin = new Date() - new Date().duration(this.options.chartOptions.xAxis[i].min);
- var xMax = new Date() - new Date().duration(this.options.chartOptions.xAxis[i].max);
+ for (var i = this.options.chartOptions.xAxis.length - 1; i > -1; i--){
+ var xMin = actualDate - new Date().duration(this.options.chartOptions.xAxis[i].min);
+ var xMax = actualDate - new Date().duration(this.options.chartOptions.xAxis[i].max);
chart.xAxis[i].update({ min: xMin, max: xMax }, false);
}
}
else {
- var xMin = new Date() - new Date().duration(this.options.tmin);
- var xMax = new Date() - new Date().duration(this.options.tmax);
+ var xMin = actualDate - new Date().duration(this.options.tmin);
+ var xMax = actualDate - new Date().duration(this.options.tmax);
var dayDuration = 24*3600*1000;
if (this.options.zoom == "day"){
@@ -576,13 +612,17 @@ $.widget("sv.plot_period", $.sv.widget, {
return [[ value[0], maxValue, minValue ]];
});
- chart.series[seriesIndex].setData(values, true, true, false);
+ chart.series[seriesIndex].setData(values, false);
}
else if (response[i]) {
- chart.series[seriesIndex].setData(response[i], true, true, false);
+ chart.series[seriesIndex].setData(response[i], false);
}
+
+ // disable data grouping for series with 5000 points and more if boost mode is enabled in order to let boost mode work
+ if (response[i] && response[i].length >= 5000 && chart.series[seriesIndex].options.dataGrouping.enabled && chart.options.boost.enabled)
+ chart.series[seriesIndex].update({"dataGrouping": {"enabled": false}}, false);
}
-
+ //DEBUG: console.log('chart redraw _update() end');
chart.redraw();
},
@@ -1690,11 +1730,11 @@ $.widget("sv.plot_xyplot", $.sv.widget, {
var exportmenu = (this.options.exportmenu >= 1);
var styles = [];
- // series
- var series = [];
- var seriesCount = this.items.length;
+ // series
+ var series = [];
+ var seriesCount = this.items.length;
- for (var i = 0; i < seriesCount; i++) {
+ for (var i = 0; i < seriesCount; i++) {
var stack = (stacks.length-1 >= i ? stacks[i]: stacks[stacks.length-1]);
var stackingMode = (stacking[stack] ? stacking[stack] : stacking[0]);
series.push({
@@ -1706,7 +1746,8 @@ $.widget("sv.plot_xyplot", $.sv.widget, {
showInNavigator: true,
stacking: (exposure[i] != null && exposure[i].toLowerCase().endsWith('stack') ? stackingMode : null),
stack: (exposure[i] != null && exposure[i].toLowerCase().endsWith('stack') ? stack : null),
- borderRadius: 0
+ borderRadius: 0,
+ dataGrouping: {enabled: (exposure[i] != null && exposure[i].toLowerCase().endsWith('stair') ? false : true)},
});
}
@@ -1754,25 +1795,33 @@ $.widget("sv.plot_xyplot", $.sv.widget, {
max: xMax,
},
stickToMax: false
- },
+ },
rangeSelector:{ enabled: false},
- yAxis: yaxis,
- legend: {
- enabled: label.length > 0,
- align: 'center',
- verticalAlign: 'top',
- floating: true,
- },
- tooltip: {
- shared: true,
- split: false,
- pointFormatter: function() {
- var unit = this.series.yAxis.userOptions.svUnit;
- var value = (this.series.yAxis.categories) ? this.series.yAxis.categories[this.y] : parseFloat(this.y).transUnit(unit);
- return '\u25CF ' + this.series.name + ': ' + value + '
';
- }
- },
- navigation: { // options for export context menu
+ yAxis: yaxis,
+ legend: {
+ enabled: label.length > 0,
+ align: 'center',
+ verticalAlign: 'top',
+ floating: true,
+ },
+ boost: {
+ debug: {
+ timeRendering:false,
+ timeSeriesProcessing:false,
+ timeSetup:false
+ },
+ enabled:true
+ },
+ tooltip: {
+ shared: true,
+ split: false,
+ pointFormatter: function() {
+ var unit = this.series.yAxis.userOptions.svUnit;
+ var value = (this.series.yAxis.categories) ? this.series.yAxis.categories[this.y] : parseFloat(this.y).transUnit(unit);
+ return '\u25CF ' + this.series.name + ': ' + value + '
';
+ }
+ },
+ navigation: { // options for export context menu
buttonOptions: {
enabled: exportmenu,
height: 22,
@@ -1851,8 +1900,12 @@ $.widget("sv.plot_xyplot", $.sv.widget, {
var itemCount = response.length;
for (var i = 0; i < itemCount; i++) {
- if (response[i])
- chart.series[i].setData(response[i], true, true, false);
+ if (response[i]){
+ chart.series[i].setData(response[i], false);
+ // disable data grouping for series with 5000 points and more if boost mode is enabled in order to let boost mode work
+ if (response[i].length >= 5000 && chart.series[i].options.dataGrouping.enabled && chart.options.boost.enabled)
+ chart.series[i].update({"dataGrouping": {"enabled": false}}, false);
+ }
}
chart.redraw();
},
@@ -1914,4 +1967,3 @@ $.widget("sv.plot_timeshift", $.sv.widget, {
}
}
});
-
diff --git a/widgets/quad.html b/widgets/quad.html
index 5d87ef3b1..c8cadbc55 100755
--- a/widgets/quad.html
+++ b/widgets/quad.html
@@ -515,7 +515,7 @@
{{ _context['linetext_widget'] }}
{% endif %}
{% elseif item_auto and stateengine is defined and (not column_order or 'stateengine' in column_order) %}
- {{ clock.countdown('', item_auto~'.suspend.visu', item_auto~'.suspend_start.unix_timestamp', item_auto~'.settings.suspendduration.duration_format', '1s', '', ' ') }}
+ {{ clock.countdown('', item_auto~'.suspend.visu', item_auto~'.suspend_start.unix_timestamp', item_auto~'.settings.suspendduration.duration_format', '1s', '', ' ', 1) }}
/**
{{ basic.print(id~'dimmerprint', item_auto~'.suspend_end', 'text') }}
*/
@@ -733,8 +733,12 @@
possible elements are: 'colorpicker', 'ww_popup', 'ww_slider', 'values', 'sequencer', 'locks', 'stateengine', 'uzsu', 'plot'
For empty columns either use ' ' or a number to define the column width (e.g. '40' = 40 pixels width)
Combine elements in one column by putting them in arrays. Standard is [['locks', 'sequencer', 'colorpicker'],'values', 'stateengine', 'plot', 'uzsu']
+ * @param {color(icon0to5,blink,simulate,:)=} activity indicator which is active until response (or a timeout is reached); pass either a color, icon class, 'blink' or 'simulate'. Timeout is 3s by default and can be set globally using the configuration key "indicator_duration". Add a colon and integer number to specify an individual timeout, e.g. 'blink:15' (optional)
+ You can also set an indicator icon, text and color by passing these as additional parameters in the icon, text and color arrays. Just provide one icon more than you have values to switch. A dynamic icon can be used also along with the 'simulate' option.
+ The indicator options will not be applied to the select element of type 'menu' which will convert all options to 'blink'.
+
*/
-{% macro color(id, item_value_r, item_value_g, item_value_b, min, max, step, colors, style, colormodel, linetext, item_switch_r, item_switch_g, item_switch_b, min_display, max_display, item_uzsu, uzsu_attribs, popupcolor, item_switch_ww, item_value_ww, item_plot, icon_plot, item_auto, extpopup, locks, item_seq, icon_color, linetext_widget, live, column_order) %}
+{% macro color(id, item_value_r, item_value_g, item_value_b, min, max, step, colors, style, colormodel, linetext, item_switch_r, item_switch_g, item_switch_b, min_display, max_display, item_uzsu, uzsu_attribs, popupcolor, item_switch_ww, item_value_ww, item_plot, icon_plot, item_auto, extpopup, locks, item_seq, icon_color, linetext_widget, live, column_order, indicator) %}
{% import "@widgets/basic.html" as basic %}
{% import "@widgets/plot.html" as plot %}
{% import "@widgets/icon.html" as icon %}
@@ -902,7 +906,7 @@
{{ _context['linetext_widget'] }}
{% endif %}
{% elseif item_auto and stateengine is defined and (not column_order or 'stateengine' in column_order) %}
- {{ clock.countdown('', item_auto~'.suspend.visu', item_auto~'.suspend_start.unix_timestamp', item_auto~'.settings.suspendduration.duration_format', '1s', '', ' ') }}
+ {{ clock.countdown('', item_auto~'.suspend.visu', item_auto~'.suspend_start.unix_timestamp', item_auto~'.settings.suspendduration.duration_format', '1s', '', ' ', 1) }}
/**
{{ basic.print(id~'dimmerprint', item_auto~'.suspend_end', 'text') }}
*/
@@ -1184,7 +1188,9 @@
[slider_item, slider_min, slider_max, slider_step, '', 'handle']]
* @param {widget[?]=} Widget(s) to be shown right after linetext. Can be used to show a countdown or other additional information. Example: basic.symbol('', 'licht.og.essen.sa') - don't put basic.symbol() in high commas! (optional)
- * @param {placeholder=} placeholder attributes for future features, etc.
+ * @param {color(icon0to5,blink,simulate,:)=} activity indicator which is active until response (or a timeout is reached); pass either a color, icon class, 'blink' or 'simulate'. Timeout is 3s by default and can be set globally using the configuration key "indicator_duration". Add a colon and integer number to specify an individual timeout, e.g. 'blink:15' (optional)
+ You can also set an indicator icon, text and color by passing these as additional parameters in the icon, text and color arrays. Just provide one icon more than you have values to switch. A dynamic icon can be used also along with the 'simulate' option.
+ The indicator options will not be applied to the select element of type 'menu' which will convert all options to 'blink'.
* @param {text[](move_up,move_down,stop,pos_slider,pos_shutter,pos_shutter_ext,pos_popup_shutter,pos_popup_blind,pos1,pos2,stateengine,uzsu,plot,extpopup,anynumber)=} array with element description: Reorder elements to your liking (esp. relevant for smartphones as several columns might be too much)
possible elements are: 'move_down', 'move_up', 'stop', 'pos_slider', 'pos_shutter', 'pos_shutter_ext' (with the two saved positions), 'pos_popup_shutter', 'pos_popup_blind', 'pos1', 'pos2', 'stateengine', 'uzsu', 'plot', 'extpopup'
For empty columns either use ' ' or a number to define the column width (e.g. '40' = 40 pixels width)
@@ -1193,7 +1199,7 @@
* @param {unspecified[]=} a list with positional attributes. Should be left untouched as it is set automatically (optional)
*/
-{% macro shutter(id, linetext, item_move, item_stop, item_pos, item_shift, item_angle, item_saved, min, max, step, mode, background, value_pos_1, value_pos_2, move_on_longpress, live, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, linetext_widget, place4, column_order, _blind_or_shutter, _pos_attribs) %}
+{% macro shutter(id, linetext, item_move, item_stop, item_pos, item_shift, item_angle, item_saved, min, max, step, mode, background, value_pos_1, value_pos_2, move_on_longpress, live, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, linetext_widget, indicator, column_order, _blind_or_shutter, _pos_attribs) %}
{% import "@widgets/basic.html" as basic %}
{% import "@widgets/device.html" as device %}
{% import "@widgets/icon.html" as icon %}
@@ -1384,7 +1390,7 @@
{{ _context['linetext_widget'] }}
{% endif %}
{% elseif item_auto and stateengine is defined and (not column_order or 'stateengine' in column_order) %}
- {{ clock.countdown('', item_auto~'.suspend.visu', item_auto~'.suspend_start.unix_timestamp', item_auto~'.settings.suspendduration.duration_format', '1s', '', ' ') }}
+ {{ clock.countdown('', item_auto~'.suspend.visu', item_auto~'.suspend_start.unix_timestamp', item_auto~'.settings.suspendduration.duration_format', '1s', '', ' ', 1) }}
/**
{{ basic.print(id~'dimmerprint', item_auto~'.suspend_end', 'text') }}
*/
@@ -1416,9 +1422,9 @@
{% if column == 'move_down' and item_move %}
{% if move_on_longpress is same as true or move_on_longpress == 'true' or move_on_longpress is empty %}
- {{ basic.stateswitch(id~'_down', item_stop, '', max < min ? 0 : 1, 'control_arrow_down', '', '', 'blink', item_move, max < min ? 0 : 1) }}
+ {{ basic.stateswitch(id~'_down', item_stop, '', max < min ? 0 : 1, 'control_arrow_down', '', '', indicator, item_move, max < min ? 0 : 1) }}
{% else %}
- {{ basic.stateswitch(id~'_down', item_move, '', max < min ? 0 : 1, 'control_arrow_down', '', '', 'blink') }}
+ {{ basic.stateswitch(id~'_down', item_move, '', max < min ? 0 : 1, 'control_arrow_down', '', '', indicator) }}
{% endif %}
{% if elements[loop.index] == 'div' %}
@@ -1427,9 +1433,9 @@
{% if column == 'move_up' and item_move %}
{% if move_on_longpress is same as true or move_on_longpress == 'true' or move_on_longpress is empty %}
- {{ basic.stateswitch(id~'_up', item_stop, '', max < min ? 1 : 0, 'control_arrow_up', '', '', 'blink', item_move, max < min ? 1 : 0) }}
+ {{ basic.stateswitch(id~'_up', item_stop, '', max < min ? 1 : 0, 'control_arrow_up', '', '', indicator, item_move, max < min ? 1 : 0) }}
{% else %}
- {{ basic.stateswitch(id~'_up', item_move, '', max < min ? 1 : 0, 'control_arrow_up', '', '', 'blink') }}
+ {{ basic.stateswitch(id~'_up', item_move, '', max < min ? 1 : 0, 'control_arrow_up', '', '', indicator) }}
{% endif %}
{% if elements[loop.index] == 'div' %}
@@ -1437,7 +1443,7 @@
{% endif %}
{% if column == 'stop' and item_stop %}
- {{ basic.stateswitch(id~'_stop', item_stop, 'icon', '', 'control_cancel', '', 'icon0', 'blink') }}
+ {{ basic.stateswitch(id~'_stop', item_stop, 'icon', '', 'control_cancel', '', 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
@@ -1487,7 +1493,7 @@
{% if item_saved %}
- {{ basic.stateswitch(id~'_saved1_ext', item_saved, '', value_pos_1, '', text_pos_1, 'icon0', 'blink') }}
+ {{ basic.stateswitch(id~'_saved1_ext', item_saved, '', value_pos_1, '', text_pos_1, 'icon0', indicator) }}
{% endif %}
@@ -1496,7 +1502,7 @@
{% if item_saved %}
- {{ basic.stateswitch(id~'_saved2_ext', item_saved, '', value_pos_2, '', text_pos_2, 'icon0', 'blink') }}
+ {{ basic.stateswitch(id~'_saved2_ext', item_saved, '', value_pos_2, '', text_pos_2, 'icon0', indicator) }}
{% endif %}
@@ -1508,19 +1514,19 @@
{% endif %}
{% if column == 'pos' and item_saved and value_pos_2 and value_pos_1 %}
- {{ basic.select(id~'pos', item_saved, 'mini', [value_pos_1, value_pos_2, 0], '', [text_pos_1, text_pos_2, 0], 'icon1', 'horizontal') }}
+ {{ basic.select(id~'pos', item_saved, 'mini', [value_pos_1, value_pos_2, 0], '', [text_pos_1, text_pos_2, 0], 'icon1', 'horizontal', '', '', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% elseif column == 'pos1' and item_saved and value_pos_1 and 'pos' not in elements %}
- {{ basic.stateswitch(id~'_saved1', item_saved, '', [value_pos_1, 0], '', [0, text_pos_1], 'icon0', 'blink') }}
+ {{ basic.stateswitch(id~'_saved1', item_saved, '', [value_pos_1, 0], '', [0, text_pos_1], 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% elseif column == 'pos2' and item_saved and value_pos_2 and 'pos' not in elements %}
- {{ basic.stateswitch(id~'_saved2', item_saved, '', [value_pos_2, 0], '', [0, text_pos_2], 'icon0', 'blink') }}
+ {{ basic.stateswitch(id~'_saved2', item_saved, '', [value_pos_2, 0], '', [0, text_pos_2], 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
@@ -1639,16 +1645,18 @@
* @param {unspecified[]=} a list with positional attributes: item_saved = an item for some saved positions, value_pos_1 =
the value to send for position 1, value_pos_2 = the value to send for position 2, text_pos_1 = the text printed on button for position 1, text_pos_2 = the text printed on button for position 2 (optional)
* @param {widget[?]=} Widget(s) to be shown right after linetext. Can be used to show a countdown or other additional information. Example: basic.symbol('', 'licht.og.essen.sa') - don't put basic.symbol() in high commas! (optional)
- * @param {placeholder=} placeholder attributes for future features, etc.
+ * @param {color(icon0to5,blink,simulate,:)=} activity indicator which is active until response (or a timeout is reached); pass either a color, icon class, 'blink' or 'simulate'. Timeout is 3s by default and can be set globally using the configuration key "indicator_duration". Add a colon and integer number to specify an individual timeout, e.g. 'blink:15' (optional)
+ You can also set an indicator icon, text and color by passing these as additional parameters in the icon, text and color arrays. Just provide one icon more than you have values to switch. A dynamic icon can be used also along with the 'simulate' option.
+ The indicator options will not be applied to the select element of type 'menu' which will convert all options to 'blink'.
* @param {text[](move_up,move_down,stop,pos_slider,pos_shutter,pos_shutter_ext,pos_popup_shutter,pos_popup_blind,pos1,pos2,stateengine,uzsu,plot,extpopup,anynumber)=[[move_down, move_up], pos_popup_shutter, stateengine, plot, uzsu]} array with element description: Reorder elements to your liking (esp. relevant for smartphones as several columns might be too much)
possible elements are: 'move_down', 'move_up', 'stop', 'pos_slider', 'pos_shutter', 'pos_shutter_ext' (with the two saved positions), 'pos_popup_shutter', 'pos_popup_blind', 'pos1', 'pos2', 'stateengine', 'uzsu', 'plot', 'extpopup'
For empty columns either use ' ' or a number to define the column width (e.g. '40' = 40 pixels width)
Combine elements in one column by putting them in arrays. Standard is [['move_down', 'move_up'],'pos_popup_shutter', 'stateengine', 'plot', 'uzsu']
*/
-{% macro blind(id, linetext, item_move, item_stop, item_pos, item_shift, item_angle, min, max, step, move_on_longpress, live, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, pos_attribs, linetext_widget, place4, column_order) %}
+{% macro blind(id, linetext, item_move, item_stop, item_pos, item_shift, item_angle, min, max, step, move_on_longpress, live, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, pos_attribs, linetext_widget, indicator, column_order) %}
{% import _self as newwidget %}
- {{ newwidget.shutter(id, linetext, item_move, item_stop, item_pos, item_shift, item_angle, '', min, max, step, '', '', '', '', move_on_longpress, live, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, linetext_widget, place4, column_order, 'blind', pos_attribs) }}
+ {{ newwidget.shutter(id, linetext, item_move, item_stop, item_pos, item_shift, item_angle, '', min, max, step, '', '', '', '', move_on_longpress, live, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, linetext_widget, indicator, column_order, 'blind', pos_attribs) }}
{% endmacro %}
/**
@@ -1697,14 +1705,16 @@
[slider_item, slider_min, slider_max, slider_step, '', 'handle']]
* @param {text=} the path/url or item to the image. For squeezebox create an item with the following value: 'http://IP:PORT/music/current/cover.jpg?player=MACADDRESS'
* @param {value=1} 'live mode': if enabled, values will be sent during sliding. '0' sends values only when sliding is stopped, after click into track or if value is edited in input field. (optional, default = 1)
- * @param {placeholder=} placeholder attributes for future features, etc.
+ * @param {color(icon0to5,blink,simulate,:)=} activity indicator which is active until response (or a timeout is reached); pass either a color, icon class, 'blink' or 'simulate'. Timeout is 3s by default and can be set globally using the configuration key "indicator_duration". Add a colon and integer number to specify an individual timeout, e.g. 'blink:15' (optional)
+ You can also set an indicator icon, text and color by passing these as additional parameters in the icon, text and color arrays. Just provide one icon more than you have values to switch. A dynamic icon can be used also along with the 'simulate' option.
+ The indicator options will not be applied to the select element of type 'menu' which will convert all options to 'blink'.
* @param {text[](previous,play,pause,stop,next,power,eject,mute,volume_slider,cover,volume_popup,volume_up,volume_down,song_position,uzsu,plot,stateengine,repeat,source,source_popup,speaker,playpause,playpausestop,playstop,shuffle,anynumber)=} array with element description: Reorder elements to your liking (esp. relevant for smartphones as several columns might be too much)
possible elements are: 'previous', 'play', 'pause', 'stop', 'next', 'power', 'eject', 'mute', 'volume_slider', 'cover',
'volume_popup', 'volume_up', 'volume_down', 'song_position', 'uzsu', 'plot', 'stateengine', 'repeat', 'source', 'speaker', 'playpause', 'playstop', 'playpausestop', 'shuffle', 'source_popup'
For empty columns either use ' ' or a number to define the column width (e.g. '40' = 40 pixels width)
Combine elements in one column by putting them in arrays.
*/
-{% macro playercontrol(id, linetext, item_previous, item_play, item_pause, item_stop, item_next, item_power, item_eject, item_repeat, item_shuffle, source, item_mute, item_volume, item_volumeup, item_volumedown, volume_min, volume_max, volume_step, volume_min_display, volume_max_display, volume_threshold, item_album, item_artist, item_title, item_time, item_duration, item_speaker, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, coverUrl, live, place2, column_order) %}
+{% macro playercontrol(id, linetext, item_previous, item_play, item_pause, item_stop, item_next, item_power, item_eject, item_repeat, item_shuffle, source, item_mute, item_volume, item_volumeup, item_volumedown, volume_min, volume_max, volume_step, volume_min_display, volume_max_display, volume_threshold, item_album, item_artist, item_title, item_time, item_duration, item_speaker, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, coverUrl, live, indicator, column_order) %}
{% import "@widgets/basic.html" as basic %}
{% import "@widgets/plot.html" as plot %}
{% import "@widgets/device.html" as device %}
@@ -1971,14 +1981,14 @@
{% endif %}
{% if column == 'power' and item_power %}
- {{ basic.stateswitch(id~'_power', item_power, 'icon', [0,1], '', '', ['icon0','icon1'], 'blink') }}
+ {{ basic.stateswitch(id~'_power', item_power, 'icon', [0,1], '', '', ['icon0','icon1'], indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'eject' and item_eject %}
- {{ basic.stateswitch(id~'_eject', item_eject, 'icon', '1', 'audio_eject', '', 'icon0', '') }}
+ {{ basic.stateswitch(id~'_eject', item_eject, 'icon', '1', 'audio_eject', '', 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
@@ -2003,34 +2013,34 @@
{% endif %}
{% if column == 'previous' and item_previous %}
- {{ basic.stateswitch(id~'_prev', item_previous, 'icon', '1', 'audio_previous', '', 'icon0', '') }}
+ {{ basic.stateswitch(id~'_prev', item_previous, 'icon', '1', 'audio_previous', '', 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'next' and item_next %}
- {{ basic.stateswitch(id~'_prev', item_next, 'icon', '1', 'audio_next', '', 'icon0', '') }}
+ {{ basic.stateswitch(id~'_prev', item_next, 'icon', '1', 'audio_next', '', 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'play' and item_play %}
- {{ basic.stateswitch(id~'_play', item_play, 'icon', '1', 'audio_play', '', 'icon1', '') }}
+ {{ basic.stateswitch(id~'_play', item_play, 'icon', '1', 'audio_play', '', 'icon1', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% elseif column == 'pause' and item_pause %}
- {{ basic.stateswitch(id~'_pause', item_pause, 'icon', '1', 'audio_pause', '', 'icon1', 'blink') }}
+ {{ basic.stateswitch(id~'_pause', item_pause, 'icon', '1', 'audio_pause', '', 'icon1', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% elseif column == 'playstop' and item_play %}
- {{ basic.stateswitch(id~'_playstop', item_play, 'icon', ['0','1'], ['audio_play', 'audio_stop'], '', ['icon0', 'icon1'], 'blink') }}
+ {{ basic.stateswitch(id~'_playstop', item_play, 'icon', ['0','1'], ['audio_play', 'audio_stop'], '', ['icon0', 'icon1'], indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% elseif column == 'playpause' and item_pause %}
- {{ basic.stateswitch(id~'_playpause', item_play, 'icon', ['0','1'], ['audio_play', 'audio_pause'], '', ['icon0', 'icon1'], 'blink') }}
+ {{ basic.stateswitch(id~'_playpause', item_play, 'icon', ['0','1'], ['audio_play', 'audio_pause'], '', ['icon0', 'icon1'], indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
@@ -2041,25 +2051,25 @@
{% endif %}
{% endif %}
{% if column == 'stop' and item_stop %}
- {{ basic.stateswitch(id~'_stop', item_stop, 'icon', '1', 'audio_stop', '', 'icon0', '') }}
+ {{ basic.stateswitch(id~'_stop', item_stop, 'icon', '1', 'audio_stop', '', 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'mute' and item_mute %}
- {{ basic.stateswitch(id~'_mute', item_mute, 'icon', [0,1], 'audio_volume_mute', '', '', '') }}
+ {{ basic.stateswitch(id~'_mute', item_mute, 'icon', [0,1], 'audio_volume_mute', '', '', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'volume_up' and item_volumeup %}
- {{ basic.stateswitch(id~'_volup', item_volumeup, 'icon', '1', 'audio_volume_high', '', 'icon0', '') }}
+ {{ basic.stateswitch(id~'_volup', item_volumeup, 'icon', '1', 'audio_volume_high', '', 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'volume_down' and item_volumedown %}
- {{ basic.stateswitch(id~'_voldown', item_volumedown, 'icon', '1', 'audio_volume_low', '', 'icon0', '') }}
+ {{ basic.stateswitch(id~'_voldown', item_volumedown, 'icon', '1', 'audio_volume_low', '', 'icon0', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
@@ -2087,15 +2097,15 @@
{% set text_source = text_source|merge([item[2]|default('')]) %}
{% endif %}
{% endfor %}
- {{ basic.select(id~'_select', item_source, type_source, value_source, pic_source, text_source, 'icon1') }}
+ {{ basic.select(id~'_select', item_source, type_source, value_source, pic_source, text_source, 'icon1', 'horizontal', '', '', indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'speaker' and item_speaker %}
- {{ basic.stateswitch(id~'_speaker1', item_speaker[0], 'mini', [1,0], '', 'A', ['icon1', 'icon0'], '') }}
- {{ basic.stateswitch(id~'_speaker2', item_speaker[1], 'mini', [1,0], '', 'B', ['icon1', 'icon0'], '') }}
+ {{ basic.stateswitch(id~'_speaker1', item_speaker[0], 'mini', [1,0], '', 'A', ['icon1', 'icon0'], indicator) }}
+ {{ basic.stateswitch(id~'_speaker2', item_speaker[1], 'mini', [1,0], '', 'B', ['icon1', 'icon0'], indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
@@ -2103,13 +2113,13 @@
{% if column == 'repeat' and item_repeat %}
- {{ basic.stateswitch(id~'_repeat', item_repeat, 'icon', [0,1,2], ['audio_repeat_song','audio_repeat_song','audio_repeat'], '', ['icon0','icon1','icon1'], '') }}
+ {{ basic.stateswitch(id~'_repeat', item_repeat, 'icon', [0,1,2], ['audio_repeat_song','audio_repeat_song','audio_repeat'], '', ['icon0','icon1','icon1'], indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
{% endif %}
{% if column == 'shuffle' and item_shuffle %}
- {{ basic.stateswitch(id~'_shuffle', item_shuffle, 'icon', [0,1,2], ['audio_shuffle','audio_shuffle','audio_shuffle_album'], '', ['icon0','icon1','icon1'], '') }}
+ {{ basic.stateswitch(id~'_shuffle', item_shuffle, 'icon', [0,1,2], ['audio_shuffle','audio_shuffle','audio_shuffle_album'], '', ['icon0','icon1','icon1'], indicator) }}
{% if elements[loop.index] == 'div' %}
{% endif %}
@@ -2236,17 +2246,17 @@
* @param {text=} the value to send on releasing after a longpress (optional)
* @param {placeholder=} placeholder attributes for future features, etc.
* @param {placeholder=} placeholder attributes for future features, etc.
- If you want to implement two state switches for one single item (e.g. on/off and timer or restart, etc.)
- you can provide the following attributes as single statements without arrays.
+ If you want to implement two state switches for one single item (e.g. on/off and timer or restart, etc.)
+ you can provide the following attributes as single statements without arrays.
* @param {text=} text for the whole line (optional)
* @param {text[?]=} text for each column (optional)
* @param {item[?](dict)=} a gad/item for UZSU
* @param {uzsuparam[]=} Array with standard UZSU parameters: pic_on, pic_off, valueType, valueParameterList, color_on, color_off. (optional)
Normally the array must have the same dimension as the "type" parameter, e.g. "[['', '', 'num'], '', ['', '', 'bool']]" for a table of 3 columns.
- Exception: if the parameter "item_uzsu" is a singe item in string format a new column with an uzsu icon is displayed behind the main column block.
+ Exception: if the parameter "item_uzsu" is a singe item in string format a new column with an uzsu icon is displayed behind the main column block.
* @param {plotparam[?]=} array with all plot.period attributes to show a plot in popup. Alternatively just the item to be plotted.
Normally the array must have the same dimension as the "type" parameter, e.g. "[['plotitem1', 'avg', '2d','now'], 'plotitem2', '']" for a table of 3 columns.
- Exception: a plot parameter array with exactly 17 entries causes a new column with a plot icon to be displayed behind the main column block. Example: "['plotitem1', 'avg', '2d','now', '','','','','','','','','','','','','temp']
+ Exception: a plot parameter array with exactly 17 entries causes a new column with a plot icon to be displayed behind the main column block. Example: "['plotitem1', 'avg', '2d','now', '','','','','','','','','','','','','temp']
* @param {image=measure_power_meter} icon triggering the plot popup
* @param {item[?](foo)=} "root item" which holds stateengine information. show current state of stateengine/stateengine item. Adjust icons and states below accordingly
* @param {unspecified[]=} Array of arrays for extended popup window. Use this to create an icon to open a popup with switches, sliders, flips or select menues.
@@ -2258,7 +2268,7 @@
[slider_item, slider_min, slider_max, slider_step, '', 'handle']]
* @param {item[](bool,num)=} array with items for locking. You have to be aware of the order: item_lock, item_bwmlock (presence sensor), item_force (force on/off/neutral)
* @param {sliderparam[?]=} additional item for changing value (e.g. timer). A slider popup will be shown
- You can provide additional attributes as an array: item, min, max, step, format, value_display (handle, etc.)
+ You can provide additional attributes as an array: item, min, max, step, format, value_display (handle, etc.)
* @param {widget[?]=} Widget(s) to be shown right after linetext. Can be used to show a countdown or other additional information. Example: basic.symbol('', 'licht.og.essen.sa') - don't put basic.symbol() in high commas! (optional)
* @param {placeholder=} placeholder attributes for future features, etc.
* @param {text[](switch,stateengine,uzsu,plot,locks,slider,extpopup,anynumber)=['locks', 'switch', 'slider', 'stateengine', 'plot', 'uzsu']} array with element description: Reorder elements to your liking (esp. relevant for smartphones as several columns might be too much)
@@ -2267,8 +2277,12 @@
Combine elements in one column by putting them in arrays. Standard is ['locks', 'switch', 'slider', 'stateengine', 'plot', 'uzsu']
Be aware that this only works with lines containing one switch only! For multiple switches leave column_order empty and rely on the defaults.
* @param {text(switch,select)=} Should be left untouched as it is set automatically (optional)
+ * @param {item(list)=} Should be left untouched. an item containing all selectable values (optional) - overrides existing value definitions, available for select menu type only
+ * @param {item(list)=} Should be left untouched. an item containing the texts corresponding to the selectable values (optional even if itemvals is specified), available for select menu type only
+
*/
-{% macro stateswitch(id, item_switch, type, value, pic, text, color, indicator, item_longpress, value_longpress, value_longrelease, place1, place2, linetext, columntext, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, locks, item_slider, linetext_widget, place4, column_order, _switch_or_select) %}
+
+{% macro stateswitch(id, item_switch, type, value, pic, text, color, indicator, item_longpress, value_longpress, value_longrelease, place1, place2, linetext, columntext, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, locks, item_slider, linetext_widget, place4, column_order, _switch_or_select, itemvals, itemtxts) %}
{% import "@widgets/basic.html" as basic %}
{% import "@widgets/device.html" as device %}
{% import "@widgets/icon.html" as icon %}
@@ -2495,7 +2509,7 @@
{% set sc_1 = item_auto~'.suspend_start.unix_timestamp' %}
{% set sc_2 = item_auto~'.settings.suspendduration.duration_format' %}
{% endif %}
- {{ clock.countdown('', sc_0, sc_1, sc_2, '1s', '', ' ') }}
+ {{ clock.countdown('', sc_0, sc_1, sc_2, '1s', '', ' ', 1) }}
/**
{{ basic.print(id~'sw_widget', se, 'text') }}
*/
@@ -2537,7 +2551,7 @@
{% if column == 'switch' and item_switch[i] %}
{% if columntext[i] %}{{ columntext[i]|e }}{% endif %}
{% if _switch_or_select[i] == 'select' or _switch_or_select == 'select' %}
- {{ basic.select(id~'_select'~z~i, item_switch[i], type[i], value[i]|default(value[i][0]), pic[i]|default(pic[i][0]), text[i]|default(text[i][0]), color_on[i]|default(''), indicator[i]) }}
+ {{ basic.select(id~'_select'~z~i, item_switch[i], type[i], value[i]|default(value[i][0]), pic[i]|default(pic[i][0]), text[i]|default(text[i][0]), color_on[i]|default(''), '', itemvals[i]|default(''), itemtxts[i]|default(''), indicator[i]) }}
{% else %}
{{ basic.stateswitch(id~'_stateswitch'~z~i, item_switch[i], type[i], value[i]|default(''), pic[i]|default(''), text[i]|default(''), color[i]|default(''), indicator[i]|default(''), item_longpress[i]|default(''), value_longpress[i]|default(''), value_longrelease[i]|default('')) }}
{% endif %}
@@ -2672,7 +2686,7 @@
{% if column == 'switch' and item_switch %}
{% if columntext %}{{ columntext|e }}{% endif %}
{% if _switch_or_select == 'select' %}
- {{ basic.select(id~'_select'~z~i, item_switch, type, value|default(value[0]), pic|default(pic[0]), text|default(text[0]), color_on|default(''), indicator) }}
+ {{ basic.select(id~'_select'~z~i, item_switch, type, value|default(value[0]), pic|default(pic[0]), text|default(text[0]), color_on|default(''), '', itemvals|default(''), itemtxts|default(''), indicator) }}
{% else %}
{{ basic.stateswitch(id~'_stateswitch'~z~i, item_switch, type|default(''), value|default(''), pic|default(''), text|default(''), color|default(''), indicator|default(''), item_longpress|default(''), value_longpress|default(''), value_longrelease|default('')) }}
{% endif %}
@@ -2885,9 +2899,11 @@
* @param {image[?]=} list of icons for every button (optional) - not supported for type 'menu'
* @param {text[?]=} list of texts for every menu entry or button (optional)
* @param {color[?](icon0to5)=icon1} the color for the on state of the buttons, e.g. 'icon0'through'icon5' or '#f00' or 'red' (optional, default: icon1) - not supported for type 'menu'
- * @param {text[?](horizontal,vertical,none)=horizontal} orientation of the controlgroup: 'horizontal', 'vertical' or 'none' for seperate buttons (optional, default: 'horizontal') - not supported for type 'menu'
- * @param {placeholder=} placeholder attributes for future features, etc.
- * @param {placeholder=} placeholder attributes for future features, etc.
+ * @param {item(list)=} an item containing all selectable values (optional) - overrides existing value definitions, available for menu type only
+ * @param {item(list)=} an item containing the texts corresponding to the selectable values (optional even if itemvals is specified), available for menu type only
+ * @param {color(icon0to5,blink,simulate,:)=} activity indicator which is active until response (or a timeout is reached); pass either a color, icon class, 'blink' or 'simulate'. Timeout is 3s by default and can be set globally using the configuration key "indicator_duration". Add a colon and integer number to specify an individual timeout, e.g. 'blink:15' (optional)
+ You can also set an indicator icon, text and color by passing these as additional parameters in the icon, text and color arrays. Just provide one icon more than you have values to switch. A dynamic icon can be used also along with the 'simulate' option.
+ The indicator options will not be applied to the select element of type 'menu' which will convert all options to 'blink'.
* @param {text=} text for the whole line (optional)
* @param {text[?]=} (array with) text for each column (optional)
* @param {item[?](dict)=} a gad/item for UZSU
@@ -2917,9 +2933,9 @@
Combine elements in one column by putting them in arrays. Standard is ['locks', 'select', 'stateengine', 'plot', 'uzsu']
Be aware that this only works with lines containing one switch only! For multiple switches leave column_order empty and rely on the defaults.
*/
-{% macro select(id, item_select, type, value, pic, text, color_on, group, place1, place2, linetext, columntext, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, locks, item_slider, place3, place4, column_order) %}
+{% macro select(id, item_select, type, value, pic, text, color_on, itemvals, itemtxts, indicator, linetext, columntext, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, locks, item_slider, place3, place4, column_order) %}
{% import _self as intern %}
- {{ intern.stateswitch(id, item_select, type, value, pic, text, color_on, place0, place1, place2, place3, place4, place5, linetext, columntext, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, locks, item_slider, place6, place7, column_order, 'select') }}
+ {{ intern.stateswitch(id, item_select, type, value, pic, text, color_on, indicator, place1, place2, place3, place4, place5, linetext, columntext, item_uzsu, uzsu_attribs, item_plot, icon_plot, item_auto, extpopup, locks, item_slider, place6, place7, column_order, 'select', itemvals, itemtxts) }}
{% endmacro %}
/**
diff --git a/widgets/weather.html b/widgets/weather.html
index ebdcdcb3a..af4df5d75 100644
--- a/widgets/weather.html
+++ b/widgets/weather.html
@@ -33,11 +33,6 @@
{% macro current(id, location, repeat, itemtemp, itemwind, windfmt, itemhumi, humitxt, humifmt, itemmisc, misctxt, miscfmt, itemmisc1, misc1txt, misc1fmt) %}
{% set uid = uid(page, id) %}
-
- {% if once('digiweather') %}
-
- {% endif %}
-
- {% endif %}
-
@@ -98,10 +89,6 @@
{% macro forecastweek(id, location, repeat) %}
{% set uid = uid(page, id) %}
- {% if once('digiweather') %}
-
- {% endif %}
-