svghmi/gen_index_xhtml.xslt
branchsvghmi
changeset 2793 2a97688c94c5
parent 2792 0c0d3895b036
child 2794 c10069a02ed0
equal deleted inserted replaced
2792:0c0d3895b036 2793:2a97688c94c5
     1 <?xml version="1.0"?>
     1 <?xml version="1.0"?>
     2 <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">
     2 <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">
     3   <xsl:output method="xml" cdata-section-elements="script"/>
     3   <xsl:output method="xml" cdata-section-elements="script"/>
     4   <xsl:variable name="geometry" select="ns:GetSVGGeometry()"/>
     4   <xsl:variable name="geometry" select="ns:GetSVGGeometry()"/>
     5   <xsl:variable name="hmitree" select="ns:GetHMITree()"/>
     5   <xsl:variable name="hmitree" select="ns:GetHMITree()"/>
     6   <xsl:variable name="_categories">
     6   <xsl:variable name="_categories">
     7     <noindex>
     7     <noindex>
    81   <xsl:variable name="mark">
    81   <xsl:variable name="mark">
    82     <xsl:text>=HMI=
    82     <xsl:text>=HMI=
    83 </xsl:text>
    83 </xsl:text>
    84   </xsl:variable>
    84   </xsl:variable>
    85   <xsl:template match="/">
    85   <xsl:template match="/">
       
    86     <xsl:comment>
       
    87       <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text>
       
    88     </xsl:comment>
    86     <html xmlns="http://www.w3.org/1999/xhtml">
    89     <html xmlns="http://www.w3.org/1999/xhtml">
    87       <head/>
    90       <head/>
    88       <body style="margin:0;">
    91       <body style="margin:0;">
    89         <xsl:copy>
    92         <xsl:copy>
    90           <xsl:comment>
    93           <xsl:comment>
   102           <xsl:call-template name="scripts"/>
   105           <xsl:call-template name="scripts"/>
   103         </script>
   106         </script>
   104       </body>
   107       </body>
   105     </html>
   108     </html>
   106   </xsl:template>
   109   </xsl:template>
   107   <xsl:template name="scripts">
   110   <func:function name="func:parselabel">
   108     <xsl:text>var hmi_index = {
       
   109 </xsl:text>
       
   110     <xsl:variable name="svg" select="/"/>
       
   111     <xsl:for-each select="$indexed_hmitree/*">
       
   112       <xsl:value-of select="@index"/>
       
   113       <xsl:text>: {
       
   114 </xsl:text>
       
   115       <xsl:text>    name: "</xsl:text>
       
   116       <xsl:value-of select="@name"/>
       
   117       <xsl:text>",
       
   118 </xsl:text>
       
   119       <xsl:text>    hmipath: "</xsl:text>
       
   120       <xsl:value-of select="@hmipath"/>
       
   121       <xsl:text>"
       
   122 </xsl:text>
       
   123       <xsl:text>    ids: [
       
   124 </xsl:text>
       
   125       <xsl:variable name="hmipath" select="@hmipath"/>
       
   126       <xsl:for-each select="$svg//*[substring-after(@inkscape:label,'@') = $hmipath]">
       
   127         <xsl:text>        "</xsl:text>
       
   128         <xsl:value-of select="@id"/>
       
   129         <xsl:text>"</xsl:text>
       
   130         <xsl:if test="position()!=last()">
       
   131           <xsl:text>,</xsl:text>
       
   132         </xsl:if>
       
   133         <xsl:text>
       
   134 </xsl:text>
       
   135       </xsl:for-each>
       
   136       <xsl:text>    ]
       
   137 </xsl:text>
       
   138       <xsl:text>}</xsl:text>
       
   139       <xsl:if test="position()!=last()">
       
   140         <xsl:text>,</xsl:text>
       
   141       </xsl:if>
       
   142       <xsl:text>
       
   143 </xsl:text>
       
   144     </xsl:for-each>
       
   145     <xsl:text>}
       
   146 </xsl:text>
       
   147     <xsl:text>
       
   148 </xsl:text>
       
   149     <xsl:text>var page_desc = {
       
   150 </xsl:text>
       
   151     <xsl:for-each select="//*[starts-with(@inkscape:label,'HMI:')]">
       
   152       <xsl:value-of select="@inkscape:label"/>
       
   153       <xsl:text>
       
   154 </xsl:text>
       
   155       <xsl:variable name="ast">
       
   156         <xsl:call-template name="parse_label">
       
   157           <xsl:with-param name="label" select="@inkscape:label"/>
       
   158         </xsl:call-template>
       
   159       </xsl:variable>
       
   160       <xsl:apply-templates mode="testtree" select="exsl:node-set($ast)"/>
       
   161     </xsl:for-each>
       
   162     <xsl:text>}
       
   163 </xsl:text>
       
   164     <xsl:text>// svghmi.js
       
   165 </xsl:text>
       
   166     <xsl:text>
       
   167 </xsl:text>
       
   168     <xsl:text>(function(){
       
   169 </xsl:text>
       
   170     <xsl:text>    // Open WebSocket to relative "/ws" address
       
   171 </xsl:text>
       
   172     <xsl:text>    var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws'));
       
   173 </xsl:text>
       
   174     <xsl:text>
       
   175 </xsl:text>
       
   176     <xsl:text>    // Register message reception handler 
       
   177 </xsl:text>
       
   178     <xsl:text>    ws.onmessage = function (evt) {
       
   179 </xsl:text>
       
   180     <xsl:text>        // TODO : dispatch and cache hmi tree updates
       
   181 </xsl:text>
       
   182     <xsl:text>
       
   183 </xsl:text>
       
   184     <xsl:text>        var received_msg = evt.data;
       
   185 </xsl:text>
       
   186     <xsl:text>        // TODO : check for hmitree hash header
       
   187 </xsl:text>
       
   188     <xsl:text>        //        if not matching, reload page
       
   189 </xsl:text>
       
   190     <xsl:text>        alert("Message is received..."+received_msg); 
       
   191 </xsl:text>
       
   192     <xsl:text>    };
       
   193 </xsl:text>
       
   194     <xsl:text>
       
   195 </xsl:text>
       
   196     <xsl:text>    // Once connection established
       
   197 </xsl:text>
       
   198     <xsl:text>    ws.onopen = function (evt) {
       
   199 </xsl:text>
       
   200     <xsl:text>        // TODO : enable the HMI (was previously offline, or just starts)
       
   201 </xsl:text>
       
   202     <xsl:text>        //        show main page
       
   203 </xsl:text>
       
   204     <xsl:text>
       
   205 </xsl:text>
       
   206     <xsl:text>
       
   207 </xsl:text>
       
   208     <xsl:text>        // TODO : prefix with hmitree hash header
       
   209 </xsl:text>
       
   210     <xsl:text>        ws.send("test");
       
   211 </xsl:text>
       
   212     <xsl:text>    };
       
   213 </xsl:text>
       
   214     <xsl:text>
       
   215 </xsl:text>
       
   216     <xsl:text>    var pending_updates = {};
       
   217 </xsl:text>
       
   218     <xsl:text>    
       
   219 </xsl:text>
       
   220     <xsl:text>    // subscription state, as it should be in hmi server
       
   221 </xsl:text>
       
   222     <xsl:text>    // expected {index:period}
       
   223 </xsl:text>
       
   224     <xsl:text>    const subscriptions = new Map();
       
   225 </xsl:text>
       
   226     <xsl:text>
       
   227 </xsl:text>
       
   228     <xsl:text>
       
   229 </xsl:text>
       
   230     <xsl:text>    // subscription state as needed by widget now
       
   231 </xsl:text>
       
   232     <xsl:text>    // expected {index:[widgets]};
       
   233 </xsl:text>
       
   234     <xsl:text>    var subscribers = {};
       
   235 </xsl:text>
       
   236     <xsl:text>
       
   237 </xsl:text>
       
   238     <xsl:text>    // return the diff in between curently subscribed and subscription
       
   239 </xsl:text>
       
   240     <xsl:text>    function update_subscriptions() {
       
   241 </xsl:text>
       
   242     <xsl:text>        let delta = [];
       
   243 </xsl:text>
       
   244     <xsl:text>        Object.keys(subscribers).forEach(index =&gt; {
       
   245 </xsl:text>
       
   246     <xsl:text>
       
   247 </xsl:text>
       
   248     <xsl:text>            let previous_period = subscriptions.get(index);
       
   249 </xsl:text>
       
   250     <xsl:text>            delete subscriptions[index];
       
   251 </xsl:text>
       
   252     <xsl:text>
       
   253 </xsl:text>
       
   254     <xsl:text>            let new_period = Math.min(...widgets.map(widget =&gt; widget.period));
       
   255 </xsl:text>
       
   256     <xsl:text>
       
   257 </xsl:text>
       
   258     <xsl:text>            if(previous_period != new_period) 
       
   259 </xsl:text>
       
   260     <xsl:text>                delta.push({index: index, period: new_period});
       
   261 </xsl:text>
       
   262     <xsl:text>        })
       
   263 </xsl:text>
       
   264     <xsl:text>        return result;
       
   265 </xsl:text>
       
   266     <xsl:text>    }
       
   267 </xsl:text>
       
   268     <xsl:text>
       
   269 </xsl:text>
       
   270     <xsl:text>
       
   271 </xsl:text>
       
   272     <xsl:text>    function update_value(index, value) {
       
   273 </xsl:text>
       
   274     <xsl:text>
       
   275 </xsl:text>
       
   276     <xsl:text>    };
       
   277 </xsl:text>
       
   278     <xsl:text>
       
   279 </xsl:text>
       
   280     <xsl:text>    function switch_page(page_name) {
       
   281 </xsl:text>
       
   282     <xsl:text>
       
   283 </xsl:text>
       
   284     <xsl:text>    };
       
   285 </xsl:text>
       
   286     <xsl:text>
       
   287 </xsl:text>
       
   288     <xsl:text>})();
       
   289 </xsl:text>
       
   290   </xsl:template>
       
   291   <xsl:template name="parse_label">
       
   292     <xsl:param name="label"/>
   111     <xsl:param name="label"/>
   293     <xsl:variable name="description" select="substring-after($label,'HMI:')"/>
   112     <xsl:variable name="description" select="substring-after($label,'HMI:')"/>
   294     <xsl:variable name="_args" select="substring-before($description,'@')"/>
   113     <xsl:variable name="_args" select="substring-before($description,'@')"/>
   295     <xsl:variable name="args">
   114     <xsl:variable name="args">
   296       <xsl:choose>
   115       <xsl:choose>
   311         <xsl:otherwise>
   130         <xsl:otherwise>
   312           <xsl:value-of select="$args"/>
   131           <xsl:value-of select="$args"/>
   313         </xsl:otherwise>
   132         </xsl:otherwise>
   314       </xsl:choose>
   133       </xsl:choose>
   315     </xsl:variable>
   134     </xsl:variable>
   316     <xsl:if test="$type">
   135     <xsl:variable name="ast">
   317       <widget>
   136       <xsl:if test="$type">
   318         <xsl:attribute name="type">
   137         <widget>
   319           <xsl:value-of select="$type"/>
   138           <xsl:attribute name="type">
   320         </xsl:attribute>
   139             <xsl:value-of select="$type"/>
   321         <xsl:for-each select="str:split($args, ':')">
   140           </xsl:attribute>
   322           <arg>
   141           <xsl:for-each select="str:split($args, ':')">
   323             <xsl:attribute name="value">
   142             <arg>
   324               <xsl:value-of select="."/>
   143               <xsl:attribute name="value">
   325             </xsl:attribute>
   144                 <xsl:value-of select="."/>
   326           </arg>
   145               </xsl:attribute>
   327         </xsl:for-each>
   146             </arg>
   328         <xsl:variable name="paths" select="substring-after($description,'@')"/>
   147           </xsl:for-each>
   329         <xsl:for-each select="str:split($paths, '@')">
   148           <xsl:variable name="paths" select="substring-after($description,'@')"/>
   330           <path>
   149           <xsl:for-each select="str:split($paths, '@')">
   331             <xsl:attribute name="value">
   150             <path>
   332               <xsl:value-of select="."/>
   151               <xsl:attribute name="value">
   333             </xsl:attribute>
   152                 <xsl:value-of select="."/>
   334           </path>
   153               </xsl:attribute>
   335         </xsl:for-each>
   154             </path>
   336       </widget>
   155           </xsl:for-each>
   337     </xsl:if>
   156         </widget>
       
   157       </xsl:if>
       
   158     </xsl:variable>
       
   159     <func:result select="exsl:node-set($ast)"/>
       
   160   </func:function>
       
   161   <xsl:template name="scripts">
       
   162     <xsl:text>var hmi_index = {
       
   163 </xsl:text>
       
   164     <xsl:variable name="svg" select="/"/>
       
   165     <xsl:for-each select="$indexed_hmitree/*">
       
   166       <xsl:value-of select="@index"/>
       
   167       <xsl:text>: {
       
   168 </xsl:text>
       
   169       <xsl:text>    name: "</xsl:text>
       
   170       <xsl:value-of select="@name"/>
       
   171       <xsl:text>",
       
   172 </xsl:text>
       
   173       <xsl:text>    hmipath: "</xsl:text>
       
   174       <xsl:value-of select="@hmipath"/>
       
   175       <xsl:text>"
       
   176 </xsl:text>
       
   177       <xsl:text>    ids: [
       
   178 </xsl:text>
       
   179       <xsl:variable name="hmipath" select="@hmipath"/>
       
   180       <xsl:for-each select="$svg//*[substring-after(@inkscape:label,'@') = $hmipath]">
       
   181         <xsl:text>        "</xsl:text>
       
   182         <xsl:value-of select="@id"/>
       
   183         <xsl:text>"</xsl:text>
       
   184         <xsl:if test="position()!=last()">
       
   185           <xsl:text>,</xsl:text>
       
   186         </xsl:if>
       
   187         <xsl:text>
       
   188 </xsl:text>
       
   189       </xsl:for-each>
       
   190       <xsl:text>    ]
       
   191 </xsl:text>
       
   192       <xsl:text>}</xsl:text>
       
   193       <xsl:if test="position()!=last()">
       
   194         <xsl:text>,</xsl:text>
       
   195       </xsl:if>
       
   196       <xsl:text>
       
   197 </xsl:text>
       
   198     </xsl:for-each>
       
   199     <xsl:text>}
       
   200 </xsl:text>
       
   201     <xsl:text>
       
   202 </xsl:text>
       
   203     <xsl:text>var page_desc = {
       
   204 </xsl:text>
       
   205     <xsl:for-each select="//*[func:parselabel(@inkscape:label)/widget/@type = 'Page']">
       
   206       <xsl:value-of select="@inkscape:label"/>
       
   207       <xsl:text>
       
   208 </xsl:text>
       
   209       <xsl:variable name="ast" select="func:parselabel(@inkscape:label)"/>
       
   210       <xsl:apply-templates mode="testtree" select="$ast"/>
       
   211     </xsl:for-each>
       
   212     <xsl:text>}
       
   213 </xsl:text>
       
   214     <xsl:text>// svghmi.js
       
   215 </xsl:text>
       
   216     <xsl:text>
       
   217 </xsl:text>
       
   218     <xsl:text>(function(){
       
   219 </xsl:text>
       
   220     <xsl:text>    // Open WebSocket to relative "/ws" address
       
   221 </xsl:text>
       
   222     <xsl:text>    var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws'));
       
   223 </xsl:text>
       
   224     <xsl:text>
       
   225 </xsl:text>
       
   226     <xsl:text>    // Register message reception handler 
       
   227 </xsl:text>
       
   228     <xsl:text>    ws.onmessage = function (evt) {
       
   229 </xsl:text>
       
   230     <xsl:text>        // TODO : dispatch and cache hmi tree updates
       
   231 </xsl:text>
       
   232     <xsl:text>
       
   233 </xsl:text>
       
   234     <xsl:text>        var received_msg = evt.data;
       
   235 </xsl:text>
       
   236     <xsl:text>        // TODO : check for hmitree hash header
       
   237 </xsl:text>
       
   238     <xsl:text>        //        if not matching, reload page
       
   239 </xsl:text>
       
   240     <xsl:text>        alert("Message is received..."+received_msg); 
       
   241 </xsl:text>
       
   242     <xsl:text>    };
       
   243 </xsl:text>
       
   244     <xsl:text>
       
   245 </xsl:text>
       
   246     <xsl:text>    // Once connection established
       
   247 </xsl:text>
       
   248     <xsl:text>    ws.onopen = function (evt) {
       
   249 </xsl:text>
       
   250     <xsl:text>        // TODO : enable the HMI (was previously offline, or just starts)
       
   251 </xsl:text>
       
   252     <xsl:text>        //        show main page
       
   253 </xsl:text>
       
   254     <xsl:text>
       
   255 </xsl:text>
       
   256     <xsl:text>
       
   257 </xsl:text>
       
   258     <xsl:text>        // TODO : prefix with hmitree hash header
       
   259 </xsl:text>
       
   260     <xsl:text>        ws.send("test");
       
   261 </xsl:text>
       
   262     <xsl:text>    };
       
   263 </xsl:text>
       
   264     <xsl:text>
       
   265 </xsl:text>
       
   266     <xsl:text>    var pending_updates = {};
       
   267 </xsl:text>
       
   268     <xsl:text>    
       
   269 </xsl:text>
       
   270     <xsl:text>    // subscription state, as it should be in hmi server
       
   271 </xsl:text>
       
   272     <xsl:text>    // expected {index:period}
       
   273 </xsl:text>
       
   274     <xsl:text>    const subscriptions = new Map();
       
   275 </xsl:text>
       
   276     <xsl:text>
       
   277 </xsl:text>
       
   278     <xsl:text>
       
   279 </xsl:text>
       
   280     <xsl:text>    // subscription state as needed by widget now
       
   281 </xsl:text>
       
   282     <xsl:text>    // expected {index:[widgets]};
       
   283 </xsl:text>
       
   284     <xsl:text>    var subscribers = {};
       
   285 </xsl:text>
       
   286     <xsl:text>
       
   287 </xsl:text>
       
   288     <xsl:text>    // return the diff in between curently subscribed and subscription
       
   289 </xsl:text>
       
   290     <xsl:text>    function update_subscriptions() {
       
   291 </xsl:text>
       
   292     <xsl:text>        let delta = [];
       
   293 </xsl:text>
       
   294     <xsl:text>        Object.keys(subscribers).forEach(index =&gt; {
       
   295 </xsl:text>
       
   296     <xsl:text>
       
   297 </xsl:text>
       
   298     <xsl:text>            let previous_period = subscriptions.get(index);
       
   299 </xsl:text>
       
   300     <xsl:text>            delete subscriptions[index];
       
   301 </xsl:text>
       
   302     <xsl:text>
       
   303 </xsl:text>
       
   304     <xsl:text>            let new_period = Math.min(...widgets.map(widget =&gt; widget.period));
       
   305 </xsl:text>
       
   306     <xsl:text>
       
   307 </xsl:text>
       
   308     <xsl:text>            if(previous_period != new_period) 
       
   309 </xsl:text>
       
   310     <xsl:text>                delta.push({index: index, period: new_period});
       
   311 </xsl:text>
       
   312     <xsl:text>        })
       
   313 </xsl:text>
       
   314     <xsl:text>        return result;
       
   315 </xsl:text>
       
   316     <xsl:text>    }
       
   317 </xsl:text>
       
   318     <xsl:text>
       
   319 </xsl:text>
       
   320     <xsl:text>
       
   321 </xsl:text>
       
   322     <xsl:text>    function update_value(index, value) {
       
   323 </xsl:text>
       
   324     <xsl:text>
       
   325 </xsl:text>
       
   326     <xsl:text>    };
       
   327 </xsl:text>
       
   328     <xsl:text>
       
   329 </xsl:text>
       
   330     <xsl:text>    function switch_page(page_name) {
       
   331 </xsl:text>
       
   332     <xsl:text>
       
   333 </xsl:text>
       
   334     <xsl:text>    };
       
   335 </xsl:text>
       
   336     <xsl:text>
       
   337 </xsl:text>
       
   338     <xsl:text>})();
       
   339 </xsl:text>
   338   </xsl:template>
   340   </xsl:template>
   339   <xsl:template mode="page_desc" match="*"/>
   341   <xsl:template mode="page_desc" match="*"/>
   340   <xsl:template mode="code_from_descs" match="*">
   342   <xsl:template mode="code_from_descs" match="*">
   341     <xsl:text>{
   343     <xsl:text>{
   342 </xsl:text>
   344 </xsl:text>