# HG changeset patch # User Edouard Tisserant # Date 1570604675 -7200 # Node ID 2a97688c94c5839e1286dcc90d7def9c78dbc0fa # Parent 0c0d3895b0364f6a06393e52fe6cd18a69fbb949 SVGHMI: use func:function for parsing labels so that it can be used in predicates diff -r 0c0d3895b036 -r 2a97688c94c5 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Tue Oct 08 13:27:00 2019 +0200 +++ b/svghmi/gen_index_xhtml.xslt Wed Oct 09 09:04:35 2019 +0200 @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<xsl:stylesheet xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns="beremiz" xmlns:cc="http://creativecommons.org/ns#" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:str="http://exslt.org/strings" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:exsl="http://exslt.org/common" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" exclude-result-prefixes="ns str regexp exsl" extension-element-prefixes="ns" version="1.0"> +<xsl:stylesheet xmlns:func="http://exslt.org/functions" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:svg="http://www.w3.org/2000/svg" xmlns:str="http://exslt.org/strings" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:exsl="http://exslt.org/common" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:ns="beremiz" xmlns:cc="http://creativecommons.org/ns#" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dc="http://purl.org/dc/elements/1.1/" extension-element-prefixes="ns func" version="1.0" exclude-result-prefixes="ns str regexp exsl func"> <xsl:output method="xml" cdata-section-elements="script"/> <xsl:variable name="geometry" select="ns:GetSVGGeometry()"/> <xsl:variable name="hmitree" select="ns:GetHMITree()"/> @@ -83,6 +83,9 @@ </xsl:text> </xsl:variable> <xsl:template match="/"> + <xsl:comment> + <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text> + </xsl:comment> <html xmlns="http://www.w3.org/1999/xhtml"> <head/> <body style="margin:0;"> @@ -104,191 +107,7 @@ </body> </html> </xsl:template> - <xsl:template name="scripts"> - <xsl:text>var hmi_index = { -</xsl:text> - <xsl:variable name="svg" select="/"/> - <xsl:for-each select="$indexed_hmitree/*"> - <xsl:value-of select="@index"/> - <xsl:text>: { -</xsl:text> - <xsl:text> name: "</xsl:text> - <xsl:value-of select="@name"/> - <xsl:text>", -</xsl:text> - <xsl:text> hmipath: "</xsl:text> - <xsl:value-of select="@hmipath"/> - <xsl:text>" -</xsl:text> - <xsl:text> ids: [ -</xsl:text> - <xsl:variable name="hmipath" select="@hmipath"/> - <xsl:for-each select="$svg//*[substring-after(@inkscape:label,'@') = $hmipath]"> - <xsl:text> "</xsl:text> - <xsl:value-of select="@id"/> - <xsl:text>"</xsl:text> - <xsl:if test="position()!=last()"> - <xsl:text>,</xsl:text> - </xsl:if> - <xsl:text> -</xsl:text> - </xsl:for-each> - <xsl:text> ] -</xsl:text> - <xsl:text>}</xsl:text> - <xsl:if test="position()!=last()"> - <xsl:text>,</xsl:text> - </xsl:if> - <xsl:text> -</xsl:text> - </xsl:for-each> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>var page_desc = { -</xsl:text> - <xsl:for-each select="//*[starts-with(@inkscape:label,'HMI:')]"> - <xsl:value-of select="@inkscape:label"/> - <xsl:text> -</xsl:text> - <xsl:variable name="ast"> - <xsl:call-template name="parse_label"> - <xsl:with-param name="label" select="@inkscape:label"/> - </xsl:call-template> - </xsl:variable> - <xsl:apply-templates mode="testtree" select="exsl:node-set($ast)"/> - </xsl:for-each> - <xsl:text>} -</xsl:text> - <xsl:text>// svghmi.js -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>(function(){ -</xsl:text> - <xsl:text> // Open WebSocket to relative "/ws" address -</xsl:text> - <xsl:text> var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> // Register message reception handler -</xsl:text> - <xsl:text> ws.onmessage = function (evt) { -</xsl:text> - <xsl:text> // TODO : dispatch and cache hmi tree updates -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> var received_msg = evt.data; -</xsl:text> - <xsl:text> // TODO : check for hmitree hash header -</xsl:text> - <xsl:text> // if not matching, reload page -</xsl:text> - <xsl:text> alert("Message is received..."+received_msg); -</xsl:text> - <xsl:text> }; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> // Once connection established -</xsl:text> - <xsl:text> ws.onopen = function (evt) { -</xsl:text> - <xsl:text> // TODO : enable the HMI (was previously offline, or just starts) -</xsl:text> - <xsl:text> // show main page -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> // TODO : prefix with hmitree hash header -</xsl:text> - <xsl:text> ws.send("test"); -</xsl:text> - <xsl:text> }; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> var pending_updates = {}; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> // subscription state, as it should be in hmi server -</xsl:text> - <xsl:text> // expected {index:period} -</xsl:text> - <xsl:text> const subscriptions = new Map(); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> // subscription state as needed by widget now -</xsl:text> - <xsl:text> // expected {index:[widgets]}; -</xsl:text> - <xsl:text> var subscribers = {}; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> // return the diff in between curently subscribed and subscription -</xsl:text> - <xsl:text> function update_subscriptions() { -</xsl:text> - <xsl:text> let delta = []; -</xsl:text> - <xsl:text> Object.keys(subscribers).forEach(index => { -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> let previous_period = subscriptions.get(index); -</xsl:text> - <xsl:text> delete subscriptions[index]; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> let new_period = Math.min(...widgets.map(widget => widget.period)); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> if(previous_period != new_period) -</xsl:text> - <xsl:text> delta.push({index: index, period: new_period}); -</xsl:text> - <xsl:text> }) -</xsl:text> - <xsl:text> return result; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> function update_value(index, value) { -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> }; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> function switch_page(page_name) { -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> }; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>})(); -</xsl:text> - </xsl:template> - <xsl:template name="parse_label"> + <func:function name="func:parselabel"> <xsl:param name="label"/> <xsl:variable name="description" select="substring-after($label,'HMI:')"/> <xsl:variable name="_args" select="substring-before($description,'@')"/> @@ -313,28 +132,211 @@ </xsl:otherwise> </xsl:choose> </xsl:variable> - <xsl:if test="$type"> - <widget> - <xsl:attribute name="type"> - <xsl:value-of select="$type"/> - </xsl:attribute> - <xsl:for-each select="str:split($args, ':')"> - <arg> - <xsl:attribute name="value"> - <xsl:value-of select="."/> - </xsl:attribute> - </arg> - </xsl:for-each> - <xsl:variable name="paths" select="substring-after($description,'@')"/> - <xsl:for-each select="str:split($paths, '@')"> - <path> - <xsl:attribute name="value"> - <xsl:value-of select="."/> - </xsl:attribute> - </path> - </xsl:for-each> - </widget> - </xsl:if> + <xsl:variable name="ast"> + <xsl:if test="$type"> + <widget> + <xsl:attribute name="type"> + <xsl:value-of select="$type"/> + </xsl:attribute> + <xsl:for-each select="str:split($args, ':')"> + <arg> + <xsl:attribute name="value"> + <xsl:value-of select="."/> + </xsl:attribute> + </arg> + </xsl:for-each> + <xsl:variable name="paths" select="substring-after($description,'@')"/> + <xsl:for-each select="str:split($paths, '@')"> + <path> + <xsl:attribute name="value"> + <xsl:value-of select="."/> + </xsl:attribute> + </path> + </xsl:for-each> + </widget> + </xsl:if> + </xsl:variable> + <func:result select="exsl:node-set($ast)"/> + </func:function> + <xsl:template name="scripts"> + <xsl:text>var hmi_index = { +</xsl:text> + <xsl:variable name="svg" select="/"/> + <xsl:for-each select="$indexed_hmitree/*"> + <xsl:value-of select="@index"/> + <xsl:text>: { +</xsl:text> + <xsl:text> name: "</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>", +</xsl:text> + <xsl:text> hmipath: "</xsl:text> + <xsl:value-of select="@hmipath"/> + <xsl:text>" +</xsl:text> + <xsl:text> ids: [ +</xsl:text> + <xsl:variable name="hmipath" select="@hmipath"/> + <xsl:for-each select="$svg//*[substring-after(@inkscape:label,'@') = $hmipath]"> + <xsl:text> "</xsl:text> + <xsl:value-of select="@id"/> + <xsl:text>"</xsl:text> + <xsl:if test="position()!=last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text> +</xsl:text> + </xsl:for-each> + <xsl:text> ] +</xsl:text> + <xsl:text>}</xsl:text> + <xsl:if test="position()!=last()"> + <xsl:text>,</xsl:text> + </xsl:if> + <xsl:text> +</xsl:text> + </xsl:for-each> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>var page_desc = { +</xsl:text> + <xsl:for-each select="//*[func:parselabel(@inkscape:label)/widget/@type = 'Page']"> + <xsl:value-of select="@inkscape:label"/> + <xsl:text> +</xsl:text> + <xsl:variable name="ast" select="func:parselabel(@inkscape:label)"/> + <xsl:apply-templates mode="testtree" select="$ast"/> + </xsl:for-each> + <xsl:text>} +</xsl:text> + <xsl:text>// svghmi.js +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>(function(){ +</xsl:text> + <xsl:text> // Open WebSocket to relative "/ws" address +</xsl:text> + <xsl:text> var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // Register message reception handler +</xsl:text> + <xsl:text> ws.onmessage = function (evt) { +</xsl:text> + <xsl:text> // TODO : dispatch and cache hmi tree updates +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> var received_msg = evt.data; +</xsl:text> + <xsl:text> // TODO : check for hmitree hash header +</xsl:text> + <xsl:text> // if not matching, reload page +</xsl:text> + <xsl:text> alert("Message is received..."+received_msg); +</xsl:text> + <xsl:text> }; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // Once connection established +</xsl:text> + <xsl:text> ws.onopen = function (evt) { +</xsl:text> + <xsl:text> // TODO : enable the HMI (was previously offline, or just starts) +</xsl:text> + <xsl:text> // show main page +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // TODO : prefix with hmitree hash header +</xsl:text> + <xsl:text> ws.send("test"); +</xsl:text> + <xsl:text> }; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> var pending_updates = {}; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // subscription state, as it should be in hmi server +</xsl:text> + <xsl:text> // expected {index:period} +</xsl:text> + <xsl:text> const subscriptions = new Map(); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // subscription state as needed by widget now +</xsl:text> + <xsl:text> // expected {index:[widgets]}; +</xsl:text> + <xsl:text> var subscribers = {}; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // return the diff in between curently subscribed and subscription +</xsl:text> + <xsl:text> function update_subscriptions() { +</xsl:text> + <xsl:text> let delta = []; +</xsl:text> + <xsl:text> Object.keys(subscribers).forEach(index => { +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> let previous_period = subscriptions.get(index); +</xsl:text> + <xsl:text> delete subscriptions[index]; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> let new_period = Math.min(...widgets.map(widget => widget.period)); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(previous_period != new_period) +</xsl:text> + <xsl:text> delta.push({index: index, period: new_period}); +</xsl:text> + <xsl:text> }) +</xsl:text> + <xsl:text> return result; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> function update_value(index, value) { +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> }; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> function switch_page(page_name) { +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> }; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>})(); +</xsl:text> </xsl:template> <xsl:template mode="page_desc" match="*"/> <xsl:template mode="code_from_descs" match="*"> diff -r 0c0d3895b036 -r 2a97688c94c5 svghmi/gen_index_xhtml.ysl2 --- a/svghmi/gen_index_xhtml.ysl2 Tue Oct 08 13:27:00 2019 +0200 +++ b/svghmi/gen_index_xhtml.ysl2 Wed Oct 09 09:04:35 2019 +0200 @@ -14,8 +14,8 @@ /* Our namespace to invoke python code */ xmlns:ns="beremiz" - extension-element-prefixes="ns" - exclude-result-prefixes="ns str regexp exsl" { + extension-element-prefixes="ns func" + exclude-result-prefixes="ns str regexp exsl func" { /* This retrieves geometry obtained through "inkscape -S" * already parsed by python and presented as a list of @@ -83,6 +83,7 @@ /* copy root node and add geometry as comment for a test */ template "/" { + comment > Made with SVGHMI. https://beremiz.org html xmlns="http://www.w3.org/1999/xhtml" { head; body style="margin:0;" { @@ -105,6 +106,40 @@ } } + func:function name="func:parselabel" { + param "label"; + const "description", "substring-after($label,'HMI:')"; + + const "_args", "substring-before($description,'@')"; + const "args" choose { + when "$_args" value "$_args"; + otherwise value "$description"; + } + + const "_type", "substring-before($args,':')"; + const "type" choose { + when "$_type" value "$_type"; + otherwise value "$args"; + } + + const "ast" if "$type" widget { + attrib "type" > «$type» + foreach "str:split($args, ':')" { + arg { + attrib "value" > «.» + } + } + const "paths", "substring-after($description,'@')"; + foreach "str:split($paths, '@')" { + path { + attrib "value" > «.» + } + } + } + + func:result select="exsl:node-set($ast)" + } + function "scripts" { /* TODO : paste hmitree hash stored in hmi tree root node */ @@ -154,10 +189,10 @@ | var page_desc = { // apply "//*[substring-after(substring-before(@inkscape:label, '@'), 'HMI' - foreach "//*[starts-with(@inkscape:label,'HMI:')]" { + foreach "//*[func:parselabel(@inkscape:label)/widget/@type = 'Page']" { | «@inkscape:label» - const "ast" call "parse_label" with "label","@inkscape:label"; - apply "exsl:node-set($ast)", mode="testtree"; + const "ast", "func:parselabel(@inkscape:label)"; + apply "$ast", mode="testtree"; } | } @@ -176,37 +211,6 @@ path value="path2"; } */ - function "parse_label" { - param "label"; - const "description", "substring-after($label,'HMI:')"; - - const "_args", "substring-before($description,'@')"; - const "args" choose { - when "$_args" value "$_args"; - otherwise value "$description"; - } - - const "_type", "substring-before($args,':')"; - const "type" choose { - when "$_type" value "$_type"; - otherwise value "$args"; - } - - if "$type" widget { - attrib "type" > «$type» - foreach "str:split($args, ':')" { - arg { - attrib "value" > «.» - } - } - const "paths", "substring-after($description,'@')"; - foreach "str:split($paths, '@')" { - path { - attrib "value" > «.» - } - } - } - } template "*", mode="page_desc" { } diff -r 0c0d3895b036 -r 2a97688c94c5 yslt_noindent.yml2 --- a/yslt_noindent.yml2 Tue Oct 08 13:27:00 2019 +0200 +++ b/yslt_noindent.yml2 Wed Oct 09 09:04:35 2019 +0200 @@ -12,7 +12,8 @@ xmlns:exsl='http://exslt.org/common', xmlns:regexp="http://exslt.org/regular-expressions", xmlns:str="http://exslt.org/strings", - extension-element-prefixes='exsl regexp str' + xmlns:func="http://exslt.org/functions", + extension-element-prefixes='exsl regexp str func' ) alias stylesheet { output *output; content;