--- a/svghmi/gen_index_xhtml.xslt Sun Nov 20 18:36:13 2022 +0100
+++ b/svghmi/gen_index_xhtml.xslt Wed Nov 23 14:18:25 2022 +0100
@@ -734,6 +734,21 @@
</func:function>
<xsl:variable name="_detachable_elements" select="func:detachable_elements($hmi_pages | $keypads)"/>
<xsl:variable name="detachable_elements" select="$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]"/>
+ <declarations:page-class/>
+ <xsl:template match="declarations:page-class">
+ <xsl:text>
+</xsl:text>
+ <xsl:text>/* </xsl:text>
+ <xsl:value-of select="local-name()"/>
+ <xsl:text> */
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>class PageWidget extends Widget{}
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ </xsl:template>
<declarations:detachable-elements/>
<xsl:template match="declarations:detachable-elements">
<xsl:text>
@@ -787,7 +802,15 @@
<xsl:variable name="page_all_elements" select="func:all_related_elements($page)"/>
<xsl:variable name="all_page_widgets" select="$hmi_widgets[@id = $page_all_elements/@id and @id != $page/@id]"/>
<xsl:variable name="page_managed_widgets" select="$all_page_widgets[not(@id=$in_forEach_widget_ids)]"/>
- <xsl:variable name="page_relative_widgets" select="$page_managed_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $desc/path/@value)]"/>
+ <xsl:variable name="page_root_path" select="$desc/path[not(@assign)]"/>
+ <xsl:if test="count($page_root_path)>1">
+ <xsl:message terminate="yes">
+ <xsl:text>Page id="</xsl:text>
+ <xsl:value-of select="$page/@id"/>
+ <xsl:text>" : only one root path can be declared</xsl:text>
+ </xsl:message>
+ </xsl:if>
+ <xsl:variable name="page_relative_widgets" select="$page_managed_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $page_root_path/@value)]"/>
<xsl:variable name="sumarized_page" select="func:sumarized_elements($page_all_elements)"/>
<xsl:variable name="required_detachables" select="$sumarized_page/ ancestor-or-self::*[@id = $detachable_elements/@id]"/>
<xsl:text> "</xsl:text>
@@ -804,31 +827,35 @@
<xsl:value-of select="$p/@h"/>
<xsl:text>],
</xsl:text>
- <xsl:if test="$desc/path/@value">
- <xsl:if test="count($desc/path/@index)=0">
+ <xsl:if test="count($page_root_path)=1">
+ <xsl:if test="count($page_root_path/@index)=0">
<xsl:message terminate="no">
<xsl:text>Page id="</xsl:text>
<xsl:value-of select="$page/@id"/>
<xsl:text>" : No match for path "</xsl:text>
- <xsl:value-of select="$desc/path/@value"/>
+ <xsl:value-of select="$page_root_path/@value"/>
<xsl:text>" in HMI tree</xsl:text>
</xsl:message>
</xsl:if>
<xsl:text> page_index: </xsl:text>
- <xsl:value-of select="$desc/path/@index"/>
+ <xsl:value-of select="$page_root_path/@index"/>
<xsl:text>,
</xsl:text>
<xsl:text> page_class: "</xsl:text>
- <xsl:value-of select="$indexed_hmitree/*[@hmipath = $desc/path/@value]/@class"/>
+ <xsl:value-of select="$indexed_hmitree/*[@hmipath = $page_root_path/@value]/@class"/>
<xsl:text>",
</xsl:text>
</xsl:if>
<xsl:text> widgets: [
</xsl:text>
+ <xsl:text> [hmi_widgets["</xsl:text>
+ <xsl:value-of select="$page/@id"/>
+ <xsl:text>"], []],
+</xsl:text>
<xsl:for-each select="$page_managed_widgets">
<xsl:variable name="widget_paths_relativeness">
<xsl:for-each select="func:widget(@id)/path">
- <xsl:value-of select="func:is_descendant_path(@value, $desc/path/@value)"/>
+ <xsl:value-of select="func:is_descendant_path(@value, $page_root_path/@value)"/>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
@@ -1440,7 +1467,7 @@
<xsl:text>,{
</xsl:text>
<xsl:if test="$widget/@enable_expr">
- <xsl:text> assignments: [],
+ <xsl:text> enable_assignments: [],
</xsl:text>
<xsl:text> compute_enable: function(value, oldval, varnum) {
</xsl:text>
@@ -1456,13 +1483,13 @@
<xsl:if test="$varid = generate-id()">
<xsl:text> if(varnum == </xsl:text>
<xsl:value-of select="$varnum"/>
- <xsl:text>) this.assignments[</xsl:text>
+ <xsl:text>) this.enable_assignments[</xsl:text>
<xsl:value-of select="position()-1"/>
<xsl:text>] = value;
</xsl:text>
<xsl:text> let </xsl:text>
<xsl:value-of select="@assign"/>
- <xsl:text> = this.assignments[</xsl:text>
+ <xsl:text> = this.enable_assignments[</xsl:text>
<xsl:value-of select="position()-1"/>
<xsl:text>];
</xsl:text>
@@ -2388,7 +2415,9 @@
</xsl:message>
</xsl:template>
<xsl:variable name="included_ids" select="$parsed_widgets/widget[not(@type = $excluded_types) and not(@id = $discardable_elements/@id)]/@id"/>
+ <xsl:variable name="page_ids" select="$parsed_widgets/widget[@type = 'Page']/@id"/>
<xsl:variable name="hmi_widgets" select="$hmi_elements[@id = $included_ids]"/>
+ <xsl:variable name="page_widgets" select="$hmi_elements[@id = $page_ids]"/>
<xsl:variable name="result_widgets" select="$result_svg_ns//*[@id = $hmi_widgets/@id]"/>
<declarations:hmi-elements/>
<xsl:template match="declarations:hmi-elements">
@@ -2402,7 +2431,7 @@
</xsl:text>
<xsl:text>var hmi_widgets = {
</xsl:text>
- <xsl:apply-templates mode="hmi_widgets" select="$hmi_widgets"/>
+ <xsl:apply-templates mode="hmi_widgets" select="$hmi_widgets | $page_widgets"/>
<xsl:text>}
</xsl:text>
<xsl:text>
@@ -6367,10 +6396,10 @@
<xsl:variable name="target_page_path">
<xsl:choose>
<xsl:when test="arg">
- <xsl:value-of select="$hmi_pages_descs[arg[1]/@value = $target_page_name]/path[1]/@value"/>
+ <xsl:value-of select="$hmi_pages_descs[arg[1]/@value = $target_page_name]/path[not(@assign)]/@value"/>
</xsl:when>
<xsl:otherwise>
- <xsl:value-of select="$page_desc/path[1]/@value"/>
+ <xsl:value-of select="$page_desc/path[not(@assign)]/@value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
@@ -7195,6 +7224,128 @@
<xsl:text> ],
</xsl:text>
</xsl:template>
+ <xsl:template match="widget[@type='Page']" mode="widget_desc">
+ <type>
+ <xsl:value-of select="@type"/>
+ </type>
+ <longdesc>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>Arguments are either:
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>- XXX reference path TODO
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>- name=value: setting variable with literal value.
+</xsl:text>
+ <xsl:text>- name=other_name: copy variable content into another
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>"active"+"inactive" labeled elements can be provided to show feedback when pressed
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>Exemples:
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>HMI:Page:notify=1@notify=/PLCVAR
+</xsl:text>
+ <xsl:text>HMI:Page:ack=2:notify=1@ack=.local_var@notify=/PLCVAR
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ </longdesc>
+ <shortdesc>
+ <xsl:text>Page </xsl:text>
+ </shortdesc>
+ </xsl:template>
+ <xsl:template match="widget[@type='Page']" mode="widget_defs">
+ <xsl:param name="hmi_element"/>
+ <xsl:variable name="disability">
+ <xsl:call-template name="defs_by_labels">
+ <xsl:with-param name="hmi_element" select="$hmi_element"/>
+ <xsl:with-param name="labels">
+ <xsl:text>/disabled</xsl:text>
+ </xsl:with-param>
+ <xsl:with-param name="mandatory" select="'no'"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <xsl:value-of select="$disability"/>
+ <xsl:variable name="has_disability" select="string-length($disability)>0"/>
+ <xsl:text> assignments: {},
+</xsl:text>
+ <xsl:text> dispatch: function(value, oldval, varnum) {
+</xsl:text>
+ <xsl:variable name="widget" select="."/>
+ <xsl:for-each select="path">
+ <xsl:variable name="varid" select="generate-id()"/>
+ <xsl:variable name="varnum" select="position()-1"/>
+ <xsl:if test="@assign">
+ <xsl:for-each select="$widget/path[@assign]">
+ <xsl:if test="$varid = generate-id()">
+ <xsl:text> if(varnum == </xsl:text>
+ <xsl:value-of select="$varnum"/>
+ <xsl:text>) this.assignments["</xsl:text>
+ <xsl:value-of select="@assign"/>
+ <xsl:text>"] = value;
+</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text> },
+</xsl:text>
+ <xsl:text> assign: function() {
+</xsl:text>
+ <xsl:variable name="paths" select="path"/>
+ <xsl:for-each select="arg[contains(@value,'=')]">
+ <xsl:variable name="name" select="substring-before(@value,'=')"/>
+ <xsl:variable name="value" select="substring-after(@value,'=')"/>
+ <xsl:variable name="index">
+ <xsl:for-each select="$paths">
+ <xsl:if test="@assign = $name">
+ <xsl:value-of select="position()-1"/>
+ </xsl:if>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="isVarName" select="regexp:test($value,'^[a-zA-Z_][a-zA-Z0-9_]+$')"/>
+ <xsl:choose>
+ <xsl:when test="$isVarName">
+ <xsl:text> const </xsl:text>
+ <xsl:value-of select="$value"/>
+ <xsl:text> = this.assignments["</xsl:text>
+ <xsl:value-of select="$value"/>
+ <xsl:text>"];
+</xsl:text>
+ <xsl:text> if(</xsl:text>
+ <xsl:value-of select="$value"/>
+ <xsl:text> != undefined)
+</xsl:text>
+ <xsl:text> this.apply_hmi_value(</xsl:text>
+ <xsl:value-of select="$index"/>
+ <xsl:text>, </xsl:text>
+ <xsl:value-of select="$value"/>
+ <xsl:text>);
+</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text> this.apply_hmi_value(</xsl:text>
+ <xsl:value-of select="$index"/>
+ <xsl:text>, </xsl:text>
+ <xsl:value-of select="$value"/>
+ <xsl:text>);
+</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <xsl:text> },
+</xsl:text>
+ </xsl:template>
<xsl:template match="widget[@type='PathSlider']" mode="widget_desc">
<type>
<xsl:value-of select="@type"/>
@@ -12128,29 +12279,37 @@
</xsl:text>
<xsl:text>
</xsl:text>
- <xsl:text>var screensaver_timer = null;
-</xsl:text>
- <xsl:text>function reset_screensaver_timer() {
-</xsl:text>
- <xsl:text> if(screensaver_timer){
-</xsl:text>
- <xsl:text> window.clearTimeout(screensaver_timer);
+ <xsl:text>if(screensaver_delay){
+</xsl:text>
+ <xsl:text> var screensaver_timer = null;
+</xsl:text>
+ <xsl:text> function reset_screensaver_timer() {
+</xsl:text>
+ <xsl:text> if(screensaver_timer){
+</xsl:text>
+ <xsl:text> window.clearTimeout(screensaver_timer);
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> screensaver_timer = window.setTimeout(() => {
+</xsl:text>
+ <xsl:text> switch_page("ScreenSaver");
+</xsl:text>
+ <xsl:text> screensaver_timer = null;
+</xsl:text>
+ <xsl:text> }, screensaver_delay*1000);
</xsl:text>
<xsl:text> }
</xsl:text>
- <xsl:text> screensaver_timer = window.setTimeout(() => {
-</xsl:text>
- <xsl:text> switch_page("ScreenSaver");
-</xsl:text>
- <xsl:text> screensaver_timer = null;
-</xsl:text>
- <xsl:text> }, screensaver_delay*1000);
+ <xsl:text> document.body.addEventListener('pointerdown', reset_screensaver_timer);
+</xsl:text>
+ <xsl:text> // initialize screensaver
+</xsl:text>
+ <xsl:text> reset_screensaver_timer();
</xsl:text>
<xsl:text>}
</xsl:text>
- <xsl:text>if(screensaver_delay)
-</xsl:text>
- <xsl:text> document.body.addEventListener('pointerdown', reset_screensaver_timer);
+ <xsl:text>
</xsl:text>
<xsl:text>
</xsl:text>
@@ -12314,6 +12473,12 @@
</xsl:text>
<xsl:text>
</xsl:text>
+ <xsl:text> // when entering a page, assignments are evaluated
+</xsl:text>
+ <xsl:text> new_desc.widgets[0][0].assign();
+</xsl:text>
+ <xsl:text>
+</xsl:text>
<xsl:text> return true;
</xsl:text>
<xsl:text>};
@@ -12474,16 +12639,12 @@
</xsl:text>
<xsl:text>
</xsl:text>
- <xsl:text>// initialize screensaver
-</xsl:text>
- <xsl:text>reset_screensaver_timer();
-</xsl:text>
- <xsl:text>
-</xsl:text>
<xsl:text>var reconnect_delay = 0;
</xsl:text>
<xsl:text>var periodic_reconnect_timer;
</xsl:text>
+ <xsl:text>var force_reconnect = false;
+</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>// Once connection established
@@ -12504,6 +12665,8 @@
</xsl:text>
<xsl:text> periodic_reconnect_timer = window.setTimeout(() => {
</xsl:text>
+ <xsl:text> force_reconnect = true;
+</xsl:text>
<xsl:text> ws.close();
</xsl:text>
<xsl:text> periodic_reconnect_timer = null;
@@ -12540,14 +12703,26 @@
</xsl:text>
<xsl:text> ws = null;
</xsl:text>
- <xsl:text> // reconect
-</xsl:text>
- <xsl:text> // TODO : add visible notification while waiting for reload
+ <xsl:text> // Do not attempt to reconnect immediately in case:
+</xsl:text>
+ <xsl:text> // - connection was closed by server (PLC stop)
+</xsl:text>
+ <xsl:text> // - connection was closed locally with an intention to reconnect
+</xsl:text>
+ <xsl:text> if(evt.code=1000 && !force_reconnect){
+</xsl:text>
+ <xsl:text> window.alert("Connection closed by server");
+</xsl:text>
+ <xsl:text> location.reload();
+</xsl:text>
+ <xsl:text> }
</xsl:text>
<xsl:text> window.setTimeout(create_ws, reconnect_delay);
</xsl:text>
<xsl:text> reconnect_delay += 500;
</xsl:text>
+ <xsl:text> force_reconnect = false;
+</xsl:text>
<xsl:text>};
</xsl:text>
<xsl:text>