|
1 <?xml version="1.0"?> |
|
2 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" xmlns:regexp="http://exslt.org/regular-expressions" xmlns:str="http://exslt.org/strings" xmlns:func="http://exslt.org/functions" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:debug="debug" xmlns:preamble="preamble" xmlns:declarations="declarations" xmlns:definitions="definitions" xmlns:epilogue="epilogue" xmlns:ns="beremiz" version="1.0" extension-element-prefixes="ns func exsl regexp str dyn" exclude-result-prefixes="ns func exsl regexp str dyn debug preamble epilogue declarations definitions"> |
|
3 <xsl:output cdata-section-elements="xhtml:script" method="xml"/> |
|
4 <xsl:variable name="svg" select="/svg:svg"/> |
|
5 <xsl:variable name="hmi_elements" select="//svg:*[starts-with(@inkscape:label, 'HMI:')]"/> |
|
6 <xsl:variable name="hmitree" select="ns:GetHMITree()"/> |
|
7 <xsl:variable name="_categories"> |
|
8 <noindex> |
|
9 <xsl:text>HMI_PLC_STATUS</xsl:text> |
|
10 </noindex> |
|
11 <noindex> |
|
12 <xsl:text>HMI_CURRENT_PAGE</xsl:text> |
|
13 </noindex> |
|
14 </xsl:variable> |
|
15 <xsl:variable name="categories" select="exsl:node-set($_categories)"/> |
|
16 <xsl:variable name="_indexed_hmitree"> |
|
17 <xsl:apply-templates mode="index" select="$hmitree"/> |
|
18 </xsl:variable> |
|
19 <xsl:variable name="indexed_hmitree" select="exsl:node-set($_indexed_hmitree)"/> |
|
20 <preamble:hmi-tree/> |
|
21 <xsl:template match="preamble:hmi-tree"> |
|
22 <xsl:text> |
|
23 </xsl:text> |
|
24 <xsl:text>/* </xsl:text> |
|
25 <xsl:value-of select="local-name()"/> |
|
26 <xsl:text> */ |
|
27 </xsl:text> |
|
28 <xsl:text> |
|
29 </xsl:text> |
|
30 <xsl:text>var hmi_hash = [</xsl:text> |
|
31 <xsl:value-of select="$hmitree/@hash"/> |
|
32 <xsl:text>]; |
|
33 </xsl:text> |
|
34 <xsl:text> |
|
35 </xsl:text> |
|
36 <xsl:text>var heartbeat_index = </xsl:text> |
|
37 <xsl:value-of select="$indexed_hmitree/*[@hmipath = '/HEARTBEAT']/@index"/> |
|
38 <xsl:text>; |
|
39 </xsl:text> |
|
40 <xsl:text> |
|
41 </xsl:text> |
|
42 <xsl:text>var hmitree_types = [ |
|
43 </xsl:text> |
|
44 <xsl:for-each select="$indexed_hmitree/*"> |
|
45 <xsl:text> /* </xsl:text> |
|
46 <xsl:value-of select="@index"/> |
|
47 <xsl:text> */ "</xsl:text> |
|
48 <xsl:value-of select="substring(local-name(), 5)"/> |
|
49 <xsl:text>"</xsl:text> |
|
50 <xsl:if test="position()!=last()"> |
|
51 <xsl:text>,</xsl:text> |
|
52 </xsl:if> |
|
53 <xsl:text> |
|
54 </xsl:text> |
|
55 </xsl:for-each> |
|
56 <xsl:text>]; |
|
57 </xsl:text> |
|
58 <xsl:text> |
|
59 </xsl:text> |
|
60 <xsl:text>var hmitree_paths = [ |
|
61 </xsl:text> |
|
62 <xsl:for-each select="$indexed_hmitree/*"> |
|
63 <xsl:text> /* </xsl:text> |
|
64 <xsl:value-of select="@index"/> |
|
65 <xsl:text> */ "</xsl:text> |
|
66 <xsl:value-of select="@hmipath"/> |
|
67 <xsl:text>"</xsl:text> |
|
68 <xsl:if test="position()!=last()"> |
|
69 <xsl:text>,</xsl:text> |
|
70 </xsl:if> |
|
71 <xsl:text> |
|
72 </xsl:text> |
|
73 </xsl:for-each> |
|
74 <xsl:text>]; |
|
75 </xsl:text> |
|
76 <xsl:text> |
|
77 </xsl:text> |
|
78 <xsl:text> |
|
79 </xsl:text> |
|
80 </xsl:template> |
|
81 <xsl:template mode="index" match="*"> |
|
82 <xsl:param name="index" select="0"/> |
|
83 <xsl:param name="parentpath" select="''"/> |
|
84 <xsl:variable name="content"> |
|
85 <xsl:variable name="path"> |
|
86 <xsl:choose> |
|
87 <xsl:when test="count(ancestor::*)=0"> |
|
88 <xsl:text>/</xsl:text> |
|
89 </xsl:when> |
|
90 <xsl:when test="count(ancestor::*)=1"> |
|
91 <xsl:text>/</xsl:text> |
|
92 <xsl:value-of select="@name"/> |
|
93 </xsl:when> |
|
94 <xsl:otherwise> |
|
95 <xsl:value-of select="$parentpath"/> |
|
96 <xsl:text>/</xsl:text> |
|
97 <xsl:value-of select="@name"/> |
|
98 </xsl:otherwise> |
|
99 </xsl:choose> |
|
100 </xsl:variable> |
|
101 <xsl:choose> |
|
102 <xsl:when test="not(local-name() = $categories/noindex)"> |
|
103 <xsl:copy> |
|
104 <xsl:attribute name="index"> |
|
105 <xsl:value-of select="$index"/> |
|
106 </xsl:attribute> |
|
107 <xsl:attribute name="hmipath"> |
|
108 <xsl:value-of select="$path"/> |
|
109 </xsl:attribute> |
|
110 <xsl:for-each select="@*"> |
|
111 <xsl:copy/> |
|
112 </xsl:for-each> |
|
113 </xsl:copy> |
|
114 <xsl:apply-templates mode="index" select="*[1]"> |
|
115 <xsl:with-param name="index" select="$index + 1"/> |
|
116 <xsl:with-param name="parentpath"> |
|
117 <xsl:value-of select="$path"/> |
|
118 </xsl:with-param> |
|
119 </xsl:apply-templates> |
|
120 </xsl:when> |
|
121 <xsl:otherwise> |
|
122 <xsl:apply-templates mode="index" select="*[1]"> |
|
123 <xsl:with-param name="index" select="$index"/> |
|
124 <xsl:with-param name="parentpath"> |
|
125 <xsl:value-of select="$path"/> |
|
126 </xsl:with-param> |
|
127 </xsl:apply-templates> |
|
128 </xsl:otherwise> |
|
129 </xsl:choose> |
|
130 </xsl:variable> |
|
131 <xsl:copy-of select="$content"/> |
|
132 <xsl:apply-templates mode="index" select="following-sibling::*[1]"> |
|
133 <xsl:with-param name="index" select="$index + count(exsl:node-set($content)/*)"/> |
|
134 <xsl:with-param name="parentpath"> |
|
135 <xsl:value-of select="$parentpath"/> |
|
136 </xsl:with-param> |
|
137 </xsl:apply-templates> |
|
138 </xsl:template> |
|
139 <xsl:variable name="pathregex" select="'^([^\[,]+)(\[[^\]]+\])?([\d,]*)$'"/> |
|
140 <xsl:template mode="parselabel" match="*"> |
|
141 <xsl:variable name="label" select="@inkscape:label"/> |
|
142 <xsl:variable name="id" select="@id"/> |
|
143 <xsl:variable name="description" select="substring-after($label,'HMI:')"/> |
|
144 <xsl:variable name="_args" select="substring-before($description,'@')"/> |
|
145 <xsl:variable name="args"> |
|
146 <xsl:choose> |
|
147 <xsl:when test="$_args"> |
|
148 <xsl:value-of select="$_args"/> |
|
149 </xsl:when> |
|
150 <xsl:otherwise> |
|
151 <xsl:value-of select="$description"/> |
|
152 </xsl:otherwise> |
|
153 </xsl:choose> |
|
154 </xsl:variable> |
|
155 <xsl:variable name="_type" select="substring-before($args,':')"/> |
|
156 <xsl:variable name="type"> |
|
157 <xsl:choose> |
|
158 <xsl:when test="$_type"> |
|
159 <xsl:value-of select="$_type"/> |
|
160 </xsl:when> |
|
161 <xsl:otherwise> |
|
162 <xsl:value-of select="$args"/> |
|
163 </xsl:otherwise> |
|
164 </xsl:choose> |
|
165 </xsl:variable> |
|
166 <xsl:if test="$type"> |
|
167 <widget> |
|
168 <xsl:attribute name="id"> |
|
169 <xsl:value-of select="$id"/> |
|
170 </xsl:attribute> |
|
171 <xsl:attribute name="type"> |
|
172 <xsl:value-of select="$type"/> |
|
173 </xsl:attribute> |
|
174 <xsl:for-each select="str:split(substring-after($args, ':'), ':')"> |
|
175 <arg> |
|
176 <xsl:attribute name="value"> |
|
177 <xsl:value-of select="."/> |
|
178 </xsl:attribute> |
|
179 </arg> |
|
180 </xsl:for-each> |
|
181 <xsl:variable name="paths" select="substring-after($description,'@')"/> |
|
182 <xsl:for-each select="str:split($paths, '@')"> |
|
183 <xsl:if test="string-length(.) > 0"> |
|
184 <path> |
|
185 <xsl:variable name="path_match" select="regexp:match(.,$pathregex)"/> |
|
186 <xsl:variable name="pathminmax" select="str:split($path_match[4],',')"/> |
|
187 <xsl:variable name="path" select="$path_match[2]"/> |
|
188 <xsl:variable name="path_accepts" select="$path_match[3]"/> |
|
189 <xsl:variable name="pathminmaxcount" select="count($pathminmax)"/> |
|
190 <xsl:attribute name="value"> |
|
191 <xsl:value-of select="$path"/> |
|
192 </xsl:attribute> |
|
193 <xsl:if test="string-length($path_accepts)"> |
|
194 <xsl:attribute name="accepts"> |
|
195 <xsl:value-of select="$path_accepts"/> |
|
196 </xsl:attribute> |
|
197 </xsl:if> |
|
198 <xsl:choose> |
|
199 <xsl:when test="$pathminmaxcount = 2"> |
|
200 <xsl:attribute name="min"> |
|
201 <xsl:value-of select="$pathminmax[1]"/> |
|
202 </xsl:attribute> |
|
203 <xsl:attribute name="max"> |
|
204 <xsl:value-of select="$pathminmax[2]"/> |
|
205 </xsl:attribute> |
|
206 </xsl:when> |
|
207 <xsl:when test="$pathminmaxcount = 1 or $pathminmaxcount > 2"> |
|
208 <xsl:message terminate="yes"> |
|
209 <xsl:text>Widget id:</xsl:text> |
|
210 <xsl:value-of select="$id"/> |
|
211 <xsl:text> label:</xsl:text> |
|
212 <xsl:value-of select="$label"/> |
|
213 <xsl:text> has wrong syntax of path section </xsl:text> |
|
214 <xsl:value-of select="$pathminmax"/> |
|
215 </xsl:message> |
|
216 </xsl:when> |
|
217 </xsl:choose> |
|
218 <xsl:if test="$indexed_hmitree"> |
|
219 <xsl:choose> |
|
220 <xsl:when test="regexp:test($path,'^\.[a-zA-Z0-9_]+$')"> |
|
221 <xsl:attribute name="type"> |
|
222 <xsl:text>PAGE_LOCAL</xsl:text> |
|
223 </xsl:attribute> |
|
224 </xsl:when> |
|
225 <xsl:when test="regexp:test($path,'^[a-zA-Z0-9_]+$')"> |
|
226 <xsl:attribute name="type"> |
|
227 <xsl:text>HMI_LOCAL</xsl:text> |
|
228 </xsl:attribute> |
|
229 </xsl:when> |
|
230 <xsl:otherwise> |
|
231 <xsl:variable name="item" select="$indexed_hmitree/*[@hmipath = $path]"/> |
|
232 <xsl:variable name="pathtype" select="local-name($item)"/> |
|
233 <xsl:if test="$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')"> |
|
234 <xsl:message terminate="yes"> |
|
235 <xsl:text>Widget id:</xsl:text> |
|
236 <xsl:value-of select="$id"/> |
|
237 <xsl:text> label:</xsl:text> |
|
238 <xsl:value-of select="$label"/> |
|
239 <xsl:text> path section </xsl:text> |
|
240 <xsl:value-of select="$pathminmax"/> |
|
241 <xsl:text> use min and max on non mumeric value</xsl:text> |
|
242 </xsl:message> |
|
243 </xsl:if> |
|
244 <xsl:if test="count($item) = 1"> |
|
245 <xsl:attribute name="index"> |
|
246 <xsl:value-of select="$item/@index"/> |
|
247 </xsl:attribute> |
|
248 <xsl:attribute name="type"> |
|
249 <xsl:value-of select="$pathtype"/> |
|
250 </xsl:attribute> |
|
251 </xsl:if> |
|
252 </xsl:otherwise> |
|
253 </xsl:choose> |
|
254 </xsl:if> |
|
255 </path> |
|
256 </xsl:if> |
|
257 </xsl:for-each> |
|
258 <xsl:if test="svg:desc"> |
|
259 <desc> |
|
260 <xsl:value-of select="svg:desc/text()"/> |
|
261 </desc> |
|
262 </xsl:if> |
|
263 </widget> |
|
264 </xsl:if> |
|
265 </xsl:template> |
|
266 <xsl:template mode="genlabel" match="arg"> |
|
267 <xsl:text>:</xsl:text> |
|
268 <xsl:value-of select="@value"/> |
|
269 </xsl:template> |
|
270 <xsl:template mode="genlabel" match="path"> |
|
271 <xsl:text>@</xsl:text> |
|
272 <xsl:value-of select="@value"/> |
|
273 <xsl:if test="string-length(@min)>0 or string-length(@max)>0"> |
|
274 <xsl:text>,</xsl:text> |
|
275 <xsl:value-of select="@min"/> |
|
276 <xsl:text>,</xsl:text> |
|
277 <xsl:value-of select="@max"/> |
|
278 </xsl:if> |
|
279 </xsl:template> |
|
280 <xsl:template mode="genlabel" match="widget"> |
|
281 <xsl:text>HMI:</xsl:text> |
|
282 <xsl:value-of select="@type"/> |
|
283 <xsl:apply-templates mode="genlabel" select="arg"/> |
|
284 <xsl:apply-templates mode="genlabel" select="path"/> |
|
285 </xsl:template> |
|
286 <xsl:variable name="_parsed_widgets"> |
|
287 <widget type="VarInitPersistent"> |
|
288 <arg value="0"/> |
|
289 <path value="lang"/> |
|
290 </widget> |
|
291 <xsl:apply-templates mode="parselabel" select="$hmi_elements"/> |
|
292 </xsl:variable> |
|
293 <xsl:variable name="parsed_widgets" select="exsl:node-set($_parsed_widgets)"/> |
|
294 <func:function name="func:widget"> |
|
295 <xsl:param name="id"/> |
|
296 <func:result select="$parsed_widgets/widget[@id = $id]"/> |
|
297 </func:function> |
|
298 <func:function name="func:is_descendant_path"> |
|
299 <xsl:param name="descend"/> |
|
300 <xsl:param name="ancest"/> |
|
301 <func:result select="string-length($ancest) > 0 and starts-with($descend,$ancest)"/> |
|
302 </func:function> |
|
303 <func:function name="func:same_class_paths"> |
|
304 <xsl:param name="a"/> |
|
305 <xsl:param name="b"/> |
|
306 <xsl:variable name="class_a" select="$indexed_hmitree/*[@hmipath = $a]/@class"/> |
|
307 <xsl:variable name="class_b" select="$indexed_hmitree/*[@hmipath = $b]/@class"/> |
|
308 <func:result select="$class_a and $class_b and $class_a = $class_b"/> |
|
309 </func:function> |
|
310 <xsl:template mode="testtree" match="*"> |
|
311 <xsl:param name="indent" select="''"/> |
|
312 <xsl:value-of select="$indent"/> |
|
313 <xsl:text> </xsl:text> |
|
314 <xsl:value-of select="local-name()"/> |
|
315 <xsl:text> </xsl:text> |
|
316 <xsl:for-each select="@*"> |
|
317 <xsl:value-of select="local-name()"/> |
|
318 <xsl:text>="</xsl:text> |
|
319 <xsl:value-of select="."/> |
|
320 <xsl:text>" </xsl:text> |
|
321 </xsl:for-each> |
|
322 <xsl:text> |
|
323 </xsl:text> |
|
324 <xsl:apply-templates mode="testtree" select="*"> |
|
325 <xsl:with-param name="indent"> |
|
326 <xsl:value-of select="concat($indent,'>')"/> |
|
327 </xsl:with-param> |
|
328 </xsl:apply-templates> |
|
329 </xsl:template> |
|
330 <debug:hmi-tree/> |
|
331 <xsl:template match="debug:hmi-tree"> |
|
332 <xsl:text> |
|
333 </xsl:text> |
|
334 <xsl:text>/* </xsl:text> |
|
335 <xsl:value-of select="local-name()"/> |
|
336 <xsl:text> */ |
|
337 </xsl:text> |
|
338 <xsl:text> |
|
339 </xsl:text> |
|
340 <xsl:text>Raw HMI tree |
|
341 </xsl:text> |
|
342 <xsl:apply-templates mode="testtree" select="$hmitree"/> |
|
343 <xsl:text> |
|
344 </xsl:text> |
|
345 <xsl:text>Indexed HMI tree |
|
346 </xsl:text> |
|
347 <xsl:apply-templates mode="testtree" select="$indexed_hmitree"/> |
|
348 <xsl:text> |
|
349 </xsl:text> |
|
350 <xsl:text>Parsed Widgets |
|
351 </xsl:text> |
|
352 <xsl:copy-of select="_parsed_widgets"/> |
|
353 <xsl:apply-templates mode="testtree" select="$parsed_widgets"/> |
|
354 <xsl:text> |
|
355 </xsl:text> |
|
356 </xsl:template> |
|
357 <xsl:variable name="all_geometry" select="ns:GetSVGGeometry()"/> |
|
358 <xsl:variable name="defs" select="//svg:defs/descendant-or-self::svg:*"/> |
|
359 <xsl:variable name="geometry" select="$all_geometry[not(@Id = $defs/@id)]"/> |
|
360 <debug:geometry/> |
|
361 <xsl:template match="debug:geometry"> |
|
362 <xsl:text> |
|
363 </xsl:text> |
|
364 <xsl:text>/* </xsl:text> |
|
365 <xsl:value-of select="local-name()"/> |
|
366 <xsl:text> */ |
|
367 </xsl:text> |
|
368 <xsl:text> |
|
369 </xsl:text> |
|
370 <xsl:text>ID, x, y, w, h |
|
371 </xsl:text> |
|
372 <xsl:for-each select="$geometry"> |
|
373 <xsl:text> </xsl:text> |
|
374 <xsl:value-of select="@Id"/> |
|
375 <xsl:text> </xsl:text> |
|
376 <xsl:value-of select="@x"/> |
|
377 <xsl:text> </xsl:text> |
|
378 <xsl:value-of select="@y"/> |
|
379 <xsl:text> </xsl:text> |
|
380 <xsl:value-of select="@w"/> |
|
381 <xsl:text> </xsl:text> |
|
382 <xsl:value-of select="@h"/> |
|
383 <xsl:text> |
|
384 </xsl:text> |
|
385 </xsl:for-each> |
|
386 <xsl:text> |
|
387 </xsl:text> |
|
388 </xsl:template> |
|
389 <func:function name="func:intersect_1d"> |
|
390 <xsl:param name="a0"/> |
|
391 <xsl:param name="a1"/> |
|
392 <xsl:param name="b0"/> |
|
393 <xsl:param name="b1"/> |
|
394 <xsl:variable name="d0" select="$a0 >= $b0"/> |
|
395 <xsl:variable name="d1" select="$a1 >= $b1"/> |
|
396 <xsl:choose> |
|
397 <xsl:when test="not($d0) and $d1"> |
|
398 <func:result select="3"/> |
|
399 </xsl:when> |
|
400 <xsl:when test="$d0 and not($d1)"> |
|
401 <func:result select="2"/> |
|
402 </xsl:when> |
|
403 <xsl:when test="$d0 and $d1 and $a0 < $b1"> |
|
404 <func:result select="1"/> |
|
405 </xsl:when> |
|
406 <xsl:when test="not($d0) and not($d1) and $b0 < $a1"> |
|
407 <func:result select="1"/> |
|
408 </xsl:when> |
|
409 <xsl:otherwise> |
|
410 <func:result select="0"/> |
|
411 </xsl:otherwise> |
|
412 </xsl:choose> |
|
413 </func:function> |
|
414 <func:function name="func:intersect"> |
|
415 <xsl:param name="a"/> |
|
416 <xsl:param name="b"/> |
|
417 <xsl:variable name="x_intersect" select="func:intersect_1d($a/@x, $a/@x+$a/@w, $b/@x, $b/@x+$b/@w)"/> |
|
418 <xsl:choose> |
|
419 <xsl:when test="$x_intersect != 0"> |
|
420 <xsl:variable name="y_intersect" select="func:intersect_1d($a/@y, $a/@y+$a/@h, $b/@y, $b/@y+$b/@h)"/> |
|
421 <func:result select="$x_intersect * $y_intersect"/> |
|
422 </xsl:when> |
|
423 <xsl:otherwise> |
|
424 <func:result select="0"/> |
|
425 </xsl:otherwise> |
|
426 </xsl:choose> |
|
427 </func:function> |
|
428 <xsl:variable name="groups" select="/svg:svg | //svg:g"/> |
|
429 <func:function name="func:overlapping_geometry"> |
|
430 <xsl:param name="elt"/> |
|
431 <xsl:variable name="g" select="$geometry[@Id = $elt/@id]"/> |
|
432 <xsl:variable name="candidates" select="$geometry[@Id != $elt/@id]"/> |
|
433 <func:result select="$candidates[(@Id = $groups/@id and (func:intersect($g, .) = 9)) or (not(@Id = $groups/@id) and (func:intersect($g, .) > 0 ))]"/> |
|
434 </func:function> |
|
435 <xsl:variable name="hmi_pages_descs" select="$parsed_widgets/widget[@type = 'Page']"/> |
|
436 <xsl:variable name="hmi_pages" select="$hmi_elements[@id = $hmi_pages_descs/@id]"/> |
|
437 <xsl:variable name="default_page"> |
|
438 <xsl:choose> |
|
439 <xsl:when test="count($hmi_pages) > 1"> |
|
440 <xsl:choose> |
|
441 <xsl:when test="$hmi_pages_descs/arg[1]/@value = 'Home'"> |
|
442 <xsl:text>Home</xsl:text> |
|
443 </xsl:when> |
|
444 <xsl:otherwise> |
|
445 <xsl:message terminate="yes"> |
|
446 <xsl:text>No Home page defined!</xsl:text> |
|
447 </xsl:message> |
|
448 </xsl:otherwise> |
|
449 </xsl:choose> |
|
450 </xsl:when> |
|
451 <xsl:when test="count($hmi_pages) = 0"> |
|
452 <xsl:message terminate="yes"> |
|
453 <xsl:text>No page defined!</xsl:text> |
|
454 </xsl:message> |
|
455 </xsl:when> |
|
456 <xsl:otherwise> |
|
457 <xsl:value-of select="func:widget($hmi_pages/@id)/arg[1]/@value"/> |
|
458 </xsl:otherwise> |
|
459 </xsl:choose> |
|
460 </xsl:variable> |
|
461 <preamble:default-page/> |
|
462 <xsl:template match="preamble:default-page"> |
|
463 <xsl:text> |
|
464 </xsl:text> |
|
465 <xsl:text>/* </xsl:text> |
|
466 <xsl:value-of select="local-name()"/> |
|
467 <xsl:text> */ |
|
468 </xsl:text> |
|
469 <xsl:text> |
|
470 </xsl:text> |
|
471 <xsl:text> |
|
472 </xsl:text> |
|
473 <xsl:text>var default_page = "</xsl:text> |
|
474 <xsl:value-of select="$default_page"/> |
|
475 <xsl:text>"; |
|
476 </xsl:text> |
|
477 <xsl:text> |
|
478 </xsl:text> |
|
479 </xsl:template> |
|
480 <xsl:variable name="keypads_descs" select="$parsed_widgets/widget[@type = 'Keypad']"/> |
|
481 <xsl:variable name="keypads" select="$hmi_elements[@id = $keypads_descs/@id]"/> |
|
482 <func:function name="func:refered_elements"> |
|
483 <xsl:param name="elems"/> |
|
484 <xsl:variable name="descend" select="$elems/descendant-or-self::svg:*"/> |
|
485 <xsl:variable name="clones" select="$descend[self::svg:use]"/> |
|
486 <xsl:variable name="originals" select="//svg:*[concat('#',@id) = $clones/@xlink:href]"/> |
|
487 <xsl:choose> |
|
488 <xsl:when test="$originals"> |
|
489 <func:result select="$descend | func:refered_elements($originals)"/> |
|
490 </xsl:when> |
|
491 <xsl:otherwise> |
|
492 <func:result select="$descend"/> |
|
493 </xsl:otherwise> |
|
494 </xsl:choose> |
|
495 </func:function> |
|
496 <xsl:variable name="_overlapping_geometry"> |
|
497 <xsl:for-each select="$hmi_pages | $keypads"> |
|
498 <xsl:variable name="k" select="concat('overlapping:', @id)"/> |
|
499 <xsl:value-of select="ns:ProgressStart($k, concat('collecting membership of ', @inkscape:label))"/> |
|
500 <elt> |
|
501 <xsl:attribute name="id"> |
|
502 <xsl:value-of select="@id"/> |
|
503 </xsl:attribute> |
|
504 <xsl:copy-of select="func:overlapping_geometry(.)"/> |
|
505 </elt> |
|
506 <xsl:value-of select="ns:ProgressEnd($k)"/> |
|
507 </xsl:for-each> |
|
508 </xsl:variable> |
|
509 <xsl:variable name="overlapping_geometry" select="exsl:node-set($_overlapping_geometry)"/> |
|
510 <func:function name="func:all_related_elements"> |
|
511 <xsl:param name="page"/> |
|
512 <xsl:variable name="page_overlapping_geometry" select="$overlapping_geometry/elt[@id = $page/@id]/*"/> |
|
513 <xsl:variable name="page_overlapping_elements" select="//svg:*[@id = $page_overlapping_geometry/@Id]"/> |
|
514 <xsl:variable name="page_sub_elements" select="func:refered_elements($page | $page_overlapping_elements)"/> |
|
515 <func:result select="$page_sub_elements"/> |
|
516 </func:function> |
|
517 <func:function name="func:required_elements"> |
|
518 <xsl:param name="pages"/> |
|
519 <xsl:choose> |
|
520 <xsl:when test="$pages"> |
|
521 <func:result select="func:all_related_elements($pages[1]) | func:required_elements($pages[position()!=1])"/> |
|
522 </xsl:when> |
|
523 <xsl:otherwise> |
|
524 <func:result select="/.."/> |
|
525 </xsl:otherwise> |
|
526 </xsl:choose> |
|
527 </func:function> |
|
528 <xsl:variable name="required_page_elements" select="func:required_elements($hmi_pages | $keypads)/ancestor-or-self::svg:*"/> |
|
529 <xsl:variable name="hmi_lists_descs" select="$parsed_widgets/widget[@type = 'List']"/> |
|
530 <xsl:variable name="hmi_lists" select="$hmi_elements[@id = $hmi_lists_descs/@id]"/> |
|
531 <xsl:variable name="required_list_elements" select="func:refered_elements($hmi_lists[@id = $required_page_elements/@id])"/> |
|
532 <xsl:variable name="required_elements" select="$defs | $required_list_elements | $required_page_elements"/> |
|
533 <xsl:variable name="discardable_elements" select="//svg:*[not(@id = $required_elements/@id)]"/> |
|
534 <func:function name="func:sumarized_elements"> |
|
535 <xsl:param name="elements"/> |
|
536 <xsl:variable name="short_list" select="$elements[not(ancestor::*/@id = $elements/@id)]"/> |
|
537 <xsl:variable name="filled_groups" select="$short_list/parent::*[ not(child::*[ not(@id = $discardable_elements/@id) and not(@id = $short_list/@id) ])]"/> |
|
538 <xsl:variable name="groups_to_add" select="$filled_groups[not(ancestor::*/@id = $filled_groups/@id)]"/> |
|
539 <func:result select="$groups_to_add | $short_list[not(ancestor::*/@id = $filled_groups/@id)]"/> |
|
540 </func:function> |
|
541 <func:function name="func:detachable_elements"> |
|
542 <xsl:param name="pages"/> |
|
543 <xsl:choose> |
|
544 <xsl:when test="$pages"> |
|
545 <func:result select="func:sumarized_elements(func:all_related_elements($pages[1])) | func:detachable_elements($pages[position()!=1])"/> |
|
546 </xsl:when> |
|
547 <xsl:otherwise> |
|
548 <func:result select="/.."/> |
|
549 </xsl:otherwise> |
|
550 </xsl:choose> |
|
551 </func:function> |
|
552 <xsl:variable name="_detachable_elements" select="func:detachable_elements($hmi_pages | $keypads)"/> |
|
553 <xsl:variable name="detachable_elements" select="$_detachable_elements[not(ancestor::*/@id = $_detachable_elements/@id)]"/> |
|
554 <declarations:detachable-elements/> |
|
555 <xsl:template match="declarations:detachable-elements"> |
|
556 <xsl:text> |
|
557 </xsl:text> |
|
558 <xsl:text>/* </xsl:text> |
|
559 <xsl:value-of select="local-name()"/> |
|
560 <xsl:text> */ |
|
561 </xsl:text> |
|
562 <xsl:text> |
|
563 </xsl:text> |
|
564 <xsl:text> |
|
565 </xsl:text> |
|
566 <xsl:text>var detachable_elements = { |
|
567 </xsl:text> |
|
568 <xsl:for-each select="$detachable_elements"> |
|
569 <xsl:text> "</xsl:text> |
|
570 <xsl:value-of select="@id"/> |
|
571 <xsl:text>":[id("</xsl:text> |
|
572 <xsl:value-of select="@id"/> |
|
573 <xsl:text>"), id("</xsl:text> |
|
574 <xsl:value-of select="../@id"/> |
|
575 <xsl:text>")]</xsl:text> |
|
576 <xsl:if test="position()!=last()"> |
|
577 <xsl:text>,</xsl:text> |
|
578 </xsl:if> |
|
579 <xsl:text> |
|
580 </xsl:text> |
|
581 </xsl:for-each> |
|
582 <xsl:text>} |
|
583 </xsl:text> |
|
584 <xsl:text> |
|
585 </xsl:text> |
|
586 </xsl:template> |
|
587 <xsl:variable name="forEach_widgets_ids" select="$parsed_widgets/widget[@type = 'ForEach']/@id"/> |
|
588 <xsl:variable name="forEach_widgets" select="$hmi_widgets[@id = $forEach_widgets_ids]"/> |
|
589 <xsl:variable name="in_forEach_widget_ids" select="func:refered_elements($forEach_widgets)[not(@id = $forEach_widgets_ids)]/@id"/> |
|
590 <xsl:template mode="page_desc" match="svg:*"> |
|
591 <xsl:if test="ancestor::*[@id = $hmi_pages/@id]"> |
|
592 <xsl:message terminate="yes"> |
|
593 <xsl:text>HMI:Page </xsl:text> |
|
594 <xsl:value-of select="@id"/> |
|
595 <xsl:text> is nested in another HMI:Page</xsl:text> |
|
596 </xsl:message> |
|
597 </xsl:if> |
|
598 <xsl:variable name="desc" select="func:widget(@id)"/> |
|
599 <xsl:variable name="pagename" select="$desc/arg[1]/@value"/> |
|
600 <xsl:variable name="msg" select="concat('generating page description ', $pagename)"/> |
|
601 <xsl:value-of select="ns:ProgressStart($pagename, $msg)"/> |
|
602 <xsl:variable name="page" select="."/> |
|
603 <xsl:variable name="p" select="$geometry[@Id = $page/@id]"/> |
|
604 <xsl:variable name="page_all_elements" select="func:all_related_elements($page)"/> |
|
605 <xsl:variable name="all_page_widgets" select="$hmi_widgets[@id = $page_all_elements/@id and @id != $page/@id]"/> |
|
606 <xsl:variable name="page_managed_widgets" select="$all_page_widgets[not(@id=$in_forEach_widget_ids)]"/> |
|
607 <xsl:variable name="page_relative_widgets" select="$page_managed_widgets[func:is_descendant_path(func:widget(@id)/path/@value, $desc/path/@value)]"/> |
|
608 <xsl:variable name="sumarized_page" select="func:sumarized_elements($page_all_elements)"/> |
|
609 <xsl:variable name="required_detachables" select="$sumarized_page/ ancestor-or-self::*[@id = $detachable_elements/@id]"/> |
|
610 <xsl:text> "</xsl:text> |
|
611 <xsl:value-of select="$pagename"/> |
|
612 <xsl:text>": { |
|
613 </xsl:text> |
|
614 <xsl:text> bbox: [</xsl:text> |
|
615 <xsl:value-of select="$p/@x"/> |
|
616 <xsl:text>, </xsl:text> |
|
617 <xsl:value-of select="$p/@y"/> |
|
618 <xsl:text>, </xsl:text> |
|
619 <xsl:value-of select="$p/@w"/> |
|
620 <xsl:text>, </xsl:text> |
|
621 <xsl:value-of select="$p/@h"/> |
|
622 <xsl:text>], |
|
623 </xsl:text> |
|
624 <xsl:if test="$desc/path/@value"> |
|
625 <xsl:if test="count($desc/path/@index)=0"> |
|
626 <xsl:message terminate="no"> |
|
627 <xsl:text>Page id="</xsl:text> |
|
628 <xsl:value-of select="$page/@id"/> |
|
629 <xsl:text>" : No match for path "</xsl:text> |
|
630 <xsl:value-of select="$desc/path/@value"/> |
|
631 <xsl:text>" in HMI tree</xsl:text> |
|
632 </xsl:message> |
|
633 </xsl:if> |
|
634 <xsl:text> page_index: </xsl:text> |
|
635 <xsl:value-of select="$desc/path/@index"/> |
|
636 <xsl:text>, |
|
637 </xsl:text> |
|
638 </xsl:if> |
|
639 <xsl:text> widgets: [ |
|
640 </xsl:text> |
|
641 <xsl:for-each select="$page_managed_widgets"> |
|
642 <xsl:variable name="widget_paths_relativeness"> |
|
643 <xsl:for-each select="func:widget(@id)/path"> |
|
644 <xsl:value-of select="func:is_descendant_path(@value, $desc/path/@value)"/> |
|
645 <xsl:if test="position()!=last()"> |
|
646 <xsl:text>,</xsl:text> |
|
647 </xsl:if> |
|
648 </xsl:for-each> |
|
649 </xsl:variable> |
|
650 <xsl:text> [hmi_widgets["</xsl:text> |
|
651 <xsl:value-of select="@id"/> |
|
652 <xsl:text>"], [</xsl:text> |
|
653 <xsl:value-of select="$widget_paths_relativeness"/> |
|
654 <xsl:text>]]</xsl:text> |
|
655 <xsl:if test="position()!=last()"> |
|
656 <xsl:text>,</xsl:text> |
|
657 </xsl:if> |
|
658 <xsl:text> |
|
659 </xsl:text> |
|
660 </xsl:for-each> |
|
661 <xsl:text> ], |
|
662 </xsl:text> |
|
663 <xsl:text> jumps: [ |
|
664 </xsl:text> |
|
665 <xsl:for-each select="$parsed_widgets/widget[@id = $all_page_widgets/@id and @type='Jump']"> |
|
666 <xsl:text> hmi_widgets["</xsl:text> |
|
667 <xsl:value-of select="@id"/> |
|
668 <xsl:text>"]</xsl:text> |
|
669 <xsl:if test="position()!=last()"> |
|
670 <xsl:text>,</xsl:text> |
|
671 </xsl:if> |
|
672 <xsl:text> |
|
673 </xsl:text> |
|
674 </xsl:for-each> |
|
675 <xsl:text> ], |
|
676 </xsl:text> |
|
677 <xsl:text> required_detachables: { |
|
678 </xsl:text> |
|
679 <xsl:for-each select="$required_detachables"> |
|
680 <xsl:text> "</xsl:text> |
|
681 <xsl:value-of select="@id"/> |
|
682 <xsl:text>": detachable_elements["</xsl:text> |
|
683 <xsl:value-of select="@id"/> |
|
684 <xsl:text>"]</xsl:text> |
|
685 <xsl:if test="position()!=last()"> |
|
686 <xsl:text>,</xsl:text> |
|
687 </xsl:if> |
|
688 <xsl:text> |
|
689 </xsl:text> |
|
690 </xsl:for-each> |
|
691 <xsl:text> } |
|
692 </xsl:text> |
|
693 <xsl:apply-templates mode="widget_page" select="$parsed_widgets/widget[@id = $all_page_widgets/@id]"> |
|
694 <xsl:with-param name="page_desc" select="$desc"/> |
|
695 </xsl:apply-templates> |
|
696 <xsl:text> }</xsl:text> |
|
697 <xsl:if test="position()!=last()"> |
|
698 <xsl:text>,</xsl:text> |
|
699 </xsl:if> |
|
700 <xsl:text> |
|
701 </xsl:text> |
|
702 <xsl:value-of select="ns:ProgressEnd($pagename)"/> |
|
703 </xsl:template> |
|
704 <definitions:page-desc/> |
|
705 <xsl:template match="definitions:page-desc"> |
|
706 <xsl:text> |
|
707 </xsl:text> |
|
708 <xsl:text>/* </xsl:text> |
|
709 <xsl:value-of select="local-name()"/> |
|
710 <xsl:text> */ |
|
711 </xsl:text> |
|
712 <xsl:text> |
|
713 </xsl:text> |
|
714 <xsl:text> |
|
715 </xsl:text> |
|
716 <xsl:text>var page_desc = { |
|
717 </xsl:text> |
|
718 <xsl:apply-templates mode="page_desc" select="$hmi_pages"/> |
|
719 <xsl:text>} |
|
720 </xsl:text> |
|
721 <xsl:text> |
|
722 </xsl:text> |
|
723 </xsl:template> |
|
724 <xsl:template mode="widget_page" match="*"/> |
|
725 <debug:detachable-pages/> |
|
726 <xsl:template match="debug:detachable-pages"> |
|
727 <xsl:text> |
|
728 </xsl:text> |
|
729 <xsl:text>/* </xsl:text> |
|
730 <xsl:value-of select="local-name()"/> |
|
731 <xsl:text> */ |
|
732 </xsl:text> |
|
733 <xsl:text> |
|
734 </xsl:text> |
|
735 <xsl:text> |
|
736 </xsl:text> |
|
737 <xsl:text>DETACHABLES: |
|
738 </xsl:text> |
|
739 <xsl:for-each select="$detachable_elements"> |
|
740 <xsl:text> </xsl:text> |
|
741 <xsl:value-of select="@id"/> |
|
742 <xsl:text> |
|
743 </xsl:text> |
|
744 </xsl:for-each> |
|
745 <xsl:text>In Foreach: |
|
746 </xsl:text> |
|
747 <xsl:for-each select="$in_forEach_widget_ids"> |
|
748 <xsl:text> </xsl:text> |
|
749 <xsl:value-of select="."/> |
|
750 <xsl:text> |
|
751 </xsl:text> |
|
752 </xsl:for-each> |
|
753 <xsl:text>Overlapping |
|
754 </xsl:text> |
|
755 <xsl:apply-templates mode="testtree" select="$overlapping_geometry"/> |
|
756 <xsl:text> |
|
757 </xsl:text> |
|
758 </xsl:template> |
|
759 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="inline_svg" match="@*"> |
|
760 <xsl:copy/> |
|
761 </xsl:template> |
|
762 <xsl:template mode="inline_svg" match="node()"> |
|
763 <xsl:if test="not(@id = $discardable_elements/@id)"> |
|
764 <xsl:copy> |
|
765 <xsl:apply-templates mode="inline_svg" select="@* | node()"/> |
|
766 </xsl:copy> |
|
767 </xsl:if> |
|
768 </xsl:template> |
|
769 <xsl:template mode="inline_svg" match="svg:svg/@width"/> |
|
770 <xsl:template mode="inline_svg" match="svg:svg/@height"/> |
|
771 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="inline_svg" match="svg:svg"> |
|
772 <svg> |
|
773 <xsl:attribute name="preserveAspectRatio"> |
|
774 <xsl:text>none</xsl:text> |
|
775 </xsl:attribute> |
|
776 <xsl:attribute name="height"> |
|
777 <xsl:text>100vh</xsl:text> |
|
778 </xsl:attribute> |
|
779 <xsl:attribute name="width"> |
|
780 <xsl:text>100vw</xsl:text> |
|
781 </xsl:attribute> |
|
782 <xsl:apply-templates mode="inline_svg" select="@* | node()"/> |
|
783 </svg> |
|
784 </xsl:template> |
|
785 <xsl:template mode="inline_svg" match="svg:svg[@viewBox!=concat('0 0 ', @width, ' ', @height)]"> |
|
786 <xsl:message terminate="yes"> |
|
787 <xsl:text>ViewBox settings other than X=0, Y=0 and Scale=1 are not supported</xsl:text> |
|
788 </xsl:message> |
|
789 </xsl:template> |
|
790 <xsl:template mode="inline_svg" match="sodipodi:namedview[@units!='px' or @inkscape:document-units!='px']"> |
|
791 <xsl:message terminate="yes"> |
|
792 <xsl:text>All units must be set to "px" in Inkscape's document properties</xsl:text> |
|
793 </xsl:message> |
|
794 </xsl:template> |
|
795 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="inline_svg" match="svg:text/@inkscape:label[starts-with(., '_')]"> |
|
796 <xsl:attribute name="{name()}"> |
|
797 <xsl:value-of select="substring(., 2)"/> |
|
798 </xsl:attribute> |
|
799 </xsl:template> |
|
800 <xsl:variable name="targets_not_to_unlink" select="$hmi_lists/descendant-or-self::svg:*"/> |
|
801 <xsl:variable name="to_unlink" select="$hmi_elements[not(@id = $hmi_pages/@id)]/descendant-or-self::svg:use"/> |
|
802 <func:function name="func:is_unlinkable"> |
|
803 <xsl:param name="targetid"/> |
|
804 <xsl:param name="eltid"/> |
|
805 <func:result select="$eltid = $to_unlink/@id and not($targetid = $targets_not_to_unlink/@id)"/> |
|
806 </func:function> |
|
807 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="inline_svg" match="svg:use"> |
|
808 <xsl:variable name="targetid" select="substring-after(@xlink:href,'#')"/> |
|
809 <xsl:choose> |
|
810 <xsl:when test="func:is_unlinkable($targetid, @id)"> |
|
811 <xsl:call-template name="unlink_clone"> |
|
812 <xsl:with-param name="targetid" select="$targetid"/> |
|
813 </xsl:call-template> |
|
814 </xsl:when> |
|
815 <xsl:otherwise> |
|
816 <xsl:copy> |
|
817 <xsl:apply-templates mode="inline_svg" select="@*"/> |
|
818 </xsl:copy> |
|
819 </xsl:otherwise> |
|
820 </xsl:choose> |
|
821 </xsl:template> |
|
822 <xsl:variable name="_excluded_use_attrs"> |
|
823 <name> |
|
824 <xsl:text>href</xsl:text> |
|
825 </name> |
|
826 <name> |
|
827 <xsl:text>width</xsl:text> |
|
828 </name> |
|
829 <name> |
|
830 <xsl:text>height</xsl:text> |
|
831 </name> |
|
832 <name> |
|
833 <xsl:text>x</xsl:text> |
|
834 </name> |
|
835 <name> |
|
836 <xsl:text>y</xsl:text> |
|
837 </name> |
|
838 <name> |
|
839 <xsl:text>id</xsl:text> |
|
840 </name> |
|
841 </xsl:variable> |
|
842 <xsl:variable name="excluded_use_attrs" select="exsl:node-set($_excluded_use_attrs)"/> |
|
843 <xsl:variable name="_merge_use_attrs"> |
|
844 <name> |
|
845 <xsl:text>transform</xsl:text> |
|
846 </name> |
|
847 <name> |
|
848 <xsl:text>style</xsl:text> |
|
849 </name> |
|
850 </xsl:variable> |
|
851 <xsl:variable name="merge_use_attrs" select="exsl:node-set($_merge_use_attrs)"/> |
|
852 <xsl:template xmlns="http://www.w3.org/2000/svg" name="unlink_clone"> |
|
853 <xsl:param name="targetid"/> |
|
854 <xsl:param name="seed" select="''"/> |
|
855 <xsl:variable name="target" select="//svg:*[@id = $targetid]"/> |
|
856 <xsl:variable name="seeded_id"> |
|
857 <xsl:choose> |
|
858 <xsl:when test="string-length($seed) > 0"> |
|
859 <xsl:value-of select="$seed"/> |
|
860 <xsl:text>_</xsl:text> |
|
861 <xsl:value-of select="@id"/> |
|
862 </xsl:when> |
|
863 <xsl:otherwise> |
|
864 <xsl:value-of select="@id"/> |
|
865 </xsl:otherwise> |
|
866 </xsl:choose> |
|
867 </xsl:variable> |
|
868 <g> |
|
869 <xsl:attribute name="id"> |
|
870 <xsl:value-of select="$seeded_id"/> |
|
871 </xsl:attribute> |
|
872 <xsl:attribute name="original"> |
|
873 <xsl:value-of select="@id"/> |
|
874 </xsl:attribute> |
|
875 <xsl:choose> |
|
876 <xsl:when test="$target[self::svg:g]"> |
|
877 <xsl:for-each select="@*[not(local-name() = $excluded_use_attrs/name | $merge_use_attrs)]"> |
|
878 <xsl:attribute name="{name()}"> |
|
879 <xsl:value-of select="."/> |
|
880 </xsl:attribute> |
|
881 </xsl:for-each> |
|
882 <xsl:if test="@style | $target/@style"> |
|
883 <xsl:attribute name="style"> |
|
884 <xsl:value-of select="@style"/> |
|
885 <xsl:if test="@style and $target/@style"> |
|
886 <xsl:text>;</xsl:text> |
|
887 </xsl:if> |
|
888 <xsl:value-of select="$target/@style"/> |
|
889 </xsl:attribute> |
|
890 </xsl:if> |
|
891 <xsl:if test="@transform | $target/@transform"> |
|
892 <xsl:attribute name="transform"> |
|
893 <xsl:value-of select="@transform"/> |
|
894 <xsl:if test="@transform and $target/@transform"> |
|
895 <xsl:text> </xsl:text> |
|
896 </xsl:if> |
|
897 <xsl:value-of select="$target/@transform"/> |
|
898 </xsl:attribute> |
|
899 </xsl:if> |
|
900 <xsl:apply-templates mode="unlink_clone" select="$target/*"> |
|
901 <xsl:with-param name="seed" select="$seeded_id"/> |
|
902 </xsl:apply-templates> |
|
903 </xsl:when> |
|
904 <xsl:otherwise> |
|
905 <xsl:for-each select="@*[not(local-name() = $excluded_use_attrs/name)]"> |
|
906 <xsl:attribute name="{name()}"> |
|
907 <xsl:value-of select="."/> |
|
908 </xsl:attribute> |
|
909 </xsl:for-each> |
|
910 <xsl:apply-templates mode="unlink_clone" select="$target"> |
|
911 <xsl:with-param name="seed" select="$seeded_id"/> |
|
912 </xsl:apply-templates> |
|
913 </xsl:otherwise> |
|
914 </xsl:choose> |
|
915 </g> |
|
916 </xsl:template> |
|
917 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="@id"> |
|
918 <xsl:param name="seed"/> |
|
919 <xsl:attribute name="id"> |
|
920 <xsl:value-of select="$seed"/> |
|
921 <xsl:text>_</xsl:text> |
|
922 <xsl:value-of select="."/> |
|
923 </xsl:attribute> |
|
924 <xsl:attribute name="original"> |
|
925 <xsl:value-of select="."/> |
|
926 </xsl:attribute> |
|
927 </xsl:template> |
|
928 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="@*"> |
|
929 <xsl:copy/> |
|
930 </xsl:template> |
|
931 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="svg:use"> |
|
932 <xsl:param name="seed"/> |
|
933 <xsl:variable name="targetid" select="substring-after(@xlink:href,'#')"/> |
|
934 <xsl:choose> |
|
935 <xsl:when test="func:is_unlinkable($targetid, @id)"> |
|
936 <xsl:call-template name="unlink_clone"> |
|
937 <xsl:with-param name="targetid" select="$targetid"/> |
|
938 <xsl:with-param name="seed" select="$seed"/> |
|
939 </xsl:call-template> |
|
940 </xsl:when> |
|
941 <xsl:otherwise> |
|
942 <xsl:copy> |
|
943 <xsl:apply-templates mode="unlink_clone" select="@*"> |
|
944 <xsl:with-param name="seed" select="$seed"/> |
|
945 </xsl:apply-templates> |
|
946 </xsl:copy> |
|
947 </xsl:otherwise> |
|
948 </xsl:choose> |
|
949 </xsl:template> |
|
950 <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="svg:*"> |
|
951 <xsl:param name="seed"/> |
|
952 <xsl:choose> |
|
953 <xsl:when test="@id = $hmi_elements/@id"> |
|
954 <use> |
|
955 <xsl:attribute name="xlink:href"> |
|
956 <xsl:value-of select="concat('#',@id)"/> |
|
957 </xsl:attribute> |
|
958 </use> |
|
959 </xsl:when> |
|
960 <xsl:otherwise> |
|
961 <xsl:copy> |
|
962 <xsl:apply-templates mode="unlink_clone" select="@* | node()"> |
|
963 <xsl:with-param name="seed" select="$seed"/> |
|
964 </xsl:apply-templates> |
|
965 </xsl:copy> |
|
966 </xsl:otherwise> |
|
967 </xsl:choose> |
|
968 </xsl:template> |
|
969 <xsl:variable name="result_svg"> |
|
970 <xsl:apply-templates mode="inline_svg" select="/"/> |
|
971 </xsl:variable> |
|
972 <xsl:variable name="result_svg_ns" select="exsl:node-set($result_svg)"/> |
|
973 <preamble:inline-svg/> |
|
974 <xsl:template match="preamble:inline-svg"> |
|
975 <xsl:text> |
|
976 </xsl:text> |
|
977 <xsl:text>/* </xsl:text> |
|
978 <xsl:value-of select="local-name()"/> |
|
979 <xsl:text> */ |
|
980 </xsl:text> |
|
981 <xsl:text> |
|
982 </xsl:text> |
|
983 <xsl:text>let id = document.getElementById.bind(document); |
|
984 </xsl:text> |
|
985 <xsl:text>var svg_root = id("</xsl:text> |
|
986 <xsl:value-of select="$svg/@id"/> |
|
987 <xsl:text>"); |
|
988 </xsl:text> |
|
989 <xsl:text> |
|
990 </xsl:text> |
|
991 </xsl:template> |
|
992 <debug:clone-unlinking/> |
|
993 <xsl:template match="debug:clone-unlinking"> |
|
994 <xsl:text> |
|
995 </xsl:text> |
|
996 <xsl:text>/* </xsl:text> |
|
997 <xsl:value-of select="local-name()"/> |
|
998 <xsl:text> */ |
|
999 </xsl:text> |
|
1000 <xsl:text> |
|
1001 </xsl:text> |
|
1002 <xsl:text> |
|
1003 </xsl:text> |
|
1004 <xsl:text>Unlinked : |
|
1005 </xsl:text> |
|
1006 <xsl:for-each select="$to_unlink"> |
|
1007 <xsl:value-of select="@id"/> |
|
1008 <xsl:text> |
|
1009 </xsl:text> |
|
1010 </xsl:for-each> |
|
1011 <xsl:text>Not to unlink : |
|
1012 </xsl:text> |
|
1013 <xsl:for-each select="$targets_not_to_unlink"> |
|
1014 <xsl:value-of select="@id"/> |
|
1015 <xsl:text> |
|
1016 </xsl:text> |
|
1017 </xsl:for-each> |
|
1018 <xsl:text> |
|
1019 </xsl:text> |
|
1020 </xsl:template> |
|
1021 <xsl:template mode="extract_i18n" match="svg:tspan"> |
|
1022 <xsl:if test="string-length(.) > 0"> |
|
1023 <line> |
|
1024 <xsl:value-of select="."/> |
|
1025 </line> |
|
1026 </xsl:if> |
|
1027 </xsl:template> |
|
1028 <xsl:template mode="extract_i18n" match="svg:text"> |
|
1029 <msg> |
|
1030 <xsl:attribute name="id"> |
|
1031 <xsl:value-of select="@id"/> |
|
1032 </xsl:attribute> |
|
1033 <xsl:attribute name="label"> |
|
1034 <xsl:value-of select="substring(@inkscape:label,2)"/> |
|
1035 </xsl:attribute> |
|
1036 <xsl:apply-templates mode="extract_i18n" select="svg:*"/> |
|
1037 </msg> |
|
1038 </xsl:template> |
|
1039 <xsl:variable name="translatable_texts" select="//svg:text[starts-with(@inkscape:label, '_')]"/> |
|
1040 <xsl:variable name="translatable_strings"> |
|
1041 <xsl:apply-templates mode="extract_i18n" select="$translatable_texts"/> |
|
1042 </xsl:variable> |
|
1043 <preamble:i18n/> |
|
1044 <xsl:template match="preamble:i18n"> |
|
1045 <xsl:text> |
|
1046 </xsl:text> |
|
1047 <xsl:text>/* </xsl:text> |
|
1048 <xsl:value-of select="local-name()"/> |
|
1049 <xsl:text> */ |
|
1050 </xsl:text> |
|
1051 <xsl:text> |
|
1052 </xsl:text> |
|
1053 <xsl:variable name="translations" select="ns:GetTranslations($translatable_strings)"/> |
|
1054 <xsl:text>var langs = [ ["Default", "C"],</xsl:text> |
|
1055 <xsl:for-each select="$translations/langs/lang"> |
|
1056 <xsl:text>["</xsl:text> |
|
1057 <xsl:value-of select="."/> |
|
1058 <xsl:text>","</xsl:text> |
|
1059 <xsl:value-of select="@code"/> |
|
1060 <xsl:text>"]</xsl:text> |
|
1061 <xsl:if test="position()!=last()"> |
|
1062 <xsl:text>,</xsl:text> |
|
1063 </xsl:if> |
|
1064 </xsl:for-each> |
|
1065 <xsl:text>]; |
|
1066 </xsl:text> |
|
1067 <xsl:text>var translations = [ |
|
1068 </xsl:text> |
|
1069 <xsl:for-each select="$translatable_texts"> |
|
1070 <xsl:variable name="n" select="position()"/> |
|
1071 <xsl:variable name="current_id" select="@id"/> |
|
1072 <xsl:variable name="text_unlinked_uses" select="$result_svg_ns//svg:text[@original = $current_id]/@id"/> |
|
1073 <xsl:text> [[</xsl:text> |
|
1074 <xsl:for-each select="@id | $text_unlinked_uses"> |
|
1075 <xsl:text>id("</xsl:text> |
|
1076 <xsl:value-of select="."/> |
|
1077 <xsl:text>")</xsl:text> |
|
1078 <xsl:if test="position()!=last()"> |
|
1079 <xsl:text>,</xsl:text> |
|
1080 </xsl:if> |
|
1081 </xsl:for-each> |
|
1082 <xsl:text>],[</xsl:text> |
|
1083 <xsl:for-each select="$translations/messages/msgid[$n]/msg"> |
|
1084 <xsl:text>"</xsl:text> |
|
1085 <xsl:for-each select="line"> |
|
1086 <xsl:value-of select="."/> |
|
1087 <xsl:if test="position()!=last()"> |
|
1088 <xsl:text>\n</xsl:text> |
|
1089 </xsl:if> |
|
1090 </xsl:for-each> |
|
1091 <xsl:text>"</xsl:text> |
|
1092 <xsl:if test="position()!=last()"> |
|
1093 <xsl:text>,</xsl:text> |
|
1094 </xsl:if> |
|
1095 </xsl:for-each> |
|
1096 <xsl:text>]]</xsl:text> |
|
1097 <xsl:if test="position()!=last()"> |
|
1098 <xsl:text>,</xsl:text> |
|
1099 </xsl:if> |
|
1100 <xsl:text> |
|
1101 </xsl:text> |
|
1102 </xsl:for-each> |
|
1103 <xsl:text>] |
|
1104 </xsl:text> |
|
1105 <xsl:text> |
|
1106 </xsl:text> |
|
1107 </xsl:template> |
|
1108 <xsl:template mode="hmi_widgets" match="svg:*"> |
|
1109 <xsl:variable name="widget" select="func:widget(@id)"/> |
|
1110 <xsl:variable name="eltid" select="@id"/> |
|
1111 <xsl:variable name="args"> |
|
1112 <xsl:for-each select="$widget/arg"> |
|
1113 <xsl:text>"</xsl:text> |
|
1114 <xsl:value-of select="func:escape_quotes(@value)"/> |
|
1115 <xsl:text>"</xsl:text> |
|
1116 <xsl:if test="position()!=last()"> |
|
1117 <xsl:text>,</xsl:text> |
|
1118 </xsl:if> |
|
1119 </xsl:for-each> |
|
1120 </xsl:variable> |
|
1121 <xsl:variable name="indexes"> |
|
1122 <xsl:for-each select="$widget/path"> |
|
1123 <xsl:choose> |
|
1124 <xsl:when test="not(@index)"> |
|
1125 <xsl:choose> |
|
1126 <xsl:when test="not(@type)"> |
|
1127 <xsl:message terminate="no"> |
|
1128 <xsl:text>Widget </xsl:text> |
|
1129 <xsl:value-of select="$widget/@type"/> |
|
1130 <xsl:text> id="</xsl:text> |
|
1131 <xsl:value-of select="$eltid"/> |
|
1132 <xsl:text>" : No match for path "</xsl:text> |
|
1133 <xsl:value-of select="@value"/> |
|
1134 <xsl:text>" in HMI tree</xsl:text> |
|
1135 </xsl:message> |
|
1136 <xsl:text>undefined</xsl:text> |
|
1137 </xsl:when> |
|
1138 <xsl:when test="@type = 'PAGE_LOCAL'"> |
|
1139 <xsl:text>"</xsl:text> |
|
1140 <xsl:value-of select="@value"/> |
|
1141 <xsl:text>"</xsl:text> |
|
1142 </xsl:when> |
|
1143 <xsl:when test="@type = 'HMI_LOCAL'"> |
|
1144 <xsl:text>hmi_local_index("</xsl:text> |
|
1145 <xsl:value-of select="@value"/> |
|
1146 <xsl:text>")</xsl:text> |
|
1147 </xsl:when> |
|
1148 <xsl:otherwise> |
|
1149 <xsl:message terminate="yes"> |
|
1150 <xsl:text>Internal error while processing widget's non indexed HMI tree path : unknown type</xsl:text> |
|
1151 </xsl:message> |
|
1152 </xsl:otherwise> |
|
1153 </xsl:choose> |
|
1154 </xsl:when> |
|
1155 <xsl:otherwise> |
|
1156 <xsl:value-of select="@index"/> |
|
1157 </xsl:otherwise> |
|
1158 </xsl:choose> |
|
1159 <xsl:if test="position()!=last()"> |
|
1160 <xsl:text>,</xsl:text> |
|
1161 </xsl:if> |
|
1162 </xsl:for-each> |
|
1163 </xsl:variable> |
|
1164 <xsl:variable name="minmaxes"> |
|
1165 <xsl:for-each select="$widget/path"> |
|
1166 <xsl:choose> |
|
1167 <xsl:when test="@min and @max"> |
|
1168 <xsl:text>[</xsl:text> |
|
1169 <xsl:value-of select="@min"/> |
|
1170 <xsl:text>,</xsl:text> |
|
1171 <xsl:value-of select="@max"/> |
|
1172 <xsl:text>]</xsl:text> |
|
1173 </xsl:when> |
|
1174 <xsl:otherwise> |
|
1175 <xsl:text>undefined</xsl:text> |
|
1176 </xsl:otherwise> |
|
1177 </xsl:choose> |
|
1178 <xsl:if test="position()!=last()"> |
|
1179 <xsl:text>,</xsl:text> |
|
1180 </xsl:if> |
|
1181 </xsl:for-each> |
|
1182 </xsl:variable> |
|
1183 <xsl:text> "</xsl:text> |
|
1184 <xsl:value-of select="@id"/> |
|
1185 <xsl:text>": new </xsl:text> |
|
1186 <xsl:value-of select="$widget/@type"/> |
|
1187 <xsl:text>Widget ("</xsl:text> |
|
1188 <xsl:value-of select="@id"/> |
|
1189 <xsl:text>",[</xsl:text> |
|
1190 <xsl:value-of select="$args"/> |
|
1191 <xsl:text>],[</xsl:text> |
|
1192 <xsl:value-of select="$indexes"/> |
|
1193 <xsl:text>],[</xsl:text> |
|
1194 <xsl:value-of select="$minmaxes"/> |
|
1195 <xsl:text>],{ |
|
1196 </xsl:text> |
|
1197 <xsl:apply-templates mode="widget_defs" select="$widget"> |
|
1198 <xsl:with-param name="hmi_element" select="."/> |
|
1199 </xsl:apply-templates> |
|
1200 <xsl:text> })</xsl:text> |
|
1201 <xsl:if test="position()!=last()"> |
|
1202 <xsl:text>,</xsl:text> |
|
1203 </xsl:if> |
|
1204 <xsl:text> |
|
1205 </xsl:text> |
|
1206 </xsl:template> |
|
1207 <preamble:local-variable-indexes/> |
|
1208 <xsl:template match="preamble:local-variable-indexes"> |
|
1209 <xsl:text> |
|
1210 </xsl:text> |
|
1211 <xsl:text>/* </xsl:text> |
|
1212 <xsl:value-of select="local-name()"/> |
|
1213 <xsl:text> */ |
|
1214 </xsl:text> |
|
1215 <xsl:text> |
|
1216 </xsl:text> |
|
1217 <xsl:text> |
|
1218 </xsl:text> |
|
1219 <xsl:text>let hmi_locals = {}; |
|
1220 </xsl:text> |
|
1221 <xsl:text>var last_remote_index = hmitree_types.length - 1; |
|
1222 </xsl:text> |
|
1223 <xsl:text>var next_available_index = hmitree_types.length; |
|
1224 </xsl:text> |
|
1225 <xsl:text>let cookies = new Map(document.cookie.split("; ").map(s=>s.split("="))); |
|
1226 </xsl:text> |
|
1227 <xsl:text> |
|
1228 </xsl:text> |
|
1229 <xsl:text>const local_defaults = { |
|
1230 </xsl:text> |
|
1231 <xsl:for-each select="$parsed_widgets/widget[starts-with(@type,'VarInit')]"> |
|
1232 <xsl:if test="count(path) != 1"> |
|
1233 <xsl:message terminate="yes"> |
|
1234 <xsl:text>VarInit </xsl:text> |
|
1235 <xsl:value-of select="@id"/> |
|
1236 <xsl:text> must have only one variable given.</xsl:text> |
|
1237 </xsl:message> |
|
1238 </xsl:if> |
|
1239 <xsl:if test="path/@type != 'PAGE_LOCAL' and path/@type != 'HMI_LOCAL'"> |
|
1240 <xsl:message terminate="yes"> |
|
1241 <xsl:text>VarInit </xsl:text> |
|
1242 <xsl:value-of select="@id"/> |
|
1243 <xsl:text> only applies to HMI variable.</xsl:text> |
|
1244 </xsl:message> |
|
1245 </xsl:if> |
|
1246 <xsl:text> "</xsl:text> |
|
1247 <xsl:value-of select="path/@value"/> |
|
1248 <xsl:text>":</xsl:text> |
|
1249 <xsl:choose> |
|
1250 <xsl:when test="@type = 'VarInitPersistent'"> |
|
1251 <xsl:text>cookies.has("</xsl:text> |
|
1252 <xsl:value-of select="path/@value"/> |
|
1253 <xsl:text>")?cookies.get("</xsl:text> |
|
1254 <xsl:value-of select="path/@value"/> |
|
1255 <xsl:text>"):</xsl:text> |
|
1256 <xsl:value-of select="arg[1]/@value"/> |
|
1257 </xsl:when> |
|
1258 <xsl:otherwise> |
|
1259 <xsl:value-of select="arg[1]/@value"/> |
|
1260 </xsl:otherwise> |
|
1261 </xsl:choose> |
|
1262 <xsl:text> |
|
1263 </xsl:text> |
|
1264 <xsl:if test="position()!=last()"> |
|
1265 <xsl:text>,</xsl:text> |
|
1266 </xsl:if> |
|
1267 </xsl:for-each> |
|
1268 <xsl:text>}; |
|
1269 </xsl:text> |
|
1270 <xsl:text> |
|
1271 </xsl:text> |
|
1272 <xsl:text>const persistent_locals = new Set([ |
|
1273 </xsl:text> |
|
1274 <xsl:for-each select="$parsed_widgets/widget[@type='VarInitPersistent']"> |
|
1275 <xsl:text> "</xsl:text> |
|
1276 <xsl:value-of select="path/@value"/> |
|
1277 <xsl:text>"</xsl:text> |
|
1278 <xsl:if test="position()!=last()"> |
|
1279 <xsl:text>,</xsl:text> |
|
1280 </xsl:if> |
|
1281 <xsl:text> |
|
1282 </xsl:text> |
|
1283 </xsl:for-each> |
|
1284 <xsl:text>]); |
|
1285 </xsl:text> |
|
1286 <xsl:text>var persistent_indexes = new Map(); |
|
1287 </xsl:text> |
|
1288 <xsl:text>var cache = hmitree_types.map(_ignored => undefined); |
|
1289 </xsl:text> |
|
1290 <xsl:text>var updates = new Map(); |
|
1291 </xsl:text> |
|
1292 <xsl:text> |
|
1293 </xsl:text> |
|
1294 <xsl:text>function page_local_index(varname, pagename){ |
|
1295 </xsl:text> |
|
1296 <xsl:text> let pagevars = hmi_locals[pagename]; |
|
1297 </xsl:text> |
|
1298 <xsl:text> let new_index; |
|
1299 </xsl:text> |
|
1300 <xsl:text> if(pagevars == undefined){ |
|
1301 </xsl:text> |
|
1302 <xsl:text> new_index = next_available_index++; |
|
1303 </xsl:text> |
|
1304 <xsl:text> hmi_locals[pagename] = {[varname]:new_index} |
|
1305 </xsl:text> |
|
1306 <xsl:text> } else { |
|
1307 </xsl:text> |
|
1308 <xsl:text> let result = pagevars[varname]; |
|
1309 </xsl:text> |
|
1310 <xsl:text> if(result != undefined) { |
|
1311 </xsl:text> |
|
1312 <xsl:text> return result; |
|
1313 </xsl:text> |
|
1314 <xsl:text> } |
|
1315 </xsl:text> |
|
1316 <xsl:text> |
|
1317 </xsl:text> |
|
1318 <xsl:text> new_index = next_available_index++; |
|
1319 </xsl:text> |
|
1320 <xsl:text> pagevars[varname] = new_index; |
|
1321 </xsl:text> |
|
1322 <xsl:text> } |
|
1323 </xsl:text> |
|
1324 <xsl:text> let defaultval = local_defaults[varname]; |
|
1325 </xsl:text> |
|
1326 <xsl:text> if(defaultval != undefined) { |
|
1327 </xsl:text> |
|
1328 <xsl:text> cache[new_index] = defaultval; |
|
1329 </xsl:text> |
|
1330 <xsl:text> updates.set(new_index, defaultval); |
|
1331 </xsl:text> |
|
1332 <xsl:text> if(persistent_locals.has(varname)) |
|
1333 </xsl:text> |
|
1334 <xsl:text> persistent_indexes.set(new_index, varname); |
|
1335 </xsl:text> |
|
1336 <xsl:text> } |
|
1337 </xsl:text> |
|
1338 <xsl:text> return new_index; |
|
1339 </xsl:text> |
|
1340 <xsl:text>} |
|
1341 </xsl:text> |
|
1342 <xsl:text> |
|
1343 </xsl:text> |
|
1344 <xsl:text>function hmi_local_index(varname){ |
|
1345 </xsl:text> |
|
1346 <xsl:text> return page_local_index(varname, "HMI_LOCAL"); |
|
1347 </xsl:text> |
|
1348 <xsl:text>} |
|
1349 </xsl:text> |
|
1350 <xsl:text> |
|
1351 </xsl:text> |
|
1352 </xsl:template> |
|
1353 <preamble:widget-base-class/> |
|
1354 <xsl:template match="preamble:widget-base-class"> |
|
1355 <xsl:text> |
|
1356 </xsl:text> |
|
1357 <xsl:text>/* </xsl:text> |
|
1358 <xsl:value-of select="local-name()"/> |
|
1359 <xsl:text> */ |
|
1360 </xsl:text> |
|
1361 <xsl:text> |
|
1362 </xsl:text> |
|
1363 <xsl:text>var pending_widget_animates = []; |
|
1364 </xsl:text> |
|
1365 <xsl:text> |
|
1366 </xsl:text> |
|
1367 <xsl:text>class Widget { |
|
1368 </xsl:text> |
|
1369 <xsl:text> offset = 0; |
|
1370 </xsl:text> |
|
1371 <xsl:text> frequency = 10; /* FIXME arbitrary default max freq. Obtain from config ? */ |
|
1372 </xsl:text> |
|
1373 <xsl:text> unsubscribable = false; |
|
1374 </xsl:text> |
|
1375 <xsl:text> pending_animate = false; |
|
1376 </xsl:text> |
|
1377 <xsl:text> |
|
1378 </xsl:text> |
|
1379 <xsl:text> constructor(elt_id,args,indexes,minmaxes,members){ |
|
1380 </xsl:text> |
|
1381 <xsl:text> this.element_id = elt_id; |
|
1382 </xsl:text> |
|
1383 <xsl:text> this.element = id(elt_id); |
|
1384 </xsl:text> |
|
1385 <xsl:text> this.args = args; |
|
1386 </xsl:text> |
|
1387 <xsl:text> this.indexes = indexes; |
|
1388 </xsl:text> |
|
1389 <xsl:text> this.minmaxes = minmaxes; |
|
1390 </xsl:text> |
|
1391 <xsl:text> Object.keys(members).forEach(prop => this[prop]=members[prop]); |
|
1392 </xsl:text> |
|
1393 <xsl:text> this.lastapply = indexes.map(() => undefined); |
|
1394 </xsl:text> |
|
1395 <xsl:text> this.inhibit = indexes.map(() => undefined); |
|
1396 </xsl:text> |
|
1397 <xsl:text> this.pending = indexes.map(() => undefined); |
|
1398 </xsl:text> |
|
1399 <xsl:text> this.bound_unhinibit = this.unhinibit.bind(this); |
|
1400 </xsl:text> |
|
1401 <xsl:text> } |
|
1402 </xsl:text> |
|
1403 <xsl:text> |
|
1404 </xsl:text> |
|
1405 <xsl:text> unsub(){ |
|
1406 </xsl:text> |
|
1407 <xsl:text> /* remove subsribers */ |
|
1408 </xsl:text> |
|
1409 <xsl:text> if(!this.unsubscribable) |
|
1410 </xsl:text> |
|
1411 <xsl:text> for(let i = 0; i < this.indexes.length; i++) { |
|
1412 </xsl:text> |
|
1413 <xsl:text> /* flush updates pending because of inhibition */ |
|
1414 </xsl:text> |
|
1415 <xsl:text> let inhibition = this.inhibit[i]; |
|
1416 </xsl:text> |
|
1417 <xsl:text> if(inhibition != undefined){ |
|
1418 </xsl:text> |
|
1419 <xsl:text> clearTimeout(inhibition); |
|
1420 </xsl:text> |
|
1421 <xsl:text> this.lastapply[i] = undefined; |
|
1422 </xsl:text> |
|
1423 <xsl:text> this.unhinibit(i); |
|
1424 </xsl:text> |
|
1425 <xsl:text> } |
|
1426 </xsl:text> |
|
1427 <xsl:text> let index = this.indexes[i]; |
|
1428 </xsl:text> |
|
1429 <xsl:text> if(this.relativeness[i]) |
|
1430 </xsl:text> |
|
1431 <xsl:text> index += this.offset; |
|
1432 </xsl:text> |
|
1433 <xsl:text> subscribers(index).delete(this); |
|
1434 </xsl:text> |
|
1435 <xsl:text> } |
|
1436 </xsl:text> |
|
1437 <xsl:text> this.offset = 0; |
|
1438 </xsl:text> |
|
1439 <xsl:text> this.relativeness = undefined; |
|
1440 </xsl:text> |
|
1441 <xsl:text> } |
|
1442 </xsl:text> |
|
1443 <xsl:text> |
|
1444 </xsl:text> |
|
1445 <xsl:text> sub(new_offset=0, relativeness, container_id){ |
|
1446 </xsl:text> |
|
1447 <xsl:text> this.offset = new_offset; |
|
1448 </xsl:text> |
|
1449 <xsl:text> this.relativeness = relativeness; |
|
1450 </xsl:text> |
|
1451 <xsl:text> this.container_id = container_id ; |
|
1452 </xsl:text> |
|
1453 <xsl:text> /* add this's subsribers */ |
|
1454 </xsl:text> |
|
1455 <xsl:text> if(!this.unsubscribable) |
|
1456 </xsl:text> |
|
1457 <xsl:text> for(let i = 0; i < this.indexes.length; i++) { |
|
1458 </xsl:text> |
|
1459 <xsl:text> let index = this.get_variable_index(i); |
|
1460 </xsl:text> |
|
1461 <xsl:text> if(index == undefined) continue; |
|
1462 </xsl:text> |
|
1463 <xsl:text> subscribers(index).add(this); |
|
1464 </xsl:text> |
|
1465 <xsl:text> } |
|
1466 </xsl:text> |
|
1467 <xsl:text> need_cache_apply.push(this); |
|
1468 </xsl:text> |
|
1469 <xsl:text> } |
|
1470 </xsl:text> |
|
1471 <xsl:text> |
|
1472 </xsl:text> |
|
1473 <xsl:text> apply_cache() { |
|
1474 </xsl:text> |
|
1475 <xsl:text> if(!this.unsubscribable) for(let index in this.indexes){ |
|
1476 </xsl:text> |
|
1477 <xsl:text> /* dispatch current cache in newly opened page widgets */ |
|
1478 </xsl:text> |
|
1479 <xsl:text> let realindex = this.get_variable_index(index); |
|
1480 </xsl:text> |
|
1481 <xsl:text> if(realindex == undefined) continue; |
|
1482 </xsl:text> |
|
1483 <xsl:text> let cached_val = cache[realindex]; |
|
1484 </xsl:text> |
|
1485 <xsl:text> if(cached_val != undefined) |
|
1486 </xsl:text> |
|
1487 <xsl:text> this._dispatch(cached_val, cached_val, index); |
|
1488 </xsl:text> |
|
1489 <xsl:text> } |
|
1490 </xsl:text> |
|
1491 <xsl:text> } |
|
1492 </xsl:text> |
|
1493 <xsl:text> |
|
1494 </xsl:text> |
|
1495 <xsl:text> get_variable_index(varnum) { |
|
1496 </xsl:text> |
|
1497 <xsl:text> let index = this.indexes[varnum]; |
|
1498 </xsl:text> |
|
1499 <xsl:text> if(typeof(index) == "string"){ |
|
1500 </xsl:text> |
|
1501 <xsl:text> index = page_local_index(index, this.container_id); |
|
1502 </xsl:text> |
|
1503 <xsl:text> } else { |
|
1504 </xsl:text> |
|
1505 <xsl:text> if(this.relativeness[varnum]){ |
|
1506 </xsl:text> |
|
1507 <xsl:text> index += this.offset; |
|
1508 </xsl:text> |
|
1509 <xsl:text> } |
|
1510 </xsl:text> |
|
1511 <xsl:text> } |
|
1512 </xsl:text> |
|
1513 <xsl:text> return index; |
|
1514 </xsl:text> |
|
1515 <xsl:text> } |
|
1516 </xsl:text> |
|
1517 <xsl:text> |
|
1518 </xsl:text> |
|
1519 <xsl:text> overshot(new_val, max) { |
|
1520 </xsl:text> |
|
1521 <xsl:text> } |
|
1522 </xsl:text> |
|
1523 <xsl:text> |
|
1524 </xsl:text> |
|
1525 <xsl:text> undershot(new_val, min) { |
|
1526 </xsl:text> |
|
1527 <xsl:text> } |
|
1528 </xsl:text> |
|
1529 <xsl:text> |
|
1530 </xsl:text> |
|
1531 <xsl:text> clip_min_max(index, new_val) { |
|
1532 </xsl:text> |
|
1533 <xsl:text> let minmax = this.minmaxes[index]; |
|
1534 </xsl:text> |
|
1535 <xsl:text> if(minmax !== undefined && typeof new_val == "number") { |
|
1536 </xsl:text> |
|
1537 <xsl:text> let [min,max] = minmax; |
|
1538 </xsl:text> |
|
1539 <xsl:text> if(new_val < min){ |
|
1540 </xsl:text> |
|
1541 <xsl:text> this.undershot(new_val, min); |
|
1542 </xsl:text> |
|
1543 <xsl:text> return min; |
|
1544 </xsl:text> |
|
1545 <xsl:text> } |
|
1546 </xsl:text> |
|
1547 <xsl:text> if(new_val > max){ |
|
1548 </xsl:text> |
|
1549 <xsl:text> this.overshot(new_val, max); |
|
1550 </xsl:text> |
|
1551 <xsl:text> return max; |
|
1552 </xsl:text> |
|
1553 <xsl:text> } |
|
1554 </xsl:text> |
|
1555 <xsl:text> } |
|
1556 </xsl:text> |
|
1557 <xsl:text> return new_val; |
|
1558 </xsl:text> |
|
1559 <xsl:text> } |
|
1560 </xsl:text> |
|
1561 <xsl:text> |
|
1562 </xsl:text> |
|
1563 <xsl:text> change_hmi_value(index, opstr) { |
|
1564 </xsl:text> |
|
1565 <xsl:text> let realindex = this.get_variable_index(index); |
|
1566 </xsl:text> |
|
1567 <xsl:text> if(realindex == undefined) return undefined; |
|
1568 </xsl:text> |
|
1569 <xsl:text> let old_val = cache[realindex]; |
|
1570 </xsl:text> |
|
1571 <xsl:text> let new_val = eval_operation_string(old_val, opstr); |
|
1572 </xsl:text> |
|
1573 <xsl:text> new_val = this.clip_min_max(index, new_val); |
|
1574 </xsl:text> |
|
1575 <xsl:text> return apply_hmi_value(realindex, new_val); |
|
1576 </xsl:text> |
|
1577 <xsl:text> } |
|
1578 </xsl:text> |
|
1579 <xsl:text> |
|
1580 </xsl:text> |
|
1581 <xsl:text> _apply_hmi_value(index, new_val) { |
|
1582 </xsl:text> |
|
1583 <xsl:text> let realindex = this.get_variable_index(index); |
|
1584 </xsl:text> |
|
1585 <xsl:text> if(realindex == undefined) return undefined; |
|
1586 </xsl:text> |
|
1587 <xsl:text> new_val = this.clip_min_max(index, new_val); |
|
1588 </xsl:text> |
|
1589 <xsl:text> return apply_hmi_value(realindex, new_val); |
|
1590 </xsl:text> |
|
1591 <xsl:text> } |
|
1592 </xsl:text> |
|
1593 <xsl:text> |
|
1594 </xsl:text> |
|
1595 <xsl:text> unhinibit(index){ |
|
1596 </xsl:text> |
|
1597 <xsl:text> this.inhibit[index] = undefined; |
|
1598 </xsl:text> |
|
1599 <xsl:text> let new_val = this.pending[index]; |
|
1600 </xsl:text> |
|
1601 <xsl:text> this.pending[index] = undefined; |
|
1602 </xsl:text> |
|
1603 <xsl:text> return this.apply_hmi_value(index, new_val); |
|
1604 </xsl:text> |
|
1605 <xsl:text> } |
|
1606 </xsl:text> |
|
1607 <xsl:text> |
|
1608 </xsl:text> |
|
1609 <xsl:text> apply_hmi_value(index, new_val) { |
|
1610 </xsl:text> |
|
1611 <xsl:text> if(this.inhibit[index] == undefined){ |
|
1612 </xsl:text> |
|
1613 <xsl:text> let now = Date.now(); |
|
1614 </xsl:text> |
|
1615 <xsl:text> let min_interval = 1000/this.frequency; |
|
1616 </xsl:text> |
|
1617 <xsl:text> let lastapply = this.lastapply[index]; |
|
1618 </xsl:text> |
|
1619 <xsl:text> if(lastapply == undefined || now > lastapply + min_interval){ |
|
1620 </xsl:text> |
|
1621 <xsl:text> this.lastapply[index] = now; |
|
1622 </xsl:text> |
|
1623 <xsl:text> return this._apply_hmi_value(index, new_val); |
|
1624 </xsl:text> |
|
1625 <xsl:text> } |
|
1626 </xsl:text> |
|
1627 <xsl:text> else { |
|
1628 </xsl:text> |
|
1629 <xsl:text> let elapsed = now - lastapply; |
|
1630 </xsl:text> |
|
1631 <xsl:text> this.pending[index] = new_val; |
|
1632 </xsl:text> |
|
1633 <xsl:text> this.inhibit[index] = setTimeout(this.bound_unhinibit, min_interval - elapsed, index); |
|
1634 </xsl:text> |
|
1635 <xsl:text> } |
|
1636 </xsl:text> |
|
1637 <xsl:text> } |
|
1638 </xsl:text> |
|
1639 <xsl:text> else { |
|
1640 </xsl:text> |
|
1641 <xsl:text> this.pending[index] = new_val; |
|
1642 </xsl:text> |
|
1643 <xsl:text> return new_val; |
|
1644 </xsl:text> |
|
1645 <xsl:text> } |
|
1646 </xsl:text> |
|
1647 <xsl:text> } |
|
1648 </xsl:text> |
|
1649 <xsl:text> |
|
1650 </xsl:text> |
|
1651 <xsl:text> new_hmi_value(index, value, oldval) { |
|
1652 </xsl:text> |
|
1653 <xsl:text> // TODO avoid searching, store index at sub() |
|
1654 </xsl:text> |
|
1655 <xsl:text> for(let i = 0; i < this.indexes.length; i++) { |
|
1656 </xsl:text> |
|
1657 <xsl:text> let refindex = this.get_variable_index(i); |
|
1658 </xsl:text> |
|
1659 <xsl:text> if(refindex == undefined) continue; |
|
1660 </xsl:text> |
|
1661 <xsl:text> |
|
1662 </xsl:text> |
|
1663 <xsl:text> if(index == refindex) { |
|
1664 </xsl:text> |
|
1665 <xsl:text> this._dispatch(value, oldval, i); |
|
1666 </xsl:text> |
|
1667 <xsl:text> break; |
|
1668 </xsl:text> |
|
1669 <xsl:text> } |
|
1670 </xsl:text> |
|
1671 <xsl:text> } |
|
1672 </xsl:text> |
|
1673 <xsl:text> } |
|
1674 </xsl:text> |
|
1675 <xsl:text> |
|
1676 </xsl:text> |
|
1677 <xsl:text> _dispatch(value, oldval, varnum) { |
|
1678 </xsl:text> |
|
1679 <xsl:text> let dispatch = this.dispatch; |
|
1680 </xsl:text> |
|
1681 <xsl:text> if(dispatch != undefined){ |
|
1682 </xsl:text> |
|
1683 <xsl:text> try { |
|
1684 </xsl:text> |
|
1685 <xsl:text> dispatch.call(this, value, oldval, varnum); |
|
1686 </xsl:text> |
|
1687 <xsl:text> } catch(err) { |
|
1688 </xsl:text> |
|
1689 <xsl:text> console.log(err); |
|
1690 </xsl:text> |
|
1691 <xsl:text> } |
|
1692 </xsl:text> |
|
1693 <xsl:text> } |
|
1694 </xsl:text> |
|
1695 <xsl:text> } |
|
1696 </xsl:text> |
|
1697 <xsl:text> |
|
1698 </xsl:text> |
|
1699 <xsl:text> _animate(){ |
|
1700 </xsl:text> |
|
1701 <xsl:text> this.animate(); |
|
1702 </xsl:text> |
|
1703 <xsl:text> this.pending_animate = false; |
|
1704 </xsl:text> |
|
1705 <xsl:text> } |
|
1706 </xsl:text> |
|
1707 <xsl:text> |
|
1708 </xsl:text> |
|
1709 <xsl:text> request_animate(){ |
|
1710 </xsl:text> |
|
1711 <xsl:text> if(!this.pending_animate){ |
|
1712 </xsl:text> |
|
1713 <xsl:text> pending_widget_animates.push(this); |
|
1714 </xsl:text> |
|
1715 <xsl:text> this.pending_animate = true; |
|
1716 </xsl:text> |
|
1717 <xsl:text> requestHMIAnimation(); |
|
1718 </xsl:text> |
|
1719 <xsl:text> } |
|
1720 </xsl:text> |
|
1721 <xsl:text> |
|
1722 </xsl:text> |
|
1723 <xsl:text> } |
|
1724 </xsl:text> |
|
1725 <xsl:text> |
|
1726 </xsl:text> |
|
1727 <xsl:text> activate_activable(eltsub) { |
|
1728 </xsl:text> |
|
1729 <xsl:text> eltsub.inactive.style.display = "none"; |
|
1730 </xsl:text> |
|
1731 <xsl:text> eltsub.active.style.display = ""; |
|
1732 </xsl:text> |
|
1733 <xsl:text> } |
|
1734 </xsl:text> |
|
1735 <xsl:text> |
|
1736 </xsl:text> |
|
1737 <xsl:text> inactivate_activable(eltsub) { |
|
1738 </xsl:text> |
|
1739 <xsl:text> eltsub.active.style.display = "none"; |
|
1740 </xsl:text> |
|
1741 <xsl:text> eltsub.inactive.style.display = ""; |
|
1742 </xsl:text> |
|
1743 <xsl:text> } |
|
1744 </xsl:text> |
|
1745 <xsl:text>} |
|
1746 </xsl:text> |
|
1747 <xsl:text> |
|
1748 </xsl:text> |
|
1749 </xsl:template> |
|
1750 <xsl:variable name="excluded_types" select="str:split('Page VarInit VarInitPersistent')"/> |
|
1751 <xsl:key name="TypesKey" match="widget" use="@type"/> |
|
1752 <declarations:hmi-classes/> |
|
1753 <xsl:template match="declarations:hmi-classes"> |
|
1754 <xsl:text> |
|
1755 </xsl:text> |
|
1756 <xsl:text>/* </xsl:text> |
|
1757 <xsl:value-of select="local-name()"/> |
|
1758 <xsl:text> */ |
|
1759 </xsl:text> |
|
1760 <xsl:text> |
|
1761 </xsl:text> |
|
1762 <xsl:variable name="used_widget_types" select="$parsed_widgets/widget[ generate-id() = generate-id(key('TypesKey', @type)) and not(@type = $excluded_types)]"/> |
|
1763 <xsl:apply-templates mode="widget_class" select="$used_widget_types"/> |
|
1764 <xsl:text> |
|
1765 </xsl:text> |
|
1766 </xsl:template> |
|
1767 <xsl:template mode="widget_class" match="widget"> |
|
1768 <xsl:text>class </xsl:text> |
|
1769 <xsl:value-of select="@type"/> |
|
1770 <xsl:text>Widget extends Widget{ |
|
1771 </xsl:text> |
|
1772 <xsl:text> /* empty class, as </xsl:text> |
|
1773 <xsl:value-of select="@type"/> |
|
1774 <xsl:text> widget didn't provide any */ |
|
1775 </xsl:text> |
|
1776 <xsl:text>} |
|
1777 </xsl:text> |
|
1778 </xsl:template> |
|
1779 <xsl:variable name="included_ids" select="$parsed_widgets/widget[not(@type = $excluded_types) and not(@id = $discardable_elements/@id)]/@id"/> |
|
1780 <xsl:variable name="hmi_widgets" select="$hmi_elements[@id = $included_ids]"/> |
|
1781 <xsl:variable name="result_widgets" select="$result_svg_ns//*[@id = $hmi_widgets/@id]"/> |
|
1782 <declarations:hmi-elements/> |
|
1783 <xsl:template match="declarations:hmi-elements"> |
|
1784 <xsl:text> |
|
1785 </xsl:text> |
|
1786 <xsl:text>/* </xsl:text> |
|
1787 <xsl:value-of select="local-name()"/> |
|
1788 <xsl:text> */ |
|
1789 </xsl:text> |
|
1790 <xsl:text> |
|
1791 </xsl:text> |
|
1792 <xsl:text>var hmi_widgets = { |
|
1793 </xsl:text> |
|
1794 <xsl:apply-templates mode="hmi_widgets" select="$hmi_widgets"/> |
|
1795 <xsl:text>} |
|
1796 </xsl:text> |
|
1797 <xsl:text> |
|
1798 </xsl:text> |
|
1799 </xsl:template> |
|
1800 <xsl:template name="defs_by_labels"> |
|
1801 <xsl:param name="labels" select="''"/> |
|
1802 <xsl:param name="mandatory" select="'yes'"/> |
|
1803 <xsl:param name="subelements" select="/.."/> |
|
1804 <xsl:param name="hmi_element"/> |
|
1805 <xsl:variable name="widget_type" select="@type"/> |
|
1806 <xsl:for-each select="str:split($labels)"> |
|
1807 <xsl:variable name="name" select="."/> |
|
1808 <xsl:variable name="elt" select="$result_widgets[@id = $hmi_element/@id]//*[@inkscape:label=$name][1]"/> |
|
1809 <xsl:choose> |
|
1810 <xsl:when test="not($elt/@id)"> |
|
1811 <xsl:if test="$mandatory='yes'"> |
|
1812 <xsl:message terminate="yes"> |
|
1813 <xsl:value-of select="$widget_type"/> |
|
1814 <xsl:text> widget must have a </xsl:text> |
|
1815 <xsl:value-of select="$name"/> |
|
1816 <xsl:text> element</xsl:text> |
|
1817 </xsl:message> |
|
1818 </xsl:if> |
|
1819 </xsl:when> |
|
1820 <xsl:otherwise> |
|
1821 <xsl:text> </xsl:text> |
|
1822 <xsl:value-of select="$name"/> |
|
1823 <xsl:text>_elt: id("</xsl:text> |
|
1824 <xsl:value-of select="$elt/@id"/> |
|
1825 <xsl:text>"), |
|
1826 </xsl:text> |
|
1827 <xsl:if test="$subelements"> |
|
1828 <xsl:text> </xsl:text> |
|
1829 <xsl:value-of select="$name"/> |
|
1830 <xsl:text>_sub: { |
|
1831 </xsl:text> |
|
1832 <xsl:for-each select="str:split($subelements)"> |
|
1833 <xsl:variable name="subname" select="."/> |
|
1834 <xsl:variable name="subelt" select="$elt/*[@inkscape:label=$subname][1]"/> |
|
1835 <xsl:choose> |
|
1836 <xsl:when test="not($subelt/@id)"> |
|
1837 <xsl:if test="$mandatory='yes'"> |
|
1838 <xsl:message terminate="yes"> |
|
1839 <xsl:value-of select="$widget_type"/> |
|
1840 <xsl:text> widget must have a </xsl:text> |
|
1841 <xsl:value-of select="$name"/> |
|
1842 <xsl:text>/</xsl:text> |
|
1843 <xsl:value-of select="$subname"/> |
|
1844 <xsl:text> element</xsl:text> |
|
1845 </xsl:message> |
|
1846 </xsl:if> |
|
1847 <xsl:text> /* missing </xsl:text> |
|
1848 <xsl:value-of select="$name"/> |
|
1849 <xsl:text>/</xsl:text> |
|
1850 <xsl:value-of select="$subname"/> |
|
1851 <xsl:text> element */ |
|
1852 </xsl:text> |
|
1853 </xsl:when> |
|
1854 <xsl:otherwise> |
|
1855 <xsl:text> "</xsl:text> |
|
1856 <xsl:value-of select="$subname"/> |
|
1857 <xsl:text>": id("</xsl:text> |
|
1858 <xsl:value-of select="$subelt/@id"/> |
|
1859 <xsl:text>")</xsl:text> |
|
1860 <xsl:if test="position()!=last()"> |
|
1861 <xsl:text>,</xsl:text> |
|
1862 </xsl:if> |
|
1863 <xsl:text> |
|
1864 </xsl:text> |
|
1865 </xsl:otherwise> |
|
1866 </xsl:choose> |
|
1867 </xsl:for-each> |
|
1868 <xsl:text> }, |
|
1869 </xsl:text> |
|
1870 </xsl:if> |
|
1871 </xsl:otherwise> |
|
1872 </xsl:choose> |
|
1873 </xsl:for-each> |
|
1874 </xsl:template> |
|
1875 <func:function name="func:escape_quotes"> |
|
1876 <xsl:param name="txt"/> |
|
1877 <xsl:choose> |
|
1878 <xsl:when test="contains($txt,'"')"> |
|
1879 <func:result select="concat(substring-before($txt,'"'),'\"',func:escape_quotes(substring-after($txt,'"')))"/> |
|
1880 </xsl:when> |
|
1881 <xsl:otherwise> |
|
1882 <func:result select="$txt"/> |
|
1883 </xsl:otherwise> |
|
1884 </xsl:choose> |
|
1885 </func:function> |
|
1886 <xsl:template match="widget[@type='Animate']" mode="widget_class"> |
|
1887 <xsl:text>class </xsl:text> |
|
1888 <xsl:text>AnimateWidget</xsl:text> |
|
1889 <xsl:text> extends Widget{ |
|
1890 </xsl:text> |
|
1891 <xsl:text> frequency = 5; |
|
1892 </xsl:text> |
|
1893 <xsl:text> speed = 0; |
|
1894 </xsl:text> |
|
1895 <xsl:text> start = false; |
|
1896 </xsl:text> |
|
1897 <xsl:text> widget_center = undefined; |
|
1898 </xsl:text> |
|
1899 <xsl:text> |
|
1900 </xsl:text> |
|
1901 <xsl:text> dispatch(value) { |
|
1902 </xsl:text> |
|
1903 <xsl:text> this.speed = value / 5; |
|
1904 </xsl:text> |
|
1905 <xsl:text> |
|
1906 </xsl:text> |
|
1907 <xsl:text> //reconfigure animation |
|
1908 </xsl:text> |
|
1909 <xsl:text> this.request_animate(); |
|
1910 </xsl:text> |
|
1911 <xsl:text> } |
|
1912 </xsl:text> |
|
1913 <xsl:text> |
|
1914 </xsl:text> |
|
1915 <xsl:text> animate(){ |
|
1916 </xsl:text> |
|
1917 <xsl:text> // change animation properties |
|
1918 </xsl:text> |
|
1919 <xsl:text> for(let child of this.element.children){ |
|
1920 </xsl:text> |
|
1921 <xsl:text> if(child.nodeName.startsWith("animate")){ |
|
1922 </xsl:text> |
|
1923 <xsl:text> if(this.speed != 0 && !this.start){ |
|
1924 </xsl:text> |
|
1925 <xsl:text> this.start = true; |
|
1926 </xsl:text> |
|
1927 <xsl:text> this.element.beginElement(); |
|
1928 </xsl:text> |
|
1929 <xsl:text> } |
|
1930 </xsl:text> |
|
1931 <xsl:text> |
|
1932 </xsl:text> |
|
1933 <xsl:text> if(this.speed > 0){ |
|
1934 </xsl:text> |
|
1935 <xsl:text> child.setAttribute("dur", this.speed+"s"); |
|
1936 </xsl:text> |
|
1937 <xsl:text> } |
|
1938 </xsl:text> |
|
1939 <xsl:text> else if(this.speed < 0){ |
|
1940 </xsl:text> |
|
1941 <xsl:text> child.setAttribute("dur", (-1)*this.speed+"s"); |
|
1942 </xsl:text> |
|
1943 <xsl:text> } |
|
1944 </xsl:text> |
|
1945 <xsl:text> else{ |
|
1946 </xsl:text> |
|
1947 <xsl:text> this.start = false; |
|
1948 </xsl:text> |
|
1949 <xsl:text> this.element.endElement(); |
|
1950 </xsl:text> |
|
1951 <xsl:text> } |
|
1952 </xsl:text> |
|
1953 <xsl:text> } |
|
1954 </xsl:text> |
|
1955 <xsl:text> } |
|
1956 </xsl:text> |
|
1957 <xsl:text> } |
|
1958 </xsl:text> |
|
1959 <xsl:text> |
|
1960 </xsl:text> |
|
1961 <xsl:text> init() { |
|
1962 </xsl:text> |
|
1963 <xsl:text> let widget_pos = this.element.getBBox(); |
|
1964 </xsl:text> |
|
1965 <xsl:text> this.widget_center = [(widget_pos.x+widget_pos.width/2), (widget_pos.y+widget_pos.height/2)]; |
|
1966 </xsl:text> |
|
1967 <xsl:text> } |
|
1968 </xsl:text> |
|
1969 <xsl:text>} |
|
1970 </xsl:text> |
|
1971 </xsl:template> |
|
1972 <xsl:template match="widget[@type='AnimateRotation']" mode="widget_desc"> |
|
1973 <type> |
|
1974 <xsl:value-of select="@type"/> |
|
1975 </type> |
|
1976 <longdesc> |
|
1977 <xsl:text>AnimateRotation - DEPRECATED, do not use. |
|
1978 </xsl:text> |
|
1979 <xsl:text>Doesn't follow WYSIWYG principle, and forces user to add animateTransform tag in SVG (using inkscape XML editor for exemple) |
|
1980 </xsl:text> |
|
1981 </longdesc> |
|
1982 <shortdesc> |
|
1983 <xsl:text>AnimateRotation - DEPRECATED</xsl:text> |
|
1984 </shortdesc> |
|
1985 <path name="speed" accepts="HMI_INT,HMI_REAL"> |
|
1986 <xsl:text>speed</xsl:text> |
|
1987 </path> |
|
1988 </xsl:template> |
|
1989 <xsl:template match="widget[@type='AnimateRotation']" mode="widget_class"> |
|
1990 <xsl:text>class </xsl:text> |
|
1991 <xsl:text>AnimateRotationWidget</xsl:text> |
|
1992 <xsl:text> extends Widget{ |
|
1993 </xsl:text> |
|
1994 <xsl:text> frequency = 5; |
|
1995 </xsl:text> |
|
1996 <xsl:text> speed = 0; |
|
1997 </xsl:text> |
|
1998 <xsl:text> widget_center = undefined; |
|
1999 </xsl:text> |
|
2000 <xsl:text> |
|
2001 </xsl:text> |
|
2002 <xsl:text> dispatch(value) { |
|
2003 </xsl:text> |
|
2004 <xsl:text> this.speed = value / 5; |
|
2005 </xsl:text> |
|
2006 <xsl:text> |
|
2007 </xsl:text> |
|
2008 <xsl:text> //reconfigure animation |
|
2009 </xsl:text> |
|
2010 <xsl:text> this.request_animate(); |
|
2011 </xsl:text> |
|
2012 <xsl:text> } |
|
2013 </xsl:text> |
|
2014 <xsl:text> |
|
2015 </xsl:text> |
|
2016 <xsl:text> animate(){ |
|
2017 </xsl:text> |
|
2018 <xsl:text> // change animation properties |
|
2019 </xsl:text> |
|
2020 <xsl:text> // TODO : rewrite with proper es6 |
|
2021 </xsl:text> |
|
2022 <xsl:text> for(let child of this.element.children){ |
|
2023 </xsl:text> |
|
2024 <xsl:text> if(child.nodeName == "animateTransform"){ |
|
2025 </xsl:text> |
|
2026 <xsl:text> if(this.speed > 0){ |
|
2027 </xsl:text> |
|
2028 <xsl:text> child.setAttribute("dur", this.speed+"s"); |
|
2029 </xsl:text> |
|
2030 <xsl:text> child.setAttribute("from", "0 "+this.widget_center[0]+" "+this.widget_center[1]); |
|
2031 </xsl:text> |
|
2032 <xsl:text> child.setAttribute("to", "360 "+this.widget_center[0]+" "+this.widget_center[1]); |
|
2033 </xsl:text> |
|
2034 <xsl:text> } |
|
2035 </xsl:text> |
|
2036 <xsl:text> else if(this.speed < 0){ |
|
2037 </xsl:text> |
|
2038 <xsl:text> child.setAttribute("dur", (-1)*this.speed+"s"); |
|
2039 </xsl:text> |
|
2040 <xsl:text> child.setAttribute("from", "360 "+this.widget_center[0]+" "+this.widget_center[1]); |
|
2041 </xsl:text> |
|
2042 <xsl:text> child.setAttribute("to", "0 "+this.widget_center[0]+" "+this.widget_center[1]); |
|
2043 </xsl:text> |
|
2044 <xsl:text> } |
|
2045 </xsl:text> |
|
2046 <xsl:text> else{ |
|
2047 </xsl:text> |
|
2048 <xsl:text> child.setAttribute("from", "0 "+this.widget_center[0]+" "+this.widget_center[1]); |
|
2049 </xsl:text> |
|
2050 <xsl:text> child.setAttribute("to", "0 "+this.widget_center[0]+" "+this.widget_center[1]); |
|
2051 </xsl:text> |
|
2052 <xsl:text> } |
|
2053 </xsl:text> |
|
2054 <xsl:text> } |
|
2055 </xsl:text> |
|
2056 <xsl:text> } |
|
2057 </xsl:text> |
|
2058 <xsl:text> } |
|
2059 </xsl:text> |
|
2060 <xsl:text> |
|
2061 </xsl:text> |
|
2062 <xsl:text> init() { |
|
2063 </xsl:text> |
|
2064 <xsl:text> let widget_pos = this.element.getBBox(); |
|
2065 </xsl:text> |
|
2066 <xsl:text> this.widget_center = [(widget_pos.x+widget_pos.width/2), (widget_pos.y+widget_pos.height/2)]; |
|
2067 </xsl:text> |
|
2068 <xsl:text> } |
|
2069 </xsl:text> |
|
2070 <xsl:text>} |
|
2071 </xsl:text> |
|
2072 </xsl:template> |
|
2073 <xsl:template match="widget[@type='Back']" mode="widget_desc"> |
|
2074 <type> |
|
2075 <xsl:value-of select="@type"/> |
|
2076 </type> |
|
2077 <longdesc> |
|
2078 <xsl:text>Back widget brings focus back to previous page in history when clicked. |
|
2079 </xsl:text> |
|
2080 </longdesc> |
|
2081 <shortdesc> |
|
2082 <xsl:text>Jump to previous page</xsl:text> |
|
2083 </shortdesc> |
|
2084 </xsl:template> |
|
2085 <xsl:template match="widget[@type='Back']" mode="widget_class"> |
|
2086 <xsl:text>class </xsl:text> |
|
2087 <xsl:text>BackWidget</xsl:text> |
|
2088 <xsl:text> extends Widget{ |
|
2089 </xsl:text> |
|
2090 <xsl:text> on_click(evt) { |
|
2091 </xsl:text> |
|
2092 <xsl:text> if(jump_history.length > 1){ |
|
2093 </xsl:text> |
|
2094 <xsl:text> jump_history.pop(); |
|
2095 </xsl:text> |
|
2096 <xsl:text> let [page_name, index] = jump_history.pop(); |
|
2097 </xsl:text> |
|
2098 <xsl:text> switch_page(page_name, index); |
|
2099 </xsl:text> |
|
2100 <xsl:text> } |
|
2101 </xsl:text> |
|
2102 <xsl:text> } |
|
2103 </xsl:text> |
|
2104 <xsl:text> init() { |
|
2105 </xsl:text> |
|
2106 <xsl:text> this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)"); |
|
2107 </xsl:text> |
|
2108 <xsl:text> } |
|
2109 </xsl:text> |
|
2110 <xsl:text>} |
|
2111 </xsl:text> |
|
2112 </xsl:template> |
|
2113 <xsl:template match="widget[@type='Button']" mode="widget_desc"> |
|
2114 <type> |
|
2115 <xsl:value-of select="@type"/> |
|
2116 </type> |
|
2117 <longdesc> |
|
2118 <xsl:text>Button widget takes one boolean variable path, and reflect current true |
|
2119 </xsl:text> |
|
2120 <xsl:text>or false value by showing "active" or "inactive" labeled element |
|
2121 </xsl:text> |
|
2122 <xsl:text>respectively. Pressing and releasing button changes variable to true and |
|
2123 </xsl:text> |
|
2124 <xsl:text>false respectively. Potential inconsistency caused by quick consecutive |
|
2125 </xsl:text> |
|
2126 <xsl:text>presses on the button is mitigated by using a state machine that wait for |
|
2127 </xsl:text> |
|
2128 <xsl:text>previous state change to be reflected on variable before applying next one. |
|
2129 </xsl:text> |
|
2130 </longdesc> |
|
2131 <shortdesc> |
|
2132 <xsl:text>Push button reflecting consistently given boolean variable</xsl:text> |
|
2133 </shortdesc> |
|
2134 <path name="value" accepts="HMI_BOOL"> |
|
2135 <xsl:text>Boolean variable</xsl:text> |
|
2136 </path> |
|
2137 </xsl:template> |
|
2138 <xsl:variable name="_button_fsm"> |
|
2139 <fsm> |
|
2140 <state name="init"> |
|
2141 <on-dispatch value="false"> |
|
2142 <jump state="released"/> |
|
2143 </on-dispatch> |
|
2144 <on-dispatch value="true"> |
|
2145 <jump state="pressed"/> |
|
2146 </on-dispatch> |
|
2147 </state> |
|
2148 <state name="pressing"> |
|
2149 <hmi-value value="true"/> |
|
2150 <on-dispatch value="true"> |
|
2151 <jump state="pressed"/> |
|
2152 </on-dispatch> |
|
2153 <on-mouse position="up"> |
|
2154 <jump state="shortpress"/> |
|
2155 </on-mouse> |
|
2156 </state> |
|
2157 <state name="pressed"> |
|
2158 <show eltname="active"/> |
|
2159 <on-mouse position="up"> |
|
2160 <jump state="releasing"/> |
|
2161 </on-mouse> |
|
2162 <on-dispatch value="false"> |
|
2163 <jump state="released"/> |
|
2164 </on-dispatch> |
|
2165 </state> |
|
2166 <state name="shortpress"> |
|
2167 <on-dispatch value="true"> |
|
2168 <jump state="releasing"/> |
|
2169 </on-dispatch> |
|
2170 <on-mouse position="down"> |
|
2171 <jump state="pressing"/> |
|
2172 </on-mouse> |
|
2173 </state> |
|
2174 <state name="releasing"> |
|
2175 <hmi-value value="false"/> |
|
2176 <on-dispatch value="false"> |
|
2177 <jump state="released"/> |
|
2178 </on-dispatch> |
|
2179 <on-mouse position="down"> |
|
2180 <jump state="shortrelease"/> |
|
2181 </on-mouse> |
|
2182 </state> |
|
2183 <state name="released"> |
|
2184 <show eltname="inactive"/> |
|
2185 <on-mouse position="down"> |
|
2186 <jump state="pressing"/> |
|
2187 </on-mouse> |
|
2188 <on-dispatch value="true"> |
|
2189 <jump state="pressed"/> |
|
2190 </on-dispatch> |
|
2191 </state> |
|
2192 <state name="shortrelease"> |
|
2193 <on-dispatch value="false"> |
|
2194 <jump state="pressing"/> |
|
2195 </on-dispatch> |
|
2196 <on-mouse position="up"> |
|
2197 <jump state="releasing"/> |
|
2198 </on-mouse> |
|
2199 </state> |
|
2200 </fsm> |
|
2201 </xsl:variable> |
|
2202 <xsl:template mode="dispatch_transition" match="fsm"> |
|
2203 <xsl:text> switch (this.state) { |
|
2204 </xsl:text> |
|
2205 <xsl:apply-templates mode="dispatch_transition" select="state"/> |
|
2206 <xsl:text> } |
|
2207 </xsl:text> |
|
2208 </xsl:template> |
|
2209 <xsl:template mode="dispatch_transition" match="state"> |
|
2210 <xsl:text> case "</xsl:text> |
|
2211 <xsl:value-of select="@name"/> |
|
2212 <xsl:text>": |
|
2213 </xsl:text> |
|
2214 <xsl:apply-templates select="on-dispatch"/> |
|
2215 <xsl:text> break; |
|
2216 </xsl:text> |
|
2217 </xsl:template> |
|
2218 <xsl:template match="on-dispatch"> |
|
2219 <xsl:text> if(value == </xsl:text> |
|
2220 <xsl:value-of select="@value"/> |
|
2221 <xsl:text>) { |
|
2222 </xsl:text> |
|
2223 <xsl:apply-templates mode="transition" select="jump"/> |
|
2224 <xsl:text> } |
|
2225 </xsl:text> |
|
2226 </xsl:template> |
|
2227 <xsl:template mode="mouse_transition" match="fsm"> |
|
2228 <xsl:param name="position"/> |
|
2229 <xsl:text> switch (this.state) { |
|
2230 </xsl:text> |
|
2231 <xsl:apply-templates mode="mouse_transition" select="state"> |
|
2232 <xsl:with-param name="position" select="$position"/> |
|
2233 </xsl:apply-templates> |
|
2234 <xsl:text> } |
|
2235 </xsl:text> |
|
2236 </xsl:template> |
|
2237 <xsl:template mode="mouse_transition" match="state"> |
|
2238 <xsl:param name="position"/> |
|
2239 <xsl:text> case "</xsl:text> |
|
2240 <xsl:value-of select="@name"/> |
|
2241 <xsl:text>": |
|
2242 </xsl:text> |
|
2243 <xsl:apply-templates select="on-mouse[@position = $position]"/> |
|
2244 <xsl:text> break; |
|
2245 </xsl:text> |
|
2246 </xsl:template> |
|
2247 <xsl:template match="on-mouse"> |
|
2248 <xsl:apply-templates mode="transition" select="jump"/> |
|
2249 </xsl:template> |
|
2250 <xsl:template mode="transition" match="jump"> |
|
2251 <xsl:text> this.state = "</xsl:text> |
|
2252 <xsl:value-of select="@state"/> |
|
2253 <xsl:text>"; |
|
2254 </xsl:text> |
|
2255 <xsl:text> this.</xsl:text> |
|
2256 <xsl:value-of select="@state"/> |
|
2257 <xsl:text>_action(); |
|
2258 </xsl:text> |
|
2259 </xsl:template> |
|
2260 <xsl:template mode="actions" match="fsm"> |
|
2261 <xsl:apply-templates mode="actions" select="state"/> |
|
2262 </xsl:template> |
|
2263 <xsl:template mode="actions" match="state"> |
|
2264 <xsl:text> </xsl:text> |
|
2265 <xsl:value-of select="@name"/> |
|
2266 <xsl:text>_action(){ |
|
2267 </xsl:text> |
|
2268 <xsl:apply-templates mode="actions" select="*"/> |
|
2269 <xsl:text> } |
|
2270 </xsl:text> |
|
2271 </xsl:template> |
|
2272 <xsl:template mode="actions" match="show"> |
|
2273 <xsl:text> this.display = "</xsl:text> |
|
2274 <xsl:value-of select="@eltname"/> |
|
2275 <xsl:text>"; |
|
2276 </xsl:text> |
|
2277 <xsl:text> this.request_animate(); |
|
2278 </xsl:text> |
|
2279 </xsl:template> |
|
2280 <xsl:template mode="actions" match="hmi-value"> |
|
2281 <xsl:text> this.apply_hmi_value(0, </xsl:text> |
|
2282 <xsl:value-of select="@value"/> |
|
2283 <xsl:text>); |
|
2284 </xsl:text> |
|
2285 </xsl:template> |
|
2286 <xsl:template match="widget[@type='Button']" mode="widget_class"> |
|
2287 <xsl:text>class </xsl:text> |
|
2288 <xsl:text>ButtonWidget</xsl:text> |
|
2289 <xsl:text> extends Widget{ |
|
2290 </xsl:text> |
|
2291 <xsl:variable name="fsm" select="exsl:node-set($_button_fsm)"/> |
|
2292 <xsl:text> frequency = 5; |
|
2293 </xsl:text> |
|
2294 <xsl:text> display = "inactive"; |
|
2295 </xsl:text> |
|
2296 <xsl:text> state = "init"; |
|
2297 </xsl:text> |
|
2298 <xsl:text> dispatch(value) { |
|
2299 </xsl:text> |
|
2300 <xsl:apply-templates mode="dispatch_transition" select="$fsm"/> |
|
2301 <xsl:text> } |
|
2302 </xsl:text> |
|
2303 <xsl:text> onmouseup(evt) { |
|
2304 </xsl:text> |
|
2305 <xsl:text> svg_root.removeEventListener("pointerup", this.bound_onmouseup, true); |
|
2306 </xsl:text> |
|
2307 <xsl:apply-templates mode="mouse_transition" select="$fsm"> |
|
2308 <xsl:with-param name="position" select="'up'"/> |
|
2309 </xsl:apply-templates> |
|
2310 <xsl:text> } |
|
2311 </xsl:text> |
|
2312 <xsl:text> onmousedown(evt) { |
|
2313 </xsl:text> |
|
2314 <xsl:text> svg_root.addEventListener("pointerup", this.bound_onmouseup, true); |
|
2315 </xsl:text> |
|
2316 <xsl:apply-templates mode="mouse_transition" select="$fsm"> |
|
2317 <xsl:with-param name="position" select="'down'"/> |
|
2318 </xsl:apply-templates> |
|
2319 <xsl:text> } |
|
2320 </xsl:text> |
|
2321 <xsl:apply-templates mode="actions" select="$fsm"/> |
|
2322 <xsl:text> animate(){ |
|
2323 </xsl:text> |
|
2324 <xsl:text> if (this.active_elt && this.inactive_elt) { |
|
2325 </xsl:text> |
|
2326 <xsl:for-each select="str:split('active inactive')"> |
|
2327 <xsl:text> if(this.display == "</xsl:text> |
|
2328 <xsl:value-of select="."/> |
|
2329 <xsl:text>") |
|
2330 </xsl:text> |
|
2331 <xsl:text> this.</xsl:text> |
|
2332 <xsl:value-of select="."/> |
|
2333 <xsl:text>_elt.style.display = ""; |
|
2334 </xsl:text> |
|
2335 <xsl:text> else |
|
2336 </xsl:text> |
|
2337 <xsl:text> this.</xsl:text> |
|
2338 <xsl:value-of select="."/> |
|
2339 <xsl:text>_elt.style.display = "none"; |
|
2340 </xsl:text> |
|
2341 </xsl:for-each> |
|
2342 <xsl:text> } |
|
2343 </xsl:text> |
|
2344 <xsl:text> } |
|
2345 </xsl:text> |
|
2346 <xsl:text> init() { |
|
2347 </xsl:text> |
|
2348 <xsl:text> this.bound_onmouseup = this.onmouseup.bind(this); |
|
2349 </xsl:text> |
|
2350 <xsl:text> this.element.addEventListener("pointerdown", this.onmousedown.bind(this)); |
|
2351 </xsl:text> |
|
2352 <xsl:text> } |
|
2353 </xsl:text> |
|
2354 <xsl:text>} |
|
2355 </xsl:text> |
|
2356 </xsl:template> |
|
2357 <xsl:template match="widget[@type='Button']" mode="widget_defs"> |
|
2358 <xsl:param name="hmi_element"/> |
|
2359 <xsl:call-template name="defs_by_labels"> |
|
2360 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
2361 <xsl:with-param name="labels"> |
|
2362 <xsl:text>active inactive</xsl:text> |
|
2363 </xsl:with-param> |
|
2364 <xsl:with-param name="mandatory" select="'no'"/> |
|
2365 </xsl:call-template> |
|
2366 </xsl:template> |
|
2367 <xsl:template match="widget[@type='CircularBar']" mode="widget_desc"> |
|
2368 <type> |
|
2369 <xsl:value-of select="@type"/> |
|
2370 </type> |
|
2371 <longdesc> |
|
2372 <xsl:text>CircularBar widget changes the end angle of a "path" labeled arc according |
|
2373 </xsl:text> |
|
2374 <xsl:text>to value of the single accepted variable. |
|
2375 </xsl:text> |
|
2376 <xsl:text> |
|
2377 </xsl:text> |
|
2378 <xsl:text>If "min" a "max" labeled texts are provided, then they are used as |
|
2379 </xsl:text> |
|
2380 <xsl:text>respective minimum and maximum value. Otherwise, value is expected to be |
|
2381 </xsl:text> |
|
2382 <xsl:text>in between 0 and 100. |
|
2383 </xsl:text> |
|
2384 <xsl:text> |
|
2385 </xsl:text> |
|
2386 <xsl:text>If "value" labeled text is found, then its content is replaced by value. |
|
2387 </xsl:text> |
|
2388 </longdesc> |
|
2389 <shortdesc> |
|
2390 <xsl:text>Change end angle of Inkscape's arc</xsl:text> |
|
2391 </shortdesc> |
|
2392 <path name="value" accepts="HMI_INT,HMI_REAL"> |
|
2393 <xsl:text>Value to display</xsl:text> |
|
2394 </path> |
|
2395 </xsl:template> |
|
2396 <xsl:template match="widget[@type='CircularBar']" mode="widget_class"> |
|
2397 <xsl:text>class </xsl:text> |
|
2398 <xsl:text>CircularBarWidget</xsl:text> |
|
2399 <xsl:text> extends Widget{ |
|
2400 </xsl:text> |
|
2401 <xsl:text> frequency = 10; |
|
2402 </xsl:text> |
|
2403 <xsl:text> range = undefined; |
|
2404 </xsl:text> |
|
2405 <xsl:text> |
|
2406 </xsl:text> |
|
2407 <xsl:text> dispatch(value) { |
|
2408 </xsl:text> |
|
2409 <xsl:text> this.display_val = value; |
|
2410 </xsl:text> |
|
2411 <xsl:text> this.request_animate(); |
|
2412 </xsl:text> |
|
2413 <xsl:text> } |
|
2414 </xsl:text> |
|
2415 <xsl:text> |
|
2416 </xsl:text> |
|
2417 <xsl:text> animate(){ |
|
2418 </xsl:text> |
|
2419 <xsl:text> if(this.value_elt) |
|
2420 </xsl:text> |
|
2421 <xsl:text> this.value_elt.textContent = String(this.display_val); |
|
2422 </xsl:text> |
|
2423 <xsl:text> let [min,max,start,end] = this.range; |
|
2424 </xsl:text> |
|
2425 <xsl:text> let [cx,cy] = this.center; |
|
2426 </xsl:text> |
|
2427 <xsl:text> let [rx,ry] = this.proportions; |
|
2428 </xsl:text> |
|
2429 <xsl:text> let tip = start + (end-start)*Number(this.display_val)/(max-min); |
|
2430 </xsl:text> |
|
2431 <xsl:text> let size = 0; |
|
2432 </xsl:text> |
|
2433 <xsl:text> |
|
2434 </xsl:text> |
|
2435 <xsl:text> if (tip-start > Math.PI) |
|
2436 </xsl:text> |
|
2437 <xsl:text> size = 1; |
|
2438 </xsl:text> |
|
2439 <xsl:text> else |
|
2440 </xsl:text> |
|
2441 <xsl:text> size = 0; |
|
2442 </xsl:text> |
|
2443 <xsl:text> |
|
2444 </xsl:text> |
|
2445 <xsl:text> this.path_elt.setAttribute('d', "M "+(cx+rx*Math.cos(start))+","+(cy+ry*Math.sin(start))+ |
|
2446 </xsl:text> |
|
2447 <xsl:text> " A "+rx+","+ry+ |
|
2448 </xsl:text> |
|
2449 <xsl:text> " 0 "+size+ |
|
2450 </xsl:text> |
|
2451 <xsl:text> " 1 "+(cx+rx*Math.cos(tip))+","+(cy+ry*Math.sin(tip))); |
|
2452 </xsl:text> |
|
2453 <xsl:text> } |
|
2454 </xsl:text> |
|
2455 <xsl:text> |
|
2456 </xsl:text> |
|
2457 <xsl:text> init() { |
|
2458 </xsl:text> |
|
2459 <xsl:text> let [start, end, cx, cy, rx, ry] = ["start", "end", "cx", "cy", "rx", "ry"]. |
|
2460 </xsl:text> |
|
2461 <xsl:text> map(tag=>Number(this.path_elt.getAttribute('sodipodi:'+tag))) |
|
2462 </xsl:text> |
|
2463 <xsl:text> |
|
2464 </xsl:text> |
|
2465 <xsl:text> if (ry == 0) |
|
2466 </xsl:text> |
|
2467 <xsl:text> ry = rx; |
|
2468 </xsl:text> |
|
2469 <xsl:text> |
|
2470 </xsl:text> |
|
2471 <xsl:text> if (start > end) |
|
2472 </xsl:text> |
|
2473 <xsl:text> end = end + 2*Math.PI; |
|
2474 </xsl:text> |
|
2475 <xsl:text> |
|
2476 </xsl:text> |
|
2477 <xsl:text> let [min,max] = [[this.min_elt,0],[this.max_elt,100]].map(([elt,def],i)=>elt? |
|
2478 </xsl:text> |
|
2479 <xsl:text> Number(elt.textContent) : |
|
2480 </xsl:text> |
|
2481 <xsl:text> this.args.length >= i+1 ? this.args[i] : def); |
|
2482 </xsl:text> |
|
2483 <xsl:text> |
|
2484 </xsl:text> |
|
2485 <xsl:text> this.range = [min, max, start, end]; |
|
2486 </xsl:text> |
|
2487 <xsl:text> this.center = [cx, cy]; |
|
2488 </xsl:text> |
|
2489 <xsl:text> this.proportions = [rx, ry]; |
|
2490 </xsl:text> |
|
2491 <xsl:text> } |
|
2492 </xsl:text> |
|
2493 <xsl:text>} |
|
2494 </xsl:text> |
|
2495 </xsl:template> |
|
2496 <xsl:template match="widget[@type='CircularBar']" mode="widget_defs"> |
|
2497 <xsl:param name="hmi_element"/> |
|
2498 <xsl:call-template name="defs_by_labels"> |
|
2499 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
2500 <xsl:with-param name="labels"> |
|
2501 <xsl:text>path</xsl:text> |
|
2502 </xsl:with-param> |
|
2503 </xsl:call-template> |
|
2504 <xsl:call-template name="defs_by_labels"> |
|
2505 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
2506 <xsl:with-param name="labels"> |
|
2507 <xsl:text>value min max</xsl:text> |
|
2508 </xsl:with-param> |
|
2509 <xsl:with-param name="mandatory" select="'no'"/> |
|
2510 </xsl:call-template> |
|
2511 </xsl:template> |
|
2512 <xsl:template match="widget[@type='CircularSlider']" mode="widget_desc"> |
|
2513 <type> |
|
2514 <xsl:value-of select="@type"/> |
|
2515 </type> |
|
2516 <longdesc> |
|
2517 <xsl:text>CircularSlider - DEPRECATED, to be replaced by PathSlider |
|
2518 </xsl:text> |
|
2519 <xsl:text>This widget moves "handle" labeled group along "range" labeled |
|
2520 </xsl:text> |
|
2521 <xsl:text>arc, according to value of the single accepted variable. |
|
2522 </xsl:text> |
|
2523 <xsl:text> |
|
2524 </xsl:text> |
|
2525 <xsl:text>If "min" a "max" labeled texts are provided, or if first and second |
|
2526 </xsl:text> |
|
2527 <xsl:text>argument are given, then they are used as respective minimum and maximum |
|
2528 </xsl:text> |
|
2529 <xsl:text>value. Otherwise, value is expected to be in between 0 and 100. |
|
2530 </xsl:text> |
|
2531 <xsl:text> |
|
2532 </xsl:text> |
|
2533 <xsl:text>If "value" labeled text is found, then its content is replaced by value. |
|
2534 </xsl:text> |
|
2535 <xsl:text>During drag, "setpoint" labeled group is moved to position defined by user |
|
2536 </xsl:text> |
|
2537 <xsl:text>while "handle" reflects current value from variable. |
|
2538 </xsl:text> |
|
2539 </longdesc> |
|
2540 <shortdesc> |
|
2541 <xsl:text>CircularSlider - DEPRECATED</xsl:text> |
|
2542 </shortdesc> |
|
2543 <arg name="min" count="optional" accepts="int,real"> |
|
2544 <xsl:text>minimum value</xsl:text> |
|
2545 </arg> |
|
2546 <arg name="min" count="optional" accepts="int,real"> |
|
2547 <xsl:text>maximum value</xsl:text> |
|
2548 </arg> |
|
2549 <path name="value" accepts="HMI_INT,HMI_REAL"> |
|
2550 <xsl:text>Value to display</xsl:text> |
|
2551 </path> |
|
2552 </xsl:template> |
|
2553 <xsl:template match="widget[@type='CircularSlider']" mode="widget_class"> |
|
2554 <xsl:text>class </xsl:text> |
|
2555 <xsl:text>CircularSliderWidget</xsl:text> |
|
2556 <xsl:text> extends Widget{ |
|
2557 </xsl:text> |
|
2558 <xsl:text> frequency = 5; |
|
2559 </xsl:text> |
|
2560 <xsl:text> range = undefined; |
|
2561 </xsl:text> |
|
2562 <xsl:text> circle = undefined; |
|
2563 </xsl:text> |
|
2564 <xsl:text> handle_pos = undefined; |
|
2565 </xsl:text> |
|
2566 <xsl:text> curr_value = 0; |
|
2567 </xsl:text> |
|
2568 <xsl:text> drag = false; |
|
2569 </xsl:text> |
|
2570 <xsl:text> enTimer = false; |
|
2571 </xsl:text> |
|
2572 <xsl:text> last_drag = false; |
|
2573 </xsl:text> |
|
2574 <xsl:text> |
|
2575 </xsl:text> |
|
2576 <xsl:text> dispatch(value) { |
|
2577 </xsl:text> |
|
2578 <xsl:text> let [min,max,start,totallength] = this.range; |
|
2579 </xsl:text> |
|
2580 <xsl:text> //save current value inside widget |
|
2581 </xsl:text> |
|
2582 <xsl:text> this.curr_value = value; |
|
2583 </xsl:text> |
|
2584 <xsl:text> |
|
2585 </xsl:text> |
|
2586 <xsl:text> //check if in range |
|
2587 </xsl:text> |
|
2588 <xsl:text> if (this.curr_value > max){ |
|
2589 </xsl:text> |
|
2590 <xsl:text> this.curr_value = max; |
|
2591 </xsl:text> |
|
2592 <xsl:text> this.apply_hmi_value(0, this.curr_value); |
|
2593 </xsl:text> |
|
2594 <xsl:text> } |
|
2595 </xsl:text> |
|
2596 <xsl:text> else if (this.curr_value < min){ |
|
2597 </xsl:text> |
|
2598 <xsl:text> this.curr_value = min; |
|
2599 </xsl:text> |
|
2600 <xsl:text> this.apply_hmi_value(0, this.curr_value); |
|
2601 </xsl:text> |
|
2602 <xsl:text> } |
|
2603 </xsl:text> |
|
2604 <xsl:text> |
|
2605 </xsl:text> |
|
2606 <xsl:text> if(this.value_elt) |
|
2607 </xsl:text> |
|
2608 <xsl:text> this.value_elt.textContent = String(value); |
|
2609 </xsl:text> |
|
2610 <xsl:text> |
|
2611 </xsl:text> |
|
2612 <xsl:text> //don't update if draging and setpoint ghost doesn't exist |
|
2613 </xsl:text> |
|
2614 <xsl:text> if(!this.drag || (this.setpoint_elt != undefined)){ |
|
2615 </xsl:text> |
|
2616 <xsl:text> this.update_DOM(value, this.handle_elt); |
|
2617 </xsl:text> |
|
2618 <xsl:text> } |
|
2619 </xsl:text> |
|
2620 <xsl:text> } |
|
2621 </xsl:text> |
|
2622 <xsl:text> |
|
2623 </xsl:text> |
|
2624 <xsl:text> update_DOM(value, elt){ |
|
2625 </xsl:text> |
|
2626 <xsl:text> let [min,max,totalDistance] = this.range; |
|
2627 </xsl:text> |
|
2628 <xsl:text> let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance))); |
|
2629 </xsl:text> |
|
2630 <xsl:text> let tip = this.range_elt.getPointAtLength(length); |
|
2631 </xsl:text> |
|
2632 <xsl:text> elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")"); |
|
2633 </xsl:text> |
|
2634 <xsl:text> |
|
2635 </xsl:text> |
|
2636 <xsl:text> // show or hide ghost if exists |
|
2637 </xsl:text> |
|
2638 <xsl:text> if(this.setpoint_elt != undefined){ |
|
2639 </xsl:text> |
|
2640 <xsl:text> if(this.last_drag!= this.drag){ |
|
2641 </xsl:text> |
|
2642 <xsl:text> if(this.drag){ |
|
2643 </xsl:text> |
|
2644 <xsl:text> this.setpoint_elt.setAttribute("style", this.setpoint_style); |
|
2645 </xsl:text> |
|
2646 <xsl:text> }else{ |
|
2647 </xsl:text> |
|
2648 <xsl:text> this.setpoint_elt.setAttribute("style", "display:none"); |
|
2649 </xsl:text> |
|
2650 <xsl:text> } |
|
2651 </xsl:text> |
|
2652 <xsl:text> this.last_drag = this.drag; |
|
2653 </xsl:text> |
|
2654 <xsl:text> } |
|
2655 </xsl:text> |
|
2656 <xsl:text> } |
|
2657 </xsl:text> |
|
2658 <xsl:text> } |
|
2659 </xsl:text> |
|
2660 <xsl:text> |
|
2661 </xsl:text> |
|
2662 <xsl:text> on_release(evt) { |
|
2663 </xsl:text> |
|
2664 <xsl:text> //unbind events |
|
2665 </xsl:text> |
|
2666 <xsl:text> window.removeEventListener("touchmove", this.on_bound_drag, true); |
|
2667 </xsl:text> |
|
2668 <xsl:text> window.removeEventListener("mousemove", this.on_bound_drag, true); |
|
2669 </xsl:text> |
|
2670 <xsl:text> |
|
2671 </xsl:text> |
|
2672 <xsl:text> window.removeEventListener("mouseup", this.bound_on_release, true) |
|
2673 </xsl:text> |
|
2674 <xsl:text> window.removeEventListener("touchend", this.bound_on_release, true); |
|
2675 </xsl:text> |
|
2676 <xsl:text> window.removeEventListener("touchcancel", this.bound_on_release, true); |
|
2677 </xsl:text> |
|
2678 <xsl:text> |
|
2679 </xsl:text> |
|
2680 <xsl:text> //reset drag flag |
|
2681 </xsl:text> |
|
2682 <xsl:text> if(this.drag){ |
|
2683 </xsl:text> |
|
2684 <xsl:text> this.drag = false; |
|
2685 </xsl:text> |
|
2686 <xsl:text> } |
|
2687 </xsl:text> |
|
2688 <xsl:text> |
|
2689 </xsl:text> |
|
2690 <xsl:text> // get final position |
|
2691 </xsl:text> |
|
2692 <xsl:text> this.update_position(evt); |
|
2693 </xsl:text> |
|
2694 <xsl:text> } |
|
2695 </xsl:text> |
|
2696 <xsl:text> |
|
2697 </xsl:text> |
|
2698 <xsl:text> on_drag(evt){ |
|
2699 </xsl:text> |
|
2700 <xsl:text> //ignore drag event for X amount of time and if not selected |
|
2701 </xsl:text> |
|
2702 <xsl:text> if(this.enTimer && this.drag){ |
|
2703 </xsl:text> |
|
2704 <xsl:text> this.update_position(evt); |
|
2705 </xsl:text> |
|
2706 <xsl:text> |
|
2707 </xsl:text> |
|
2708 <xsl:text> //reset timer |
|
2709 </xsl:text> |
|
2710 <xsl:text> this.enTimer = false; |
|
2711 </xsl:text> |
|
2712 <xsl:text> setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); |
|
2713 </xsl:text> |
|
2714 <xsl:text> } |
|
2715 </xsl:text> |
|
2716 <xsl:text> } |
|
2717 </xsl:text> |
|
2718 <xsl:text> |
|
2719 </xsl:text> |
|
2720 <xsl:text> update_position(evt){ |
|
2721 </xsl:text> |
|
2722 <xsl:text> if(this.drag && this.enTimer){ |
|
2723 </xsl:text> |
|
2724 <xsl:text> var svg_dist = 0; |
|
2725 </xsl:text> |
|
2726 <xsl:text> |
|
2727 </xsl:text> |
|
2728 <xsl:text> //calculate center of widget in html |
|
2729 </xsl:text> |
|
2730 <xsl:text> // --TODO maybe it would be better to bind this part to window change size event ??? |
|
2731 </xsl:text> |
|
2732 <xsl:text> let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox; |
|
2733 </xsl:text> |
|
2734 <xsl:text> let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle; |
|
2735 </xsl:text> |
|
2736 <xsl:text> let htmlCirc = this.range_elt.getBoundingClientRect(); |
|
2737 </xsl:text> |
|
2738 <xsl:text> let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left; |
|
2739 </xsl:text> |
|
2740 <xsl:text> let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top; |
|
2741 </xsl:text> |
|
2742 <xsl:text> |
|
2743 </xsl:text> |
|
2744 <xsl:text> |
|
2745 </xsl:text> |
|
2746 <xsl:text> //get mouse coordinates |
|
2747 </xsl:text> |
|
2748 <xsl:text> let mouseX = undefined; |
|
2749 </xsl:text> |
|
2750 <xsl:text> let mouseY = undefined; |
|
2751 </xsl:text> |
|
2752 <xsl:text> if (evt.type.startsWith("touch")){ |
|
2753 </xsl:text> |
|
2754 <xsl:text> mouseX = Math.ceil(evt.touches[0].clientX); |
|
2755 </xsl:text> |
|
2756 <xsl:text> mouseY = Math.ceil(evt.touches[0].clientY); |
|
2757 </xsl:text> |
|
2758 <xsl:text> } |
|
2759 </xsl:text> |
|
2760 <xsl:text> else{ |
|
2761 </xsl:text> |
|
2762 <xsl:text> mouseX = evt.pageX; |
|
2763 </xsl:text> |
|
2764 <xsl:text> mouseY = evt.pageY; |
|
2765 </xsl:text> |
|
2766 <xsl:text> } |
|
2767 </xsl:text> |
|
2768 <xsl:text> |
|
2769 </xsl:text> |
|
2770 <xsl:text> //calculate angle |
|
2771 </xsl:text> |
|
2772 <xsl:text> let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml); |
|
2773 </xsl:text> |
|
2774 <xsl:text> |
|
2775 </xsl:text> |
|
2776 <xsl:text> // transform from 0 to 2PI |
|
2777 </xsl:text> |
|
2778 <xsl:text> if (fi > 0){ |
|
2779 </xsl:text> |
|
2780 <xsl:text> fi = 2*Math.PI-fi; |
|
2781 </xsl:text> |
|
2782 <xsl:text> } |
|
2783 </xsl:text> |
|
2784 <xsl:text> else{ |
|
2785 </xsl:text> |
|
2786 <xsl:text> fi = -fi; |
|
2787 </xsl:text> |
|
2788 <xsl:text> } |
|
2789 </xsl:text> |
|
2790 <xsl:text> |
|
2791 </xsl:text> |
|
2792 <xsl:text> //offset it to 0 |
|
2793 </xsl:text> |
|
2794 <xsl:text> fi = fi - fiStart; |
|
2795 </xsl:text> |
|
2796 <xsl:text> if (fi < 0){ |
|
2797 </xsl:text> |
|
2798 <xsl:text> fi = fi + 2*Math.PI; |
|
2799 </xsl:text> |
|
2800 <xsl:text> } |
|
2801 </xsl:text> |
|
2802 <xsl:text> |
|
2803 </xsl:text> |
|
2804 <xsl:text> //get handle distance from mouse position |
|
2805 </xsl:text> |
|
2806 <xsl:text> if(fi<fiEnd){ |
|
2807 </xsl:text> |
|
2808 <xsl:text> this.curr_value=(fi)/(fiEnd)*(this.range[1]-this.range[0]); |
|
2809 </xsl:text> |
|
2810 <xsl:text> } |
|
2811 </xsl:text> |
|
2812 <xsl:text> else if(fiEnd<fi && fi<fiEnd+minMax){ |
|
2813 </xsl:text> |
|
2814 <xsl:text> this.curr_value = this.range[1]; |
|
2815 </xsl:text> |
|
2816 <xsl:text> } |
|
2817 </xsl:text> |
|
2818 <xsl:text> else{ |
|
2819 </xsl:text> |
|
2820 <xsl:text> this.curr_value = this.range[0]; |
|
2821 </xsl:text> |
|
2822 <xsl:text> } |
|
2823 </xsl:text> |
|
2824 <xsl:text> |
|
2825 </xsl:text> |
|
2826 <xsl:text> //apply value to hmi |
|
2827 </xsl:text> |
|
2828 <xsl:text> this.apply_hmi_value(0, Math.ceil(this.curr_value)); |
|
2829 </xsl:text> |
|
2830 <xsl:text> |
|
2831 </xsl:text> |
|
2832 <xsl:text> //redraw handle |
|
2833 </xsl:text> |
|
2834 <xsl:text> this.request_animate(); |
|
2835 </xsl:text> |
|
2836 <xsl:text> |
|
2837 </xsl:text> |
|
2838 <xsl:text> } |
|
2839 </xsl:text> |
|
2840 <xsl:text> |
|
2841 </xsl:text> |
|
2842 <xsl:text> } |
|
2843 </xsl:text> |
|
2844 <xsl:text> |
|
2845 </xsl:text> |
|
2846 <xsl:text> animate(){ |
|
2847 </xsl:text> |
|
2848 <xsl:text> // redraw handle on screen refresh |
|
2849 </xsl:text> |
|
2850 <xsl:text> // check if setpoint(ghost) handle exsist otherwise update main handle |
|
2851 </xsl:text> |
|
2852 <xsl:text> if(this.setpoint_elt != undefined){ |
|
2853 </xsl:text> |
|
2854 <xsl:text> this.update_DOM(this.curr_value, this.setpoint_elt); |
|
2855 </xsl:text> |
|
2856 <xsl:text> } |
|
2857 </xsl:text> |
|
2858 <xsl:text> else{ |
|
2859 </xsl:text> |
|
2860 <xsl:text> this.update_DOM(this.curr_value, this.handle_elt); |
|
2861 </xsl:text> |
|
2862 <xsl:text> } |
|
2863 </xsl:text> |
|
2864 <xsl:text> } |
|
2865 </xsl:text> |
|
2866 <xsl:text> |
|
2867 </xsl:text> |
|
2868 <xsl:text> on_select(evt){ |
|
2869 </xsl:text> |
|
2870 <xsl:text> //enable drag flag and timer |
|
2871 </xsl:text> |
|
2872 <xsl:text> this.drag = true; |
|
2873 </xsl:text> |
|
2874 <xsl:text> this.enTimer = true; |
|
2875 </xsl:text> |
|
2876 <xsl:text> |
|
2877 </xsl:text> |
|
2878 <xsl:text> //bind events |
|
2879 </xsl:text> |
|
2880 <xsl:text> window.addEventListener("touchmove", this.on_bound_drag, true); |
|
2881 </xsl:text> |
|
2882 <xsl:text> window.addEventListener("mousemove", this.on_bound_drag, true); |
|
2883 </xsl:text> |
|
2884 <xsl:text> |
|
2885 </xsl:text> |
|
2886 <xsl:text> window.addEventListener("mouseup", this.bound_on_release, true); |
|
2887 </xsl:text> |
|
2888 <xsl:text> window.addEventListener("touchend", this.bound_on_release, true); |
|
2889 </xsl:text> |
|
2890 <xsl:text> window.addEventListener("touchcancel", this.bound_on_release, true); |
|
2891 </xsl:text> |
|
2892 <xsl:text> |
|
2893 </xsl:text> |
|
2894 <xsl:text> //update postion on mouse press |
|
2895 </xsl:text> |
|
2896 <xsl:text> this.update_position(evt); |
|
2897 </xsl:text> |
|
2898 <xsl:text> |
|
2899 </xsl:text> |
|
2900 <xsl:text> //prevent next events |
|
2901 </xsl:text> |
|
2902 <xsl:text> evt.stopPropagation(); |
|
2903 </xsl:text> |
|
2904 <xsl:text> } |
|
2905 </xsl:text> |
|
2906 <xsl:text> |
|
2907 </xsl:text> |
|
2908 <xsl:text> init() { |
|
2909 </xsl:text> |
|
2910 <xsl:text> //get min max |
|
2911 </xsl:text> |
|
2912 <xsl:text> let min = this.min_elt ? |
|
2913 </xsl:text> |
|
2914 <xsl:text> Number(this.min_elt.textContent) : |
|
2915 </xsl:text> |
|
2916 <xsl:text> this.args.length >= 1 ? this.args[0] : 0; |
|
2917 </xsl:text> |
|
2918 <xsl:text> let max = this.max_elt ? |
|
2919 </xsl:text> |
|
2920 <xsl:text> Number(this.max_elt.textContent) : |
|
2921 </xsl:text> |
|
2922 <xsl:text> this.args.length >= 2 ? this.args[1] : 100; |
|
2923 </xsl:text> |
|
2924 <xsl:text> |
|
2925 </xsl:text> |
|
2926 <xsl:text> //fiStart ==> offset |
|
2927 </xsl:text> |
|
2928 <xsl:text> let fiStart = Number(this.range_elt.getAttribute('sodipodi:start')); |
|
2929 </xsl:text> |
|
2930 <xsl:text> let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end')); |
|
2931 </xsl:text> |
|
2932 <xsl:text> fiEnd = fiEnd - fiStart; |
|
2933 </xsl:text> |
|
2934 <xsl:text> |
|
2935 </xsl:text> |
|
2936 <xsl:text> //fiEnd ==> size of angle |
|
2937 </xsl:text> |
|
2938 <xsl:text> if (fiEnd < 0){ |
|
2939 </xsl:text> |
|
2940 <xsl:text> fiEnd = 2*Math.PI + fiEnd; |
|
2941 </xsl:text> |
|
2942 <xsl:text> } |
|
2943 </xsl:text> |
|
2944 <xsl:text> |
|
2945 </xsl:text> |
|
2946 <xsl:text> //min max barrier angle |
|
2947 </xsl:text> |
|
2948 <xsl:text> let minMax = (2*Math.PI - fiEnd)/2; |
|
2949 </xsl:text> |
|
2950 <xsl:text> |
|
2951 </xsl:text> |
|
2952 <xsl:text> //get parameters from svg |
|
2953 </xsl:text> |
|
2954 <xsl:text> let cX = Number(this.range_elt.getAttribute('sodipodi:cx')); |
|
2955 </xsl:text> |
|
2956 <xsl:text> let cY = Number(this.range_elt.getAttribute('sodipodi:cy')); |
|
2957 </xsl:text> |
|
2958 <xsl:text> this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object |
|
2959 </xsl:text> |
|
2960 <xsl:text> this.range = [min, max,this.range_elt.getTotalLength()]; |
|
2961 </xsl:text> |
|
2962 <xsl:text> let cPos = this.range_elt.getBBox(); |
|
2963 </xsl:text> |
|
2964 <xsl:text> this.handle_pos = this.range_elt.getPointAtLength(0); |
|
2965 </xsl:text> |
|
2966 <xsl:text> this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height]; |
|
2967 </xsl:text> |
|
2968 <xsl:text> |
|
2969 </xsl:text> |
|
2970 <xsl:text> //bind functions |
|
2971 </xsl:text> |
|
2972 <xsl:text> this.bound_on_select = this.on_select.bind(this); |
|
2973 </xsl:text> |
|
2974 <xsl:text> this.bound_on_release = this.on_release.bind(this); |
|
2975 </xsl:text> |
|
2976 <xsl:text> this.on_bound_drag = this.on_drag.bind(this); |
|
2977 </xsl:text> |
|
2978 <xsl:text> |
|
2979 </xsl:text> |
|
2980 <xsl:text> this.handle_elt.addEventListener("mousedown", this.bound_on_select); |
|
2981 </xsl:text> |
|
2982 <xsl:text> this.element.addEventListener("mousedown", this.bound_on_select); |
|
2983 </xsl:text> |
|
2984 <xsl:text> this.element.addEventListener("touchstart", this.bound_on_select); |
|
2985 </xsl:text> |
|
2986 <xsl:text> //touch recognised as page drag without next command |
|
2987 </xsl:text> |
|
2988 <xsl:text> document.body.addEventListener("touchstart", function(e){}, false); |
|
2989 </xsl:text> |
|
2990 <xsl:text> |
|
2991 </xsl:text> |
|
2992 <xsl:text> //save ghost style |
|
2993 </xsl:text> |
|
2994 <xsl:text> //save ghost style |
|
2995 </xsl:text> |
|
2996 <xsl:text> if(this.setpoint_elt != undefined){ |
|
2997 </xsl:text> |
|
2998 <xsl:text> this.setpoint_style = this.setpoint_elt.getAttribute("style"); |
|
2999 </xsl:text> |
|
3000 <xsl:text> this.setpoint_elt.setAttribute("style", "display:none"); |
|
3001 </xsl:text> |
|
3002 <xsl:text> } |
|
3003 </xsl:text> |
|
3004 <xsl:text> |
|
3005 </xsl:text> |
|
3006 <xsl:text> } |
|
3007 </xsl:text> |
|
3008 <xsl:text>} |
|
3009 </xsl:text> |
|
3010 </xsl:template> |
|
3011 <xsl:template match="widget[@type='CircularSlider']" mode="widget_defs"> |
|
3012 <xsl:param name="hmi_element"/> |
|
3013 <xsl:call-template name="defs_by_labels"> |
|
3014 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
3015 <xsl:with-param name="labels"> |
|
3016 <xsl:text>handle range</xsl:text> |
|
3017 </xsl:with-param> |
|
3018 </xsl:call-template> |
|
3019 <xsl:call-template name="defs_by_labels"> |
|
3020 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
3021 <xsl:with-param name="labels"> |
|
3022 <xsl:text>value min max setpoint</xsl:text> |
|
3023 </xsl:with-param> |
|
3024 <xsl:with-param name="mandatory" select="'no'"/> |
|
3025 </xsl:call-template> |
|
3026 <xsl:text> |
|
3027 </xsl:text> |
|
3028 </xsl:template> |
|
3029 <xsl:template match="widget[@type='CustomHtml']" mode="widget_desc"> |
|
3030 <type> |
|
3031 <xsl:value-of select="@type"/> |
|
3032 </type> |
|
3033 <longdesc> |
|
3034 <xsl:text>CustomHtml widget allows insertion of HTML code in a svg:foreignObject. |
|
3035 </xsl:text> |
|
3036 <xsl:text>Widget content is replaced by foreignObject. HTML code is obtained from |
|
3037 </xsl:text> |
|
3038 <xsl:text>"code" labeled text content. HTML insert position and size is given with |
|
3039 </xsl:text> |
|
3040 <xsl:text>"container" labeled element. |
|
3041 </xsl:text> |
|
3042 </longdesc> |
|
3043 <shortdesc> |
|
3044 <xsl:text>Custom HTML insert</xsl:text> |
|
3045 </shortdesc> |
|
3046 </xsl:template> |
|
3047 <xsl:template match="widget[@type='CustomHtml']" mode="widget_class"> |
|
3048 <xsl:text>class </xsl:text> |
|
3049 <xsl:text>CustomHtmlWidget</xsl:text> |
|
3050 <xsl:text> extends Widget{ |
|
3051 </xsl:text> |
|
3052 <xsl:text> frequency = 5; |
|
3053 </xsl:text> |
|
3054 <xsl:text> widget_size = undefined; |
|
3055 </xsl:text> |
|
3056 <xsl:text> |
|
3057 </xsl:text> |
|
3058 <xsl:text> dispatch(value) { |
|
3059 </xsl:text> |
|
3060 <xsl:text> this.request_animate(); |
|
3061 </xsl:text> |
|
3062 <xsl:text> } |
|
3063 </xsl:text> |
|
3064 <xsl:text> |
|
3065 </xsl:text> |
|
3066 <xsl:text> animate(){ |
|
3067 </xsl:text> |
|
3068 <xsl:text> } |
|
3069 </xsl:text> |
|
3070 <xsl:text> |
|
3071 </xsl:text> |
|
3072 <xsl:text> init() { |
|
3073 </xsl:text> |
|
3074 <xsl:text> this.widget_size = this.container_elt.getBBox(); |
|
3075 </xsl:text> |
|
3076 <xsl:text> this.element.innerHTML ='<foreignObject x="'+ |
|
3077 </xsl:text> |
|
3078 <xsl:text> this.widget_size.x+'" y="'+this.widget_size.y+ |
|
3079 </xsl:text> |
|
3080 <xsl:text> '" width="'+this.widget_size.width+'" height="'+this.widget_size.height+'"> '+ |
|
3081 </xsl:text> |
|
3082 <xsl:text> this.code_elt.textContent+ |
|
3083 </xsl:text> |
|
3084 <xsl:text> ' </foreignObject>'; |
|
3085 </xsl:text> |
|
3086 <xsl:text> } |
|
3087 </xsl:text> |
|
3088 <xsl:text>} |
|
3089 </xsl:text> |
|
3090 </xsl:template> |
|
3091 <xsl:template match="widget[@type='CustomHtml']" mode="widget_defs"> |
|
3092 <xsl:param name="hmi_element"/> |
|
3093 <xsl:call-template name="defs_by_labels"> |
|
3094 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
3095 <xsl:with-param name="labels"> |
|
3096 <xsl:text>container code</xsl:text> |
|
3097 </xsl:with-param> |
|
3098 </xsl:call-template> |
|
3099 </xsl:template> |
|
3100 <xsl:template match="widget[@type='Display']" mode="widget_desc"> |
|
3101 <type> |
|
3102 <xsl:value-of select="@type"/> |
|
3103 </type> |
|
3104 <longdesc> |
|
3105 <xsl:text>If Display widget is a svg:text element, then text content is replaced by |
|
3106 </xsl:text> |
|
3107 <xsl:text>value of given variables, space separated. |
|
3108 </xsl:text> |
|
3109 <xsl:text> |
|
3110 </xsl:text> |
|
3111 <xsl:text>Otherwise, if Display widget is a group containing a svg:text element |
|
3112 </xsl:text> |
|
3113 <xsl:text>labelled "format", then text content is replaced by printf-like formated |
|
3114 </xsl:text> |
|
3115 <xsl:text>string. In other words, if "format" labeled text is "%d %s %f", then 3 |
|
3116 </xsl:text> |
|
3117 <xsl:text>variables paths are expected : HMI_IN, HMI_STRING and HMI_REAL. |
|
3118 </xsl:text> |
|
3119 <xsl:text> |
|
3120 </xsl:text> |
|
3121 <xsl:text>In case Display widget is a svg::text element, it is also possible to give |
|
3122 </xsl:text> |
|
3123 <xsl:text>format string as first argument. |
|
3124 </xsl:text> |
|
3125 </longdesc> |
|
3126 <shortdesc> |
|
3127 <xsl:text>Printf-like formated text display </xsl:text> |
|
3128 </shortdesc> |
|
3129 <arg name="format" count="optional" accepts="string"> |
|
3130 <xsl:text>printf-like format string when not given as svg:text</xsl:text> |
|
3131 </arg> |
|
3132 <path name="fields" count="many" accepts="HMI_INT,HMI_REAL,HMI_STRING,HMI_BOOL"> |
|
3133 <xsl:text>variables to be displayed</xsl:text> |
|
3134 </path> |
|
3135 </xsl:template> |
|
3136 <xsl:template match="widget[@type='Display']" mode="widget_class"> |
|
3137 <xsl:text>class </xsl:text> |
|
3138 <xsl:text>DisplayWidget</xsl:text> |
|
3139 <xsl:text> extends Widget{ |
|
3140 </xsl:text> |
|
3141 <xsl:text> frequency = 5; |
|
3142 </xsl:text> |
|
3143 <xsl:text> dispatch(value, oldval, index) { |
|
3144 </xsl:text> |
|
3145 <xsl:text> this.fields[index] = value; |
|
3146 </xsl:text> |
|
3147 <xsl:text> this.request_animate(); |
|
3148 </xsl:text> |
|
3149 <xsl:text> } |
|
3150 </xsl:text> |
|
3151 <xsl:text>} |
|
3152 </xsl:text> |
|
3153 </xsl:template> |
|
3154 <xsl:template match="widget[@type='Display']" mode="widget_defs"> |
|
3155 <xsl:param name="hmi_element"/> |
|
3156 <xsl:variable name="format"> |
|
3157 <xsl:call-template name="defs_by_labels"> |
|
3158 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
3159 <xsl:with-param name="labels"> |
|
3160 <xsl:text>format</xsl:text> |
|
3161 </xsl:with-param> |
|
3162 <xsl:with-param name="mandatory" select="'no'"/> |
|
3163 </xsl:call-template> |
|
3164 </xsl:variable> |
|
3165 <xsl:variable name="has_format" select="string-length($format)>0"/> |
|
3166 <xsl:value-of select="$format"/> |
|
3167 <xsl:if test="$hmi_element[not(self::svg:text)] and not($has_format)"> |
|
3168 <xsl:message terminate="yes"> |
|
3169 <xsl:text>Display Widget id="</xsl:text> |
|
3170 <xsl:value-of select="$hmi_element/@id"/> |
|
3171 <xsl:text>" must be a svg::text element itself or a group containing a svg:text element labelled "format"</xsl:text> |
|
3172 </xsl:message> |
|
3173 </xsl:if> |
|
3174 <xsl:variable name="field_initializer"> |
|
3175 <xsl:for-each select="path"> |
|
3176 <xsl:choose> |
|
3177 <xsl:when test="@type='HMI_STRING'"> |
|
3178 <xsl:text>""</xsl:text> |
|
3179 </xsl:when> |
|
3180 <xsl:otherwise> |
|
3181 <xsl:text>0</xsl:text> |
|
3182 </xsl:otherwise> |
|
3183 </xsl:choose> |
|
3184 <xsl:if test="position()!=last()"> |
|
3185 <xsl:text>,</xsl:text> |
|
3186 </xsl:if> |
|
3187 </xsl:for-each> |
|
3188 </xsl:variable> |
|
3189 <xsl:text> fields: [</xsl:text> |
|
3190 <xsl:value-of select="$field_initializer"/> |
|
3191 <xsl:text>], |
|
3192 </xsl:text> |
|
3193 <xsl:text> animate: function(){ |
|
3194 </xsl:text> |
|
3195 <xsl:choose> |
|
3196 <xsl:when test="$has_format"> |
|
3197 <xsl:text> if(this.format_elt.getAttribute("lang")) { |
|
3198 </xsl:text> |
|
3199 <xsl:text> this.format = svg_text_to_multiline(this.format_elt); |
|
3200 </xsl:text> |
|
3201 <xsl:text> this.format_elt.removeAttribute("lang"); |
|
3202 </xsl:text> |
|
3203 <xsl:text> } |
|
3204 </xsl:text> |
|
3205 <xsl:text> let str = vsprintf(this.format,this.fields); |
|
3206 </xsl:text> |
|
3207 <xsl:text> multiline_to_svg_text(this.format_elt, str); |
|
3208 </xsl:text> |
|
3209 </xsl:when> |
|
3210 <xsl:otherwise> |
|
3211 <xsl:text> let str = this.args.length == 1 ? vsprintf(this.args[0],this.fields) : this.fields.join(' '); |
|
3212 </xsl:text> |
|
3213 <xsl:text> multiline_to_svg_text(this.element, str); |
|
3214 </xsl:text> |
|
3215 </xsl:otherwise> |
|
3216 </xsl:choose> |
|
3217 <xsl:text> }, |
|
3218 </xsl:text> |
|
3219 <xsl:text> |
|
3220 </xsl:text> |
|
3221 <xsl:if test="$has_format"> |
|
3222 <xsl:text> init: function() { |
|
3223 </xsl:text> |
|
3224 <xsl:text> this.format = svg_text_to_multiline(this.format_elt); |
|
3225 </xsl:text> |
|
3226 <xsl:text> }, |
|
3227 </xsl:text> |
|
3228 </xsl:if> |
|
3229 </xsl:template> |
|
3230 <preamble:display/> |
|
3231 <xsl:template match="preamble:display"> |
|
3232 <xsl:text> |
|
3233 </xsl:text> |
|
3234 <xsl:text>/* </xsl:text> |
|
3235 <xsl:value-of select="local-name()"/> |
|
3236 <xsl:text> */ |
|
3237 </xsl:text> |
|
3238 <xsl:text> |
|
3239 </xsl:text> |
|
3240 <xsl:text>/* https://github.com/alexei/sprintf.js/blob/master/src/sprintf.js */ |
|
3241 </xsl:text> |
|
3242 <xsl:text>/* global window, exports, define */ |
|
3243 </xsl:text> |
|
3244 <xsl:text> |
|
3245 </xsl:text> |
|
3246 <xsl:text>!function() { |
|
3247 </xsl:text> |
|
3248 <xsl:text> 'use strict' |
|
3249 </xsl:text> |
|
3250 <xsl:text> |
|
3251 </xsl:text> |
|
3252 <xsl:text> var re = { |
|
3253 </xsl:text> |
|
3254 <xsl:text> not_string: /[^s]/, |
|
3255 </xsl:text> |
|
3256 <xsl:text> not_bool: /[^t]/, |
|
3257 </xsl:text> |
|
3258 <xsl:text> not_type: /[^T]/, |
|
3259 </xsl:text> |
|
3260 <xsl:text> not_primitive: /[^v]/, |
|
3261 </xsl:text> |
|
3262 <xsl:text> number: /[diefg]/, |
|
3263 </xsl:text> |
|
3264 <xsl:text> numeric_arg: /[bcdiefguxX]/, |
|
3265 </xsl:text> |
|
3266 <xsl:text> json: /[j]/, |
|
3267 </xsl:text> |
|
3268 <xsl:text> not_json: /[^j]/, |
|
3269 </xsl:text> |
|
3270 <xsl:text> text: /^[^%]+/, |
|
3271 </xsl:text> |
|
3272 <xsl:text> modulo: /^%{2}/, |
|
3273 </xsl:text> |
|
3274 <xsl:text> placeholder: /^%(?:([1-9]\d*)\$|\(([^)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijostTuvxX])/, |
|
3275 </xsl:text> |
|
3276 <xsl:text> key: /^([a-z_][a-z_\d]*)/i, |
|
3277 </xsl:text> |
|
3278 <xsl:text> key_access: /^\.([a-z_][a-z_\d]*)/i, |
|
3279 </xsl:text> |
|
3280 <xsl:text> index_access: /^\[(\d+)\]/, |
|
3281 </xsl:text> |
|
3282 <xsl:text> sign: /^[+-]/ |
|
3283 </xsl:text> |
|
3284 <xsl:text> } |
|
3285 </xsl:text> |
|
3286 <xsl:text> |
|
3287 </xsl:text> |
|
3288 <xsl:text> function sprintf(key) { |
|
3289 </xsl:text> |
|
3290 <xsl:text> // arguments is not an array, but should be fine for this call |
|
3291 </xsl:text> |
|
3292 <xsl:text> return sprintf_format(sprintf_parse(key), arguments) |
|
3293 </xsl:text> |
|
3294 <xsl:text> } |
|
3295 </xsl:text> |
|
3296 <xsl:text> |
|
3297 </xsl:text> |
|
3298 <xsl:text> function vsprintf(fmt, argv) { |
|
3299 </xsl:text> |
|
3300 <xsl:text> return sprintf.apply(null, [fmt].concat(argv || [])) |
|
3301 </xsl:text> |
|
3302 <xsl:text> } |
|
3303 </xsl:text> |
|
3304 <xsl:text> |
|
3305 </xsl:text> |
|
3306 <xsl:text> function sprintf_format(parse_tree, argv) { |
|
3307 </xsl:text> |
|
3308 <xsl:text> var cursor = 1, tree_length = parse_tree.length, arg, output = '', i, k, ph, pad, pad_character, pad_length, is_positive, sign |
|
3309 </xsl:text> |
|
3310 <xsl:text> for (i = 0; i < tree_length; i++) { |
|
3311 </xsl:text> |
|
3312 <xsl:text> if (typeof parse_tree[i] === 'string') { |
|
3313 </xsl:text> |
|
3314 <xsl:text> output += parse_tree[i] |
|
3315 </xsl:text> |
|
3316 <xsl:text> } |
|
3317 </xsl:text> |
|
3318 <xsl:text> else if (typeof parse_tree[i] === 'object') { |
|
3319 </xsl:text> |
|
3320 <xsl:text> ph = parse_tree[i] // convenience purposes only |
|
3321 </xsl:text> |
|
3322 <xsl:text> if (ph.keys) { // keyword argument |
|
3323 </xsl:text> |
|
3324 <xsl:text> arg = argv[cursor] |
|
3325 </xsl:text> |
|
3326 <xsl:text> for (k = 0; k < ph.keys.length; k++) { |
|
3327 </xsl:text> |
|
3328 <xsl:text> if (arg == undefined) { |
|
3329 </xsl:text> |
|
3330 <xsl:text> throw new Error(sprintf('[sprintf] Cannot access property "%s" of undefined value "%s"', ph.keys[k], ph.keys[k-1])) |
|
3331 </xsl:text> |
|
3332 <xsl:text> } |
|
3333 </xsl:text> |
|
3334 <xsl:text> arg = arg[ph.keys[k]] |
|
3335 </xsl:text> |
|
3336 <xsl:text> } |
|
3337 </xsl:text> |
|
3338 <xsl:text> } |
|
3339 </xsl:text> |
|
3340 <xsl:text> else if (ph.param_no) { // positional argument (explicit) |
|
3341 </xsl:text> |
|
3342 <xsl:text> arg = argv[ph.param_no] |
|
3343 </xsl:text> |
|
3344 <xsl:text> } |
|
3345 </xsl:text> |
|
3346 <xsl:text> else { // positional argument (implicit) |
|
3347 </xsl:text> |
|
3348 <xsl:text> arg = argv[cursor++] |
|
3349 </xsl:text> |
|
3350 <xsl:text> } |
|
3351 </xsl:text> |
|
3352 <xsl:text> |
|
3353 </xsl:text> |
|
3354 <xsl:text> if (re.not_type.test(ph.type) && re.not_primitive.test(ph.type) && arg instanceof Function) { |
|
3355 </xsl:text> |
|
3356 <xsl:text> arg = arg() |
|
3357 </xsl:text> |
|
3358 <xsl:text> } |
|
3359 </xsl:text> |
|
3360 <xsl:text> |
|
3361 </xsl:text> |
|
3362 <xsl:text> if (re.numeric_arg.test(ph.type) && (typeof arg !== 'number' && isNaN(arg))) { |
|
3363 </xsl:text> |
|
3364 <xsl:text> throw new TypeError(sprintf('[sprintf] expecting number but found %T', arg)) |
|
3365 </xsl:text> |
|
3366 <xsl:text> } |
|
3367 </xsl:text> |
|
3368 <xsl:text> |
|
3369 </xsl:text> |
|
3370 <xsl:text> if (re.number.test(ph.type)) { |
|
3371 </xsl:text> |
|
3372 <xsl:text> is_positive = arg >= 0 |
|
3373 </xsl:text> |
|
3374 <xsl:text> } |
|
3375 </xsl:text> |
|
3376 <xsl:text> |
|
3377 </xsl:text> |
|
3378 <xsl:text> switch (ph.type) { |
|
3379 </xsl:text> |
|
3380 <xsl:text> case 'b': |
|
3381 </xsl:text> |
|
3382 <xsl:text> arg = parseInt(arg, 10).toString(2) |
|
3383 </xsl:text> |
|
3384 <xsl:text> break |
|
3385 </xsl:text> |
|
3386 <xsl:text> case 'c': |
|
3387 </xsl:text> |
|
3388 <xsl:text> arg = String.fromCharCode(parseInt(arg, 10)) |
|
3389 </xsl:text> |
|
3390 <xsl:text> break |
|
3391 </xsl:text> |
|
3392 <xsl:text> case 'd': |
|
3393 </xsl:text> |
|
3394 <xsl:text> case 'i': |
|
3395 </xsl:text> |
|
3396 <xsl:text> arg = parseInt(arg, 10) |
|
3397 </xsl:text> |
|
3398 <xsl:text> break |
|
3399 </xsl:text> |
|
3400 <xsl:text> case 'j': |
|
3401 </xsl:text> |
|
3402 <xsl:text> arg = JSON.stringify(arg, null, ph.width ? parseInt(ph.width) : 0) |
|
3403 </xsl:text> |
|
3404 <xsl:text> break |
|
3405 </xsl:text> |
|
3406 <xsl:text> case 'e': |
|
3407 </xsl:text> |
|
3408 <xsl:text> arg = ph.precision ? parseFloat(arg).toExponential(ph.precision) : parseFloat(arg).toExponential() |
|
3409 </xsl:text> |
|
3410 <xsl:text> break |
|
3411 </xsl:text> |
|
3412 <xsl:text> case 'f': |
|
3413 </xsl:text> |
|
3414 <xsl:text> arg = ph.precision ? parseFloat(arg).toFixed(ph.precision) : parseFloat(arg) |
|
3415 </xsl:text> |
|
3416 <xsl:text> break |
|
3417 </xsl:text> |
|
3418 <xsl:text> case 'g': |
|
3419 </xsl:text> |
|
3420 <xsl:text> arg = ph.precision ? String(Number(arg.toPrecision(ph.precision))) : parseFloat(arg) |
|
3421 </xsl:text> |
|
3422 <xsl:text> break |
|
3423 </xsl:text> |
|
3424 <xsl:text> case 'o': |
|
3425 </xsl:text> |
|
3426 <xsl:text> arg = (parseInt(arg, 10) >>> 0).toString(8) |
|
3427 </xsl:text> |
|
3428 <xsl:text> break |
|
3429 </xsl:text> |
|
3430 <xsl:text> case 's': |
|
3431 </xsl:text> |
|
3432 <xsl:text> arg = String(arg) |
|
3433 </xsl:text> |
|
3434 <xsl:text> arg = (ph.precision ? arg.substring(0, ph.precision) : arg) |
|
3435 </xsl:text> |
|
3436 <xsl:text> break |
|
3437 </xsl:text> |
|
3438 <xsl:text> case 't': |
|
3439 </xsl:text> |
|
3440 <xsl:text> arg = String(!!arg) |
|
3441 </xsl:text> |
|
3442 <xsl:text> arg = (ph.precision ? arg.substring(0, ph.precision) : arg) |
|
3443 </xsl:text> |
|
3444 <xsl:text> break |
|
3445 </xsl:text> |
|
3446 <xsl:text> case 'T': |
|
3447 </xsl:text> |
|
3448 <xsl:text> arg = Object.prototype.toString.call(arg).slice(8, -1).toLowerCase() |
|
3449 </xsl:text> |
|
3450 <xsl:text> arg = (ph.precision ? arg.substring(0, ph.precision) : arg) |
|
3451 </xsl:text> |
|
3452 <xsl:text> break |
|
3453 </xsl:text> |
|
3454 <xsl:text> case 'u': |
|
3455 </xsl:text> |
|
3456 <xsl:text> arg = parseInt(arg, 10) >>> 0 |
|
3457 </xsl:text> |
|
3458 <xsl:text> break |
|
3459 </xsl:text> |
|
3460 <xsl:text> case 'v': |
|
3461 </xsl:text> |
|
3462 <xsl:text> arg = arg.valueOf() |
|
3463 </xsl:text> |
|
3464 <xsl:text> arg = (ph.precision ? arg.substring(0, ph.precision) : arg) |
|
3465 </xsl:text> |
|
3466 <xsl:text> break |
|
3467 </xsl:text> |
|
3468 <xsl:text> case 'x': |
|
3469 </xsl:text> |
|
3470 <xsl:text> arg = (parseInt(arg, 10) >>> 0).toString(16) |
|
3471 </xsl:text> |
|
3472 <xsl:text> break |
|
3473 </xsl:text> |
|
3474 <xsl:text> case 'X': |
|
3475 </xsl:text> |
|
3476 <xsl:text> arg = (parseInt(arg, 10) >>> 0).toString(16).toUpperCase() |
|
3477 </xsl:text> |
|
3478 <xsl:text> break |
|
3479 </xsl:text> |
|
3480 <xsl:text> } |
|
3481 </xsl:text> |
|
3482 <xsl:text> if (re.json.test(ph.type)) { |
|
3483 </xsl:text> |
|
3484 <xsl:text> output += arg |
|
3485 </xsl:text> |
|
3486 <xsl:text> } |
|
3487 </xsl:text> |
|
3488 <xsl:text> else { |
|
3489 </xsl:text> |
|
3490 <xsl:text> if (re.number.test(ph.type) && (!is_positive || ph.sign)) { |
|
3491 </xsl:text> |
|
3492 <xsl:text> sign = is_positive ? '+' : '-' |
|
3493 </xsl:text> |
|
3494 <xsl:text> arg = arg.toString().replace(re.sign, '') |
|
3495 </xsl:text> |
|
3496 <xsl:text> } |
|
3497 </xsl:text> |
|
3498 <xsl:text> else { |
|
3499 </xsl:text> |
|
3500 <xsl:text> sign = '' |
|
3501 </xsl:text> |
|
3502 <xsl:text> } |
|
3503 </xsl:text> |
|
3504 <xsl:text> pad_character = ph.pad_char ? ph.pad_char === '0' ? '0' : ph.pad_char.charAt(1) : ' ' |
|
3505 </xsl:text> |
|
3506 <xsl:text> pad_length = ph.width - (sign + arg).length |
|
3507 </xsl:text> |
|
3508 <xsl:text> pad = ph.width ? (pad_length > 0 ? pad_character.repeat(pad_length) : '') : '' |
|
3509 </xsl:text> |
|
3510 <xsl:text> output += ph.align ? sign + arg + pad : (pad_character === '0' ? sign + pad + arg : pad + sign + arg) |
|
3511 </xsl:text> |
|
3512 <xsl:text> } |
|
3513 </xsl:text> |
|
3514 <xsl:text> } |
|
3515 </xsl:text> |
|
3516 <xsl:text> } |
|
3517 </xsl:text> |
|
3518 <xsl:text> return output |
|
3519 </xsl:text> |
|
3520 <xsl:text> } |
|
3521 </xsl:text> |
|
3522 <xsl:text> |
|
3523 </xsl:text> |
|
3524 <xsl:text> var sprintf_cache = Object.create(null) |
|
3525 </xsl:text> |
|
3526 <xsl:text> |
|
3527 </xsl:text> |
|
3528 <xsl:text> function sprintf_parse(fmt) { |
|
3529 </xsl:text> |
|
3530 <xsl:text> if (sprintf_cache[fmt]) { |
|
3531 </xsl:text> |
|
3532 <xsl:text> return sprintf_cache[fmt] |
|
3533 </xsl:text> |
|
3534 <xsl:text> } |
|
3535 </xsl:text> |
|
3536 <xsl:text> |
|
3537 </xsl:text> |
|
3538 <xsl:text> var _fmt = fmt, match, parse_tree = [], arg_names = 0 |
|
3539 </xsl:text> |
|
3540 <xsl:text> while (_fmt) { |
|
3541 </xsl:text> |
|
3542 <xsl:text> if ((match = re.text.exec(_fmt)) !== null) { |
|
3543 </xsl:text> |
|
3544 <xsl:text> parse_tree.push(match[0]) |
|
3545 </xsl:text> |
|
3546 <xsl:text> } |
|
3547 </xsl:text> |
|
3548 <xsl:text> else if ((match = re.modulo.exec(_fmt)) !== null) { |
|
3549 </xsl:text> |
|
3550 <xsl:text> parse_tree.push('%') |
|
3551 </xsl:text> |
|
3552 <xsl:text> } |
|
3553 </xsl:text> |
|
3554 <xsl:text> else if ((match = re.placeholder.exec(_fmt)) !== null) { |
|
3555 </xsl:text> |
|
3556 <xsl:text> if (match[2]) { |
|
3557 </xsl:text> |
|
3558 <xsl:text> arg_names |= 1 |
|
3559 </xsl:text> |
|
3560 <xsl:text> var field_list = [], replacement_field = match[2], field_match = [] |
|
3561 </xsl:text> |
|
3562 <xsl:text> if ((field_match = re.key.exec(replacement_field)) !== null) { |
|
3563 </xsl:text> |
|
3564 <xsl:text> field_list.push(field_match[1]) |
|
3565 </xsl:text> |
|
3566 <xsl:text> while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { |
|
3567 </xsl:text> |
|
3568 <xsl:text> if ((field_match = re.key_access.exec(replacement_field)) !== null) { |
|
3569 </xsl:text> |
|
3570 <xsl:text> field_list.push(field_match[1]) |
|
3571 </xsl:text> |
|
3572 <xsl:text> } |
|
3573 </xsl:text> |
|
3574 <xsl:text> else if ((field_match = re.index_access.exec(replacement_field)) !== null) { |
|
3575 </xsl:text> |
|
3576 <xsl:text> field_list.push(field_match[1]) |
|
3577 </xsl:text> |
|
3578 <xsl:text> } |
|
3579 </xsl:text> |
|
3580 <xsl:text> else { |
|
3581 </xsl:text> |
|
3582 <xsl:text> throw new SyntaxError('[sprintf] failed to parse named argument key') |
|
3583 </xsl:text> |
|
3584 <xsl:text> } |
|
3585 </xsl:text> |
|
3586 <xsl:text> } |
|
3587 </xsl:text> |
|
3588 <xsl:text> } |
|
3589 </xsl:text> |
|
3590 <xsl:text> else { |
|
3591 </xsl:text> |
|
3592 <xsl:text> throw new SyntaxError('[sprintf] failed to parse named argument key') |
|
3593 </xsl:text> |
|
3594 <xsl:text> } |
|
3595 </xsl:text> |
|
3596 <xsl:text> match[2] = field_list |
|
3597 </xsl:text> |
|
3598 <xsl:text> } |
|
3599 </xsl:text> |
|
3600 <xsl:text> else { |
|
3601 </xsl:text> |
|
3602 <xsl:text> arg_names |= 2 |
|
3603 </xsl:text> |
|
3604 <xsl:text> } |
|
3605 </xsl:text> |
|
3606 <xsl:text> if (arg_names === 3) { |
|
3607 </xsl:text> |
|
3608 <xsl:text> throw new Error('[sprintf] mixing positional and named placeholders is not (yet) supported') |
|
3609 </xsl:text> |
|
3610 <xsl:text> } |
|
3611 </xsl:text> |
|
3612 <xsl:text> |
|
3613 </xsl:text> |
|
3614 <xsl:text> parse_tree.push( |
|
3615 </xsl:text> |
|
3616 <xsl:text> { |
|
3617 </xsl:text> |
|
3618 <xsl:text> placeholder: match[0], |
|
3619 </xsl:text> |
|
3620 <xsl:text> param_no: match[1], |
|
3621 </xsl:text> |
|
3622 <xsl:text> keys: match[2], |
|
3623 </xsl:text> |
|
3624 <xsl:text> sign: match[3], |
|
3625 </xsl:text> |
|
3626 <xsl:text> pad_char: match[4], |
|
3627 </xsl:text> |
|
3628 <xsl:text> align: match[5], |
|
3629 </xsl:text> |
|
3630 <xsl:text> width: match[6], |
|
3631 </xsl:text> |
|
3632 <xsl:text> precision: match[7], |
|
3633 </xsl:text> |
|
3634 <xsl:text> type: match[8] |
|
3635 </xsl:text> |
|
3636 <xsl:text> } |
|
3637 </xsl:text> |
|
3638 <xsl:text> ) |
|
3639 </xsl:text> |
|
3640 <xsl:text> } |
|
3641 </xsl:text> |
|
3642 <xsl:text> else { |
|
3643 </xsl:text> |
|
3644 <xsl:text> throw new SyntaxError('[sprintf] unexpected placeholder') |
|
3645 </xsl:text> |
|
3646 <xsl:text> } |
|
3647 </xsl:text> |
|
3648 <xsl:text> _fmt = _fmt.substring(match[0].length) |
|
3649 </xsl:text> |
|
3650 <xsl:text> } |
|
3651 </xsl:text> |
|
3652 <xsl:text> return sprintf_cache[fmt] = parse_tree |
|
3653 </xsl:text> |
|
3654 <xsl:text> } |
|
3655 </xsl:text> |
|
3656 <xsl:text> |
|
3657 </xsl:text> |
|
3658 <xsl:text> /** |
|
3659 </xsl:text> |
|
3660 <xsl:text> * export to either browser or node.js |
|
3661 </xsl:text> |
|
3662 <xsl:text> */ |
|
3663 </xsl:text> |
|
3664 <xsl:text> /* eslint-disable quote-props */ |
|
3665 </xsl:text> |
|
3666 <xsl:text> if (typeof exports !== 'undefined') { |
|
3667 </xsl:text> |
|
3668 <xsl:text> exports['sprintf'] = sprintf |
|
3669 </xsl:text> |
|
3670 <xsl:text> exports['vsprintf'] = vsprintf |
|
3671 </xsl:text> |
|
3672 <xsl:text> } |
|
3673 </xsl:text> |
|
3674 <xsl:text> if (typeof window !== 'undefined') { |
|
3675 </xsl:text> |
|
3676 <xsl:text> window['sprintf'] = sprintf |
|
3677 </xsl:text> |
|
3678 <xsl:text> window['vsprintf'] = vsprintf |
|
3679 </xsl:text> |
|
3680 <xsl:text> |
|
3681 </xsl:text> |
|
3682 <xsl:text> if (typeof define === 'function' && define['amd']) { |
|
3683 </xsl:text> |
|
3684 <xsl:text> define(function() { |
|
3685 </xsl:text> |
|
3686 <xsl:text> return { |
|
3687 </xsl:text> |
|
3688 <xsl:text> 'sprintf': sprintf, |
|
3689 </xsl:text> |
|
3690 <xsl:text> 'vsprintf': vsprintf |
|
3691 </xsl:text> |
|
3692 <xsl:text> } |
|
3693 </xsl:text> |
|
3694 <xsl:text> }) |
|
3695 </xsl:text> |
|
3696 <xsl:text> } |
|
3697 </xsl:text> |
|
3698 <xsl:text> } |
|
3699 </xsl:text> |
|
3700 <xsl:text> /* eslint-enable quote-props */ |
|
3701 </xsl:text> |
|
3702 <xsl:text>}(); // eslint-disable-line |
|
3703 </xsl:text> |
|
3704 <xsl:text> |
|
3705 </xsl:text> |
|
3706 </xsl:template> |
|
3707 <xsl:template match="widget[@type='DropDown']" mode="widget_desc"> |
|
3708 <type> |
|
3709 <xsl:value-of select="@type"/> |
|
3710 </type> |
|
3711 <longdesc> |
|
3712 <xsl:text>DropDown widget let user select an entry in a list of texts, given as |
|
3713 </xsl:text> |
|
3714 <xsl:text>arguments. Single variable path is index of selection. |
|
3715 </xsl:text> |
|
3716 <xsl:text> |
|
3717 </xsl:text> |
|
3718 <xsl:text>It needs "text" (svg:text), "box" (svg:rect), "button" (svg:*), |
|
3719 </xsl:text> |
|
3720 <xsl:text>and "highlight" (svg:rect) labeled elements. |
|
3721 </xsl:text> |
|
3722 <xsl:text> |
|
3723 </xsl:text> |
|
3724 <xsl:text>When user clicks on "button", "text" is duplicated to display enties in the |
|
3725 </xsl:text> |
|
3726 <xsl:text>limit of available space in page, and "box" is extended to contain all |
|
3727 </xsl:text> |
|
3728 <xsl:text>texts. "highlight" is moved over pre-selected entry. |
|
3729 </xsl:text> |
|
3730 <xsl:text> |
|
3731 </xsl:text> |
|
3732 <xsl:text>When only one argument is given, and argment contains "#langs" then list of |
|
3733 </xsl:text> |
|
3734 <xsl:text>texts is automatically set to the list of human-readable languages supported |
|
3735 </xsl:text> |
|
3736 <xsl:text>by this HMI. |
|
3737 </xsl:text> |
|
3738 </longdesc> |
|
3739 <shortdesc> |
|
3740 <xsl:text>Let user select text entry in a drop-down menu</xsl:text> |
|
3741 </shortdesc> |
|
3742 <arg name="entries" count="many" accepts="string"> |
|
3743 <xsl:text>drop-down menu entries</xsl:text> |
|
3744 </arg> |
|
3745 <path name="selection" accepts="HMI_INT"> |
|
3746 <xsl:text>selection index</xsl:text> |
|
3747 </path> |
|
3748 </xsl:template> |
|
3749 <xsl:template match="widget[@type='DropDown']" mode="widget_class"> |
|
3750 <xsl:text>class </xsl:text> |
|
3751 <xsl:text>DropDownWidget</xsl:text> |
|
3752 <xsl:text> extends Widget{ |
|
3753 </xsl:text> |
|
3754 <xsl:text> dispatch(value) { |
|
3755 </xsl:text> |
|
3756 <xsl:text> if(!this.opened) this.set_selection(value); |
|
3757 </xsl:text> |
|
3758 <xsl:text> } |
|
3759 </xsl:text> |
|
3760 <xsl:text> init() { |
|
3761 </xsl:text> |
|
3762 <xsl:text> this.button_elt.onclick = this.on_button_click.bind(this); |
|
3763 </xsl:text> |
|
3764 <xsl:text> // Save original size of rectangle |
|
3765 </xsl:text> |
|
3766 <xsl:text> this.box_bbox = this.box_elt.getBBox() |
|
3767 </xsl:text> |
|
3768 <xsl:text> this.highlight_bbox = this.highlight_elt.getBBox() |
|
3769 </xsl:text> |
|
3770 <xsl:text> this.highlight_elt.style.visibility = "hidden"; |
|
3771 </xsl:text> |
|
3772 <xsl:text> |
|
3773 </xsl:text> |
|
3774 <xsl:text> // Compute margins |
|
3775 </xsl:text> |
|
3776 <xsl:text> this.text_bbox = this.text_elt.getBBox(); |
|
3777 </xsl:text> |
|
3778 <xsl:text> let lmargin = this.text_bbox.x - this.box_bbox.x; |
|
3779 </xsl:text> |
|
3780 <xsl:text> let tmargin = this.text_bbox.y - this.box_bbox.y; |
|
3781 </xsl:text> |
|
3782 <xsl:text> this.margins = [lmargin, tmargin].map(x => Math.max(x,0)); |
|
3783 </xsl:text> |
|
3784 <xsl:text> |
|
3785 </xsl:text> |
|
3786 <xsl:text> // Index of first visible element in the menu, when opened |
|
3787 </xsl:text> |
|
3788 <xsl:text> this.menu_offset = 0; |
|
3789 </xsl:text> |
|
3790 <xsl:text> |
|
3791 </xsl:text> |
|
3792 <xsl:text> // How mutch to lift the menu vertically so that it does not cross bottom border |
|
3793 </xsl:text> |
|
3794 <xsl:text> this.lift = 0; |
|
3795 </xsl:text> |
|
3796 <xsl:text> |
|
3797 </xsl:text> |
|
3798 <xsl:text> // Event handlers cannot be object method ('this' is unknown) |
|
3799 </xsl:text> |
|
3800 <xsl:text> // as a workaround, handler given to addEventListener is bound in advance. |
|
3801 </xsl:text> |
|
3802 <xsl:text> this.bound_close_on_click_elsewhere = this.close_on_click_elsewhere.bind(this); |
|
3803 </xsl:text> |
|
3804 <xsl:text> this.bound_on_selection_click = this.on_selection_click.bind(this); |
|
3805 </xsl:text> |
|
3806 <xsl:text> this.bound_on_backward_click = this.on_backward_click.bind(this); |
|
3807 </xsl:text> |
|
3808 <xsl:text> this.bound_on_forward_click = this.on_forward_click.bind(this); |
|
3809 </xsl:text> |
|
3810 <xsl:text> this.opened = false; |
|
3811 </xsl:text> |
|
3812 <xsl:text> this.clickables = []; |
|
3813 </xsl:text> |
|
3814 <xsl:text> } |
|
3815 </xsl:text> |
|
3816 <xsl:text> on_button_click() { |
|
3817 </xsl:text> |
|
3818 <xsl:text> this.open(); |
|
3819 </xsl:text> |
|
3820 <xsl:text> } |
|
3821 </xsl:text> |
|
3822 <xsl:text> // Called when a menu entry is clicked |
|
3823 </xsl:text> |
|
3824 <xsl:text> on_selection_click(selection) { |
|
3825 </xsl:text> |
|
3826 <xsl:text> this.close(); |
|
3827 </xsl:text> |
|
3828 <xsl:text> this.apply_hmi_value(0, selection); |
|
3829 </xsl:text> |
|
3830 <xsl:text> } |
|
3831 </xsl:text> |
|
3832 <xsl:text> on_backward_click(){ |
|
3833 </xsl:text> |
|
3834 <xsl:text> this.scroll(false); |
|
3835 </xsl:text> |
|
3836 <xsl:text> } |
|
3837 </xsl:text> |
|
3838 <xsl:text> on_forward_click(){ |
|
3839 </xsl:text> |
|
3840 <xsl:text> this.scroll(true); |
|
3841 </xsl:text> |
|
3842 <xsl:text> } |
|
3843 </xsl:text> |
|
3844 <xsl:text> set_selection(value) { |
|
3845 </xsl:text> |
|
3846 <xsl:text> let display_str; |
|
3847 </xsl:text> |
|
3848 <xsl:text> if(value >= 0 && value < this.content.length){ |
|
3849 </xsl:text> |
|
3850 <xsl:text> // if valid selection resolve content |
|
3851 </xsl:text> |
|
3852 <xsl:text> display_str = this.content[value]; |
|
3853 </xsl:text> |
|
3854 <xsl:text> this.last_selection = value; |
|
3855 </xsl:text> |
|
3856 <xsl:text> } else { |
|
3857 </xsl:text> |
|
3858 <xsl:text> // otherwise show problem |
|
3859 </xsl:text> |
|
3860 <xsl:text> display_str = "?"+String(value)+"?"; |
|
3861 </xsl:text> |
|
3862 <xsl:text> } |
|
3863 </xsl:text> |
|
3864 <xsl:text> // It is assumed that first span always stays, |
|
3865 </xsl:text> |
|
3866 <xsl:text> // and contains selection when menu is closed |
|
3867 </xsl:text> |
|
3868 <xsl:text> this.text_elt.firstElementChild.textContent = display_str; |
|
3869 </xsl:text> |
|
3870 <xsl:text> } |
|
3871 </xsl:text> |
|
3872 <xsl:text> grow_text(up_to) { |
|
3873 </xsl:text> |
|
3874 <xsl:text> let count = 1; |
|
3875 </xsl:text> |
|
3876 <xsl:text> let txt = this.text_elt; |
|
3877 </xsl:text> |
|
3878 <xsl:text> let first = txt.firstElementChild; |
|
3879 </xsl:text> |
|
3880 <xsl:text> // Real world (pixels) boundaries of current page |
|
3881 </xsl:text> |
|
3882 <xsl:text> let bounds = svg_root.getBoundingClientRect(); |
|
3883 </xsl:text> |
|
3884 <xsl:text> this.lift = 0; |
|
3885 </xsl:text> |
|
3886 <xsl:text> while(count < up_to) { |
|
3887 </xsl:text> |
|
3888 <xsl:text> let next = first.cloneNode(); |
|
3889 </xsl:text> |
|
3890 <xsl:text> // relative line by line text flow instead of absolute y coordinate |
|
3891 </xsl:text> |
|
3892 <xsl:text> next.removeAttribute("y"); |
|
3893 </xsl:text> |
|
3894 <xsl:text> next.setAttribute("dy", "1.1em"); |
|
3895 </xsl:text> |
|
3896 <xsl:text> // default content to allow computing text element bbox |
|
3897 </xsl:text> |
|
3898 <xsl:text> next.textContent = "..."; |
|
3899 </xsl:text> |
|
3900 <xsl:text> // append new span to text element |
|
3901 </xsl:text> |
|
3902 <xsl:text> txt.appendChild(next); |
|
3903 </xsl:text> |
|
3904 <xsl:text> // now check if text extended by one row fits to page |
|
3905 </xsl:text> |
|
3906 <xsl:text> // FIXME : exclude margins to be more accurate on box size |
|
3907 </xsl:text> |
|
3908 <xsl:text> let rect = txt.getBoundingClientRect(); |
|
3909 </xsl:text> |
|
3910 <xsl:text> if(rect.bottom > bounds.bottom){ |
|
3911 </xsl:text> |
|
3912 <xsl:text> // in case of overflow at the bottom, lift up one row |
|
3913 </xsl:text> |
|
3914 <xsl:text> let backup = first.getAttribute("dy"); |
|
3915 </xsl:text> |
|
3916 <xsl:text> // apply lift as a dy added too first span (y attrib stays) |
|
3917 </xsl:text> |
|
3918 <xsl:text> first.setAttribute("dy", "-"+String((this.lift+1)*1.1)+"em"); |
|
3919 </xsl:text> |
|
3920 <xsl:text> rect = txt.getBoundingClientRect(); |
|
3921 </xsl:text> |
|
3922 <xsl:text> if(rect.top > bounds.top){ |
|
3923 </xsl:text> |
|
3924 <xsl:text> this.lift += 1; |
|
3925 </xsl:text> |
|
3926 <xsl:text> } else { |
|
3927 </xsl:text> |
|
3928 <xsl:text> // if it goes over the top, then backtrack |
|
3929 </xsl:text> |
|
3930 <xsl:text> // restore dy attribute on first span |
|
3931 </xsl:text> |
|
3932 <xsl:text> if(backup) |
|
3933 </xsl:text> |
|
3934 <xsl:text> first.setAttribute("dy", backup); |
|
3935 </xsl:text> |
|
3936 <xsl:text> else |
|
3937 </xsl:text> |
|
3938 <xsl:text> first.removeAttribute("dy"); |
|
3939 </xsl:text> |
|
3940 <xsl:text> // remove unwanted child |
|
3941 </xsl:text> |
|
3942 <xsl:text> txt.removeChild(next); |
|
3943 </xsl:text> |
|
3944 <xsl:text> return count; |
|
3945 </xsl:text> |
|
3946 <xsl:text> } |
|
3947 </xsl:text> |
|
3948 <xsl:text> } |
|
3949 </xsl:text> |
|
3950 <xsl:text> count++; |
|
3951 </xsl:text> |
|
3952 <xsl:text> } |
|
3953 </xsl:text> |
|
3954 <xsl:text> return count; |
|
3955 </xsl:text> |
|
3956 <xsl:text> } |
|
3957 </xsl:text> |
|
3958 <xsl:text> close_on_click_elsewhere(e) { |
|
3959 </xsl:text> |
|
3960 <xsl:text> // inhibit events not targetting spans (menu items) |
|
3961 </xsl:text> |
|
3962 <xsl:text> if([this.text_elt, this.element].indexOf(e.target.parentNode) == -1){ |
|
3963 </xsl:text> |
|
3964 <xsl:text> e.stopPropagation(); |
|
3965 </xsl:text> |
|
3966 <xsl:text> // close menu in case click is outside box |
|
3967 </xsl:text> |
|
3968 <xsl:text> if(e.target !== this.box_elt) |
|
3969 </xsl:text> |
|
3970 <xsl:text> this.close(); |
|
3971 </xsl:text> |
|
3972 <xsl:text> } |
|
3973 </xsl:text> |
|
3974 <xsl:text> } |
|
3975 </xsl:text> |
|
3976 <xsl:text> close(){ |
|
3977 </xsl:text> |
|
3978 <xsl:text> // Stop hogging all click events |
|
3979 </xsl:text> |
|
3980 <xsl:text> svg_root.removeEventListener("pointerdown", this.numb_event, true); |
|
3981 </xsl:text> |
|
3982 <xsl:text> svg_root.removeEventListener("pointerup", this.numb_event, true); |
|
3983 </xsl:text> |
|
3984 <xsl:text> svg_root.removeEventListener("click", this.bound_close_on_click_elsewhere, true); |
|
3985 </xsl:text> |
|
3986 <xsl:text> // Restore position and sixe of widget elements |
|
3987 </xsl:text> |
|
3988 <xsl:text> this.reset_text(); |
|
3989 </xsl:text> |
|
3990 <xsl:text> this.reset_clickables(); |
|
3991 </xsl:text> |
|
3992 <xsl:text> this.reset_box(); |
|
3993 </xsl:text> |
|
3994 <xsl:text> this.reset_highlight(); |
|
3995 </xsl:text> |
|
3996 <xsl:text> // Put the button back in place |
|
3997 </xsl:text> |
|
3998 <xsl:text> this.element.appendChild(this.button_elt); |
|
3999 </xsl:text> |
|
4000 <xsl:text> // Mark as closed (to allow dispatch) |
|
4001 </xsl:text> |
|
4002 <xsl:text> this.opened = false; |
|
4003 </xsl:text> |
|
4004 <xsl:text> // Dispatch last cached value |
|
4005 </xsl:text> |
|
4006 <xsl:text> this.apply_cache(); |
|
4007 </xsl:text> |
|
4008 <xsl:text> } |
|
4009 </xsl:text> |
|
4010 <xsl:text> // Make item (text span) clickable by overlaying a rectangle on top of it |
|
4011 </xsl:text> |
|
4012 <xsl:text> make_clickable(span, func) { |
|
4013 </xsl:text> |
|
4014 <xsl:text> let txt = this.text_elt; |
|
4015 </xsl:text> |
|
4016 <xsl:text> let original_text_y = this.text_bbox.y; |
|
4017 </xsl:text> |
|
4018 <xsl:text> let highlight = this.highlight_elt; |
|
4019 </xsl:text> |
|
4020 <xsl:text> let original_h_y = this.highlight_bbox.y; |
|
4021 </xsl:text> |
|
4022 <xsl:text> let clickable = highlight.cloneNode(); |
|
4023 </xsl:text> |
|
4024 <xsl:text> let yoffset = span.getBBox().y - original_text_y; |
|
4025 </xsl:text> |
|
4026 <xsl:text> clickable.y.baseVal.value = original_h_y + yoffset; |
|
4027 </xsl:text> |
|
4028 <xsl:text> clickable.style.pointerEvents = "bounding-box"; |
|
4029 </xsl:text> |
|
4030 <xsl:text> //clickable.style.visibility = "hidden"; |
|
4031 </xsl:text> |
|
4032 <xsl:text> //clickable.onclick = () => alert("love JS"); |
|
4033 </xsl:text> |
|
4034 <xsl:text> clickable.onclick = func; |
|
4035 </xsl:text> |
|
4036 <xsl:text> this.element.appendChild(clickable); |
|
4037 </xsl:text> |
|
4038 <xsl:text> this.clickables.push(clickable) |
|
4039 </xsl:text> |
|
4040 <xsl:text> } |
|
4041 </xsl:text> |
|
4042 <xsl:text> reset_clickables() { |
|
4043 </xsl:text> |
|
4044 <xsl:text> while(this.clickables.length){ |
|
4045 </xsl:text> |
|
4046 <xsl:text> this.element.removeChild(this.clickables.pop()); |
|
4047 </xsl:text> |
|
4048 <xsl:text> } |
|
4049 </xsl:text> |
|
4050 <xsl:text> } |
|
4051 </xsl:text> |
|
4052 <xsl:text> // Set text content when content is smaller than menu (no scrolling) |
|
4053 </xsl:text> |
|
4054 <xsl:text> set_complete_text(){ |
|
4055 </xsl:text> |
|
4056 <xsl:text> let spans = this.text_elt.children; |
|
4057 </xsl:text> |
|
4058 <xsl:text> let c = 0; |
|
4059 </xsl:text> |
|
4060 <xsl:text> for(let item of this.content){ |
|
4061 </xsl:text> |
|
4062 <xsl:text> let span=spans[c]; |
|
4063 </xsl:text> |
|
4064 <xsl:text> span.textContent = item; |
|
4065 </xsl:text> |
|
4066 <xsl:text> let sel = c; |
|
4067 </xsl:text> |
|
4068 <xsl:text> this.make_clickable(span, (evt) => this.bound_on_selection_click(sel)); |
|
4069 </xsl:text> |
|
4070 <xsl:text> c++; |
|
4071 </xsl:text> |
|
4072 <xsl:text> } |
|
4073 </xsl:text> |
|
4074 <xsl:text> } |
|
4075 </xsl:text> |
|
4076 <xsl:text> // Move partial view : |
|
4077 </xsl:text> |
|
4078 <xsl:text> // false : upward, lower value |
|
4079 </xsl:text> |
|
4080 <xsl:text> // true : downward, higher value |
|
4081 </xsl:text> |
|
4082 <xsl:text> scroll(forward){ |
|
4083 </xsl:text> |
|
4084 <xsl:text> let contentlength = this.content.length; |
|
4085 </xsl:text> |
|
4086 <xsl:text> let spans = this.text_elt.children; |
|
4087 </xsl:text> |
|
4088 <xsl:text> let spanslength = spans.length; |
|
4089 </xsl:text> |
|
4090 <xsl:text> // reduce accounted menu size according to prsence of scroll buttons |
|
4091 </xsl:text> |
|
4092 <xsl:text> // since we scroll there is necessarly one button |
|
4093 </xsl:text> |
|
4094 <xsl:text> spanslength--; |
|
4095 </xsl:text> |
|
4096 <xsl:text> if(forward){ |
|
4097 </xsl:text> |
|
4098 <xsl:text> // reduce accounted menu size because of back button |
|
4099 </xsl:text> |
|
4100 <xsl:text> // in current view |
|
4101 </xsl:text> |
|
4102 <xsl:text> if(this.menu_offset > 0) spanslength--; |
|
4103 </xsl:text> |
|
4104 <xsl:text> this.menu_offset = Math.min( |
|
4105 </xsl:text> |
|
4106 <xsl:text> contentlength - spans.length + 1, |
|
4107 </xsl:text> |
|
4108 <xsl:text> this.menu_offset + spanslength); |
|
4109 </xsl:text> |
|
4110 <xsl:text> }else{ |
|
4111 </xsl:text> |
|
4112 <xsl:text> // reduce accounted menu size because of back button |
|
4113 </xsl:text> |
|
4114 <xsl:text> // in view once scrolled |
|
4115 </xsl:text> |
|
4116 <xsl:text> if(this.menu_offset - spanslength > 0) spanslength--; |
|
4117 </xsl:text> |
|
4118 <xsl:text> this.menu_offset = Math.max( |
|
4119 </xsl:text> |
|
4120 <xsl:text> 0, |
|
4121 </xsl:text> |
|
4122 <xsl:text> this.menu_offset - spanslength); |
|
4123 </xsl:text> |
|
4124 <xsl:text> } |
|
4125 </xsl:text> |
|
4126 <xsl:text> if(this.menu_offset == 1) |
|
4127 </xsl:text> |
|
4128 <xsl:text> this.menu_offset = 0; |
|
4129 </xsl:text> |
|
4130 <xsl:text> |
|
4131 </xsl:text> |
|
4132 <xsl:text> this.reset_highlight(); |
|
4133 </xsl:text> |
|
4134 <xsl:text> |
|
4135 </xsl:text> |
|
4136 <xsl:text> this.reset_clickables(); |
|
4137 </xsl:text> |
|
4138 <xsl:text> this.set_partial_text(); |
|
4139 </xsl:text> |
|
4140 <xsl:text> |
|
4141 </xsl:text> |
|
4142 <xsl:text> this.highlight_selection(); |
|
4143 </xsl:text> |
|
4144 <xsl:text> } |
|
4145 </xsl:text> |
|
4146 <xsl:text> // Setup partial view text content |
|
4147 </xsl:text> |
|
4148 <xsl:text> // with jumps at first and last entry when appropriate |
|
4149 </xsl:text> |
|
4150 <xsl:text> set_partial_text(){ |
|
4151 </xsl:text> |
|
4152 <xsl:text> let spans = this.text_elt.children; |
|
4153 </xsl:text> |
|
4154 <xsl:text> let contentlength = this.content.length; |
|
4155 </xsl:text> |
|
4156 <xsl:text> let spanslength = spans.length; |
|
4157 </xsl:text> |
|
4158 <xsl:text> let i = this.menu_offset, c = 0; |
|
4159 </xsl:text> |
|
4160 <xsl:text> let m = this.box_bbox; |
|
4161 </xsl:text> |
|
4162 <xsl:text> while(c < spanslength){ |
|
4163 </xsl:text> |
|
4164 <xsl:text> let span=spans[c]; |
|
4165 </xsl:text> |
|
4166 <xsl:text> let onclickfunc; |
|
4167 </xsl:text> |
|
4168 <xsl:text> // backward jump only present if not exactly at start |
|
4169 </xsl:text> |
|
4170 <xsl:text> if(c == 0 && i != 0){ |
|
4171 </xsl:text> |
|
4172 <xsl:text> span.textContent = "▲"; |
|
4173 </xsl:text> |
|
4174 <xsl:text> onclickfunc = this.bound_on_backward_click; |
|
4175 </xsl:text> |
|
4176 <xsl:text> let o = span.getBBox(); |
|
4177 </xsl:text> |
|
4178 <xsl:text> span.setAttribute("dx", (m.width - o.width)/2); |
|
4179 </xsl:text> |
|
4180 <xsl:text> // presence of forward jump when not right at the end |
|
4181 </xsl:text> |
|
4182 <xsl:text> }else if(c == spanslength-1 && i < contentlength - 1){ |
|
4183 </xsl:text> |
|
4184 <xsl:text> span.textContent = "▼"; |
|
4185 </xsl:text> |
|
4186 <xsl:text> onclickfunc = this.bound_on_forward_click; |
|
4187 </xsl:text> |
|
4188 <xsl:text> let o = span.getBBox(); |
|
4189 </xsl:text> |
|
4190 <xsl:text> span.setAttribute("dx", (m.width - o.width)/2); |
|
4191 </xsl:text> |
|
4192 <xsl:text> // otherwise normal content |
|
4193 </xsl:text> |
|
4194 <xsl:text> }else{ |
|
4195 </xsl:text> |
|
4196 <xsl:text> span.textContent = this.content[i]; |
|
4197 </xsl:text> |
|
4198 <xsl:text> let sel = i; |
|
4199 </xsl:text> |
|
4200 <xsl:text> onclickfunc = (evt) => this.bound_on_selection_click(sel); |
|
4201 </xsl:text> |
|
4202 <xsl:text> span.removeAttribute("dx"); |
|
4203 </xsl:text> |
|
4204 <xsl:text> i++; |
|
4205 </xsl:text> |
|
4206 <xsl:text> } |
|
4207 </xsl:text> |
|
4208 <xsl:text> this.make_clickable(span, onclickfunc); |
|
4209 </xsl:text> |
|
4210 <xsl:text> c++; |
|
4211 </xsl:text> |
|
4212 <xsl:text> } |
|
4213 </xsl:text> |
|
4214 <xsl:text> } |
|
4215 </xsl:text> |
|
4216 <xsl:text> numb_event(e) { |
|
4217 </xsl:text> |
|
4218 <xsl:text> e.stopPropagation(); |
|
4219 </xsl:text> |
|
4220 <xsl:text> } |
|
4221 </xsl:text> |
|
4222 <xsl:text> open(){ |
|
4223 </xsl:text> |
|
4224 <xsl:text> let length = this.content.length; |
|
4225 </xsl:text> |
|
4226 <xsl:text> // systematically reset text, to strip eventual whitespace spans |
|
4227 </xsl:text> |
|
4228 <xsl:text> this.reset_text(); |
|
4229 </xsl:text> |
|
4230 <xsl:text> // grow as much as needed or possible |
|
4231 </xsl:text> |
|
4232 <xsl:text> let slots = this.grow_text(length); |
|
4233 </xsl:text> |
|
4234 <xsl:text> // Depending on final size |
|
4235 </xsl:text> |
|
4236 <xsl:text> if(slots == length) { |
|
4237 </xsl:text> |
|
4238 <xsl:text> // show all at once |
|
4239 </xsl:text> |
|
4240 <xsl:text> this.set_complete_text(); |
|
4241 </xsl:text> |
|
4242 <xsl:text> } else { |
|
4243 </xsl:text> |
|
4244 <xsl:text> // eventualy align menu to current selection, compensating for lift |
|
4245 </xsl:text> |
|
4246 <xsl:text> let offset = this.last_selection - this.lift; |
|
4247 </xsl:text> |
|
4248 <xsl:text> if(offset > 0) |
|
4249 </xsl:text> |
|
4250 <xsl:text> this.menu_offset = Math.min(offset + 1, length - slots + 1); |
|
4251 </xsl:text> |
|
4252 <xsl:text> else |
|
4253 </xsl:text> |
|
4254 <xsl:text> this.menu_offset = 0; |
|
4255 </xsl:text> |
|
4256 <xsl:text> // show surrounding values |
|
4257 </xsl:text> |
|
4258 <xsl:text> this.set_partial_text(); |
|
4259 </xsl:text> |
|
4260 <xsl:text> } |
|
4261 </xsl:text> |
|
4262 <xsl:text> // Now that text size is known, we can set the box around it |
|
4263 </xsl:text> |
|
4264 <xsl:text> this.adjust_box_to_text(); |
|
4265 </xsl:text> |
|
4266 <xsl:text> // Take button out until menu closed |
|
4267 </xsl:text> |
|
4268 <xsl:text> this.element.removeChild(this.button_elt); |
|
4269 </xsl:text> |
|
4270 <xsl:text> // Rise widget to top by moving it to last position among siblings |
|
4271 </xsl:text> |
|
4272 <xsl:text> this.element.parentNode.appendChild(this.element.parentNode.removeChild(this.element)); |
|
4273 </xsl:text> |
|
4274 <xsl:text> // disable interaction with background |
|
4275 </xsl:text> |
|
4276 <xsl:text> svg_root.addEventListener("pointerdown", this.numb_event, true); |
|
4277 </xsl:text> |
|
4278 <xsl:text> svg_root.addEventListener("pointerup", this.numb_event, true); |
|
4279 </xsl:text> |
|
4280 <xsl:text> svg_root.addEventListener("click", this.bound_close_on_click_elsewhere, true); |
|
4281 </xsl:text> |
|
4282 <xsl:text> this.highlight_selection(); |
|
4283 </xsl:text> |
|
4284 <xsl:text> |
|
4285 </xsl:text> |
|
4286 <xsl:text> // mark as open |
|
4287 </xsl:text> |
|
4288 <xsl:text> this.opened = true; |
|
4289 </xsl:text> |
|
4290 <xsl:text> } |
|
4291 </xsl:text> |
|
4292 <xsl:text> // Put text element in normalized state |
|
4293 </xsl:text> |
|
4294 <xsl:text> reset_text(){ |
|
4295 </xsl:text> |
|
4296 <xsl:text> let txt = this.text_elt; |
|
4297 </xsl:text> |
|
4298 <xsl:text> let first = txt.firstElementChild; |
|
4299 </xsl:text> |
|
4300 <xsl:text> // remove attribute eventually added to first text line while opening |
|
4301 </xsl:text> |
|
4302 <xsl:text> first.onclick = null; |
|
4303 </xsl:text> |
|
4304 <xsl:text> first.removeAttribute("dy"); |
|
4305 </xsl:text> |
|
4306 <xsl:text> first.removeAttribute("dx"); |
|
4307 </xsl:text> |
|
4308 <xsl:text> // keep only the first line of text |
|
4309 </xsl:text> |
|
4310 <xsl:text> for(let span of Array.from(txt.children).slice(1)){ |
|
4311 </xsl:text> |
|
4312 <xsl:text> txt.removeChild(span) |
|
4313 </xsl:text> |
|
4314 <xsl:text> } |
|
4315 </xsl:text> |
|
4316 <xsl:text> } |
|
4317 </xsl:text> |
|
4318 <xsl:text> // Put rectangle element in saved original state |
|
4319 </xsl:text> |
|
4320 <xsl:text> reset_box(){ |
|
4321 </xsl:text> |
|
4322 <xsl:text> let m = this.box_bbox; |
|
4323 </xsl:text> |
|
4324 <xsl:text> let b = this.box_elt; |
|
4325 </xsl:text> |
|
4326 <xsl:text> b.x.baseVal.value = m.x; |
|
4327 </xsl:text> |
|
4328 <xsl:text> b.y.baseVal.value = m.y; |
|
4329 </xsl:text> |
|
4330 <xsl:text> b.width.baseVal.value = m.width; |
|
4331 </xsl:text> |
|
4332 <xsl:text> b.height.baseVal.value = m.height; |
|
4333 </xsl:text> |
|
4334 <xsl:text> } |
|
4335 </xsl:text> |
|
4336 <xsl:text> highlight_selection(){ |
|
4337 </xsl:text> |
|
4338 <xsl:text> if(this.last_selection == undefined) return; |
|
4339 </xsl:text> |
|
4340 <xsl:text> let highlighted_row = this.last_selection - this.menu_offset; |
|
4341 </xsl:text> |
|
4342 <xsl:text> if(highlighted_row < 0) return; |
|
4343 </xsl:text> |
|
4344 <xsl:text> let spans = this.text_elt.children; |
|
4345 </xsl:text> |
|
4346 <xsl:text> let spanslength = spans.length; |
|
4347 </xsl:text> |
|
4348 <xsl:text> let contentlength = this.content.length; |
|
4349 </xsl:text> |
|
4350 <xsl:text> if(this.menu_offset != 0) { |
|
4351 </xsl:text> |
|
4352 <xsl:text> spanslength--; |
|
4353 </xsl:text> |
|
4354 <xsl:text> highlighted_row++; |
|
4355 </xsl:text> |
|
4356 <xsl:text> } |
|
4357 </xsl:text> |
|
4358 <xsl:text> if(this.menu_offset + spanslength < contentlength - 1) spanslength--; |
|
4359 </xsl:text> |
|
4360 <xsl:text> if(highlighted_row > spanslength) return; |
|
4361 </xsl:text> |
|
4362 <xsl:text> let original_text_y = this.text_bbox.y; |
|
4363 </xsl:text> |
|
4364 <xsl:text> let highlight = this.highlight_elt; |
|
4365 </xsl:text> |
|
4366 <xsl:text> let span = spans[highlighted_row]; |
|
4367 </xsl:text> |
|
4368 <xsl:text> let yoffset = span.getBBox().y - original_text_y; |
|
4369 </xsl:text> |
|
4370 <xsl:text> highlight.y.baseVal.value = this.highlight_bbox.y + yoffset; |
|
4371 </xsl:text> |
|
4372 <xsl:text> highlight.style.visibility = "visible"; |
|
4373 </xsl:text> |
|
4374 <xsl:text> } |
|
4375 </xsl:text> |
|
4376 <xsl:text> reset_highlight(){ |
|
4377 </xsl:text> |
|
4378 <xsl:text> let highlight = this.highlight_elt; |
|
4379 </xsl:text> |
|
4380 <xsl:text> highlight.y.baseVal.value = this.highlight_bbox.y; |
|
4381 </xsl:text> |
|
4382 <xsl:text> highlight.style.visibility = "hidden"; |
|
4383 </xsl:text> |
|
4384 <xsl:text> } |
|
4385 </xsl:text> |
|
4386 <xsl:text> // Use margin and text size to compute box size |
|
4387 </xsl:text> |
|
4388 <xsl:text> adjust_box_to_text(){ |
|
4389 </xsl:text> |
|
4390 <xsl:text> let [lmargin, tmargin] = this.margins; |
|
4391 </xsl:text> |
|
4392 <xsl:text> let m = this.text_elt.getBBox(); |
|
4393 </xsl:text> |
|
4394 <xsl:text> let b = this.box_elt; |
|
4395 </xsl:text> |
|
4396 <xsl:text> // b.x.baseVal.value = m.x - lmargin; |
|
4397 </xsl:text> |
|
4398 <xsl:text> b.y.baseVal.value = m.y - tmargin; |
|
4399 </xsl:text> |
|
4400 <xsl:text> // b.width.baseVal.value = 2 * lmargin + m.width; |
|
4401 </xsl:text> |
|
4402 <xsl:text> b.height.baseVal.value = 2 * tmargin + m.height; |
|
4403 </xsl:text> |
|
4404 <xsl:text> } |
|
4405 </xsl:text> |
|
4406 <xsl:text>} |
|
4407 </xsl:text> |
|
4408 </xsl:template> |
|
4409 <xsl:template match="widget[@type='DropDown']" mode="widget_defs"> |
|
4410 <xsl:param name="hmi_element"/> |
|
4411 <xsl:call-template name="defs_by_labels"> |
|
4412 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
4413 <xsl:with-param name="labels"> |
|
4414 <xsl:text>text box button highlight</xsl:text> |
|
4415 </xsl:with-param> |
|
4416 </xsl:call-template> |
|
4417 <xsl:text> content:</xsl:text> |
|
4418 <xsl:choose> |
|
4419 <xsl:when test="count(arg) = 1 and arg[1]/@value = '#langs'"> |
|
4420 <xsl:text>langs</xsl:text> |
|
4421 </xsl:when> |
|
4422 <xsl:otherwise> |
|
4423 <xsl:text>[ |
|
4424 </xsl:text> |
|
4425 <xsl:for-each select="arg"> |
|
4426 <xsl:text>"</xsl:text> |
|
4427 <xsl:value-of select="@value"/> |
|
4428 <xsl:text>", |
|
4429 </xsl:text> |
|
4430 </xsl:for-each> |
|
4431 <xsl:text> ]</xsl:text> |
|
4432 </xsl:otherwise> |
|
4433 </xsl:choose> |
|
4434 <xsl:text>, |
|
4435 </xsl:text> |
|
4436 </xsl:template> |
|
4437 <xsl:template match="widget[@type='ForEach']" mode="widget_desc"> |
|
4438 <type> |
|
4439 <xsl:value-of select="@type"/> |
|
4440 </type> |
|
4441 <longdesc> |
|
4442 <xsl:text>ForEach widget is used to span a small set of widget over a larger set of |
|
4443 </xsl:text> |
|
4444 <xsl:text>repeated HMI_NODEs. |
|
4445 </xsl:text> |
|
4446 <xsl:text> |
|
4447 </xsl:text> |
|
4448 <xsl:text>Idea is somewhat similar to relative page, but it all happens inside the |
|
4449 </xsl:text> |
|
4450 <xsl:text>ForEach widget, no page involved. |
|
4451 </xsl:text> |
|
4452 <xsl:text> |
|
4453 </xsl:text> |
|
4454 <xsl:text>Together with relative Jump widgets it can be used to build a menu to reach |
|
4455 </xsl:text> |
|
4456 <xsl:text>relative pages covering many identical HMI_NODES siblings. |
|
4457 </xsl:text> |
|
4458 <xsl:text> |
|
4459 </xsl:text> |
|
4460 <xsl:text>ForEach widget takes a HMI_CLASS name as argument and a HMI_NODE path as |
|
4461 </xsl:text> |
|
4462 <xsl:text>variable. |
|
4463 </xsl:text> |
|
4464 <xsl:text> |
|
4465 </xsl:text> |
|
4466 <xsl:text>Direct sub-elements can be either groups of widget to be spanned, labeled |
|
4467 </xsl:text> |
|
4468 <xsl:text>"ClassName:offset", or buttons to control the spanning, labeled |
|
4469 </xsl:text> |
|
4470 <xsl:text>"ClassName:+/-number". |
|
4471 </xsl:text> |
|
4472 </longdesc> |
|
4473 <shortdesc> |
|
4474 <xsl:text>span widgets over a set of repeated HMI_NODEs</xsl:text> |
|
4475 </shortdesc> |
|
4476 <arg name="class_name" accepts="string"> |
|
4477 <xsl:text>HMI_CLASS name</xsl:text> |
|
4478 </arg> |
|
4479 <path name="root" accepts="HMI_NODE"> |
|
4480 <xsl:text> where to find HMI_NODEs whose HMI_CLASS is class_name</xsl:text> |
|
4481 </path> |
|
4482 </xsl:template> |
|
4483 <xsl:template match="widget[@type='ForEach']" mode="widget_defs"> |
|
4484 <xsl:param name="hmi_element"/> |
|
4485 <xsl:if test="count(path) != 1"> |
|
4486 <xsl:message terminate="yes"> |
|
4487 <xsl:text>ForEach widget </xsl:text> |
|
4488 <xsl:value-of select="$hmi_element/@id"/> |
|
4489 <xsl:text> must have one HMI path given.</xsl:text> |
|
4490 </xsl:message> |
|
4491 </xsl:if> |
|
4492 <xsl:if test="count(arg) != 1"> |
|
4493 <xsl:message terminate="yes"> |
|
4494 <xsl:text>ForEach widget </xsl:text> |
|
4495 <xsl:value-of select="$hmi_element/@id"/> |
|
4496 <xsl:text> must have one argument given : a class name.</xsl:text> |
|
4497 </xsl:message> |
|
4498 </xsl:if> |
|
4499 <xsl:variable name="class" select="arg[1]/@value"/> |
|
4500 <xsl:variable name="base_path" select="path/@value"/> |
|
4501 <xsl:variable name="hmi_index_base" select="$indexed_hmitree/*[@hmipath = $base_path]"/> |
|
4502 <xsl:variable name="hmi_tree_base" select="$hmitree/descendant-or-self::*[@path = $hmi_index_base/@path]"/> |
|
4503 <xsl:variable name="hmi_tree_items" select="$hmi_tree_base/*[@class = $class]"/> |
|
4504 <xsl:variable name="hmi_index_items" select="$indexed_hmitree/*[@path = $hmi_tree_items/@path]"/> |
|
4505 <xsl:variable name="items_paths" select="$hmi_index_items/@hmipath"/> |
|
4506 <xsl:text> index_pool: [ |
|
4507 </xsl:text> |
|
4508 <xsl:for-each select="$hmi_index_items"> |
|
4509 <xsl:text> </xsl:text> |
|
4510 <xsl:value-of select="@index"/> |
|
4511 <xsl:if test="position()!=last()"> |
|
4512 <xsl:text>,</xsl:text> |
|
4513 </xsl:if> |
|
4514 <xsl:text> |
|
4515 </xsl:text> |
|
4516 </xsl:for-each> |
|
4517 <xsl:text> ], |
|
4518 </xsl:text> |
|
4519 <xsl:text> init: function() { |
|
4520 </xsl:text> |
|
4521 <xsl:variable name="prefix" select="concat($class,':')"/> |
|
4522 <xsl:variable name="buttons_regex" select="concat('^',$prefix,'[+\-][0-9]+')"/> |
|
4523 <xsl:variable name="buttons" select="$hmi_element/*[regexp:test(@inkscape:label, $buttons_regex)]"/> |
|
4524 <xsl:for-each select="$buttons"> |
|
4525 <xsl:variable name="op" select="substring-after(@inkscape:label, $prefix)"/> |
|
4526 <xsl:text> id("</xsl:text> |
|
4527 <xsl:value-of select="@id"/> |
|
4528 <xsl:text>").setAttribute("onclick", "hmi_widgets['</xsl:text> |
|
4529 <xsl:value-of select="$hmi_element/@id"/> |
|
4530 <xsl:text>'].on_click('</xsl:text> |
|
4531 <xsl:value-of select="$op"/> |
|
4532 <xsl:text>', evt)"); |
|
4533 </xsl:text> |
|
4534 </xsl:for-each> |
|
4535 <xsl:text> |
|
4536 </xsl:text> |
|
4537 <xsl:text> this.items = [ |
|
4538 </xsl:text> |
|
4539 <xsl:variable name="items_regex" select="concat('^',$prefix,'[0-9]+')"/> |
|
4540 <xsl:variable name="unordered_items" select="$hmi_element//*[regexp:test(@inkscape:label, $items_regex)]"/> |
|
4541 <xsl:for-each select="$unordered_items"> |
|
4542 <xsl:variable name="elt_label" select="concat($prefix, string(position()))"/> |
|
4543 <xsl:variable name="elt" select="$unordered_items[@inkscape:label = $elt_label]"/> |
|
4544 <xsl:variable name="pos" select="position()"/> |
|
4545 <xsl:variable name="item_path" select="$items_paths[$pos]"/> |
|
4546 <xsl:text> [ /* item="</xsl:text> |
|
4547 <xsl:value-of select="$elt_label"/> |
|
4548 <xsl:text>" path="</xsl:text> |
|
4549 <xsl:value-of select="$item_path"/> |
|
4550 <xsl:text>" */ |
|
4551 </xsl:text> |
|
4552 <xsl:if test="count($elt)=0"> |
|
4553 <xsl:message terminate="yes"> |
|
4554 <xsl:text>Missing item labeled </xsl:text> |
|
4555 <xsl:value-of select="$elt_label"/> |
|
4556 <xsl:text> in ForEach widget </xsl:text> |
|
4557 <xsl:value-of select="$hmi_element/@id"/> |
|
4558 </xsl:message> |
|
4559 </xsl:if> |
|
4560 <xsl:for-each select="func:refered_elements($elt)[@id = $hmi_elements/@id][not(@id = $elt/@id)]"> |
|
4561 <xsl:if test="not(func:is_descendant_path(func:widget(@id)/path/@value, $item_path))"> |
|
4562 <xsl:message terminate="yes"> |
|
4563 <xsl:text>Widget id="</xsl:text> |
|
4564 <xsl:value-of select="@id"/> |
|
4565 <xsl:text>" label="</xsl:text> |
|
4566 <xsl:value-of select="@inkscape:label"/> |
|
4567 <xsl:text>" is having wrong path. Accroding to ForEach widget ancestor id="</xsl:text> |
|
4568 <xsl:value-of select="$hmi_element/@id"/> |
|
4569 <xsl:text>", path should be descendant of "</xsl:text> |
|
4570 <xsl:value-of select="$item_path"/> |
|
4571 <xsl:text>".</xsl:text> |
|
4572 </xsl:message> |
|
4573 </xsl:if> |
|
4574 <xsl:text> hmi_widgets["</xsl:text> |
|
4575 <xsl:value-of select="@id"/> |
|
4576 <xsl:text>"]</xsl:text> |
|
4577 <xsl:if test="position()!=last()"> |
|
4578 <xsl:text>,</xsl:text> |
|
4579 </xsl:if> |
|
4580 <xsl:text> |
|
4581 </xsl:text> |
|
4582 </xsl:for-each> |
|
4583 <xsl:text> ]</xsl:text> |
|
4584 <xsl:if test="position()!=last()"> |
|
4585 <xsl:text>,</xsl:text> |
|
4586 </xsl:if> |
|
4587 <xsl:text> |
|
4588 </xsl:text> |
|
4589 </xsl:for-each> |
|
4590 <xsl:text> ] |
|
4591 </xsl:text> |
|
4592 <xsl:text> }, |
|
4593 </xsl:text> |
|
4594 <xsl:text> item_offset: 0, |
|
4595 </xsl:text> |
|
4596 </xsl:template> |
|
4597 <xsl:template match="widget[@type='ForEach']" mode="widget_class"> |
|
4598 <xsl:text>class </xsl:text> |
|
4599 <xsl:text>ForEachWidget</xsl:text> |
|
4600 <xsl:text> extends Widget{ |
|
4601 </xsl:text> |
|
4602 <xsl:text> |
|
4603 </xsl:text> |
|
4604 <xsl:text> unsub_items(){ |
|
4605 </xsl:text> |
|
4606 <xsl:text> for(let item of this.items){ |
|
4607 </xsl:text> |
|
4608 <xsl:text> for(let widget of item) { |
|
4609 </xsl:text> |
|
4610 <xsl:text> widget.unsub(); |
|
4611 </xsl:text> |
|
4612 <xsl:text> } |
|
4613 </xsl:text> |
|
4614 <xsl:text> } |
|
4615 </xsl:text> |
|
4616 <xsl:text> } |
|
4617 </xsl:text> |
|
4618 <xsl:text> |
|
4619 </xsl:text> |
|
4620 <xsl:text> unsub(){ |
|
4621 </xsl:text> |
|
4622 <xsl:text> this.unsub_items(); |
|
4623 </xsl:text> |
|
4624 <xsl:text> this.offset = 0; |
|
4625 </xsl:text> |
|
4626 <xsl:text> this.relativeness = undefined; |
|
4627 </xsl:text> |
|
4628 <xsl:text> } |
|
4629 </xsl:text> |
|
4630 <xsl:text> |
|
4631 </xsl:text> |
|
4632 <xsl:text> sub_items(){ |
|
4633 </xsl:text> |
|
4634 <xsl:text> for(let i = 0; i < this.items.length; i++) { |
|
4635 </xsl:text> |
|
4636 <xsl:text> let item = this.items[i]; |
|
4637 </xsl:text> |
|
4638 <xsl:text> let orig_item_index = this.index_pool[i]; |
|
4639 </xsl:text> |
|
4640 <xsl:text> let item_index = this.index_pool[i+this.item_offset]; |
|
4641 </xsl:text> |
|
4642 <xsl:text> let item_index_offset = item_index - orig_item_index; |
|
4643 </xsl:text> |
|
4644 <xsl:text> if(this.relativeness[0]) |
|
4645 </xsl:text> |
|
4646 <xsl:text> item_index_offset += this.offset; |
|
4647 </xsl:text> |
|
4648 <xsl:text> for(let widget of item) { |
|
4649 </xsl:text> |
|
4650 <xsl:text> /* all variables of all widgets in a ForEach are all relative. |
|
4651 </xsl:text> |
|
4652 <xsl:text> Really. |
|
4653 </xsl:text> |
|
4654 <xsl:text> |
|
4655 </xsl:text> |
|
4656 <xsl:text> TODO: allow absolute variables in ForEach widgets |
|
4657 </xsl:text> |
|
4658 <xsl:text> */ |
|
4659 </xsl:text> |
|
4660 <xsl:text> widget.sub(item_index_offset, widget.indexes.map(_=>true)); |
|
4661 </xsl:text> |
|
4662 <xsl:text> } |
|
4663 </xsl:text> |
|
4664 <xsl:text> } |
|
4665 </xsl:text> |
|
4666 <xsl:text> } |
|
4667 </xsl:text> |
|
4668 <xsl:text> |
|
4669 </xsl:text> |
|
4670 <xsl:text> sub(new_offset=0, relativeness=[]){ |
|
4671 </xsl:text> |
|
4672 <xsl:text> this.offset = new_offset; |
|
4673 </xsl:text> |
|
4674 <xsl:text> this.relativeness = relativeness; |
|
4675 </xsl:text> |
|
4676 <xsl:text> this.sub_items(); |
|
4677 </xsl:text> |
|
4678 <xsl:text> } |
|
4679 </xsl:text> |
|
4680 <xsl:text> |
|
4681 </xsl:text> |
|
4682 <xsl:text> apply_cache() { |
|
4683 </xsl:text> |
|
4684 <xsl:text> this.items.forEach(item=>item.forEach(widget=>widget.apply_cache())); |
|
4685 </xsl:text> |
|
4686 <xsl:text> } |
|
4687 </xsl:text> |
|
4688 <xsl:text> |
|
4689 </xsl:text> |
|
4690 <xsl:text> on_click(opstr, evt) { |
|
4691 </xsl:text> |
|
4692 <xsl:text> let new_item_offset = eval(String(this.item_offset)+opstr); |
|
4693 </xsl:text> |
|
4694 <xsl:text> if(new_item_offset + this.items.length > this.index_pool.length) { |
|
4695 </xsl:text> |
|
4696 <xsl:text> if(this.item_offset + this.items.length == this.index_pool.length) |
|
4697 </xsl:text> |
|
4698 <xsl:text> new_item_offset = 0; |
|
4699 </xsl:text> |
|
4700 <xsl:text> else |
|
4701 </xsl:text> |
|
4702 <xsl:text> new_item_offset = this.index_pool.length - this.items.length; |
|
4703 </xsl:text> |
|
4704 <xsl:text> } else if(new_item_offset < 0) { |
|
4705 </xsl:text> |
|
4706 <xsl:text> if(this.item_offset == 0) |
|
4707 </xsl:text> |
|
4708 <xsl:text> new_item_offset = this.index_pool.length - this.items.length; |
|
4709 </xsl:text> |
|
4710 <xsl:text> else |
|
4711 </xsl:text> |
|
4712 <xsl:text> new_item_offset = 0; |
|
4713 </xsl:text> |
|
4714 <xsl:text> } |
|
4715 </xsl:text> |
|
4716 <xsl:text> this.item_offset = new_item_offset; |
|
4717 </xsl:text> |
|
4718 <xsl:text> this.unsub_items(); |
|
4719 </xsl:text> |
|
4720 <xsl:text> this.sub_items(); |
|
4721 </xsl:text> |
|
4722 <xsl:text> update_subscriptions(); |
|
4723 </xsl:text> |
|
4724 <xsl:text> need_cache_apply.push(this); |
|
4725 </xsl:text> |
|
4726 <xsl:text> jumps_need_update = true; |
|
4727 </xsl:text> |
|
4728 <xsl:text> requestHMIAnimation(); |
|
4729 </xsl:text> |
|
4730 <xsl:text> } |
|
4731 </xsl:text> |
|
4732 <xsl:text>} |
|
4733 </xsl:text> |
|
4734 </xsl:template> |
|
4735 <xsl:template match="widget[@type='Input']" mode="widget_desc"> |
|
4736 <type> |
|
4737 <xsl:value-of select="@type"/> |
|
4738 </type> |
|
4739 <longdesc> |
|
4740 <xsl:text>Input widget takes one variable path, and displays current value in |
|
4741 </xsl:text> |
|
4742 <xsl:text>optional "value" labeled sub-element. |
|
4743 </xsl:text> |
|
4744 <xsl:text> |
|
4745 </xsl:text> |
|
4746 <xsl:text>Click on optional "edit" labeled element opens keypad to edit value. |
|
4747 </xsl:text> |
|
4748 <xsl:text> |
|
4749 </xsl:text> |
|
4750 <xsl:text>Operation on current value is performed when click on sub-elements with |
|
4751 </xsl:text> |
|
4752 <xsl:text>label starting with '=', '+' or '-' sign. Value after sign is used as |
|
4753 </xsl:text> |
|
4754 <xsl:text>operand. |
|
4755 </xsl:text> |
|
4756 </longdesc> |
|
4757 <shortdesc> |
|
4758 <xsl:text>Input field with predefined operation buttons</xsl:text> |
|
4759 </shortdesc> |
|
4760 <arg name="format" accepts="string"> |
|
4761 <xsl:text>optional printf-like format </xsl:text> |
|
4762 </arg> |
|
4763 <path name="edit" accepts="HMI_INT, HMI_REAL, HMI_STRING"> |
|
4764 <xsl:text>single variable to edit</xsl:text> |
|
4765 </path> |
|
4766 </xsl:template> |
|
4767 <xsl:template match="widget[@type='Input']" mode="widget_class"> |
|
4768 <xsl:text>class </xsl:text> |
|
4769 <xsl:text>InputWidget</xsl:text> |
|
4770 <xsl:text> extends Widget{ |
|
4771 </xsl:text> |
|
4772 <xsl:text> on_op_click(opstr) { |
|
4773 </xsl:text> |
|
4774 <xsl:text> this.change_hmi_value(0, opstr); |
|
4775 </xsl:text> |
|
4776 <xsl:text> } |
|
4777 </xsl:text> |
|
4778 <xsl:text> edit_callback(new_val) { |
|
4779 </xsl:text> |
|
4780 <xsl:text> this.apply_hmi_value(0, new_val); |
|
4781 </xsl:text> |
|
4782 <xsl:text> } |
|
4783 </xsl:text> |
|
4784 <xsl:text> |
|
4785 </xsl:text> |
|
4786 <xsl:text> is_inhibited = false; |
|
4787 </xsl:text> |
|
4788 <xsl:text> alert(msg){ |
|
4789 </xsl:text> |
|
4790 <xsl:text> this.is_inhibited = true; |
|
4791 </xsl:text> |
|
4792 <xsl:text> this.display = msg; |
|
4793 </xsl:text> |
|
4794 <xsl:text> setTimeout(() => this.stopalert(), 1000); |
|
4795 </xsl:text> |
|
4796 <xsl:text> this.request_animate(); |
|
4797 </xsl:text> |
|
4798 <xsl:text> } |
|
4799 </xsl:text> |
|
4800 <xsl:text> |
|
4801 </xsl:text> |
|
4802 <xsl:text> stopalert(){ |
|
4803 </xsl:text> |
|
4804 <xsl:text> this.is_inhibited = false; |
|
4805 </xsl:text> |
|
4806 <xsl:text> this.display = this.last_value; |
|
4807 </xsl:text> |
|
4808 <xsl:text> this.request_animate(); |
|
4809 </xsl:text> |
|
4810 <xsl:text> } |
|
4811 </xsl:text> |
|
4812 <xsl:text> |
|
4813 </xsl:text> |
|
4814 <xsl:text> overshot(new_val, max) { |
|
4815 </xsl:text> |
|
4816 <xsl:text> this.alert("max"); |
|
4817 </xsl:text> |
|
4818 <xsl:text> } |
|
4819 </xsl:text> |
|
4820 <xsl:text> |
|
4821 </xsl:text> |
|
4822 <xsl:text> undershot(new_val, min) { |
|
4823 </xsl:text> |
|
4824 <xsl:text> this.alert("min"); |
|
4825 </xsl:text> |
|
4826 <xsl:text> } |
|
4827 </xsl:text> |
|
4828 <xsl:text>} |
|
4829 </xsl:text> |
|
4830 </xsl:template> |
|
4831 <xsl:template match="widget[@type='Input']" mode="widget_defs"> |
|
4832 <xsl:param name="hmi_element"/> |
|
4833 <xsl:variable name="value_elt"> |
|
4834 <xsl:call-template name="defs_by_labels"> |
|
4835 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
4836 <xsl:with-param name="labels"> |
|
4837 <xsl:text>value</xsl:text> |
|
4838 </xsl:with-param> |
|
4839 <xsl:with-param name="mandatory" select="'no'"/> |
|
4840 </xsl:call-template> |
|
4841 </xsl:variable> |
|
4842 <xsl:variable name="have_value" select="string-length($value_elt)>0"/> |
|
4843 <xsl:value-of select="$value_elt"/> |
|
4844 <xsl:variable name="edit_elt"> |
|
4845 <xsl:call-template name="defs_by_labels"> |
|
4846 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
4847 <xsl:with-param name="labels"> |
|
4848 <xsl:text>edit</xsl:text> |
|
4849 </xsl:with-param> |
|
4850 <xsl:with-param name="mandatory" select="'no'"/> |
|
4851 </xsl:call-template> |
|
4852 </xsl:variable> |
|
4853 <xsl:variable name="have_edit" select="string-length($edit_elt)>0"/> |
|
4854 <xsl:value-of select="$edit_elt"/> |
|
4855 <xsl:if test="$have_value"> |
|
4856 <xsl:text> frequency: 5, |
|
4857 </xsl:text> |
|
4858 </xsl:if> |
|
4859 <xsl:text> dispatch: function(value) { |
|
4860 </xsl:text> |
|
4861 <xsl:if test="$have_value or $have_edit"> |
|
4862 <xsl:choose> |
|
4863 <xsl:when test="count(arg) = 1"> |
|
4864 <xsl:text> this.last_value = vsprintf("</xsl:text> |
|
4865 <xsl:value-of select="arg[1]/@value"/> |
|
4866 <xsl:text>", [value]); |
|
4867 </xsl:text> |
|
4868 </xsl:when> |
|
4869 <xsl:otherwise> |
|
4870 <xsl:text> this.last_value = value; |
|
4871 </xsl:text> |
|
4872 </xsl:otherwise> |
|
4873 </xsl:choose> |
|
4874 <xsl:text> if(!this.is_inhibited){ |
|
4875 </xsl:text> |
|
4876 <xsl:text> this.display = this.last_value; |
|
4877 </xsl:text> |
|
4878 <xsl:if test="$have_value"> |
|
4879 <xsl:text> this.request_animate(); |
|
4880 </xsl:text> |
|
4881 </xsl:if> |
|
4882 <xsl:text> } |
|
4883 </xsl:text> |
|
4884 </xsl:if> |
|
4885 <xsl:text> }, |
|
4886 </xsl:text> |
|
4887 <xsl:if test="$have_value"> |
|
4888 <xsl:text> animate: function(){ |
|
4889 </xsl:text> |
|
4890 <xsl:text> this.value_elt.textContent = String(this.display); |
|
4891 </xsl:text> |
|
4892 <xsl:text> }, |
|
4893 </xsl:text> |
|
4894 </xsl:if> |
|
4895 <xsl:text> init: function() { |
|
4896 </xsl:text> |
|
4897 <xsl:if test="$have_edit"> |
|
4898 <xsl:text> this.edit_elt.onclick = () => edit_value("</xsl:text> |
|
4899 <xsl:value-of select="path/@value"/> |
|
4900 <xsl:text>", "</xsl:text> |
|
4901 <xsl:value-of select="path/@type"/> |
|
4902 <xsl:text>", this, this.last_value); |
|
4903 </xsl:text> |
|
4904 <xsl:if test="$have_value"> |
|
4905 <xsl:text> this.value_elt.style.pointerEvents = "none"; |
|
4906 </xsl:text> |
|
4907 </xsl:if> |
|
4908 </xsl:if> |
|
4909 <xsl:for-each select="$hmi_element/*[regexp:test(@inkscape:label,'^[=+\-].+')]"> |
|
4910 <xsl:text> id("</xsl:text> |
|
4911 <xsl:value-of select="@id"/> |
|
4912 <xsl:text>").onclick = () => this.on_op_click("</xsl:text> |
|
4913 <xsl:value-of select="func:escape_quotes(@inkscape:label)"/> |
|
4914 <xsl:text>"); |
|
4915 </xsl:text> |
|
4916 </xsl:for-each> |
|
4917 <xsl:text> }, |
|
4918 </xsl:text> |
|
4919 </xsl:template> |
|
4920 <xsl:template match="widget[@type='JsonTable']" mode="widget_desc"> |
|
4921 <type> |
|
4922 <xsl:value-of select="@type"/> |
|
4923 </type> |
|
4924 <longdesc> |
|
4925 <xsl:text>Send given variables as POST to http URL argument, spread returned JSON in |
|
4926 </xsl:text> |
|
4927 <xsl:text>SVG sub-elements of "data" labeled element. |
|
4928 </xsl:text> |
|
4929 <xsl:text> |
|
4930 </xsl:text> |
|
4931 <xsl:text>Documentation to be written. see svbghmi exemple. |
|
4932 </xsl:text> |
|
4933 </longdesc> |
|
4934 <shortdesc> |
|
4935 <xsl:text>Http POST variables, spread JSON back</xsl:text> |
|
4936 </shortdesc> |
|
4937 <arg name="url" accepts="string"> |
|
4938 <xsl:text> </xsl:text> |
|
4939 </arg> |
|
4940 <path name="edit" accepts="HMI_INT, HMI_REAL, HMI_STRING"> |
|
4941 <xsl:text>single variable to edit</xsl:text> |
|
4942 </path> |
|
4943 </xsl:template> |
|
4944 <xsl:template match="widget[@type='JsonTable']" mode="widget_class"> |
|
4945 <xsl:text>class </xsl:text> |
|
4946 <xsl:text>JsonTableWidget</xsl:text> |
|
4947 <xsl:text> extends Widget{ |
|
4948 </xsl:text> |
|
4949 <xsl:text> // arbitrary defaults to avoid missing entries in query |
|
4950 </xsl:text> |
|
4951 <xsl:text> cache = [0,0,0]; |
|
4952 </xsl:text> |
|
4953 <xsl:text> init_common() { |
|
4954 </xsl:text> |
|
4955 <xsl:text> this.spread_json_data_bound = this.spread_json_data.bind(this); |
|
4956 </xsl:text> |
|
4957 <xsl:text> this.handle_http_response_bound = this.handle_http_response.bind(this); |
|
4958 </xsl:text> |
|
4959 <xsl:text> this.fetch_error_bound = this.fetch_error.bind(this); |
|
4960 </xsl:text> |
|
4961 <xsl:text> this.promised = false; |
|
4962 </xsl:text> |
|
4963 <xsl:text> } |
|
4964 </xsl:text> |
|
4965 <xsl:text> |
|
4966 </xsl:text> |
|
4967 <xsl:text> handle_http_response(response) { |
|
4968 </xsl:text> |
|
4969 <xsl:text> if (!response.ok) { |
|
4970 </xsl:text> |
|
4971 <xsl:text> console.log("HTTP error, status = " + response.status); |
|
4972 </xsl:text> |
|
4973 <xsl:text> } |
|
4974 </xsl:text> |
|
4975 <xsl:text> return response.json(); |
|
4976 </xsl:text> |
|
4977 <xsl:text> } |
|
4978 </xsl:text> |
|
4979 <xsl:text> |
|
4980 </xsl:text> |
|
4981 <xsl:text> fetch_error(e){ |
|
4982 </xsl:text> |
|
4983 <xsl:text> console.log("HTTP fetch error, message = " + e.message + "Widget:" + this.element_id); |
|
4984 </xsl:text> |
|
4985 <xsl:text> } |
|
4986 </xsl:text> |
|
4987 <xsl:text> |
|
4988 </xsl:text> |
|
4989 <xsl:text> do_http_request(...opt) { |
|
4990 </xsl:text> |
|
4991 <xsl:text> this.abort_controller = new AbortController(); |
|
4992 </xsl:text> |
|
4993 <xsl:text> return Promise.resolve().then(() => { |
|
4994 </xsl:text> |
|
4995 <xsl:text> |
|
4996 </xsl:text> |
|
4997 <xsl:text> const query = { |
|
4998 </xsl:text> |
|
4999 <xsl:text> args: this.args, |
|
5000 </xsl:text> |
|
5001 <xsl:text> range: this.cache[1], |
|
5002 </xsl:text> |
|
5003 <xsl:text> position: this.cache[2], |
|
5004 </xsl:text> |
|
5005 <xsl:text> visible: this.visible, |
|
5006 </xsl:text> |
|
5007 <xsl:text> extra: this.cache.slice(4), |
|
5008 </xsl:text> |
|
5009 <xsl:text> options: opt |
|
5010 </xsl:text> |
|
5011 <xsl:text> }; |
|
5012 </xsl:text> |
|
5013 <xsl:text> |
|
5014 </xsl:text> |
|
5015 <xsl:text> const options = { |
|
5016 </xsl:text> |
|
5017 <xsl:text> method: 'POST', |
|
5018 </xsl:text> |
|
5019 <xsl:text> body: JSON.stringify(query), |
|
5020 </xsl:text> |
|
5021 <xsl:text> headers: {'Content-Type': 'application/json'}, |
|
5022 </xsl:text> |
|
5023 <xsl:text> signal: this.abort_controller.signal |
|
5024 </xsl:text> |
|
5025 <xsl:text> }; |
|
5026 </xsl:text> |
|
5027 <xsl:text> |
|
5028 </xsl:text> |
|
5029 <xsl:text> return fetch(this.args[0], options) |
|
5030 </xsl:text> |
|
5031 <xsl:text> .then(this.handle_http_response_bound) |
|
5032 </xsl:text> |
|
5033 <xsl:text> .then(this.spread_json_data_bound) |
|
5034 </xsl:text> |
|
5035 <xsl:text> .catch(this.fetch_error_bound); |
|
5036 </xsl:text> |
|
5037 <xsl:text> }); |
|
5038 </xsl:text> |
|
5039 <xsl:text> } |
|
5040 </xsl:text> |
|
5041 <xsl:text> |
|
5042 </xsl:text> |
|
5043 <xsl:text> unsub(){ |
|
5044 </xsl:text> |
|
5045 <xsl:text> this.abort_controller.abort(); |
|
5046 </xsl:text> |
|
5047 <xsl:text> super.unsub(); |
|
5048 </xsl:text> |
|
5049 <xsl:text> } |
|
5050 </xsl:text> |
|
5051 <xsl:text> |
|
5052 </xsl:text> |
|
5053 <xsl:text> sub(...args){ |
|
5054 </xsl:text> |
|
5055 <xsl:text> this.cache[0] = undefined; |
|
5056 </xsl:text> |
|
5057 <xsl:text> super.sub(...args); |
|
5058 </xsl:text> |
|
5059 <xsl:text> } |
|
5060 </xsl:text> |
|
5061 <xsl:text> |
|
5062 </xsl:text> |
|
5063 <xsl:text> dispatch(value, oldval, index) { |
|
5064 </xsl:text> |
|
5065 <xsl:text> |
|
5066 </xsl:text> |
|
5067 <xsl:text> if(this.cache[index] != value) |
|
5068 </xsl:text> |
|
5069 <xsl:text> this.cache[index] = value; |
|
5070 </xsl:text> |
|
5071 <xsl:text> else |
|
5072 </xsl:text> |
|
5073 <xsl:text> return; |
|
5074 </xsl:text> |
|
5075 <xsl:text> |
|
5076 </xsl:text> |
|
5077 <xsl:text> if(!this.promised){ |
|
5078 </xsl:text> |
|
5079 <xsl:text> this.promised = true; |
|
5080 </xsl:text> |
|
5081 <xsl:text> this.do_http_request().finally(() => { |
|
5082 </xsl:text> |
|
5083 <xsl:text> this.promised = false; |
|
5084 </xsl:text> |
|
5085 <xsl:text> }); |
|
5086 </xsl:text> |
|
5087 <xsl:text> } |
|
5088 </xsl:text> |
|
5089 <xsl:text> } |
|
5090 </xsl:text> |
|
5091 <xsl:text> make_on_click(...options){ |
|
5092 </xsl:text> |
|
5093 <xsl:text> let that = this; |
|
5094 </xsl:text> |
|
5095 <xsl:text> return function(evt){ |
|
5096 </xsl:text> |
|
5097 <xsl:text> that.do_http_request(...options); |
|
5098 </xsl:text> |
|
5099 <xsl:text> } |
|
5100 </xsl:text> |
|
5101 <xsl:text> } |
|
5102 </xsl:text> |
|
5103 <xsl:text> // on_click(evt, ...options) { |
|
5104 </xsl:text> |
|
5105 <xsl:text> // this.do_http_request(...options); |
|
5106 </xsl:text> |
|
5107 <xsl:text> // } |
|
5108 </xsl:text> |
|
5109 <xsl:text>} |
|
5110 </xsl:text> |
|
5111 </xsl:template> |
|
5112 <xsl:template mode="json_table_elt_render" match="svg:*"> |
|
5113 <xsl:message terminate="yes"> |
|
5114 <xsl:text>JsonTable Widget can't contain element of type </xsl:text> |
|
5115 <xsl:value-of select="local-name()"/> |
|
5116 <xsl:text>.</xsl:text> |
|
5117 </xsl:message> |
|
5118 </xsl:template> |
|
5119 <xsl:variable name="hmi_textstylelists_descs" select="$parsed_widgets/widget[@type = 'TextStyleList']"/> |
|
5120 <xsl:variable name="hmi_textstylelists" select="$hmi_elements[@id = $hmi_textstylelists_descs/@id]"/> |
|
5121 <xsl:variable name="textstylelist_related"> |
|
5122 <xsl:for-each select="$hmi_textstylelists"> |
|
5123 <list> |
|
5124 <xsl:attribute name="listid"> |
|
5125 <xsl:value-of select="@id"/> |
|
5126 </xsl:attribute> |
|
5127 <xsl:for-each select="func:refered_elements(.)"> |
|
5128 <elt> |
|
5129 <xsl:attribute name="eltid"> |
|
5130 <xsl:value-of select="@id"/> |
|
5131 </xsl:attribute> |
|
5132 </elt> |
|
5133 </xsl:for-each> |
|
5134 </list> |
|
5135 </xsl:for-each> |
|
5136 </xsl:variable> |
|
5137 <xsl:variable name="textstylelist_related_ns" select="exsl:node-set($textstylelist_related)"/> |
|
5138 <func:function name="func:json_expressions"> |
|
5139 <xsl:param name="expressions"/> |
|
5140 <xsl:param name="label"/> |
|
5141 <xsl:choose> |
|
5142 <xsl:when test="$label"> |
|
5143 <xsl:variable name="suffixes" select="str:split($label)"/> |
|
5144 <xsl:variable name="res"> |
|
5145 <xsl:for-each select="$suffixes"> |
|
5146 <expression> |
|
5147 <xsl:variable name="suffix" select="."/> |
|
5148 <xsl:variable name="pos" select="position()"/> |
|
5149 <xsl:variable name="expr" select="$expressions[position() <= $pos][last()]/expression"/> |
|
5150 <xsl:choose> |
|
5151 <xsl:when test="contains($suffix,'=')"> |
|
5152 <xsl:variable name="name" select="substring-before($suffix,'=')"/> |
|
5153 <xsl:if test="$expr/@name[. != $name]"> |
|
5154 <xsl:message terminate="yes"> |
|
5155 <xsl:text>JsonTable : missplaced '=' or inconsistent names in Json data expressions.</xsl:text> |
|
5156 </xsl:message> |
|
5157 </xsl:if> |
|
5158 <xsl:attribute name="name"> |
|
5159 <xsl:value-of select="$name"/> |
|
5160 </xsl:attribute> |
|
5161 <xsl:attribute name="content"> |
|
5162 <xsl:value-of select="$expr/@content"/> |
|
5163 <xsl:value-of select="substring-after($suffix,'=')"/> |
|
5164 </xsl:attribute> |
|
5165 </xsl:when> |
|
5166 <xsl:otherwise> |
|
5167 <xsl:copy-of select="$expr/@name"/> |
|
5168 <xsl:attribute name="content"> |
|
5169 <xsl:value-of select="$expr/@content"/> |
|
5170 <xsl:value-of select="$suffix"/> |
|
5171 </xsl:attribute> |
|
5172 </xsl:otherwise> |
|
5173 </xsl:choose> |
|
5174 </expression> |
|
5175 </xsl:for-each> |
|
5176 </xsl:variable> |
|
5177 <func:result select="exsl:node-set($res)"/> |
|
5178 </xsl:when> |
|
5179 <xsl:otherwise> |
|
5180 <func:result select="$expressions"/> |
|
5181 </xsl:otherwise> |
|
5182 </xsl:choose> |
|
5183 </func:function> |
|
5184 <xsl:variable name="initexpr"> |
|
5185 <expression> |
|
5186 <xsl:attribute name="content"> |
|
5187 <xsl:text>jdata</xsl:text> |
|
5188 </xsl:attribute> |
|
5189 </expression> |
|
5190 </xsl:variable> |
|
5191 <xsl:variable name="initexpr_ns" select="exsl:node-set($initexpr)"/> |
|
5192 <xsl:template mode="json_table_elt_render" match="svg:use"> |
|
5193 <xsl:param name="expressions"/> |
|
5194 <xsl:variable name="targetid" select="substring-after(@xlink:href,'#')"/> |
|
5195 <xsl:variable name="from_list" select="$hmi_lists[(@id | */@id) = $targetid]"/> |
|
5196 <xsl:choose> |
|
5197 <xsl:when test="count($from_list) > 0"> |
|
5198 <xsl:text> id("</xsl:text> |
|
5199 <xsl:value-of select="@id"/> |
|
5200 <xsl:text>").setAttribute("xlink:href", |
|
5201 </xsl:text> |
|
5202 <xsl:text> "#"+hmi_widgets["</xsl:text> |
|
5203 <xsl:value-of select="$from_list/@id"/> |
|
5204 <xsl:text>"].items[</xsl:text> |
|
5205 <xsl:value-of select="$expressions/expression[1]/@content"/> |
|
5206 <xsl:text>]); |
|
5207 </xsl:text> |
|
5208 </xsl:when> |
|
5209 <xsl:otherwise> |
|
5210 <xsl:message terminate="no"> |
|
5211 <xsl:text>Clones (svg:use) in JsonTable Widget must point to a valid HMI:List widget or item. Reference "</xsl:text> |
|
5212 <xsl:value-of select="@xlink:href"/> |
|
5213 <xsl:text>" is not valid and will not be updated.</xsl:text> |
|
5214 </xsl:message> |
|
5215 </xsl:otherwise> |
|
5216 </xsl:choose> |
|
5217 </xsl:template> |
|
5218 <xsl:template mode="json_table_elt_render" match="svg:text"> |
|
5219 <xsl:param name="expressions"/> |
|
5220 <xsl:variable name="value_expr" select="$expressions/expression[1]/@content"/> |
|
5221 <xsl:variable name="original" select="@original"/> |
|
5222 <xsl:variable name="from_textstylelist" select="$textstylelist_related_ns/list[elt/@eltid = $original]"/> |
|
5223 <xsl:choose> |
|
5224 <xsl:when test="count($from_textstylelist) > 0"> |
|
5225 <xsl:variable name="content_expr" select="$expressions/expression[2]/@content"/> |
|
5226 <xsl:if test="string-length($content_expr) = 0 or $expressions/expression[2]/@name != 'textContent'"> |
|
5227 <xsl:message terminate="yes"> |
|
5228 <xsl:text>Clones (svg:use) in JsonTable Widget pointing to a HMI:TextStyleList widget or item must have a "textContent=.someVal" assignement following value expression in label.</xsl:text> |
|
5229 </xsl:message> |
|
5230 </xsl:if> |
|
5231 <xsl:text> { |
|
5232 </xsl:text> |
|
5233 <xsl:text> let elt = id("</xsl:text> |
|
5234 <xsl:value-of select="@id"/> |
|
5235 <xsl:text>"); |
|
5236 </xsl:text> |
|
5237 <xsl:text> elt.textContent = String(</xsl:text> |
|
5238 <xsl:value-of select="$content_expr"/> |
|
5239 <xsl:text>); |
|
5240 </xsl:text> |
|
5241 <xsl:text> elt.style = hmi_widgets["</xsl:text> |
|
5242 <xsl:value-of select="$from_textstylelist/@listid"/> |
|
5243 <xsl:text>"].styles[</xsl:text> |
|
5244 <xsl:value-of select="$value_expr"/> |
|
5245 <xsl:text>]; |
|
5246 </xsl:text> |
|
5247 <xsl:text> } |
|
5248 </xsl:text> |
|
5249 </xsl:when> |
|
5250 <xsl:otherwise> |
|
5251 <xsl:text> id("</xsl:text> |
|
5252 <xsl:value-of select="@id"/> |
|
5253 <xsl:text>").textContent = String(</xsl:text> |
|
5254 <xsl:value-of select="$value_expr"/> |
|
5255 <xsl:text>); |
|
5256 </xsl:text> |
|
5257 </xsl:otherwise> |
|
5258 </xsl:choose> |
|
5259 </xsl:template> |
|
5260 <func:function name="func:filter_non_widget_label"> |
|
5261 <xsl:param name="elt"/> |
|
5262 <xsl:param name="widget_elts"/> |
|
5263 <xsl:variable name="eltid"> |
|
5264 <xsl:choose> |
|
5265 <xsl:when test="$elt/@original"> |
|
5266 <xsl:value-of select="$elt/@original"/> |
|
5267 </xsl:when> |
|
5268 <xsl:otherwise> |
|
5269 <xsl:value-of select="$elt/@id"/> |
|
5270 </xsl:otherwise> |
|
5271 </xsl:choose> |
|
5272 </xsl:variable> |
|
5273 <func:result select="$widget_elts[@id=$eltid]/@inkscape:label"/> |
|
5274 </func:function> |
|
5275 <xsl:template mode="json_table_render_except_comments" match="svg:*"> |
|
5276 <xsl:param name="expressions"/> |
|
5277 <xsl:param name="widget_elts"/> |
|
5278 <xsl:variable name="label" select="func:filter_non_widget_label(., $widget_elts)"/> |
|
5279 <xsl:if test="not(starts-with($label,'#'))"> |
|
5280 <xsl:apply-templates mode="json_table_render" select="."> |
|
5281 <xsl:with-param name="expressions" select="$expressions"/> |
|
5282 <xsl:with-param name="widget_elts" select="$widget_elts"/> |
|
5283 <xsl:with-param name="label" select="$label"/> |
|
5284 </xsl:apply-templates> |
|
5285 </xsl:if> |
|
5286 </xsl:template> |
|
5287 <xsl:template mode="json_table_render" match="svg:*"> |
|
5288 <xsl:param name="expressions"/> |
|
5289 <xsl:param name="widget_elts"/> |
|
5290 <xsl:param name="label"/> |
|
5291 <xsl:variable name="new_expressions" select="func:json_expressions($expressions, $label)"/> |
|
5292 <xsl:variable name="elt" select="."/> |
|
5293 <xsl:for-each select="$new_expressions/expression[position() > 1][starts-with(@name,'onClick')]"> |
|
5294 <xsl:text> id("</xsl:text> |
|
5295 <xsl:value-of select="$elt/@id"/> |
|
5296 <xsl:text>").onclick = this.make_on_click('</xsl:text> |
|
5297 <xsl:value-of select="@name"/> |
|
5298 <xsl:text>', </xsl:text> |
|
5299 <xsl:value-of select="@content"/> |
|
5300 <xsl:text>); |
|
5301 </xsl:text> |
|
5302 </xsl:for-each> |
|
5303 <xsl:apply-templates mode="json_table_elt_render" select="."> |
|
5304 <xsl:with-param name="expressions" select="$new_expressions"/> |
|
5305 </xsl:apply-templates> |
|
5306 </xsl:template> |
|
5307 <xsl:template mode="json_table_render" match="svg:g"> |
|
5308 <xsl:param name="expressions"/> |
|
5309 <xsl:param name="widget_elts"/> |
|
5310 <xsl:param name="label"/> |
|
5311 <xsl:variable name="varprefix"> |
|
5312 <xsl:text>obj_</xsl:text> |
|
5313 <xsl:value-of select="@id"/> |
|
5314 <xsl:text>_</xsl:text> |
|
5315 </xsl:variable> |
|
5316 <xsl:text> try { |
|
5317 </xsl:text> |
|
5318 <xsl:for-each select="$expressions/expression"> |
|
5319 <xsl:text> let </xsl:text> |
|
5320 <xsl:value-of select="$varprefix"/> |
|
5321 <xsl:value-of select="position()"/> |
|
5322 <xsl:text> = </xsl:text> |
|
5323 <xsl:value-of select="@content"/> |
|
5324 <xsl:text>; |
|
5325 </xsl:text> |
|
5326 <xsl:text> if(</xsl:text> |
|
5327 <xsl:value-of select="$varprefix"/> |
|
5328 <xsl:value-of select="position()"/> |
|
5329 <xsl:text> == undefined) { |
|
5330 </xsl:text> |
|
5331 <xsl:text> throw null; |
|
5332 </xsl:text> |
|
5333 <xsl:text> } |
|
5334 </xsl:text> |
|
5335 </xsl:for-each> |
|
5336 <xsl:variable name="new_expressions"> |
|
5337 <xsl:for-each select="$expressions/expression"> |
|
5338 <xsl:copy> |
|
5339 <xsl:copy-of select="@name"/> |
|
5340 <xsl:attribute name="content"> |
|
5341 <xsl:value-of select="$varprefix"/> |
|
5342 <xsl:value-of select="position()"/> |
|
5343 </xsl:attribute> |
|
5344 </xsl:copy> |
|
5345 </xsl:for-each> |
|
5346 </xsl:variable> |
|
5347 <xsl:text> id("</xsl:text> |
|
5348 <xsl:value-of select="@id"/> |
|
5349 <xsl:text>").style = "</xsl:text> |
|
5350 <xsl:value-of select="@style"/> |
|
5351 <xsl:text>"; |
|
5352 </xsl:text> |
|
5353 <xsl:apply-templates mode="json_table_render_except_comments" select="*"> |
|
5354 <xsl:with-param name="expressions" select="func:json_expressions(exsl:node-set($new_expressions), $label)"/> |
|
5355 <xsl:with-param name="widget_elts" select="$widget_elts"/> |
|
5356 </xsl:apply-templates> |
|
5357 <xsl:text> } catch(err) { |
|
5358 </xsl:text> |
|
5359 <xsl:text> id("</xsl:text> |
|
5360 <xsl:value-of select="@id"/> |
|
5361 <xsl:text>").style = "display:none"; |
|
5362 </xsl:text> |
|
5363 <xsl:text> } |
|
5364 </xsl:text> |
|
5365 </xsl:template> |
|
5366 <xsl:template match="widget[@type='JsonTable']" mode="widget_defs"> |
|
5367 <xsl:param name="hmi_element"/> |
|
5368 <xsl:call-template name="defs_by_labels"> |
|
5369 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
5370 <xsl:with-param name="labels"> |
|
5371 <xsl:text>data</xsl:text> |
|
5372 </xsl:with-param> |
|
5373 </xsl:call-template> |
|
5374 <xsl:variable name="data_elt" select="$result_svg_ns//*[@id = $hmi_element/@id]/*[@inkscape:label = 'data']"/> |
|
5375 <xsl:text> visible: </xsl:text> |
|
5376 <xsl:value-of select="count($data_elt/*[@inkscape:label])"/> |
|
5377 <xsl:text>, |
|
5378 </xsl:text> |
|
5379 <xsl:text> spread_json_data: function(janswer) { |
|
5380 </xsl:text> |
|
5381 <xsl:text> let [range,position,jdata] = janswer; |
|
5382 </xsl:text> |
|
5383 <xsl:text> [[1, range], [2, position], [3, this.visible]].map(([i,v]) => { |
|
5384 </xsl:text> |
|
5385 <xsl:text> this.apply_hmi_value(i,v); |
|
5386 </xsl:text> |
|
5387 <xsl:text> this.cache[i] = v; |
|
5388 </xsl:text> |
|
5389 <xsl:text> }); |
|
5390 </xsl:text> |
|
5391 <xsl:apply-templates mode="json_table_render_except_comments" select="$data_elt"> |
|
5392 <xsl:with-param name="expressions" select="$initexpr_ns"/> |
|
5393 <xsl:with-param name="widget_elts" select="$hmi_element/*[@inkscape:label = 'data']/descendant::svg:*"/> |
|
5394 </xsl:apply-templates> |
|
5395 <xsl:text> }, |
|
5396 </xsl:text> |
|
5397 <xsl:text> init() { |
|
5398 </xsl:text> |
|
5399 <xsl:text> this.init_common(); |
|
5400 </xsl:text> |
|
5401 <xsl:for-each select="$hmi_element/*[starts-with(@inkscape:label,'action_')]"> |
|
5402 <xsl:text> id("</xsl:text> |
|
5403 <xsl:value-of select="@id"/> |
|
5404 <xsl:text>").onclick = this.make_on_click("</xsl:text> |
|
5405 <xsl:value-of select="func:escape_quotes(@inkscape:label)"/> |
|
5406 <xsl:text>"); |
|
5407 </xsl:text> |
|
5408 </xsl:for-each> |
|
5409 <xsl:text> } |
|
5410 </xsl:text> |
|
5411 </xsl:template> |
|
5412 <xsl:template match="widget[@type='Jump']" mode="widget_desc"> |
|
5413 <type> |
|
5414 <xsl:value-of select="@type"/> |
|
5415 </type> |
|
5416 <longdesc> |
|
5417 <xsl:text>Jump widget brings focus to a different page. Mandatory single argument |
|
5418 </xsl:text> |
|
5419 <xsl:text>gives name of the page. |
|
5420 </xsl:text> |
|
5421 <xsl:text> |
|
5422 </xsl:text> |
|
5423 <xsl:text>Optional single path is used as new reference when jumping to a relative |
|
5424 </xsl:text> |
|
5425 <xsl:text>page, it must point to a HMI_NODE. |
|
5426 </xsl:text> |
|
5427 <xsl:text> |
|
5428 </xsl:text> |
|
5429 <xsl:text>"active"+"inactive" labeled elements can be provided and reflect current |
|
5430 </xsl:text> |
|
5431 <xsl:text>page being shown. |
|
5432 </xsl:text> |
|
5433 <xsl:text> |
|
5434 </xsl:text> |
|
5435 <xsl:text>"disabled" labeled element, if provided, is shown instead of "active" or |
|
5436 </xsl:text> |
|
5437 <xsl:text>"inactive" widget when pointed HMI_NODE is null. |
|
5438 </xsl:text> |
|
5439 </longdesc> |
|
5440 <shortdesc> |
|
5441 <xsl:text>Jump to given page</xsl:text> |
|
5442 </shortdesc> |
|
5443 <arg name="page" accepts="string"> |
|
5444 <xsl:text>name of page to jump to</xsl:text> |
|
5445 </arg> |
|
5446 <path name="reference" count="optional" accepts="HMI_NODE"> |
|
5447 <xsl:text>reference for relative jump</xsl:text> |
|
5448 </path> |
|
5449 </xsl:template> |
|
5450 <xsl:template match="widget[@type='Jump']" mode="widget_class"> |
|
5451 <xsl:text>class </xsl:text> |
|
5452 <xsl:text>JumpWidget</xsl:text> |
|
5453 <xsl:text> extends Widget{ |
|
5454 </xsl:text> |
|
5455 <xsl:text> activable = false; |
|
5456 </xsl:text> |
|
5457 <xsl:text> active = false; |
|
5458 </xsl:text> |
|
5459 <xsl:text> disabled = false; |
|
5460 </xsl:text> |
|
5461 <xsl:text> frequency = 2; |
|
5462 </xsl:text> |
|
5463 <xsl:text> |
|
5464 </xsl:text> |
|
5465 <xsl:text> update_activity() { |
|
5466 </xsl:text> |
|
5467 <xsl:text> if(this.active) { |
|
5468 </xsl:text> |
|
5469 <xsl:text> /* show active */ |
|
5470 </xsl:text> |
|
5471 <xsl:text> this.active_elt.style.display = ""; |
|
5472 </xsl:text> |
|
5473 <xsl:text> /* hide inactive */ |
|
5474 </xsl:text> |
|
5475 <xsl:text> this.inactive_elt.style.display = "none"; |
|
5476 </xsl:text> |
|
5477 <xsl:text> } else { |
|
5478 </xsl:text> |
|
5479 <xsl:text> /* show inactive */ |
|
5480 </xsl:text> |
|
5481 <xsl:text> this.inactive_elt.style.display = ""; |
|
5482 </xsl:text> |
|
5483 <xsl:text> /* hide active */ |
|
5484 </xsl:text> |
|
5485 <xsl:text> this.active_elt.style.display = "none"; |
|
5486 </xsl:text> |
|
5487 <xsl:text> } |
|
5488 </xsl:text> |
|
5489 <xsl:text> } |
|
5490 </xsl:text> |
|
5491 <xsl:text> |
|
5492 </xsl:text> |
|
5493 <xsl:text> update_disability() { |
|
5494 </xsl:text> |
|
5495 <xsl:text> if(this.disabled) { |
|
5496 </xsl:text> |
|
5497 <xsl:text> /* show disabled */ |
|
5498 </xsl:text> |
|
5499 <xsl:text> this.disabled_elt.style.display = ""; |
|
5500 </xsl:text> |
|
5501 <xsl:text> /* hide inactive */ |
|
5502 </xsl:text> |
|
5503 <xsl:text> this.inactive_elt.style.display = "none"; |
|
5504 </xsl:text> |
|
5505 <xsl:text> /* hide active */ |
|
5506 </xsl:text> |
|
5507 <xsl:text> this.active_elt.style.display = "none"; |
|
5508 </xsl:text> |
|
5509 <xsl:text> } else { |
|
5510 </xsl:text> |
|
5511 <xsl:text> /* hide disabled */ |
|
5512 </xsl:text> |
|
5513 <xsl:text> this.disabled_elt.style.display = "none"; |
|
5514 </xsl:text> |
|
5515 <xsl:text> this.update_activity(); |
|
5516 </xsl:text> |
|
5517 <xsl:text> } |
|
5518 </xsl:text> |
|
5519 <xsl:text> } |
|
5520 </xsl:text> |
|
5521 <xsl:text> |
|
5522 </xsl:text> |
|
5523 <xsl:text> make_on_click() { |
|
5524 </xsl:text> |
|
5525 <xsl:text> let that = this; |
|
5526 </xsl:text> |
|
5527 <xsl:text> const name = this.args[0]; |
|
5528 </xsl:text> |
|
5529 <xsl:text> return function(evt){ |
|
5530 </xsl:text> |
|
5531 <xsl:text> /* TODO: in order to allow jumps to page selected through for exemple a dropdown, |
|
5532 </xsl:text> |
|
5533 <xsl:text> support path pointing to local variable whom value |
|
5534 </xsl:text> |
|
5535 <xsl:text> would be an HMI_TREE index and then jump to a relative page not hard-coded in advance */ |
|
5536 </xsl:text> |
|
5537 <xsl:text> |
|
5538 </xsl:text> |
|
5539 <xsl:text> if(!that.disabled) { |
|
5540 </xsl:text> |
|
5541 <xsl:text> const index = that.indexes.length > 0 ? that.indexes[0] + that.offset : undefined; |
|
5542 </xsl:text> |
|
5543 <xsl:text> switch_page(name, index); |
|
5544 </xsl:text> |
|
5545 <xsl:text> } |
|
5546 </xsl:text> |
|
5547 <xsl:text> } |
|
5548 </xsl:text> |
|
5549 <xsl:text> } |
|
5550 </xsl:text> |
|
5551 <xsl:text> |
|
5552 </xsl:text> |
|
5553 <xsl:text> notify_page_change(page_name, index) { |
|
5554 </xsl:text> |
|
5555 <xsl:text> if(this.activable) { |
|
5556 </xsl:text> |
|
5557 <xsl:text> const ref_index = this.indexes.length > 0 ? this.indexes[0] + this.offset : undefined; |
|
5558 </xsl:text> |
|
5559 <xsl:text> const ref_name = this.args[0]; |
|
5560 </xsl:text> |
|
5561 <xsl:text> this.active = ((ref_name == undefined || ref_name == page_name) && index == ref_index); |
|
5562 </xsl:text> |
|
5563 <xsl:text> this.update_state(); |
|
5564 </xsl:text> |
|
5565 <xsl:text> } |
|
5566 </xsl:text> |
|
5567 <xsl:text> } |
|
5568 </xsl:text> |
|
5569 <xsl:text> |
|
5570 </xsl:text> |
|
5571 <xsl:text> dispatch(value) { |
|
5572 </xsl:text> |
|
5573 <xsl:text> this.disabled = !Number(value); |
|
5574 </xsl:text> |
|
5575 <xsl:text> this.update_state(); |
|
5576 </xsl:text> |
|
5577 <xsl:text> } |
|
5578 </xsl:text> |
|
5579 <xsl:text>} |
|
5580 </xsl:text> |
|
5581 </xsl:template> |
|
5582 <xsl:template match="widget[@type='Jump']" mode="widget_defs"> |
|
5583 <xsl:param name="hmi_element"/> |
|
5584 <xsl:variable name="activity"> |
|
5585 <xsl:call-template name="defs_by_labels"> |
|
5586 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
5587 <xsl:with-param name="labels"> |
|
5588 <xsl:text>active inactive</xsl:text> |
|
5589 </xsl:with-param> |
|
5590 <xsl:with-param name="mandatory" select="'no'"/> |
|
5591 </xsl:call-template> |
|
5592 </xsl:variable> |
|
5593 <xsl:variable name="have_activity" select="string-length($activity)>0"/> |
|
5594 <xsl:value-of select="$activity"/> |
|
5595 <xsl:variable name="disability"> |
|
5596 <xsl:call-template name="defs_by_labels"> |
|
5597 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
5598 <xsl:with-param name="labels"> |
|
5599 <xsl:text>disabled</xsl:text> |
|
5600 </xsl:with-param> |
|
5601 <xsl:with-param name="mandatory" select="'no'"/> |
|
5602 </xsl:call-template> |
|
5603 </xsl:variable> |
|
5604 <xsl:variable name="have_disability" select="$have_activity and string-length($disability)>0"/> |
|
5605 <xsl:value-of select="$disability"/> |
|
5606 <xsl:text> init: function() { |
|
5607 </xsl:text> |
|
5608 <xsl:text> this.element.onclick = this.make_on_click(); |
|
5609 </xsl:text> |
|
5610 <xsl:if test="$have_activity"> |
|
5611 <xsl:text> this.activable = true; |
|
5612 </xsl:text> |
|
5613 </xsl:if> |
|
5614 <xsl:if test="not($have_disability)"> |
|
5615 <xsl:text> this.unsubscribable = true; |
|
5616 </xsl:text> |
|
5617 </xsl:if> |
|
5618 <xsl:text> this.update_state = </xsl:text> |
|
5619 <xsl:choose> |
|
5620 <xsl:when test="$have_disability"> |
|
5621 <xsl:text>this.update_disability</xsl:text> |
|
5622 </xsl:when> |
|
5623 <xsl:when test="$have_activity"> |
|
5624 <xsl:text>this.update_activity</xsl:text> |
|
5625 </xsl:when> |
|
5626 <xsl:otherwise> |
|
5627 <xsl:text>null</xsl:text> |
|
5628 </xsl:otherwise> |
|
5629 </xsl:choose> |
|
5630 <xsl:text>; |
|
5631 </xsl:text> |
|
5632 <xsl:text> }, |
|
5633 </xsl:text> |
|
5634 </xsl:template> |
|
5635 <xsl:template match="widget[@type='Jump']" mode="widget_page"> |
|
5636 <xsl:param name="page_desc"/> |
|
5637 <xsl:param name="page_desc"/> |
|
5638 <xsl:if test="path"> |
|
5639 <xsl:variable name="target_page_name"> |
|
5640 <xsl:choose> |
|
5641 <xsl:when test="arg"> |
|
5642 <xsl:value-of select="arg[1]/@value"/> |
|
5643 </xsl:when> |
|
5644 <xsl:otherwise> |
|
5645 <xsl:value-of select="$page_desc/arg[1]/@value"/> |
|
5646 </xsl:otherwise> |
|
5647 </xsl:choose> |
|
5648 </xsl:variable> |
|
5649 <xsl:variable name="target_page_path"> |
|
5650 <xsl:choose> |
|
5651 <xsl:when test="arg"> |
|
5652 <xsl:value-of select="$hmi_pages_descs[arg[1]/@value = $target_page_name]/path[1]/@value"/> |
|
5653 </xsl:when> |
|
5654 <xsl:otherwise> |
|
5655 <xsl:value-of select="$page_desc/path[1]/@value"/> |
|
5656 </xsl:otherwise> |
|
5657 </xsl:choose> |
|
5658 </xsl:variable> |
|
5659 <xsl:if test="not(func:same_class_paths($target_page_path, path[1]/@value))"> |
|
5660 <xsl:message terminate="yes"> |
|
5661 <xsl:text>Jump id="</xsl:text> |
|
5662 <xsl:value-of select="@id"/> |
|
5663 <xsl:text>" to page "</xsl:text> |
|
5664 <xsl:value-of select="$target_page_name"/> |
|
5665 <xsl:text>" with incompatible path "</xsl:text> |
|
5666 <xsl:value-of select="path[1]/@value"/> |
|
5667 <xsl:text> (must be same class as "</xsl:text> |
|
5668 <xsl:value-of select="$target_page_path"/> |
|
5669 <xsl:text>")</xsl:text> |
|
5670 </xsl:message> |
|
5671 </xsl:if> |
|
5672 </xsl:if> |
|
5673 </xsl:template> |
|
5674 <declarations:jump/> |
|
5675 <xsl:template match="declarations:jump"> |
|
5676 <xsl:text> |
|
5677 </xsl:text> |
|
5678 <xsl:text>/* </xsl:text> |
|
5679 <xsl:value-of select="local-name()"/> |
|
5680 <xsl:text> */ |
|
5681 </xsl:text> |
|
5682 <xsl:text> |
|
5683 </xsl:text> |
|
5684 <xsl:text>var jumps_need_update = false; |
|
5685 </xsl:text> |
|
5686 <xsl:text>var jump_history = [[default_page, undefined]]; |
|
5687 </xsl:text> |
|
5688 <xsl:text> |
|
5689 </xsl:text> |
|
5690 <xsl:text>function update_jumps() { |
|
5691 </xsl:text> |
|
5692 <xsl:text> page_desc[current_visible_page].jumps.map(w=>w.notify_page_change(current_visible_page,current_page_index)); |
|
5693 </xsl:text> |
|
5694 <xsl:text> jumps_need_update = false; |
|
5695 </xsl:text> |
|
5696 <xsl:text>}; |
|
5697 </xsl:text> |
|
5698 <xsl:text> |
|
5699 </xsl:text> |
|
5700 <xsl:text> |
|
5701 </xsl:text> |
|
5702 </xsl:template> |
|
5703 <xsl:template match="widget[@type='Keypad']" mode="widget_desc"> |
|
5704 <type> |
|
5705 <xsl:value-of select="@type"/> |
|
5706 </type> |
|
5707 <longdesc> |
|
5708 <xsl:text>Keypad - to be written |
|
5709 </xsl:text> |
|
5710 </longdesc> |
|
5711 <shortdesc> |
|
5712 <xsl:text>Keypad </xsl:text> |
|
5713 </shortdesc> |
|
5714 <arg name="supported_types" accepts="string"> |
|
5715 <xsl:text>keypad can input those types </xsl:text> |
|
5716 </arg> |
|
5717 </xsl:template> |
|
5718 <declarations:keypad/> |
|
5719 <xsl:template match="declarations:keypad"> |
|
5720 <xsl:text> |
|
5721 </xsl:text> |
|
5722 <xsl:text>/* </xsl:text> |
|
5723 <xsl:value-of select="local-name()"/> |
|
5724 <xsl:text> */ |
|
5725 </xsl:text> |
|
5726 <xsl:text> |
|
5727 </xsl:text> |
|
5728 <xsl:text> |
|
5729 </xsl:text> |
|
5730 <xsl:text>var keypads = { |
|
5731 </xsl:text> |
|
5732 <xsl:for-each select="$keypads_descs"> |
|
5733 <xsl:variable name="keypad_id" select="@id"/> |
|
5734 <xsl:for-each select="arg"> |
|
5735 <xsl:variable name="g" select="$geometry[@Id = $keypad_id]"/> |
|
5736 <xsl:text> "</xsl:text> |
|
5737 <xsl:value-of select="@value"/> |
|
5738 <xsl:text>":["</xsl:text> |
|
5739 <xsl:value-of select="$keypad_id"/> |
|
5740 <xsl:text>", </xsl:text> |
|
5741 <xsl:value-of select="$g/@x"/> |
|
5742 <xsl:text>, </xsl:text> |
|
5743 <xsl:value-of select="$g/@y"/> |
|
5744 <xsl:text>], |
|
5745 </xsl:text> |
|
5746 </xsl:for-each> |
|
5747 </xsl:for-each> |
|
5748 <xsl:text>} |
|
5749 </xsl:text> |
|
5750 <xsl:text> |
|
5751 </xsl:text> |
|
5752 </xsl:template> |
|
5753 <xsl:template match="widget[@type='Keypad']" mode="widget_class"> |
|
5754 <xsl:text>class </xsl:text> |
|
5755 <xsl:text>KeypadWidget</xsl:text> |
|
5756 <xsl:text> extends Widget{ |
|
5757 </xsl:text> |
|
5758 <xsl:text> on_key_click(symbols) { |
|
5759 </xsl:text> |
|
5760 <xsl:text> var syms = symbols.split(" "); |
|
5761 </xsl:text> |
|
5762 <xsl:text> this.shift |= this.caps; |
|
5763 </xsl:text> |
|
5764 <xsl:text> this.editstr += syms[this.shift?syms.length-1:0]; |
|
5765 </xsl:text> |
|
5766 <xsl:text> this.shift = false; |
|
5767 </xsl:text> |
|
5768 <xsl:text> this.update(); |
|
5769 </xsl:text> |
|
5770 <xsl:text> } |
|
5771 </xsl:text> |
|
5772 <xsl:text> |
|
5773 </xsl:text> |
|
5774 <xsl:text> on_Esc_click() { |
|
5775 </xsl:text> |
|
5776 <xsl:text> end_modal.call(this); |
|
5777 </xsl:text> |
|
5778 <xsl:text> } |
|
5779 </xsl:text> |
|
5780 <xsl:text> |
|
5781 </xsl:text> |
|
5782 <xsl:text> on_Enter_click() { |
|
5783 </xsl:text> |
|
5784 <xsl:text> let coercedval = (typeof this.initial) == "number" ? Number(this.editstr) : this.editstr; |
|
5785 </xsl:text> |
|
5786 <xsl:text> if(typeof coercedval == 'number' && isNaN(coercedval)){ |
|
5787 </xsl:text> |
|
5788 <xsl:text> // revert to initial so it explicitely shows input was ignored |
|
5789 </xsl:text> |
|
5790 <xsl:text> this.editstr = String(this.initial); |
|
5791 </xsl:text> |
|
5792 <xsl:text> this.update(); |
|
5793 </xsl:text> |
|
5794 <xsl:text> } else { |
|
5795 </xsl:text> |
|
5796 <xsl:text> let callback_obj = this.result_callback_obj; |
|
5797 </xsl:text> |
|
5798 <xsl:text> end_modal.call(this); |
|
5799 </xsl:text> |
|
5800 <xsl:text> callback_obj.edit_callback(coercedval); |
|
5801 </xsl:text> |
|
5802 <xsl:text> } |
|
5803 </xsl:text> |
|
5804 <xsl:text> } |
|
5805 </xsl:text> |
|
5806 <xsl:text> |
|
5807 </xsl:text> |
|
5808 <xsl:text> on_BackSpace_click() { |
|
5809 </xsl:text> |
|
5810 <xsl:text> this.editstr = this.editstr.slice(0,this.editstr.length-1); |
|
5811 </xsl:text> |
|
5812 <xsl:text> this.update(); |
|
5813 </xsl:text> |
|
5814 <xsl:text> } |
|
5815 </xsl:text> |
|
5816 <xsl:text> |
|
5817 </xsl:text> |
|
5818 <xsl:text> on_Sign_click() { |
|
5819 </xsl:text> |
|
5820 <xsl:text> if(this.editstr[0] == "-") |
|
5821 </xsl:text> |
|
5822 <xsl:text> this.editstr = this.editstr.slice(1,this.editstr.length); |
|
5823 </xsl:text> |
|
5824 <xsl:text> else |
|
5825 </xsl:text> |
|
5826 <xsl:text> this.editstr = "-" + this.editstr; |
|
5827 </xsl:text> |
|
5828 <xsl:text> this.update(); |
|
5829 </xsl:text> |
|
5830 <xsl:text> } |
|
5831 </xsl:text> |
|
5832 <xsl:text> |
|
5833 </xsl:text> |
|
5834 <xsl:text> on_NumDot_click() { |
|
5835 </xsl:text> |
|
5836 <xsl:text> if(this.editstr.indexOf(".") == "-1"){ |
|
5837 </xsl:text> |
|
5838 <xsl:text> this.editstr += "."; |
|
5839 </xsl:text> |
|
5840 <xsl:text> this.update(); |
|
5841 </xsl:text> |
|
5842 <xsl:text> } |
|
5843 </xsl:text> |
|
5844 <xsl:text> } |
|
5845 </xsl:text> |
|
5846 <xsl:text> |
|
5847 </xsl:text> |
|
5848 <xsl:text> on_Space_click() { |
|
5849 </xsl:text> |
|
5850 <xsl:text> this.editstr += " "; |
|
5851 </xsl:text> |
|
5852 <xsl:text> this.update(); |
|
5853 </xsl:text> |
|
5854 <xsl:text> } |
|
5855 </xsl:text> |
|
5856 <xsl:text> |
|
5857 </xsl:text> |
|
5858 <xsl:text> caps = false; |
|
5859 </xsl:text> |
|
5860 <xsl:text> _caps = undefined; |
|
5861 </xsl:text> |
|
5862 <xsl:text> on_CapsLock_click() { |
|
5863 </xsl:text> |
|
5864 <xsl:text> this.caps = !this.caps; |
|
5865 </xsl:text> |
|
5866 <xsl:text> this.update(); |
|
5867 </xsl:text> |
|
5868 <xsl:text> } |
|
5869 </xsl:text> |
|
5870 <xsl:text> |
|
5871 </xsl:text> |
|
5872 <xsl:text> shift = false; |
|
5873 </xsl:text> |
|
5874 <xsl:text> _shift = undefined; |
|
5875 </xsl:text> |
|
5876 <xsl:text> on_Shift_click() { |
|
5877 </xsl:text> |
|
5878 <xsl:text> this.shift = !this.shift; |
|
5879 </xsl:text> |
|
5880 <xsl:text> this.caps = false; |
|
5881 </xsl:text> |
|
5882 <xsl:text> this.update(); |
|
5883 </xsl:text> |
|
5884 <xsl:text> } |
|
5885 </xsl:text> |
|
5886 <xsl:text> editstr = ""; |
|
5887 </xsl:text> |
|
5888 <xsl:text> _editstr = undefined; |
|
5889 </xsl:text> |
|
5890 <xsl:text> result_callback_obj = undefined; |
|
5891 </xsl:text> |
|
5892 <xsl:text> start_edit(info, valuetype, callback_obj, initial,size) { |
|
5893 </xsl:text> |
|
5894 <xsl:text> show_modal.call(this,size); |
|
5895 </xsl:text> |
|
5896 <xsl:text> this.editstr = String(initial); |
|
5897 </xsl:text> |
|
5898 <xsl:text> this.result_callback_obj = callback_obj; |
|
5899 </xsl:text> |
|
5900 <xsl:text> this.Info_elt.textContent = info; |
|
5901 </xsl:text> |
|
5902 <xsl:text> this.shift = false; |
|
5903 </xsl:text> |
|
5904 <xsl:text> this.caps = false; |
|
5905 </xsl:text> |
|
5906 <xsl:text> this.initial = initial; |
|
5907 </xsl:text> |
|
5908 <xsl:text> |
|
5909 </xsl:text> |
|
5910 <xsl:text> this.update(); |
|
5911 </xsl:text> |
|
5912 <xsl:text> } |
|
5913 </xsl:text> |
|
5914 <xsl:text> |
|
5915 </xsl:text> |
|
5916 <xsl:text> update() { |
|
5917 </xsl:text> |
|
5918 <xsl:text> if(this.editstr != this._editstr){ |
|
5919 </xsl:text> |
|
5920 <xsl:text> this._editstr = this.editstr; |
|
5921 </xsl:text> |
|
5922 <xsl:text> this.Value_elt.textContent = this.editstr; |
|
5923 </xsl:text> |
|
5924 <xsl:text> } |
|
5925 </xsl:text> |
|
5926 <xsl:text> if(this.Shift_sub && this.shift != this._shift){ |
|
5927 </xsl:text> |
|
5928 <xsl:text> this._shift = this.shift; |
|
5929 </xsl:text> |
|
5930 <xsl:text> (this.shift?this.activate_activable:this.inactivate_activable)(this.Shift_sub); |
|
5931 </xsl:text> |
|
5932 <xsl:text> } |
|
5933 </xsl:text> |
|
5934 <xsl:text> if(this.CapsLock_sub && this.caps != this._caps){ |
|
5935 </xsl:text> |
|
5936 <xsl:text> this._caps = this.caps; |
|
5937 </xsl:text> |
|
5938 <xsl:text> (this.caps?this.activate_activable:this.inactivate_activable)(this.CapsLock_sub); |
|
5939 </xsl:text> |
|
5940 <xsl:text> } |
|
5941 </xsl:text> |
|
5942 <xsl:text> } |
|
5943 </xsl:text> |
|
5944 <xsl:text>} |
|
5945 </xsl:text> |
|
5946 </xsl:template> |
|
5947 <xsl:template match="widget[@type='Keypad']" mode="widget_defs"> |
|
5948 <xsl:param name="hmi_element"/> |
|
5949 <xsl:call-template name="defs_by_labels"> |
|
5950 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
5951 <xsl:with-param name="labels"> |
|
5952 <xsl:text>Esc Enter BackSpace Keys Info Value</xsl:text> |
|
5953 </xsl:with-param> |
|
5954 </xsl:call-template> |
|
5955 <xsl:call-template name="defs_by_labels"> |
|
5956 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
5957 <xsl:with-param name="labels"> |
|
5958 <xsl:text>Sign Space NumDot</xsl:text> |
|
5959 </xsl:with-param> |
|
5960 <xsl:with-param name="mandatory" select="'no'"/> |
|
5961 </xsl:call-template> |
|
5962 <xsl:call-template name="defs_by_labels"> |
|
5963 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
5964 <xsl:with-param name="labels"> |
|
5965 <xsl:text>CapsLock Shift</xsl:text> |
|
5966 </xsl:with-param> |
|
5967 <xsl:with-param name="mandatory" select="'no'"/> |
|
5968 <xsl:with-param name="subelements" select="'active inactive'"/> |
|
5969 </xsl:call-template> |
|
5970 <xsl:text> init: function() { |
|
5971 </xsl:text> |
|
5972 <xsl:for-each select="$hmi_element/*[@inkscape:label = 'Keys']/*"> |
|
5973 <xsl:text> id("</xsl:text> |
|
5974 <xsl:value-of select="@id"/> |
|
5975 <xsl:text>").setAttribute("onclick", "hmi_widgets['</xsl:text> |
|
5976 <xsl:value-of select="$hmi_element/@id"/> |
|
5977 <xsl:text>'].on_key_click('</xsl:text> |
|
5978 <xsl:value-of select="func:escape_quotes(@inkscape:label)"/> |
|
5979 <xsl:text>')"); |
|
5980 </xsl:text> |
|
5981 </xsl:for-each> |
|
5982 <xsl:for-each select="str:split('Esc Enter BackSpace Sign Space NumDot CapsLock Shift')"> |
|
5983 <xsl:text> if(this.</xsl:text> |
|
5984 <xsl:value-of select="."/> |
|
5985 <xsl:text>_elt) |
|
5986 </xsl:text> |
|
5987 <xsl:text> this.</xsl:text> |
|
5988 <xsl:value-of select="."/> |
|
5989 <xsl:text>_elt.setAttribute("onclick", "hmi_widgets['</xsl:text> |
|
5990 <xsl:value-of select="$hmi_element/@id"/> |
|
5991 <xsl:text>'].on_</xsl:text> |
|
5992 <xsl:value-of select="."/> |
|
5993 <xsl:text>_click()"); |
|
5994 </xsl:text> |
|
5995 </xsl:for-each> |
|
5996 <xsl:text> }, |
|
5997 </xsl:text> |
|
5998 <xsl:text> |
|
5999 </xsl:text> |
|
6000 <xsl:variable name="g" select="$geometry[@Id = $hmi_element/@id]"/> |
|
6001 <xsl:text> coordinates: [</xsl:text> |
|
6002 <xsl:value-of select="$g/@x"/> |
|
6003 <xsl:text>, </xsl:text> |
|
6004 <xsl:value-of select="$g/@y"/> |
|
6005 <xsl:text>], |
|
6006 </xsl:text> |
|
6007 </xsl:template> |
|
6008 <xsl:template match="widget[@type='List']" mode="widget_desc"> |
|
6009 <type> |
|
6010 <xsl:value-of select="@type"/> |
|
6011 </type> |
|
6012 </xsl:template> |
|
6013 <xsl:template match="widget[@type='List']" mode="widget_defs"> |
|
6014 <xsl:param name="hmi_element"/> |
|
6015 <xsl:text> items: { |
|
6016 </xsl:text> |
|
6017 <xsl:for-each select="$hmi_element/*[@inkscape:label]"> |
|
6018 <xsl:text> </xsl:text> |
|
6019 <xsl:value-of select="@inkscape:label"/> |
|
6020 <xsl:text>: "</xsl:text> |
|
6021 <xsl:value-of select="@id"/> |
|
6022 <xsl:text>", |
|
6023 </xsl:text> |
|
6024 </xsl:for-each> |
|
6025 <xsl:text> }, |
|
6026 </xsl:text> |
|
6027 </xsl:template> |
|
6028 <xsl:template match="widget[@type='TextStyleList']" mode="widget_defs"> |
|
6029 <xsl:param name="hmi_element"/> |
|
6030 </xsl:template> |
|
6031 <xsl:template match="widget[@type='TextStyleList']" mode="widget_defs"> |
|
6032 <xsl:param name="hmi_element"/> |
|
6033 <xsl:text> styles: { |
|
6034 </xsl:text> |
|
6035 <xsl:for-each select="$hmi_element/*[@inkscape:label]"> |
|
6036 <xsl:variable name="style" select="func:refered_elements(.)[self::svg:text]/@style"/> |
|
6037 <xsl:text> </xsl:text> |
|
6038 <xsl:value-of select="@inkscape:label"/> |
|
6039 <xsl:text>: "</xsl:text> |
|
6040 <xsl:value-of select="$style"/> |
|
6041 <xsl:text>", |
|
6042 </xsl:text> |
|
6043 </xsl:for-each> |
|
6044 <xsl:text> }, |
|
6045 </xsl:text> |
|
6046 </xsl:template> |
|
6047 <xsl:template match="widget[@type='Meter']" mode="widget_desc"> |
|
6048 <type> |
|
6049 <xsl:value-of select="@type"/> |
|
6050 </type> |
|
6051 <longdesc> |
|
6052 <xsl:text>Meter widget moves the end of "needle" labeled path along "range" labeled |
|
6053 </xsl:text> |
|
6054 <xsl:text>path, according to value of the single accepted variable. |
|
6055 </xsl:text> |
|
6056 <xsl:text> |
|
6057 </xsl:text> |
|
6058 <xsl:text>Needle is reduced to a single segment. If "min" a "max" labeled texts |
|
6059 </xsl:text> |
|
6060 <xsl:text>are provided, or if first and second argument are given, then they are used |
|
6061 </xsl:text> |
|
6062 <xsl:text>as respective minimum and maximum value. Otherwise, value is expected to be |
|
6063 </xsl:text> |
|
6064 <xsl:text>in between 0 and 100. |
|
6065 </xsl:text> |
|
6066 <xsl:text> |
|
6067 </xsl:text> |
|
6068 <xsl:text>If "value" labeled text is found, then its content is replaced by value. |
|
6069 </xsl:text> |
|
6070 </longdesc> |
|
6071 <shortdesc> |
|
6072 <xsl:text>Moves "needle" along "range"</xsl:text> |
|
6073 </shortdesc> |
|
6074 <arg name="min" count="optional" accepts="int,real"> |
|
6075 <xsl:text>minimum value</xsl:text> |
|
6076 </arg> |
|
6077 <arg name="max" count="optional" accepts="int,real"> |
|
6078 <xsl:text>maximum value</xsl:text> |
|
6079 </arg> |
|
6080 <path name="value" accepts="HMI_INT,HMI_REAL"> |
|
6081 <xsl:text>Value to display</xsl:text> |
|
6082 </path> |
|
6083 </xsl:template> |
|
6084 <xsl:template match="widget[@type='Meter']" mode="widget_class"> |
|
6085 <xsl:text>class </xsl:text> |
|
6086 <xsl:text>MeterWidget</xsl:text> |
|
6087 <xsl:text> extends Widget{ |
|
6088 </xsl:text> |
|
6089 <xsl:text> frequency = 10; |
|
6090 </xsl:text> |
|
6091 <xsl:text> origin = undefined; |
|
6092 </xsl:text> |
|
6093 <xsl:text> range = undefined; |
|
6094 </xsl:text> |
|
6095 <xsl:text> |
|
6096 </xsl:text> |
|
6097 <xsl:text> dispatch(value) { |
|
6098 </xsl:text> |
|
6099 <xsl:text> this.display_val = value; |
|
6100 </xsl:text> |
|
6101 <xsl:text> this.request_animate(); |
|
6102 </xsl:text> |
|
6103 <xsl:text> } |
|
6104 </xsl:text> |
|
6105 <xsl:text> |
|
6106 </xsl:text> |
|
6107 <xsl:text> animate(){ |
|
6108 </xsl:text> |
|
6109 <xsl:text> if(this.value_elt) |
|
6110 </xsl:text> |
|
6111 <xsl:text> this.value_elt.textContent = String(this.display_val); |
|
6112 </xsl:text> |
|
6113 <xsl:text> let [min,max,totallength] = this.range; |
|
6114 </xsl:text> |
|
6115 <xsl:text> let length = Math.max(0,Math.min(totallength,(Number(this.display_val)-min)*totallength/(max-min))); |
|
6116 </xsl:text> |
|
6117 <xsl:text> let tip = this.range_elt.getPointAtLength(length); |
|
6118 </xsl:text> |
|
6119 <xsl:text> this.needle_elt.setAttribute('d', "M "+this.origin.x+","+this.origin.y+" "+tip.x+","+tip.y); |
|
6120 </xsl:text> |
|
6121 <xsl:text> } |
|
6122 </xsl:text> |
|
6123 <xsl:text> |
|
6124 </xsl:text> |
|
6125 <xsl:text> init() { |
|
6126 </xsl:text> |
|
6127 <xsl:text> let [min,max] = [[this.min_elt,0],[this.max_elt,100]].map(([elt,def],i)=>elt? |
|
6128 </xsl:text> |
|
6129 <xsl:text> Number(elt.textContent) : |
|
6130 </xsl:text> |
|
6131 <xsl:text> this.args.length >= i+1 ? this.args[i] : def); |
|
6132 </xsl:text> |
|
6133 <xsl:text> |
|
6134 </xsl:text> |
|
6135 <xsl:text> this.range = [min, max, this.range_elt.getTotalLength()] |
|
6136 </xsl:text> |
|
6137 <xsl:text> this.origin = this.needle_elt.getPointAtLength(0); |
|
6138 </xsl:text> |
|
6139 <xsl:text> } |
|
6140 </xsl:text> |
|
6141 <xsl:text>} |
|
6142 </xsl:text> |
|
6143 </xsl:template> |
|
6144 <xsl:template match="widget[@type='Meter']" mode="widget_defs"> |
|
6145 <xsl:param name="hmi_element"/> |
|
6146 <xsl:call-template name="defs_by_labels"> |
|
6147 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
6148 <xsl:with-param name="labels"> |
|
6149 <xsl:text>needle range</xsl:text> |
|
6150 </xsl:with-param> |
|
6151 </xsl:call-template> |
|
6152 <xsl:call-template name="defs_by_labels"> |
|
6153 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
6154 <xsl:with-param name="labels"> |
|
6155 <xsl:text>value min max</xsl:text> |
|
6156 </xsl:with-param> |
|
6157 <xsl:with-param name="mandatory" select="'no'"/> |
|
6158 </xsl:call-template> |
|
6159 </xsl:template> |
|
6160 <xsl:template match="widget[@type='MultiState']" mode="widget_defs"> |
|
6161 <xsl:param name="hmi_element"/> |
|
6162 <longdesc> |
|
6163 <xsl:text>Mutlistateh widget hides all subelements whose label do not match given |
|
6164 </xsl:text> |
|
6165 <xsl:text>variable value representation. For exemple if given variable type |
|
6166 </xsl:text> |
|
6167 <xsl:text>is HMI_INT and value is 1, then elements with label '1' will be displayed. |
|
6168 </xsl:text> |
|
6169 <xsl:text>Label can have comments, so '1#some comment' would also match. If matching |
|
6170 </xsl:text> |
|
6171 <xsl:text>variable of type HMI_STRING, then double quotes must be used. For exemple, |
|
6172 </xsl:text> |
|
6173 <xsl:text>'"hello"' or '"hello"#another comment' match HMI_STRING 'hello'. |
|
6174 </xsl:text> |
|
6175 <xsl:text> |
|
6176 </xsl:text> |
|
6177 <xsl:text>Click on widget changes variable value to next value in given list, or to |
|
6178 </xsl:text> |
|
6179 <xsl:text>first one if not initialized to value already part of the list. |
|
6180 </xsl:text> |
|
6181 </longdesc> |
|
6182 <shortdesc> |
|
6183 <xsl:text>Show elements whose label match value.</xsl:text> |
|
6184 </shortdesc> |
|
6185 <path name="value" accepts="HMI_INT,HMI_STRING"> |
|
6186 <xsl:text>value to compare to labels</xsl:text> |
|
6187 </path> |
|
6188 </xsl:template> |
|
6189 <xsl:template match="widget[@type='MultiState']" mode="widget_class"> |
|
6190 <xsl:text>class </xsl:text> |
|
6191 <xsl:text>MultiStateWidget</xsl:text> |
|
6192 <xsl:text> extends Widget{ |
|
6193 </xsl:text> |
|
6194 <xsl:text> frequency = 5; |
|
6195 </xsl:text> |
|
6196 <xsl:text> state = 0; |
|
6197 </xsl:text> |
|
6198 <xsl:text> dispatch(value) { |
|
6199 </xsl:text> |
|
6200 <xsl:text> this.state = value; |
|
6201 </xsl:text> |
|
6202 <xsl:text> for(let choice of this.choices){ |
|
6203 </xsl:text> |
|
6204 <xsl:text> if(this.state != choice.value){ |
|
6205 </xsl:text> |
|
6206 <xsl:text> choice.elt.setAttribute("style", "display:none"); |
|
6207 </xsl:text> |
|
6208 <xsl:text> } else { |
|
6209 </xsl:text> |
|
6210 <xsl:text> choice.elt.setAttribute("style", choice.style); |
|
6211 </xsl:text> |
|
6212 <xsl:text> } |
|
6213 </xsl:text> |
|
6214 <xsl:text> } |
|
6215 </xsl:text> |
|
6216 <xsl:text> } |
|
6217 </xsl:text> |
|
6218 <xsl:text> |
|
6219 </xsl:text> |
|
6220 <xsl:text> on_click(evt) { |
|
6221 </xsl:text> |
|
6222 <xsl:text> //get current selected value |
|
6223 </xsl:text> |
|
6224 <xsl:text> let next_ind; |
|
6225 </xsl:text> |
|
6226 <xsl:text> for(next_ind=0; next_ind<this.choices.length; next_ind++){ |
|
6227 </xsl:text> |
|
6228 <xsl:text> if(this.state == this.choices[next_ind].value){ |
|
6229 </xsl:text> |
|
6230 <xsl:text> next_ind = next_ind + 1; |
|
6231 </xsl:text> |
|
6232 <xsl:text> break; |
|
6233 </xsl:text> |
|
6234 <xsl:text> } |
|
6235 </xsl:text> |
|
6236 <xsl:text> } |
|
6237 </xsl:text> |
|
6238 <xsl:text> |
|
6239 </xsl:text> |
|
6240 <xsl:text> //get next selected value |
|
6241 </xsl:text> |
|
6242 <xsl:text> if(this.choices.length > next_ind){ |
|
6243 </xsl:text> |
|
6244 <xsl:text> this.state = this.choices[next_ind].value; |
|
6245 </xsl:text> |
|
6246 <xsl:text> } |
|
6247 </xsl:text> |
|
6248 <xsl:text> else{ |
|
6249 </xsl:text> |
|
6250 <xsl:text> this.state = this.choices[0].value; |
|
6251 </xsl:text> |
|
6252 <xsl:text> } |
|
6253 </xsl:text> |
|
6254 <xsl:text> |
|
6255 </xsl:text> |
|
6256 <xsl:text> //post value to plc |
|
6257 </xsl:text> |
|
6258 <xsl:text> this.apply_hmi_value(0, this.state); |
|
6259 </xsl:text> |
|
6260 <xsl:text> } |
|
6261 </xsl:text> |
|
6262 <xsl:text> |
|
6263 </xsl:text> |
|
6264 <xsl:text> init() { |
|
6265 </xsl:text> |
|
6266 <xsl:text> this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)"); |
|
6267 </xsl:text> |
|
6268 <xsl:text> } |
|
6269 </xsl:text> |
|
6270 <xsl:text>} |
|
6271 </xsl:text> |
|
6272 </xsl:template> |
|
6273 <xsl:template match="widget[@type='MultiState']" mode="widget_defs"> |
|
6274 <xsl:param name="hmi_element"/> |
|
6275 <xsl:text> choices: [ |
|
6276 </xsl:text> |
|
6277 <xsl:variable name="regex" select="'^("[^"].*"|\-?[0-9]+|false|true)(#.*)?$'"/> |
|
6278 <xsl:for-each select="$result_svg_ns//*[@id = $hmi_element/@id]//*[regexp:test(@inkscape:label,$regex)]"> |
|
6279 <xsl:variable name="literal" select="regexp:match(@inkscape:label,$regex)[2]"/> |
|
6280 <xsl:text> { |
|
6281 </xsl:text> |
|
6282 <xsl:text> elt:id("</xsl:text> |
|
6283 <xsl:value-of select="@id"/> |
|
6284 <xsl:text>"), |
|
6285 </xsl:text> |
|
6286 <xsl:text> style:"</xsl:text> |
|
6287 <xsl:value-of select="@style"/> |
|
6288 <xsl:text>", |
|
6289 </xsl:text> |
|
6290 <xsl:text> value:</xsl:text> |
|
6291 <xsl:value-of select="$literal"/> |
|
6292 <xsl:text> |
|
6293 </xsl:text> |
|
6294 <xsl:text> }</xsl:text> |
|
6295 <xsl:if test="position()!=last()"> |
|
6296 <xsl:text>,</xsl:text> |
|
6297 </xsl:if> |
|
6298 <xsl:text> |
|
6299 </xsl:text> |
|
6300 </xsl:for-each> |
|
6301 <xsl:text> ], |
|
6302 </xsl:text> |
|
6303 </xsl:template> |
|
6304 <xsl:template match="widget[@type='ScrollBar']" mode="widget_desc"> |
|
6305 <type> |
|
6306 <xsl:value-of select="@type"/> |
|
6307 </type> |
|
6308 <longdesc> |
|
6309 <xsl:text>ScrollBar - documentation to be written |
|
6310 </xsl:text> |
|
6311 </longdesc> |
|
6312 <shortdesc> |
|
6313 <xsl:text>ScrollBar</xsl:text> |
|
6314 </shortdesc> |
|
6315 <path name="value" accepts="HMI_INT"> |
|
6316 <xsl:text>value</xsl:text> |
|
6317 </path> |
|
6318 <path name="range" accepts="HMI_INT"> |
|
6319 <xsl:text>range</xsl:text> |
|
6320 </path> |
|
6321 <path name="visible" accepts="HMI_INT"> |
|
6322 <xsl:text>visible</xsl:text> |
|
6323 </path> |
|
6324 </xsl:template> |
|
6325 <xsl:template match="widget[@type='ScrollBar']" mode="widget_class"> |
|
6326 <xsl:text>class </xsl:text> |
|
6327 <xsl:text>ScrollBarWidget</xsl:text> |
|
6328 <xsl:text> extends Widget{ |
|
6329 </xsl:text> |
|
6330 <xsl:text> frequency = 10; |
|
6331 </xsl:text> |
|
6332 <xsl:text> position = undefined; |
|
6333 </xsl:text> |
|
6334 <xsl:text> range = undefined; |
|
6335 </xsl:text> |
|
6336 <xsl:text> size = undefined; |
|
6337 </xsl:text> |
|
6338 <xsl:text> mincursize = 0.1; |
|
6339 </xsl:text> |
|
6340 <xsl:text> |
|
6341 </xsl:text> |
|
6342 <xsl:text> dispatch(value,oldval, index) { |
|
6343 </xsl:text> |
|
6344 <xsl:text> switch(index) { |
|
6345 </xsl:text> |
|
6346 <xsl:text> case 0: |
|
6347 </xsl:text> |
|
6348 <xsl:text> this.range = Math.max(1,value); |
|
6349 </xsl:text> |
|
6350 <xsl:text> break; |
|
6351 </xsl:text> |
|
6352 <xsl:text> case 1: |
|
6353 </xsl:text> |
|
6354 <xsl:text> this.position = value; |
|
6355 </xsl:text> |
|
6356 <xsl:text> break; |
|
6357 </xsl:text> |
|
6358 <xsl:text> case 2: |
|
6359 </xsl:text> |
|
6360 <xsl:text> this.size = value; |
|
6361 </xsl:text> |
|
6362 <xsl:text> break; |
|
6363 </xsl:text> |
|
6364 <xsl:text> } |
|
6365 </xsl:text> |
|
6366 <xsl:text> |
|
6367 </xsl:text> |
|
6368 <xsl:text> this.request_animate(); |
|
6369 </xsl:text> |
|
6370 <xsl:text> } |
|
6371 </xsl:text> |
|
6372 <xsl:text> |
|
6373 </xsl:text> |
|
6374 <xsl:text> get_ratios() { |
|
6375 </xsl:text> |
|
6376 <xsl:text> let range = this.range; |
|
6377 </xsl:text> |
|
6378 <xsl:text> let size = Math.max(this.range * this.mincursize, Math.min(this.size, range)); |
|
6379 </xsl:text> |
|
6380 <xsl:text> let maxh = this.range_elt.height.baseVal.value; |
|
6381 </xsl:text> |
|
6382 <xsl:text> let pixels = maxh; |
|
6383 </xsl:text> |
|
6384 <xsl:text> let units = range; |
|
6385 </xsl:text> |
|
6386 <xsl:text> return [size, maxh, range, pixels, units]; |
|
6387 </xsl:text> |
|
6388 <xsl:text> } |
|
6389 </xsl:text> |
|
6390 <xsl:text> |
|
6391 </xsl:text> |
|
6392 <xsl:text> animate(){ |
|
6393 </xsl:text> |
|
6394 <xsl:text> if(this.position == undefined || this.range == undefined || this.size == undefined) |
|
6395 </xsl:text> |
|
6396 <xsl:text> return; |
|
6397 </xsl:text> |
|
6398 <xsl:text> let [size, maxh, range, pixels, units] = this.get_ratios(); |
|
6399 </xsl:text> |
|
6400 <xsl:text> |
|
6401 </xsl:text> |
|
6402 <xsl:text> let new_y = this.range_elt.y.baseVal.value + Math.round(Math.min(this.position,range-size) * pixels / units); |
|
6403 </xsl:text> |
|
6404 <xsl:text> let new_height = Math.round(maxh * size/range); |
|
6405 </xsl:text> |
|
6406 <xsl:text> |
|
6407 </xsl:text> |
|
6408 <xsl:text> this.cursor_elt.y.baseVal.value = new_y; |
|
6409 </xsl:text> |
|
6410 <xsl:text> this.cursor_elt.height.baseVal.value = new_height; |
|
6411 </xsl:text> |
|
6412 <xsl:text> } |
|
6413 </xsl:text> |
|
6414 <xsl:text> |
|
6415 </xsl:text> |
|
6416 <xsl:text> init_mandatory() { |
|
6417 </xsl:text> |
|
6418 <xsl:text> this.cursor_elt.onpointerdown = () => this.on_cursor_down(); |
|
6419 </xsl:text> |
|
6420 <xsl:text> |
|
6421 </xsl:text> |
|
6422 <xsl:text> this.bound_drag = this.drag.bind(this); |
|
6423 </xsl:text> |
|
6424 <xsl:text> this.bound_drop = this.drop.bind(this); |
|
6425 </xsl:text> |
|
6426 <xsl:text> } |
|
6427 </xsl:text> |
|
6428 <xsl:text> |
|
6429 </xsl:text> |
|
6430 <xsl:text> apply_position(position){ |
|
6431 </xsl:text> |
|
6432 <xsl:text> this.position = Math.round(Math.max(Math.min(position, this.range - this.size), 0)); |
|
6433 </xsl:text> |
|
6434 <xsl:text> this.apply_hmi_value(1, this.position); |
|
6435 </xsl:text> |
|
6436 <xsl:text> } |
|
6437 </xsl:text> |
|
6438 <xsl:text> |
|
6439 </xsl:text> |
|
6440 <xsl:text> on_page_click(is_up){ |
|
6441 </xsl:text> |
|
6442 <xsl:text> this.apply_position(is_up ? this.position-this.size |
|
6443 </xsl:text> |
|
6444 <xsl:text> : this.position+this.size); |
|
6445 </xsl:text> |
|
6446 <xsl:text> } |
|
6447 </xsl:text> |
|
6448 <xsl:text> |
|
6449 </xsl:text> |
|
6450 <xsl:text> on_cursor_down(e){ |
|
6451 </xsl:text> |
|
6452 <xsl:text> // get scrollbar -> root transform |
|
6453 </xsl:text> |
|
6454 <xsl:text> let ctm = this.range_elt.getCTM(); |
|
6455 </xsl:text> |
|
6456 <xsl:text> // relative motion -> discard translation |
|
6457 </xsl:text> |
|
6458 <xsl:text> ctm.e = 0; |
|
6459 </xsl:text> |
|
6460 <xsl:text> ctm.f = 0; |
|
6461 </xsl:text> |
|
6462 <xsl:text> // root -> scrollbar transform |
|
6463 </xsl:text> |
|
6464 <xsl:text> this.invctm = ctm.inverse(); |
|
6465 </xsl:text> |
|
6466 <xsl:text> svg_root.addEventListener("pointerup", this.bound_drop, true); |
|
6467 </xsl:text> |
|
6468 <xsl:text> svg_root.addEventListener("pointermove", this.bound_drag, true); |
|
6469 </xsl:text> |
|
6470 <xsl:text> this.dragpos = this.position; |
|
6471 </xsl:text> |
|
6472 <xsl:text> } |
|
6473 </xsl:text> |
|
6474 <xsl:text> |
|
6475 </xsl:text> |
|
6476 <xsl:text> drop(e) { |
|
6477 </xsl:text> |
|
6478 <xsl:text> svg_root.removeEventListener("pointerup", this.bound_drop, true); |
|
6479 </xsl:text> |
|
6480 <xsl:text> svg_root.removeEventListener("pointermove", this.bound_drag, true); |
|
6481 </xsl:text> |
|
6482 <xsl:text> } |
|
6483 </xsl:text> |
|
6484 <xsl:text> |
|
6485 </xsl:text> |
|
6486 <xsl:text> drag(e) { |
|
6487 </xsl:text> |
|
6488 <xsl:text> let [size, maxh, range, pixels, units] = this.get_ratios(); |
|
6489 </xsl:text> |
|
6490 <xsl:text> if(pixels == 0) return; |
|
6491 </xsl:text> |
|
6492 <xsl:text> let point = new DOMPoint(e.movementX, e.movementY); |
|
6493 </xsl:text> |
|
6494 <xsl:text> let movement = point.matrixTransform(this.invctm).y; |
|
6495 </xsl:text> |
|
6496 <xsl:text> this.dragpos += movement * units / pixels; |
|
6497 </xsl:text> |
|
6498 <xsl:text> this.apply_position(this.dragpos); |
|
6499 </xsl:text> |
|
6500 <xsl:text> } |
|
6501 </xsl:text> |
|
6502 <xsl:text>} |
|
6503 </xsl:text> |
|
6504 </xsl:template> |
|
6505 <xsl:template match="widget[@type='ScrollBar']" mode="widget_defs"> |
|
6506 <xsl:param name="hmi_element"/> |
|
6507 <xsl:call-template name="defs_by_labels"> |
|
6508 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
6509 <xsl:with-param name="labels"> |
|
6510 <xsl:text>cursor range</xsl:text> |
|
6511 </xsl:with-param> |
|
6512 </xsl:call-template> |
|
6513 <xsl:variable name="pagebuttons"> |
|
6514 <xsl:call-template name="defs_by_labels"> |
|
6515 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
6516 <xsl:with-param name="labels"> |
|
6517 <xsl:text>pageup pagedown</xsl:text> |
|
6518 </xsl:with-param> |
|
6519 <xsl:with-param name="mandatory" select="'no'"/> |
|
6520 </xsl:call-template> |
|
6521 </xsl:variable> |
|
6522 <xsl:variable name="have_pagebuttons" select="string-length($pagebuttons)>0"/> |
|
6523 <xsl:value-of select="$pagebuttons"/> |
|
6524 <xsl:text> init: function() { |
|
6525 </xsl:text> |
|
6526 <xsl:text> this.init_mandatory(); |
|
6527 </xsl:text> |
|
6528 <xsl:if test="$have_pagebuttons"> |
|
6529 <xsl:text> this.pageup_elt.onclick = () => this.on_page_click(true); |
|
6530 </xsl:text> |
|
6531 <xsl:text> this.pagedown_elt.onclick = () => this.on_page_click(false); |
|
6532 </xsl:text> |
|
6533 </xsl:if> |
|
6534 <xsl:text> }, |
|
6535 </xsl:text> |
|
6536 </xsl:template> |
|
6537 <xsl:template match="widget[@type='Slider']" mode="widget_desc"> |
|
6538 <type> |
|
6539 <xsl:value-of select="@type"/> |
|
6540 </type> |
|
6541 <longdesc> |
|
6542 <xsl:text>Slider - DEPRECATED - use ScrollBar or PathSlider instead |
|
6543 </xsl:text> |
|
6544 </longdesc> |
|
6545 <shortdesc> |
|
6546 <xsl:text>Slider - DEPRECATED - use ScrollBar instead</xsl:text> |
|
6547 </shortdesc> |
|
6548 <path name="value" accepts="HMI_INT"> |
|
6549 <xsl:text>value</xsl:text> |
|
6550 </path> |
|
6551 <path name="range" accepts="HMI_INT"> |
|
6552 <xsl:text>range</xsl:text> |
|
6553 </path> |
|
6554 <path name="visible" accepts="HMI_INT"> |
|
6555 <xsl:text>visible</xsl:text> |
|
6556 </path> |
|
6557 </xsl:template> |
|
6558 <xsl:template match="widget[@type='Slider']" mode="widget_class"> |
|
6559 <xsl:text>class </xsl:text> |
|
6560 <xsl:text>SliderWidget</xsl:text> |
|
6561 <xsl:text> extends Widget{ |
|
6562 </xsl:text> |
|
6563 <xsl:text> frequency = 5; |
|
6564 </xsl:text> |
|
6565 <xsl:text> range = undefined; |
|
6566 </xsl:text> |
|
6567 <xsl:text> handle_orig = undefined; |
|
6568 </xsl:text> |
|
6569 <xsl:text> scroll_size = undefined; |
|
6570 </xsl:text> |
|
6571 <xsl:text> scroll_range = 0; |
|
6572 </xsl:text> |
|
6573 <xsl:text> scroll_visible = 7; |
|
6574 </xsl:text> |
|
6575 <xsl:text> min_size = 0.07; |
|
6576 </xsl:text> |
|
6577 <xsl:text> fi = undefined; |
|
6578 </xsl:text> |
|
6579 <xsl:text> curr_value = 0; |
|
6580 </xsl:text> |
|
6581 <xsl:text> drag = false; |
|
6582 </xsl:text> |
|
6583 <xsl:text> enTimer = false; |
|
6584 </xsl:text> |
|
6585 <xsl:text> handle_click = undefined; |
|
6586 </xsl:text> |
|
6587 <xsl:text> last_drag = false; |
|
6588 </xsl:text> |
|
6589 <xsl:text> |
|
6590 </xsl:text> |
|
6591 <xsl:text> dispatch(value,oldval, index) { |
|
6592 </xsl:text> |
|
6593 <xsl:text> if (index == 0){ |
|
6594 </xsl:text> |
|
6595 <xsl:text> let [min,max,start,totallength] = this.range; |
|
6596 </xsl:text> |
|
6597 <xsl:text> //save current value inside widget |
|
6598 </xsl:text> |
|
6599 <xsl:text> this.curr_value = value; |
|
6600 </xsl:text> |
|
6601 <xsl:text> |
|
6602 </xsl:text> |
|
6603 <xsl:text> //check if in range |
|
6604 </xsl:text> |
|
6605 <xsl:text> if (this.curr_value > max){ |
|
6606 </xsl:text> |
|
6607 <xsl:text> this.curr_value = max; |
|
6608 </xsl:text> |
|
6609 <xsl:text> this.apply_hmi_value(0, this.curr_value); |
|
6610 </xsl:text> |
|
6611 <xsl:text> } |
|
6612 </xsl:text> |
|
6613 <xsl:text> else if (this.curr_value < min){ |
|
6614 </xsl:text> |
|
6615 <xsl:text> this.curr_value = min; |
|
6616 </xsl:text> |
|
6617 <xsl:text> this.apply_hmi_value(0, this.curr_value); |
|
6618 </xsl:text> |
|
6619 <xsl:text> } |
|
6620 </xsl:text> |
|
6621 <xsl:text> |
|
6622 </xsl:text> |
|
6623 <xsl:text> if(this.value_elt) |
|
6624 </xsl:text> |
|
6625 <xsl:text> this.value_elt.textContent = String(value); |
|
6626 </xsl:text> |
|
6627 <xsl:text> } |
|
6628 </xsl:text> |
|
6629 <xsl:text> else if(index == 1){ |
|
6630 </xsl:text> |
|
6631 <xsl:text> this.scroll_range = value; |
|
6632 </xsl:text> |
|
6633 <xsl:text> this.set_scroll(); |
|
6634 </xsl:text> |
|
6635 <xsl:text> } |
|
6636 </xsl:text> |
|
6637 <xsl:text> else if(index == 2){ |
|
6638 </xsl:text> |
|
6639 <xsl:text> this.scroll_visible = value; |
|
6640 </xsl:text> |
|
6641 <xsl:text> this.set_scroll(); |
|
6642 </xsl:text> |
|
6643 <xsl:text> } |
|
6644 </xsl:text> |
|
6645 <xsl:text> |
|
6646 </xsl:text> |
|
6647 <xsl:text> //don't update if draging and setpoint ghost doesn't exist |
|
6648 </xsl:text> |
|
6649 <xsl:text> if(!this.drag || (this.setpoint_elt != undefined)){ |
|
6650 </xsl:text> |
|
6651 <xsl:text> this.update_DOM(this.curr_value, this.handle_elt); |
|
6652 </xsl:text> |
|
6653 <xsl:text> } |
|
6654 </xsl:text> |
|
6655 <xsl:text> } |
|
6656 </xsl:text> |
|
6657 <xsl:text> |
|
6658 </xsl:text> |
|
6659 <xsl:text> set_scroll(){ |
|
6660 </xsl:text> |
|
6661 <xsl:text> //check if range is bigger than visible and set scroll size |
|
6662 </xsl:text> |
|
6663 <xsl:text> if(this.scroll_range > this.scroll_visible){ |
|
6664 </xsl:text> |
|
6665 <xsl:text> this.scroll_size = this.scroll_range - this.scroll_visible; |
|
6666 </xsl:text> |
|
6667 <xsl:text> this.range[0] = 0; |
|
6668 </xsl:text> |
|
6669 <xsl:text> this.range[1] = this.scroll_size; |
|
6670 </xsl:text> |
|
6671 <xsl:text> } |
|
6672 </xsl:text> |
|
6673 <xsl:text> else{ |
|
6674 </xsl:text> |
|
6675 <xsl:text> this.scroll_size = 1; |
|
6676 </xsl:text> |
|
6677 <xsl:text> this.range[0] = 0; |
|
6678 </xsl:text> |
|
6679 <xsl:text> this.range[1] = 1; |
|
6680 </xsl:text> |
|
6681 <xsl:text> } |
|
6682 </xsl:text> |
|
6683 <xsl:text> } |
|
6684 </xsl:text> |
|
6685 <xsl:text> |
|
6686 </xsl:text> |
|
6687 <xsl:text> update_DOM(value, elt){ |
|
6688 </xsl:text> |
|
6689 <xsl:text> let [min,max,start,totallength] = this.range; |
|
6690 </xsl:text> |
|
6691 <xsl:text> // check if handle is resizeable |
|
6692 </xsl:text> |
|
6693 <xsl:text> if (this.scroll_size != undefined){ //size changes |
|
6694 </xsl:text> |
|
6695 <xsl:text> //get parameters |
|
6696 </xsl:text> |
|
6697 <xsl:text> let length = Math.max(min,Math.min(max,(Number(value)-min)*max/(max-min))); |
|
6698 </xsl:text> |
|
6699 <xsl:text> let tip = this.range_elt.getPointAtLength(length); |
|
6700 </xsl:text> |
|
6701 <xsl:text> let handle_min = totallength*this.min_size; |
|
6702 </xsl:text> |
|
6703 <xsl:text> |
|
6704 </xsl:text> |
|
6705 <xsl:text> let step = 1; |
|
6706 </xsl:text> |
|
6707 <xsl:text> //check if range is bigger than max displayed and recalculate step |
|
6708 </xsl:text> |
|
6709 <xsl:text> if ((totallength/handle_min) < (max-min+1)){ |
|
6710 </xsl:text> |
|
6711 <xsl:text> step = (max-min+1)/(totallength/handle_min-1); |
|
6712 </xsl:text> |
|
6713 <xsl:text> } |
|
6714 </xsl:text> |
|
6715 <xsl:text> |
|
6716 </xsl:text> |
|
6717 <xsl:text> let kx,ky,offseY,offseX = undefined; |
|
6718 </xsl:text> |
|
6719 <xsl:text> //scale on x or y axes |
|
6720 </xsl:text> |
|
6721 <xsl:text> if (this.fi > 0.75){ |
|
6722 </xsl:text> |
|
6723 <xsl:text> //get scale factor |
|
6724 </xsl:text> |
|
6725 <xsl:text> if(step > 1){ |
|
6726 </xsl:text> |
|
6727 <xsl:text> ky = handle_min/this.handle_orig.height; |
|
6728 </xsl:text> |
|
6729 <xsl:text> } |
|
6730 </xsl:text> |
|
6731 <xsl:text> else{ |
|
6732 </xsl:text> |
|
6733 <xsl:text> ky = (totallength-handle_min*(max-min))/this.handle_orig.height; |
|
6734 </xsl:text> |
|
6735 <xsl:text> } |
|
6736 </xsl:text> |
|
6737 <xsl:text> kx = 1; |
|
6738 </xsl:text> |
|
6739 <xsl:text> //get 0 offset to stay inside range |
|
6740 </xsl:text> |
|
6741 <xsl:text> offseY = start.y - (this.handle_orig.height + this.handle_orig.y) * ky; |
|
6742 </xsl:text> |
|
6743 <xsl:text> offseX = 0; |
|
6744 </xsl:text> |
|
6745 <xsl:text> //get distance from value |
|
6746 </xsl:text> |
|
6747 <xsl:text> tip.y =this.range_elt.getPointAtLength(0).y - length/step *handle_min; |
|
6748 </xsl:text> |
|
6749 <xsl:text> } |
|
6750 </xsl:text> |
|
6751 <xsl:text> else{ |
|
6752 </xsl:text> |
|
6753 <xsl:text> //get scale factor |
|
6754 </xsl:text> |
|
6755 <xsl:text> if(step > 1){ |
|
6756 </xsl:text> |
|
6757 <xsl:text> kx = handle_min/this.handle_orig.width; |
|
6758 </xsl:text> |
|
6759 <xsl:text> } |
|
6760 </xsl:text> |
|
6761 <xsl:text> else{ |
|
6762 </xsl:text> |
|
6763 <xsl:text> kx = (totallength-handle_min*(max-min))/this.handle_orig.width; |
|
6764 </xsl:text> |
|
6765 <xsl:text> } |
|
6766 </xsl:text> |
|
6767 <xsl:text> ky = 1; |
|
6768 </xsl:text> |
|
6769 <xsl:text> //get 0 offset to stay inside range |
|
6770 </xsl:text> |
|
6771 <xsl:text> offseX = start.x - (this.handle_orig.x * kx); |
|
6772 </xsl:text> |
|
6773 <xsl:text> offseY = 0; |
|
6774 </xsl:text> |
|
6775 <xsl:text> //get distance from value |
|
6776 </xsl:text> |
|
6777 <xsl:text> tip.x =this.range_elt.getPointAtLength(0).x + length/step *handle_min; |
|
6778 </xsl:text> |
|
6779 <xsl:text> } |
|
6780 </xsl:text> |
|
6781 <xsl:text> elt.setAttribute('transform',"matrix("+(kx)+" 0 0 "+(ky)+" "+(tip.x-start.x+offseX)+" "+(tip.y-start.y+offseY)+")"); |
|
6782 </xsl:text> |
|
6783 <xsl:text> } |
|
6784 </xsl:text> |
|
6785 <xsl:text> else{ //size stays the same |
|
6786 </xsl:text> |
|
6787 <xsl:text> let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min))); |
|
6788 </xsl:text> |
|
6789 <xsl:text> let tip = this.range_elt.getPointAtLength(length); |
|
6790 </xsl:text> |
|
6791 <xsl:text> elt.setAttribute('transform',"translate("+(tip.x-start.x)+","+(tip.y-start.y)+")"); |
|
6792 </xsl:text> |
|
6793 <xsl:text> } |
|
6794 </xsl:text> |
|
6795 <xsl:text> |
|
6796 </xsl:text> |
|
6797 <xsl:text> // show or hide ghost if exists |
|
6798 </xsl:text> |
|
6799 <xsl:text> if(this.setpoint_elt != undefined){ |
|
6800 </xsl:text> |
|
6801 <xsl:text> if(this.last_drag!= this.drag){ |
|
6802 </xsl:text> |
|
6803 <xsl:text> if(this.drag){ |
|
6804 </xsl:text> |
|
6805 <xsl:text> this.setpoint_elt.setAttribute("style", this.setpoint_style); |
|
6806 </xsl:text> |
|
6807 <xsl:text> }else{ |
|
6808 </xsl:text> |
|
6809 <xsl:text> this.setpoint_elt.setAttribute("style", "display:none"); |
|
6810 </xsl:text> |
|
6811 <xsl:text> } |
|
6812 </xsl:text> |
|
6813 <xsl:text> this.last_drag = this.drag; |
|
6814 </xsl:text> |
|
6815 <xsl:text> } |
|
6816 </xsl:text> |
|
6817 <xsl:text> } |
|
6818 </xsl:text> |
|
6819 <xsl:text> } |
|
6820 </xsl:text> |
|
6821 <xsl:text> |
|
6822 </xsl:text> |
|
6823 <xsl:text> on_release(evt) { |
|
6824 </xsl:text> |
|
6825 <xsl:text> //unbind events |
|
6826 </xsl:text> |
|
6827 <xsl:text> window.removeEventListener("touchmove", this.on_bound_drag, true); |
|
6828 </xsl:text> |
|
6829 <xsl:text> window.removeEventListener("mousemove", this.on_bound_drag, true); |
|
6830 </xsl:text> |
|
6831 <xsl:text> |
|
6832 </xsl:text> |
|
6833 <xsl:text> window.removeEventListener("mouseup", this.bound_on_release, true); |
|
6834 </xsl:text> |
|
6835 <xsl:text> window.removeEventListener("touchend", this.bound_on_release, true); |
|
6836 </xsl:text> |
|
6837 <xsl:text> window.removeEventListener("touchcancel", this.bound_on_release, true); |
|
6838 </xsl:text> |
|
6839 <xsl:text> |
|
6840 </xsl:text> |
|
6841 <xsl:text> //reset drag flag |
|
6842 </xsl:text> |
|
6843 <xsl:text> if(this.drag){ |
|
6844 </xsl:text> |
|
6845 <xsl:text> this.drag = false; |
|
6846 </xsl:text> |
|
6847 <xsl:text> } |
|
6848 </xsl:text> |
|
6849 <xsl:text> |
|
6850 </xsl:text> |
|
6851 <xsl:text> // get final position |
|
6852 </xsl:text> |
|
6853 <xsl:text> this.update_position(evt); |
|
6854 </xsl:text> |
|
6855 <xsl:text> |
|
6856 </xsl:text> |
|
6857 <xsl:text> } |
|
6858 </xsl:text> |
|
6859 <xsl:text> |
|
6860 </xsl:text> |
|
6861 <xsl:text> on_drag(evt){ |
|
6862 </xsl:text> |
|
6863 <xsl:text> //ignore drag event for X amount of time and if not selected |
|
6864 </xsl:text> |
|
6865 <xsl:text> if(this.enTimer && this.drag){ |
|
6866 </xsl:text> |
|
6867 <xsl:text> this.update_position(evt); |
|
6868 </xsl:text> |
|
6869 <xsl:text> |
|
6870 </xsl:text> |
|
6871 <xsl:text> //reset timer |
|
6872 </xsl:text> |
|
6873 <xsl:text> this.enTimer = false; |
|
6874 </xsl:text> |
|
6875 <xsl:text> setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); |
|
6876 </xsl:text> |
|
6877 <xsl:text> } |
|
6878 </xsl:text> |
|
6879 <xsl:text> } |
|
6880 </xsl:text> |
|
6881 <xsl:text> |
|
6882 </xsl:text> |
|
6883 <xsl:text> update_position(evt){ |
|
6884 </xsl:text> |
|
6885 <xsl:text> var html_dist = 0; |
|
6886 </xsl:text> |
|
6887 <xsl:text> let [min,max,start,totallength] = this.range; |
|
6888 </xsl:text> |
|
6889 <xsl:text> |
|
6890 </xsl:text> |
|
6891 <xsl:text> //calculate size of widget in html |
|
6892 </xsl:text> |
|
6893 <xsl:text> var range_borders = this.range_elt.getBoundingClientRect(); |
|
6894 </xsl:text> |
|
6895 <xsl:text> var [minX,minY,maxX,maxY] = [range_borders.left,range_borders.bottom,range_borders.right,range_borders.top]; |
|
6896 </xsl:text> |
|
6897 <xsl:text> var range_length = Math.sqrt( range_borders.height*range_borders.height + range_borders.width*range_borders.width ); |
|
6898 </xsl:text> |
|
6899 <xsl:text> |
|
6900 </xsl:text> |
|
6901 <xsl:text> //get range and mouse coordinates |
|
6902 </xsl:text> |
|
6903 <xsl:text> var mouseX = undefined; |
|
6904 </xsl:text> |
|
6905 <xsl:text> var mouseY = undefined; |
|
6906 </xsl:text> |
|
6907 <xsl:text> if (evt.type.startsWith("touch")){ |
|
6908 </xsl:text> |
|
6909 <xsl:text> mouseX = Math.ceil(evt.touches[0].clientX); |
|
6910 </xsl:text> |
|
6911 <xsl:text> mouseY = Math.ceil(evt.touches[0].clientY); |
|
6912 </xsl:text> |
|
6913 <xsl:text> } |
|
6914 </xsl:text> |
|
6915 <xsl:text> else{ |
|
6916 </xsl:text> |
|
6917 <xsl:text> mouseX = evt.pageX; |
|
6918 </xsl:text> |
|
6919 <xsl:text> mouseY = evt.pageY; |
|
6920 </xsl:text> |
|
6921 <xsl:text> } |
|
6922 </xsl:text> |
|
6923 <xsl:text> |
|
6924 </xsl:text> |
|
6925 <xsl:text> // calculate position |
|
6926 </xsl:text> |
|
6927 <xsl:text> if (this.handle_click){ //if clicked on handle |
|
6928 </xsl:text> |
|
6929 <xsl:text> let moveDist = 0, resizeAdd = 0; |
|
6930 </xsl:text> |
|
6931 <xsl:text> let range_percent = 1; |
|
6932 </xsl:text> |
|
6933 <xsl:text> |
|
6934 </xsl:text> |
|
6935 <xsl:text> //set paramters for resizeable handle |
|
6936 </xsl:text> |
|
6937 <xsl:text> if (this.scroll_size != undefined){ |
|
6938 </xsl:text> |
|
6939 <xsl:text> // add one more object to stay inside range |
|
6940 </xsl:text> |
|
6941 <xsl:text> resizeAdd = 1; |
|
6942 </xsl:text> |
|
6943 <xsl:text> |
|
6944 </xsl:text> |
|
6945 <xsl:text> //chack if range is bigger than display option and |
|
6946 </xsl:text> |
|
6947 <xsl:text> // calculate percent of range with out handle |
|
6948 </xsl:text> |
|
6949 <xsl:text> if(((max/(max*this.min_size)) < (max-min+1))){ |
|
6950 </xsl:text> |
|
6951 <xsl:text> range_percent = 1-this.min_size; |
|
6952 </xsl:text> |
|
6953 <xsl:text> } |
|
6954 </xsl:text> |
|
6955 <xsl:text> else{ |
|
6956 </xsl:text> |
|
6957 <xsl:text> range_percent = 1-(max-max*this.min_size*(max-min))/max; |
|
6958 </xsl:text> |
|
6959 <xsl:text> } |
|
6960 </xsl:text> |
|
6961 <xsl:text> } |
|
6962 </xsl:text> |
|
6963 <xsl:text> |
|
6964 </xsl:text> |
|
6965 <xsl:text> //calculate value difference on x or y axis |
|
6966 </xsl:text> |
|
6967 <xsl:text> if(this.fi > 0.7){ |
|
6968 </xsl:text> |
|
6969 <xsl:text> moveDist = ((max-min+resizeAdd)/(range_length*range_percent))*((this.handle_click[1]-mouseY)/Math.sin(this.fi)); |
|
6970 </xsl:text> |
|
6971 <xsl:text> } |
|
6972 </xsl:text> |
|
6973 <xsl:text> else{ |
|
6974 </xsl:text> |
|
6975 <xsl:text> moveDist = ((max-min+resizeAdd)/(range_length*range_percent))*((mouseX-this.handle_click[0])/Math.cos(this.fi)); |
|
6976 </xsl:text> |
|
6977 <xsl:text> } |
|
6978 </xsl:text> |
|
6979 <xsl:text> |
|
6980 </xsl:text> |
|
6981 <xsl:text> this.curr_value = Math.ceil(this.handle_click[2] + moveDist); |
|
6982 </xsl:text> |
|
6983 <xsl:text> } |
|
6984 </xsl:text> |
|
6985 <xsl:text> else{ //if clicked on widget |
|
6986 </xsl:text> |
|
6987 <xsl:text> //get handle distance from mouse position |
|
6988 </xsl:text> |
|
6989 <xsl:text> if (minX > mouseX && minY < mouseY){ |
|
6990 </xsl:text> |
|
6991 <xsl:text> html_dist = 0; |
|
6992 </xsl:text> |
|
6993 <xsl:text> } |
|
6994 </xsl:text> |
|
6995 <xsl:text> else if (maxX < mouseX && maxY > mouseY){ |
|
6996 </xsl:text> |
|
6997 <xsl:text> html_dist = range_length; |
|
6998 </xsl:text> |
|
6999 <xsl:text> } |
|
7000 </xsl:text> |
|
7001 <xsl:text> else{ |
|
7002 </xsl:text> |
|
7003 <xsl:text> if(this.fi > 0.7){ |
|
7004 </xsl:text> |
|
7005 <xsl:text> html_dist = (minY - mouseY)/Math.sin(this.fi); |
|
7006 </xsl:text> |
|
7007 <xsl:text> } |
|
7008 </xsl:text> |
|
7009 <xsl:text> else{ |
|
7010 </xsl:text> |
|
7011 <xsl:text> html_dist = (mouseX - minX)/Math.cos(this.fi); |
|
7012 </xsl:text> |
|
7013 <xsl:text> } |
|
7014 </xsl:text> |
|
7015 <xsl:text> } |
|
7016 </xsl:text> |
|
7017 <xsl:text> //calculate distance |
|
7018 </xsl:text> |
|
7019 <xsl:text> this.curr_value=Math.ceil((html_dist/range_length)*(this.range[1]-this.range[0])+this.range[0]); |
|
7020 </xsl:text> |
|
7021 <xsl:text> } |
|
7022 </xsl:text> |
|
7023 <xsl:text> |
|
7024 </xsl:text> |
|
7025 <xsl:text> //check if in range and apply |
|
7026 </xsl:text> |
|
7027 <xsl:text> if (this.curr_value > max){ |
|
7028 </xsl:text> |
|
7029 <xsl:text> this.curr_value = max; |
|
7030 </xsl:text> |
|
7031 <xsl:text> } |
|
7032 </xsl:text> |
|
7033 <xsl:text> else if (this.curr_value < min){ |
|
7034 </xsl:text> |
|
7035 <xsl:text> this.curr_value = min; |
|
7036 </xsl:text> |
|
7037 <xsl:text> } |
|
7038 </xsl:text> |
|
7039 <xsl:text> this.apply_hmi_value(0, this.curr_value); |
|
7040 </xsl:text> |
|
7041 <xsl:text> |
|
7042 </xsl:text> |
|
7043 <xsl:text> //redraw handle |
|
7044 </xsl:text> |
|
7045 <xsl:text> this.request_animate(); |
|
7046 </xsl:text> |
|
7047 <xsl:text> |
|
7048 </xsl:text> |
|
7049 <xsl:text> } |
|
7050 </xsl:text> |
|
7051 <xsl:text> |
|
7052 </xsl:text> |
|
7053 <xsl:text> animate(){ |
|
7054 </xsl:text> |
|
7055 <xsl:text> // redraw handle on screen refresh |
|
7056 </xsl:text> |
|
7057 <xsl:text> // check if setpoint(ghost) handle exsist otherwise update main handle |
|
7058 </xsl:text> |
|
7059 <xsl:text> if(this.setpoint_elt != undefined){ |
|
7060 </xsl:text> |
|
7061 <xsl:text> this.update_DOM(this.curr_value, this.setpoint_elt); |
|
7062 </xsl:text> |
|
7063 <xsl:text> } |
|
7064 </xsl:text> |
|
7065 <xsl:text> else{ |
|
7066 </xsl:text> |
|
7067 <xsl:text> this.update_DOM(this.curr_value, this.handle_elt); |
|
7068 </xsl:text> |
|
7069 <xsl:text> } |
|
7070 </xsl:text> |
|
7071 <xsl:text> } |
|
7072 </xsl:text> |
|
7073 <xsl:text> |
|
7074 </xsl:text> |
|
7075 <xsl:text> on_select(evt){ |
|
7076 </xsl:text> |
|
7077 <xsl:text> //enable drag flag and timer |
|
7078 </xsl:text> |
|
7079 <xsl:text> this.drag = true; |
|
7080 </xsl:text> |
|
7081 <xsl:text> this.enTimer = true; |
|
7082 </xsl:text> |
|
7083 <xsl:text> |
|
7084 </xsl:text> |
|
7085 <xsl:text> //bind events |
|
7086 </xsl:text> |
|
7087 <xsl:text> window.addEventListener("touchmove", this.on_bound_drag, true); |
|
7088 </xsl:text> |
|
7089 <xsl:text> window.addEventListener("mousemove", this.on_bound_drag, true); |
|
7090 </xsl:text> |
|
7091 <xsl:text> |
|
7092 </xsl:text> |
|
7093 <xsl:text> window.addEventListener("mouseup", this.bound_on_release, true); |
|
7094 </xsl:text> |
|
7095 <xsl:text> window.addEventListener("touchend", this.bound_on_release, true); |
|
7096 </xsl:text> |
|
7097 <xsl:text> window.addEventListener("touchcancel", this.bound_on_release, true); |
|
7098 </xsl:text> |
|
7099 <xsl:text> |
|
7100 </xsl:text> |
|
7101 <xsl:text> // check if handle was pressed |
|
7102 </xsl:text> |
|
7103 <xsl:text> if (evt.currentTarget == this.handle_elt){ |
|
7104 </xsl:text> |
|
7105 <xsl:text> //get mouse position on the handle |
|
7106 </xsl:text> |
|
7107 <xsl:text> let mouseX = undefined; |
|
7108 </xsl:text> |
|
7109 <xsl:text> let mouseY = undefined; |
|
7110 </xsl:text> |
|
7111 <xsl:text> if (evt.type.startsWith("touch")){ |
|
7112 </xsl:text> |
|
7113 <xsl:text> mouseX = Math.ceil(evt.touches[0].clientX); |
|
7114 </xsl:text> |
|
7115 <xsl:text> mouseY = Math.ceil(evt.touches[0].clientY); |
|
7116 </xsl:text> |
|
7117 <xsl:text> } |
|
7118 </xsl:text> |
|
7119 <xsl:text> else{ |
|
7120 </xsl:text> |
|
7121 <xsl:text> mouseX = evt.pageX; |
|
7122 </xsl:text> |
|
7123 <xsl:text> mouseY = evt.pageY; |
|
7124 </xsl:text> |
|
7125 <xsl:text> } |
|
7126 </xsl:text> |
|
7127 <xsl:text> //save coordinates and orig value |
|
7128 </xsl:text> |
|
7129 <xsl:text> this.handle_click = [mouseX,mouseY,this.curr_value]; |
|
7130 </xsl:text> |
|
7131 <xsl:text> } |
|
7132 </xsl:text> |
|
7133 <xsl:text> else{ |
|
7134 </xsl:text> |
|
7135 <xsl:text> // get new handle position and reset if handle was not pressed |
|
7136 </xsl:text> |
|
7137 <xsl:text> this.handle_click = undefined; |
|
7138 </xsl:text> |
|
7139 <xsl:text> this.update_position(evt); |
|
7140 </xsl:text> |
|
7141 <xsl:text> } |
|
7142 </xsl:text> |
|
7143 <xsl:text> |
|
7144 </xsl:text> |
|
7145 <xsl:text> //prevent next events |
|
7146 </xsl:text> |
|
7147 <xsl:text> evt.stopPropagation(); |
|
7148 </xsl:text> |
|
7149 <xsl:text> |
|
7150 </xsl:text> |
|
7151 <xsl:text> } |
|
7152 </xsl:text> |
|
7153 <xsl:text> |
|
7154 </xsl:text> |
|
7155 <xsl:text> |
|
7156 </xsl:text> |
|
7157 <xsl:text> init() { |
|
7158 </xsl:text> |
|
7159 <xsl:text> //set min max value if not defined |
|
7160 </xsl:text> |
|
7161 <xsl:text> let min = this.min_elt ? |
|
7162 </xsl:text> |
|
7163 <xsl:text> Number(this.min_elt.textContent) : |
|
7164 </xsl:text> |
|
7165 <xsl:text> this.args.length >= 1 ? this.args[0] : 0; |
|
7166 </xsl:text> |
|
7167 <xsl:text> let max = this.max_elt ? |
|
7168 </xsl:text> |
|
7169 <xsl:text> Number(this.max_elt.textContent) : |
|
7170 </xsl:text> |
|
7171 <xsl:text> this.args.length >= 2 ? this.args[1] : 100; |
|
7172 </xsl:text> |
|
7173 <xsl:text> |
|
7174 </xsl:text> |
|
7175 <xsl:text> |
|
7176 </xsl:text> |
|
7177 <xsl:text> // save initial parameters |
|
7178 </xsl:text> |
|
7179 <xsl:text> this.range_elt.style.strokeMiterlimit="0"; |
|
7180 </xsl:text> |
|
7181 <xsl:text> this.range = [min, max, this.range_elt.getPointAtLength(0),this.range_elt.getTotalLength()]; |
|
7182 </xsl:text> |
|
7183 <xsl:text> let start = this.range_elt.getPointAtLength(0); |
|
7184 </xsl:text> |
|
7185 <xsl:text> let end = this.range_elt.getPointAtLength(this.range_elt.getTotalLength()); |
|
7186 </xsl:text> |
|
7187 <xsl:text> this.fi = Math.atan2(start.y-end.y, end.x-start.x); |
|
7188 </xsl:text> |
|
7189 <xsl:text> this.handle_orig = this.handle_elt.getBBox(); |
|
7190 </xsl:text> |
|
7191 <xsl:text> |
|
7192 </xsl:text> |
|
7193 <xsl:text> //bind functions |
|
7194 </xsl:text> |
|
7195 <xsl:text> this.bound_on_select = this.on_select.bind(this); |
|
7196 </xsl:text> |
|
7197 <xsl:text> this.bound_on_release = this.on_release.bind(this); |
|
7198 </xsl:text> |
|
7199 <xsl:text> this.on_bound_drag = this.on_drag.bind(this); |
|
7200 </xsl:text> |
|
7201 <xsl:text> |
|
7202 </xsl:text> |
|
7203 <xsl:text> this.handle_elt.addEventListener("mousedown", this.bound_on_select); |
|
7204 </xsl:text> |
|
7205 <xsl:text> this.element.addEventListener("mousedown", this.bound_on_select); |
|
7206 </xsl:text> |
|
7207 <xsl:text> this.element.addEventListener("touchstart", this.bound_on_select); |
|
7208 </xsl:text> |
|
7209 <xsl:text> //touch recognised as page drag without next command |
|
7210 </xsl:text> |
|
7211 <xsl:text> document.body.addEventListener("touchstart", function(e){}, false); |
|
7212 </xsl:text> |
|
7213 <xsl:text> |
|
7214 </xsl:text> |
|
7215 <xsl:text> //save ghost style |
|
7216 </xsl:text> |
|
7217 <xsl:text> if(this.setpoint_elt != undefined){ |
|
7218 </xsl:text> |
|
7219 <xsl:text> this.setpoint_style = this.setpoint_elt.getAttribute("style"); |
|
7220 </xsl:text> |
|
7221 <xsl:text> this.setpoint_elt.setAttribute("style", "display:none"); |
|
7222 </xsl:text> |
|
7223 <xsl:text> } |
|
7224 </xsl:text> |
|
7225 <xsl:text> |
|
7226 </xsl:text> |
|
7227 <xsl:text> } |
|
7228 </xsl:text> |
|
7229 <xsl:text>} |
|
7230 </xsl:text> |
|
7231 </xsl:template> |
|
7232 <xsl:template match="widget[@type='Slider']" mode="widget_defs"> |
|
7233 <xsl:param name="hmi_element"/> |
|
7234 <xsl:call-template name="defs_by_labels"> |
|
7235 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
7236 <xsl:with-param name="labels"> |
|
7237 <xsl:text>handle range</xsl:text> |
|
7238 </xsl:with-param> |
|
7239 </xsl:call-template> |
|
7240 <xsl:call-template name="defs_by_labels"> |
|
7241 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
7242 <xsl:with-param name="labels"> |
|
7243 <xsl:text>value min max setpoint</xsl:text> |
|
7244 </xsl:with-param> |
|
7245 <xsl:with-param name="mandatory" select="'no'"/> |
|
7246 </xsl:call-template> |
|
7247 </xsl:template> |
|
7248 <xsl:template match="widget[@type='Switch']" mode="widget_desc"> |
|
7249 <type> |
|
7250 <xsl:value-of select="@type"/> |
|
7251 </type> |
|
7252 <longdesc> |
|
7253 <xsl:text>Switch widget hides all subelements whose label do not match given |
|
7254 </xsl:text> |
|
7255 <xsl:text>variable current value representation. For exemple if given variable type |
|
7256 </xsl:text> |
|
7257 <xsl:text>is HMI_INT and value is 1, then elements with label '1' will be displayed. |
|
7258 </xsl:text> |
|
7259 <xsl:text>Label can have comments, so '1#some comment' would also match. If matching |
|
7260 </xsl:text> |
|
7261 <xsl:text>variable of type HMI_STRING, then double quotes must be used. For exemple, |
|
7262 </xsl:text> |
|
7263 <xsl:text>'"hello"' or '"hello"#another comment' match HMI_STRING 'hello'. |
|
7264 </xsl:text> |
|
7265 </longdesc> |
|
7266 <shortdesc> |
|
7267 <xsl:text>Show elements whose label match value.</xsl:text> |
|
7268 </shortdesc> |
|
7269 <path name="value" accepts="HMI_INT,HMI_STRING"> |
|
7270 <xsl:text>value to compare to labels</xsl:text> |
|
7271 </path> |
|
7272 </xsl:template> |
|
7273 <xsl:template match="widget[@type='Switch']" mode="widget_class"> |
|
7274 <xsl:text>class </xsl:text> |
|
7275 <xsl:text>SwitchWidget</xsl:text> |
|
7276 <xsl:text> extends Widget{ |
|
7277 </xsl:text> |
|
7278 <xsl:text> frequency = 5; |
|
7279 </xsl:text> |
|
7280 <xsl:text> dispatch(value) { |
|
7281 </xsl:text> |
|
7282 <xsl:text> for(let choice of this.choices){ |
|
7283 </xsl:text> |
|
7284 <xsl:text> if(value != choice.value){ |
|
7285 </xsl:text> |
|
7286 <xsl:text> choice.elt.setAttribute("style", "display:none"); |
|
7287 </xsl:text> |
|
7288 <xsl:text> } else { |
|
7289 </xsl:text> |
|
7290 <xsl:text> choice.elt.setAttribute("style", choice.style); |
|
7291 </xsl:text> |
|
7292 <xsl:text> } |
|
7293 </xsl:text> |
|
7294 <xsl:text> } |
|
7295 </xsl:text> |
|
7296 <xsl:text> } |
|
7297 </xsl:text> |
|
7298 <xsl:text>} |
|
7299 </xsl:text> |
|
7300 </xsl:template> |
|
7301 <xsl:template match="widget[@type='Switch']" mode="widget_defs"> |
|
7302 <xsl:param name="hmi_element"/> |
|
7303 <xsl:text> choices: [ |
|
7304 </xsl:text> |
|
7305 <xsl:variable name="regex" select="'^("[^"].*"|\-?[0-9]+|false|true)(#.*)?$'"/> |
|
7306 <xsl:variable name="subelts" select="$result_widgets[@id = $hmi_element/@id]//*"/> |
|
7307 <xsl:variable name="subwidgets" select="$subelts//*[@id = $hmi_widgets/@id]"/> |
|
7308 <xsl:variable name="accepted" select="$subelts[not(ancestor-or-self::*/@id = $subwidgets/@id)]"/> |
|
7309 <xsl:for-each select="$accepted[regexp:test(@inkscape:label,$regex)]"> |
|
7310 <xsl:variable name="literal" select="regexp:match(@inkscape:label,$regex)[2]"/> |
|
7311 <xsl:text> { |
|
7312 </xsl:text> |
|
7313 <xsl:text> elt:id("</xsl:text> |
|
7314 <xsl:value-of select="@id"/> |
|
7315 <xsl:text>"), |
|
7316 </xsl:text> |
|
7317 <xsl:text> style:"</xsl:text> |
|
7318 <xsl:value-of select="@style"/> |
|
7319 <xsl:text>", |
|
7320 </xsl:text> |
|
7321 <xsl:text> value:</xsl:text> |
|
7322 <xsl:value-of select="$literal"/> |
|
7323 <xsl:text> |
|
7324 </xsl:text> |
|
7325 <xsl:text> }</xsl:text> |
|
7326 <xsl:if test="position()!=last()"> |
|
7327 <xsl:text>,</xsl:text> |
|
7328 </xsl:if> |
|
7329 <xsl:text> |
|
7330 </xsl:text> |
|
7331 </xsl:for-each> |
|
7332 <xsl:text> ], |
|
7333 </xsl:text> |
|
7334 </xsl:template> |
|
7335 <xsl:template match="widget[@type='ToggleButton']" mode="widget_desc"> |
|
7336 <type> |
|
7337 <xsl:value-of select="@type"/> |
|
7338 </type> |
|
7339 <longdesc> |
|
7340 <xsl:text>Button widget takes one boolean variable path, and reflect current true |
|
7341 </xsl:text> |
|
7342 <xsl:text>or false value by showing "active" or "inactive" labeled element |
|
7343 </xsl:text> |
|
7344 <xsl:text>respectively. Clicking or touching button toggles variable. |
|
7345 </xsl:text> |
|
7346 </longdesc> |
|
7347 <shortdesc> |
|
7348 <xsl:text>Toggle button reflecting given boolean variable</xsl:text> |
|
7349 </shortdesc> |
|
7350 <path name="value" accepts="HMI_BOOL"> |
|
7351 <xsl:text>Boolean variable</xsl:text> |
|
7352 </path> |
|
7353 </xsl:template> |
|
7354 <xsl:template match="widget[@type='ToggleButton']" mode="widget_class"> |
|
7355 <xsl:text>class </xsl:text> |
|
7356 <xsl:text>ToggleButtonWidget</xsl:text> |
|
7357 <xsl:text> extends Widget{ |
|
7358 </xsl:text> |
|
7359 <xsl:text> frequency = 5; |
|
7360 </xsl:text> |
|
7361 <xsl:text> state = 0; |
|
7362 </xsl:text> |
|
7363 <xsl:text> active_style = undefined; |
|
7364 </xsl:text> |
|
7365 <xsl:text> inactive_style = undefined; |
|
7366 </xsl:text> |
|
7367 <xsl:text> |
|
7368 </xsl:text> |
|
7369 <xsl:text> dispatch(value) { |
|
7370 </xsl:text> |
|
7371 <xsl:text> this.state = value; |
|
7372 </xsl:text> |
|
7373 <xsl:text> //redraw toggle button |
|
7374 </xsl:text> |
|
7375 <xsl:text> this.request_animate(); |
|
7376 </xsl:text> |
|
7377 <xsl:text> } |
|
7378 </xsl:text> |
|
7379 <xsl:text> |
|
7380 </xsl:text> |
|
7381 <xsl:text> on_click(evt) { |
|
7382 </xsl:text> |
|
7383 <xsl:text> //toggle state and apply |
|
7384 </xsl:text> |
|
7385 <xsl:text> this.state = this.state ? false : true; |
|
7386 </xsl:text> |
|
7387 <xsl:text> this.apply_hmi_value(0, this.state); |
|
7388 </xsl:text> |
|
7389 <xsl:text> |
|
7390 </xsl:text> |
|
7391 <xsl:text> //redraw toggle button |
|
7392 </xsl:text> |
|
7393 <xsl:text> this.request_animate(); |
|
7394 </xsl:text> |
|
7395 <xsl:text> } |
|
7396 </xsl:text> |
|
7397 <xsl:text> |
|
7398 </xsl:text> |
|
7399 <xsl:text> activate(val) { |
|
7400 </xsl:text> |
|
7401 <xsl:text> let [active, inactive] = val ? ["none",""] : ["", "none"]; |
|
7402 </xsl:text> |
|
7403 <xsl:text> if (this.active_elt) |
|
7404 </xsl:text> |
|
7405 <xsl:text> this.active_elt.style.display = active; |
|
7406 </xsl:text> |
|
7407 <xsl:text> if (this.inactive_elt) |
|
7408 </xsl:text> |
|
7409 <xsl:text> this.inactive_elt.style.display = inactive; |
|
7410 </xsl:text> |
|
7411 <xsl:text> } |
|
7412 </xsl:text> |
|
7413 <xsl:text> |
|
7414 </xsl:text> |
|
7415 <xsl:text> animate(){ |
|
7416 </xsl:text> |
|
7417 <xsl:text> // redraw toggle button on screen refresh |
|
7418 </xsl:text> |
|
7419 <xsl:text> this.activate(this.state); |
|
7420 </xsl:text> |
|
7421 <xsl:text> } |
|
7422 </xsl:text> |
|
7423 <xsl:text> |
|
7424 </xsl:text> |
|
7425 <xsl:text> init() { |
|
7426 </xsl:text> |
|
7427 <xsl:text> this.activate(false); |
|
7428 </xsl:text> |
|
7429 <xsl:text> this.element.onclick = (evt) => this.on_click(evt); |
|
7430 </xsl:text> |
|
7431 <xsl:text> } |
|
7432 </xsl:text> |
|
7433 <xsl:text>} |
|
7434 </xsl:text> |
|
7435 </xsl:template> |
|
7436 <xsl:template match="widget[@type='ToggleButton']" mode="widget_defs"> |
|
7437 <xsl:param name="hmi_element"/> |
|
7438 <xsl:call-template name="defs_by_labels"> |
|
7439 <xsl:with-param name="hmi_element" select="$hmi_element"/> |
|
7440 <xsl:with-param name="labels"> |
|
7441 <xsl:text>active inactive</xsl:text> |
|
7442 </xsl:with-param> |
|
7443 <xsl:with-param name="mandatory" select="'no'"/> |
|
7444 </xsl:call-template> |
|
7445 </xsl:template> |
|
7446 <xsl:template match="/"> |
|
7447 <xsl:comment> |
|
7448 <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text> |
|
7449 </xsl:comment> |
|
7450 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> |
|
7451 <head> |
|
7452 <style type="text/css" media="screen"> |
|
7453 <xsl:value-of select="ns:GetFonts()"/> |
|
7454 </style> |
|
7455 </head> |
|
7456 <body style="margin:0;overflow:hidden;user-select:none;touch-action:none;"> |
|
7457 <xsl:copy-of select="$result_svg"/> |
|
7458 <script> |
|
7459 <xsl:text> |
|
7460 // |
|
7461 // |
|
7462 // Early independent declarations |
|
7463 // |
|
7464 // |
|
7465 </xsl:text> |
|
7466 <xsl:apply-templates select="document('')/*/preamble:*"/> |
|
7467 <xsl:text> |
|
7468 // |
|
7469 // |
|
7470 // Declarations depending on preamble |
|
7471 // |
|
7472 // |
|
7473 </xsl:text> |
|
7474 <xsl:apply-templates select="document('')/*/declarations:*"/> |
|
7475 <xsl:text> |
|
7476 // |
|
7477 // |
|
7478 // Order independent declaration and code |
|
7479 // |
|
7480 // |
|
7481 </xsl:text> |
|
7482 <xsl:apply-templates select="document('')/*/definitions:*"/> |
|
7483 <xsl:text> |
|
7484 // |
|
7485 // |
|
7486 // Statements that needs to be at the end |
|
7487 // |
|
7488 // |
|
7489 </xsl:text> |
|
7490 <xsl:apply-templates select="document('')/*/epilogue:*"/> |
|
7491 <xsl:text>// svghmi.js |
|
7492 </xsl:text> |
|
7493 <xsl:text> |
|
7494 </xsl:text> |
|
7495 <xsl:text>var need_cache_apply = []; |
|
7496 </xsl:text> |
|
7497 <xsl:text> |
|
7498 </xsl:text> |
|
7499 <xsl:text>function dispatch_value(index, value) { |
|
7500 </xsl:text> |
|
7501 <xsl:text> let widgets = subscribers(index); |
|
7502 </xsl:text> |
|
7503 <xsl:text> |
|
7504 </xsl:text> |
|
7505 <xsl:text> let oldval = cache[index]; |
|
7506 </xsl:text> |
|
7507 <xsl:text> cache[index] = value; |
|
7508 </xsl:text> |
|
7509 <xsl:text> |
|
7510 </xsl:text> |
|
7511 <xsl:text> if(widgets.size > 0) { |
|
7512 </xsl:text> |
|
7513 <xsl:text> for(let widget of widgets){ |
|
7514 </xsl:text> |
|
7515 <xsl:text> widget.new_hmi_value(index, value, oldval); |
|
7516 </xsl:text> |
|
7517 <xsl:text> } |
|
7518 </xsl:text> |
|
7519 <xsl:text> } |
|
7520 </xsl:text> |
|
7521 <xsl:text>}; |
|
7522 </xsl:text> |
|
7523 <xsl:text> |
|
7524 </xsl:text> |
|
7525 <xsl:text>function init_widgets() { |
|
7526 </xsl:text> |
|
7527 <xsl:text> Object.keys(hmi_widgets).forEach(function(id) { |
|
7528 </xsl:text> |
|
7529 <xsl:text> let widget = hmi_widgets[id]; |
|
7530 </xsl:text> |
|
7531 <xsl:text> let init = widget.init; |
|
7532 </xsl:text> |
|
7533 <xsl:text> if(typeof(init) == "function"){ |
|
7534 </xsl:text> |
|
7535 <xsl:text> try { |
|
7536 </xsl:text> |
|
7537 <xsl:text> init.call(widget); |
|
7538 </xsl:text> |
|
7539 <xsl:text> } catch(err) { |
|
7540 </xsl:text> |
|
7541 <xsl:text> console.log(err); |
|
7542 </xsl:text> |
|
7543 <xsl:text> } |
|
7544 </xsl:text> |
|
7545 <xsl:text> } |
|
7546 </xsl:text> |
|
7547 <xsl:text> }); |
|
7548 </xsl:text> |
|
7549 <xsl:text>}; |
|
7550 </xsl:text> |
|
7551 <xsl:text> |
|
7552 </xsl:text> |
|
7553 <xsl:text>// Open WebSocket to relative "/ws" address |
|
7554 </xsl:text> |
|
7555 <xsl:text> |
|
7556 </xsl:text> |
|
7557 <xsl:text>var ws_url = |
|
7558 </xsl:text> |
|
7559 <xsl:text> window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws') |
|
7560 </xsl:text> |
|
7561 <xsl:text> + '?mode=' + (window.location.hash == "#watchdog" |
|
7562 </xsl:text> |
|
7563 <xsl:text> ? "watchdog" |
|
7564 </xsl:text> |
|
7565 <xsl:text> : "multiclient"); |
|
7566 </xsl:text> |
|
7567 <xsl:text>var ws = new WebSocket(ws_url); |
|
7568 </xsl:text> |
|
7569 <xsl:text>ws.binaryType = 'arraybuffer'; |
|
7570 </xsl:text> |
|
7571 <xsl:text> |
|
7572 </xsl:text> |
|
7573 <xsl:text>const dvgetters = { |
|
7574 </xsl:text> |
|
7575 <xsl:text> INT: (dv,offset) => [dv.getInt16(offset, true), 2], |
|
7576 </xsl:text> |
|
7577 <xsl:text> BOOL: (dv,offset) => [dv.getInt8(offset, true), 1], |
|
7578 </xsl:text> |
|
7579 <xsl:text> NODE: (dv,offset) => [dv.getInt8(offset, true), 1], |
|
7580 </xsl:text> |
|
7581 <xsl:text> REAL: (dv,offset) => [dv.getFloat32(offset, true), 4], |
|
7582 </xsl:text> |
|
7583 <xsl:text> STRING: (dv, offset) => { |
|
7584 </xsl:text> |
|
7585 <xsl:text> const size = dv.getInt8(offset); |
|
7586 </xsl:text> |
|
7587 <xsl:text> return [ |
|
7588 </xsl:text> |
|
7589 <xsl:text> String.fromCharCode.apply(null, new Uint8Array( |
|
7590 </xsl:text> |
|
7591 <xsl:text> dv.buffer, /* original buffer */ |
|
7592 </xsl:text> |
|
7593 <xsl:text> offset + 1, /* string starts after size*/ |
|
7594 </xsl:text> |
|
7595 <xsl:text> size /* size of string */ |
|
7596 </xsl:text> |
|
7597 <xsl:text> )), size + 1]; /* total increment */ |
|
7598 </xsl:text> |
|
7599 <xsl:text> } |
|
7600 </xsl:text> |
|
7601 <xsl:text>}; |
|
7602 </xsl:text> |
|
7603 <xsl:text> |
|
7604 </xsl:text> |
|
7605 <xsl:text>// Apply updates recieved through ws.onmessage to subscribed widgets |
|
7606 </xsl:text> |
|
7607 <xsl:text>function apply_updates() { |
|
7608 </xsl:text> |
|
7609 <xsl:text> updates.forEach((value, index) => { |
|
7610 </xsl:text> |
|
7611 <xsl:text> dispatch_value(index, value); |
|
7612 </xsl:text> |
|
7613 <xsl:text> }); |
|
7614 </xsl:text> |
|
7615 <xsl:text> updates.clear(); |
|
7616 </xsl:text> |
|
7617 <xsl:text>} |
|
7618 </xsl:text> |
|
7619 <xsl:text> |
|
7620 </xsl:text> |
|
7621 <xsl:text>// Called on requestAnimationFrame, modifies DOM |
|
7622 </xsl:text> |
|
7623 <xsl:text>var requestAnimationFrameID = null; |
|
7624 </xsl:text> |
|
7625 <xsl:text>function animate() { |
|
7626 </xsl:text> |
|
7627 <xsl:text> // Do the page swith if any one pending |
|
7628 </xsl:text> |
|
7629 <xsl:text> if(current_subscribed_page != current_visible_page){ |
|
7630 </xsl:text> |
|
7631 <xsl:text> switch_visible_page(current_subscribed_page); |
|
7632 </xsl:text> |
|
7633 <xsl:text> } |
|
7634 </xsl:text> |
|
7635 <xsl:text> |
|
7636 </xsl:text> |
|
7637 <xsl:text> while(widget = need_cache_apply.pop()){ |
|
7638 </xsl:text> |
|
7639 <xsl:text> widget.apply_cache(); |
|
7640 </xsl:text> |
|
7641 <xsl:text> } |
|
7642 </xsl:text> |
|
7643 <xsl:text> |
|
7644 </xsl:text> |
|
7645 <xsl:text> if(jumps_need_update) update_jumps(); |
|
7646 </xsl:text> |
|
7647 <xsl:text> |
|
7648 </xsl:text> |
|
7649 <xsl:text> apply_updates(); |
|
7650 </xsl:text> |
|
7651 <xsl:text> |
|
7652 </xsl:text> |
|
7653 <xsl:text> pending_widget_animates.forEach(widget => widget._animate()); |
|
7654 </xsl:text> |
|
7655 <xsl:text> pending_widget_animates = []; |
|
7656 </xsl:text> |
|
7657 <xsl:text> |
|
7658 </xsl:text> |
|
7659 <xsl:text> requestAnimationFrameID = null; |
|
7660 </xsl:text> |
|
7661 <xsl:text>} |
|
7662 </xsl:text> |
|
7663 <xsl:text> |
|
7664 </xsl:text> |
|
7665 <xsl:text>function requestHMIAnimation() { |
|
7666 </xsl:text> |
|
7667 <xsl:text> if(requestAnimationFrameID == null){ |
|
7668 </xsl:text> |
|
7669 <xsl:text> requestAnimationFrameID = window.requestAnimationFrame(animate); |
|
7670 </xsl:text> |
|
7671 <xsl:text> } |
|
7672 </xsl:text> |
|
7673 <xsl:text>} |
|
7674 </xsl:text> |
|
7675 <xsl:text> |
|
7676 </xsl:text> |
|
7677 <xsl:text>// Message reception handler |
|
7678 </xsl:text> |
|
7679 <xsl:text>// Hash is verified and HMI values updates resulting from binary parsing |
|
7680 </xsl:text> |
|
7681 <xsl:text>// are stored until browser can compute next frame, DOM is left untouched |
|
7682 </xsl:text> |
|
7683 <xsl:text>ws.onmessage = function (evt) { |
|
7684 </xsl:text> |
|
7685 <xsl:text> |
|
7686 </xsl:text> |
|
7687 <xsl:text> let data = evt.data; |
|
7688 </xsl:text> |
|
7689 <xsl:text> let dv = new DataView(data); |
|
7690 </xsl:text> |
|
7691 <xsl:text> let i = 0; |
|
7692 </xsl:text> |
|
7693 <xsl:text> try { |
|
7694 </xsl:text> |
|
7695 <xsl:text> for(let hash_int of hmi_hash) { |
|
7696 </xsl:text> |
|
7697 <xsl:text> if(hash_int != dv.getUint8(i)){ |
|
7698 </xsl:text> |
|
7699 <xsl:text> throw new Error("Hash doesn't match"); |
|
7700 </xsl:text> |
|
7701 <xsl:text> }; |
|
7702 </xsl:text> |
|
7703 <xsl:text> i++; |
|
7704 </xsl:text> |
|
7705 <xsl:text> }; |
|
7706 </xsl:text> |
|
7707 <xsl:text> |
|
7708 </xsl:text> |
|
7709 <xsl:text> while(i < data.byteLength){ |
|
7710 </xsl:text> |
|
7711 <xsl:text> let index = dv.getUint32(i, true); |
|
7712 </xsl:text> |
|
7713 <xsl:text> i += 4; |
|
7714 </xsl:text> |
|
7715 <xsl:text> let iectype = hmitree_types[index]; |
|
7716 </xsl:text> |
|
7717 <xsl:text> if(iectype != undefined){ |
|
7718 </xsl:text> |
|
7719 <xsl:text> let dvgetter = dvgetters[iectype]; |
|
7720 </xsl:text> |
|
7721 <xsl:text> let [value, bytesize] = dvgetter(dv,i); |
|
7722 </xsl:text> |
|
7723 <xsl:text> updates.set(index, value); |
|
7724 </xsl:text> |
|
7725 <xsl:text> i += bytesize; |
|
7726 </xsl:text> |
|
7727 <xsl:text> } else { |
|
7728 </xsl:text> |
|
7729 <xsl:text> throw new Error("Unknown index "+index); |
|
7730 </xsl:text> |
|
7731 <xsl:text> } |
|
7732 </xsl:text> |
|
7733 <xsl:text> }; |
|
7734 </xsl:text> |
|
7735 <xsl:text> // register for rendering on next frame, since there are updates |
|
7736 </xsl:text> |
|
7737 <xsl:text> requestHMIAnimation(); |
|
7738 </xsl:text> |
|
7739 <xsl:text> } catch(err) { |
|
7740 </xsl:text> |
|
7741 <xsl:text> // 1003 is for "Unsupported Data" |
|
7742 </xsl:text> |
|
7743 <xsl:text> // ws.close(1003, err.message); |
|
7744 </xsl:text> |
|
7745 <xsl:text> |
|
7746 </xsl:text> |
|
7747 <xsl:text> // TODO : remove debug alert ? |
|
7748 </xsl:text> |
|
7749 <xsl:text> alert("Error : "+err.message+"\nHMI will be reloaded."); |
|
7750 </xsl:text> |
|
7751 <xsl:text> |
|
7752 </xsl:text> |
|
7753 <xsl:text> // force reload ignoring cache |
|
7754 </xsl:text> |
|
7755 <xsl:text> location.reload(true); |
|
7756 </xsl:text> |
|
7757 <xsl:text> } |
|
7758 </xsl:text> |
|
7759 <xsl:text>}; |
|
7760 </xsl:text> |
|
7761 <xsl:text> |
|
7762 </xsl:text> |
|
7763 <xsl:text>hmi_hash_u8 = new Uint8Array(hmi_hash); |
|
7764 </xsl:text> |
|
7765 <xsl:text> |
|
7766 </xsl:text> |
|
7767 <xsl:text>function send_blob(data) { |
|
7768 </xsl:text> |
|
7769 <xsl:text> if(data.length > 0) { |
|
7770 </xsl:text> |
|
7771 <xsl:text> ws.send(new Blob([hmi_hash_u8].concat(data))); |
|
7772 </xsl:text> |
|
7773 <xsl:text> }; |
|
7774 </xsl:text> |
|
7775 <xsl:text>}; |
|
7776 </xsl:text> |
|
7777 <xsl:text> |
|
7778 </xsl:text> |
|
7779 <xsl:text>const typedarray_types = { |
|
7780 </xsl:text> |
|
7781 <xsl:text> INT: (number) => new Int16Array([number]), |
|
7782 </xsl:text> |
|
7783 <xsl:text> BOOL: (truth) => new Int16Array([truth]), |
|
7784 </xsl:text> |
|
7785 <xsl:text> NODE: (truth) => new Int16Array([truth]), |
|
7786 </xsl:text> |
|
7787 <xsl:text> REAL: (number) => new Float32Array([number]), |
|
7788 </xsl:text> |
|
7789 <xsl:text> STRING: (str) => { |
|
7790 </xsl:text> |
|
7791 <xsl:text> // beremiz default string max size is 128 |
|
7792 </xsl:text> |
|
7793 <xsl:text> str = str.slice(0,128); |
|
7794 </xsl:text> |
|
7795 <xsl:text> binary = new Uint8Array(str.length + 1); |
|
7796 </xsl:text> |
|
7797 <xsl:text> binary[0] = str.length; |
|
7798 </xsl:text> |
|
7799 <xsl:text> for(let i = 0; i < str.length; i++){ |
|
7800 </xsl:text> |
|
7801 <xsl:text> binary[i+1] = str.charCodeAt(i); |
|
7802 </xsl:text> |
|
7803 <xsl:text> } |
|
7804 </xsl:text> |
|
7805 <xsl:text> return binary; |
|
7806 </xsl:text> |
|
7807 <xsl:text> } |
|
7808 </xsl:text> |
|
7809 <xsl:text> /* TODO */ |
|
7810 </xsl:text> |
|
7811 <xsl:text>}; |
|
7812 </xsl:text> |
|
7813 <xsl:text> |
|
7814 </xsl:text> |
|
7815 <xsl:text>function send_reset() { |
|
7816 </xsl:text> |
|
7817 <xsl:text> send_blob(new Uint8Array([1])); /* reset = 1 */ |
|
7818 </xsl:text> |
|
7819 <xsl:text>}; |
|
7820 </xsl:text> |
|
7821 <xsl:text> |
|
7822 </xsl:text> |
|
7823 <xsl:text>var subscriptions = []; |
|
7824 </xsl:text> |
|
7825 <xsl:text> |
|
7826 </xsl:text> |
|
7827 <xsl:text>function subscribers(index) { |
|
7828 </xsl:text> |
|
7829 <xsl:text> let entry = subscriptions[index]; |
|
7830 </xsl:text> |
|
7831 <xsl:text> let res; |
|
7832 </xsl:text> |
|
7833 <xsl:text> if(entry == undefined){ |
|
7834 </xsl:text> |
|
7835 <xsl:text> res = new Set(); |
|
7836 </xsl:text> |
|
7837 <xsl:text> subscriptions[index] = [res,0]; |
|
7838 </xsl:text> |
|
7839 <xsl:text> }else{ |
|
7840 </xsl:text> |
|
7841 <xsl:text> [res, _ign] = entry; |
|
7842 </xsl:text> |
|
7843 <xsl:text> } |
|
7844 </xsl:text> |
|
7845 <xsl:text> return res |
|
7846 </xsl:text> |
|
7847 <xsl:text>} |
|
7848 </xsl:text> |
|
7849 <xsl:text> |
|
7850 </xsl:text> |
|
7851 <xsl:text>function get_subscription_period(index) { |
|
7852 </xsl:text> |
|
7853 <xsl:text> let entry = subscriptions[index]; |
|
7854 </xsl:text> |
|
7855 <xsl:text> if(entry == undefined) |
|
7856 </xsl:text> |
|
7857 <xsl:text> return 0; |
|
7858 </xsl:text> |
|
7859 <xsl:text> let [_ign, period] = entry; |
|
7860 </xsl:text> |
|
7861 <xsl:text> return period; |
|
7862 </xsl:text> |
|
7863 <xsl:text>} |
|
7864 </xsl:text> |
|
7865 <xsl:text> |
|
7866 </xsl:text> |
|
7867 <xsl:text>function set_subscription_period(index, period) { |
|
7868 </xsl:text> |
|
7869 <xsl:text> let entry = subscriptions[index]; |
|
7870 </xsl:text> |
|
7871 <xsl:text> if(entry == undefined){ |
|
7872 </xsl:text> |
|
7873 <xsl:text> subscriptions[index] = [new Set(), period]; |
|
7874 </xsl:text> |
|
7875 <xsl:text> } else { |
|
7876 </xsl:text> |
|
7877 <xsl:text> entry[1] = period; |
|
7878 </xsl:text> |
|
7879 <xsl:text> } |
|
7880 </xsl:text> |
|
7881 <xsl:text>} |
|
7882 </xsl:text> |
|
7883 <xsl:text> |
|
7884 </xsl:text> |
|
7885 <xsl:text>// artificially subscribe the watchdog widget to "/heartbeat" hmi variable |
|
7886 </xsl:text> |
|
7887 <xsl:text>// Since dispatch directly calls change_hmi_value, |
|
7888 </xsl:text> |
|
7889 <xsl:text>// PLC will periodically send variable at given frequency |
|
7890 </xsl:text> |
|
7891 <xsl:text>subscribers(heartbeat_index).add({ |
|
7892 </xsl:text> |
|
7893 <xsl:text> /* type: "Watchdog", */ |
|
7894 </xsl:text> |
|
7895 <xsl:text> frequency: 1, |
|
7896 </xsl:text> |
|
7897 <xsl:text> indexes: [heartbeat_index], |
|
7898 </xsl:text> |
|
7899 <xsl:text> new_hmi_value: function(index, value, oldval) { |
|
7900 </xsl:text> |
|
7901 <xsl:text> apply_hmi_value(heartbeat_index, value+1); |
|
7902 </xsl:text> |
|
7903 <xsl:text> } |
|
7904 </xsl:text> |
|
7905 <xsl:text>}); |
|
7906 </xsl:text> |
|
7907 <xsl:text> |
|
7908 </xsl:text> |
|
7909 <xsl:text>function svg_text_to_multiline(elt) { |
|
7910 </xsl:text> |
|
7911 <xsl:text> return(Array.prototype.map.call(elt.children, x=>x.textContent).join("\n")); |
|
7912 </xsl:text> |
|
7913 <xsl:text>} |
|
7914 </xsl:text> |
|
7915 <xsl:text> |
|
7916 </xsl:text> |
|
7917 <xsl:text>function multiline_to_svg_text(elt, str) { |
|
7918 </xsl:text> |
|
7919 <xsl:text> str.split('\n').map((line,i) => {elt.children[i].textContent = line;}); |
|
7920 </xsl:text> |
|
7921 <xsl:text>} |
|
7922 </xsl:text> |
|
7923 <xsl:text> |
|
7924 </xsl:text> |
|
7925 <xsl:text>function switch_langnum(langnum) { |
|
7926 </xsl:text> |
|
7927 <xsl:text> langnum = Math.max(0, Math.min(langs.length - 1, langnum)); |
|
7928 </xsl:text> |
|
7929 <xsl:text> |
|
7930 </xsl:text> |
|
7931 <xsl:text> for (let translation of translations) { |
|
7932 </xsl:text> |
|
7933 <xsl:text> let [objs, msgs] = translation; |
|
7934 </xsl:text> |
|
7935 <xsl:text> let msg = msgs[langnum]; |
|
7936 </xsl:text> |
|
7937 <xsl:text> for (let obj of objs) { |
|
7938 </xsl:text> |
|
7939 <xsl:text> multiline_to_svg_text(obj, msg); |
|
7940 </xsl:text> |
|
7941 <xsl:text> obj.setAttribute("lang",langnum); |
|
7942 </xsl:text> |
|
7943 <xsl:text> } |
|
7944 </xsl:text> |
|
7945 <xsl:text> } |
|
7946 </xsl:text> |
|
7947 <xsl:text> return langnum; |
|
7948 </xsl:text> |
|
7949 <xsl:text>} |
|
7950 </xsl:text> |
|
7951 <xsl:text> |
|
7952 </xsl:text> |
|
7953 <xsl:text>// backup original texts |
|
7954 </xsl:text> |
|
7955 <xsl:text>for (let translation of translations) { |
|
7956 </xsl:text> |
|
7957 <xsl:text> let [objs, msgs] = translation; |
|
7958 </xsl:text> |
|
7959 <xsl:text> msgs.unshift(svg_text_to_multiline(objs[0])); |
|
7960 </xsl:text> |
|
7961 <xsl:text>} |
|
7962 </xsl:text> |
|
7963 <xsl:text> |
|
7964 </xsl:text> |
|
7965 <xsl:text>var lang_local_index = hmi_local_index("lang"); |
|
7966 </xsl:text> |
|
7967 <xsl:text>var langcode_local_index = hmi_local_index("lang_code"); |
|
7968 </xsl:text> |
|
7969 <xsl:text>var langname_local_index = hmi_local_index("lang_name"); |
|
7970 </xsl:text> |
|
7971 <xsl:text>subscribers(lang_local_index).add({ |
|
7972 </xsl:text> |
|
7973 <xsl:text> indexes: [lang_local_index], |
|
7974 </xsl:text> |
|
7975 <xsl:text> new_hmi_value: function(index, value, oldval) { |
|
7976 </xsl:text> |
|
7977 <xsl:text> let current_lang = switch_langnum(value); |
|
7978 </xsl:text> |
|
7979 <xsl:text> let [langname,langcode] = langs[current_lang]; |
|
7980 </xsl:text> |
|
7981 <xsl:text> apply_hmi_value(langcode_local_index, langcode); |
|
7982 </xsl:text> |
|
7983 <xsl:text> apply_hmi_value(langname_local_index, langname); |
|
7984 </xsl:text> |
|
7985 <xsl:text> switch_page(); |
|
7986 </xsl:text> |
|
7987 <xsl:text> } |
|
7988 </xsl:text> |
|
7989 <xsl:text>}); |
|
7990 </xsl:text> |
|
7991 <xsl:text> |
|
7992 </xsl:text> |
|
7993 <xsl:text>function setup_lang(){ |
|
7994 </xsl:text> |
|
7995 <xsl:text> let current_lang = cache[lang_local_index]; |
|
7996 </xsl:text> |
|
7997 <xsl:text> let new_lang = switch_langnum(current_lang); |
|
7998 </xsl:text> |
|
7999 <xsl:text> if(current_lang != new_lang){ |
|
8000 </xsl:text> |
|
8001 <xsl:text> apply_hmi_value(lang_local_index, new_lang); |
|
8002 </xsl:text> |
|
8003 <xsl:text> } |
|
8004 </xsl:text> |
|
8005 <xsl:text>} |
|
8006 </xsl:text> |
|
8007 <xsl:text> |
|
8008 </xsl:text> |
|
8009 <xsl:text>setup_lang(); |
|
8010 </xsl:text> |
|
8011 <xsl:text> |
|
8012 </xsl:text> |
|
8013 <xsl:text>function update_subscriptions() { |
|
8014 </xsl:text> |
|
8015 <xsl:text> let delta = []; |
|
8016 </xsl:text> |
|
8017 <xsl:text> for(let index in subscriptions){ |
|
8018 </xsl:text> |
|
8019 <xsl:text> let widgets = subscribers(index); |
|
8020 </xsl:text> |
|
8021 <xsl:text> |
|
8022 </xsl:text> |
|
8023 <xsl:text> // periods are in ms |
|
8024 </xsl:text> |
|
8025 <xsl:text> let previous_period = get_subscription_period(index); |
|
8026 </xsl:text> |
|
8027 <xsl:text> |
|
8028 </xsl:text> |
|
8029 <xsl:text> // subscribing with a zero period is unsubscribing |
|
8030 </xsl:text> |
|
8031 <xsl:text> let new_period = 0; |
|
8032 </xsl:text> |
|
8033 <xsl:text> if(widgets.size > 0) { |
|
8034 </xsl:text> |
|
8035 <xsl:text> let maxfreq = 0; |
|
8036 </xsl:text> |
|
8037 <xsl:text> for(let widget of widgets){ |
|
8038 </xsl:text> |
|
8039 <xsl:text> let wf = widget.frequency; |
|
8040 </xsl:text> |
|
8041 <xsl:text> if(wf != undefined && maxfreq < wf) |
|
8042 </xsl:text> |
|
8043 <xsl:text> maxfreq = wf; |
|
8044 </xsl:text> |
|
8045 <xsl:text> } |
|
8046 </xsl:text> |
|
8047 <xsl:text> |
|
8048 </xsl:text> |
|
8049 <xsl:text> if(maxfreq != 0) |
|
8050 </xsl:text> |
|
8051 <xsl:text> new_period = 1000/maxfreq; |
|
8052 </xsl:text> |
|
8053 <xsl:text> } |
|
8054 </xsl:text> |
|
8055 <xsl:text> |
|
8056 </xsl:text> |
|
8057 <xsl:text> if(previous_period != new_period) { |
|
8058 </xsl:text> |
|
8059 <xsl:text> set_subscription_period(index, new_period); |
|
8060 </xsl:text> |
|
8061 <xsl:text> if(index <= last_remote_index){ |
|
8062 </xsl:text> |
|
8063 <xsl:text> delta.push( |
|
8064 </xsl:text> |
|
8065 <xsl:text> new Uint8Array([2]), /* subscribe = 2 */ |
|
8066 </xsl:text> |
|
8067 <xsl:text> new Uint32Array([index]), |
|
8068 </xsl:text> |
|
8069 <xsl:text> new Uint16Array([new_period])); |
|
8070 </xsl:text> |
|
8071 <xsl:text> } |
|
8072 </xsl:text> |
|
8073 <xsl:text> } |
|
8074 </xsl:text> |
|
8075 <xsl:text> } |
|
8076 </xsl:text> |
|
8077 <xsl:text> send_blob(delta); |
|
8078 </xsl:text> |
|
8079 <xsl:text>}; |
|
8080 </xsl:text> |
|
8081 <xsl:text> |
|
8082 </xsl:text> |
|
8083 <xsl:text>function send_hmi_value(index, value) { |
|
8084 </xsl:text> |
|
8085 <xsl:text> if(index > last_remote_index){ |
|
8086 </xsl:text> |
|
8087 <xsl:text> updates.set(index, value); |
|
8088 </xsl:text> |
|
8089 <xsl:text> |
|
8090 </xsl:text> |
|
8091 <xsl:text> if(persistent_indexes.has(index)){ |
|
8092 </xsl:text> |
|
8093 <xsl:text> let varname = persistent_indexes.get(index); |
|
8094 </xsl:text> |
|
8095 <xsl:text> document.cookie = varname+"="+value+"; max-age=3153600000"; |
|
8096 </xsl:text> |
|
8097 <xsl:text> } |
|
8098 </xsl:text> |
|
8099 <xsl:text> |
|
8100 </xsl:text> |
|
8101 <xsl:text> requestHMIAnimation(); |
|
8102 </xsl:text> |
|
8103 <xsl:text> return; |
|
8104 </xsl:text> |
|
8105 <xsl:text> } |
|
8106 </xsl:text> |
|
8107 <xsl:text> |
|
8108 </xsl:text> |
|
8109 <xsl:text> let iectype = hmitree_types[index]; |
|
8110 </xsl:text> |
|
8111 <xsl:text> let tobinary = typedarray_types[iectype]; |
|
8112 </xsl:text> |
|
8113 <xsl:text> send_blob([ |
|
8114 </xsl:text> |
|
8115 <xsl:text> new Uint8Array([0]), /* setval = 0 */ |
|
8116 </xsl:text> |
|
8117 <xsl:text> new Uint32Array([index]), |
|
8118 </xsl:text> |
|
8119 <xsl:text> tobinary(value)]); |
|
8120 </xsl:text> |
|
8121 <xsl:text> |
|
8122 </xsl:text> |
|
8123 <xsl:text> // DON'T DO THAT unless read_iterator in svghmi.c modifies wbuf as well, not only rbuf |
|
8124 </xsl:text> |
|
8125 <xsl:text> // cache[index] = value; |
|
8126 </xsl:text> |
|
8127 <xsl:text>}; |
|
8128 </xsl:text> |
|
8129 <xsl:text> |
|
8130 </xsl:text> |
|
8131 <xsl:text>function apply_hmi_value(index, new_val) { |
|
8132 </xsl:text> |
|
8133 <xsl:text> let old_val = cache[index]; |
|
8134 </xsl:text> |
|
8135 <xsl:text> if(new_val != undefined && old_val != new_val) |
|
8136 </xsl:text> |
|
8137 <xsl:text> send_hmi_value(index, new_val); |
|
8138 </xsl:text> |
|
8139 <xsl:text> return new_val; |
|
8140 </xsl:text> |
|
8141 <xsl:text>} |
|
8142 </xsl:text> |
|
8143 <xsl:text> |
|
8144 </xsl:text> |
|
8145 <xsl:text>const quotes = {"'":null, '"':null}; |
|
8146 </xsl:text> |
|
8147 <xsl:text> |
|
8148 </xsl:text> |
|
8149 <xsl:text>function eval_operation_string(old_val, opstr) { |
|
8150 </xsl:text> |
|
8151 <xsl:text> let op = opstr[0]; |
|
8152 </xsl:text> |
|
8153 <xsl:text> let given_val; |
|
8154 </xsl:text> |
|
8155 <xsl:text> if(opstr.length < 2) |
|
8156 </xsl:text> |
|
8157 <xsl:text> return undefined; |
|
8158 </xsl:text> |
|
8159 <xsl:text> if(opstr[1] in quotes){ |
|
8160 </xsl:text> |
|
8161 <xsl:text> if(opstr.length < 3) |
|
8162 </xsl:text> |
|
8163 <xsl:text> return undefined; |
|
8164 </xsl:text> |
|
8165 <xsl:text> if(opstr[opstr.length-1] == opstr[1]){ |
|
8166 </xsl:text> |
|
8167 <xsl:text> given_val = opstr.slice(2,opstr.length-1); |
|
8168 </xsl:text> |
|
8169 <xsl:text> } |
|
8170 </xsl:text> |
|
8171 <xsl:text> } else { |
|
8172 </xsl:text> |
|
8173 <xsl:text> given_val = Number(opstr.slice(1)); |
|
8174 </xsl:text> |
|
8175 <xsl:text> } |
|
8176 </xsl:text> |
|
8177 <xsl:text> let new_val; |
|
8178 </xsl:text> |
|
8179 <xsl:text> switch(op){ |
|
8180 </xsl:text> |
|
8181 <xsl:text> case "=": |
|
8182 </xsl:text> |
|
8183 <xsl:text> new_val = given_val; |
|
8184 </xsl:text> |
|
8185 <xsl:text> break; |
|
8186 </xsl:text> |
|
8187 <xsl:text> case "+": |
|
8188 </xsl:text> |
|
8189 <xsl:text> new_val = old_val + given_val; |
|
8190 </xsl:text> |
|
8191 <xsl:text> break; |
|
8192 </xsl:text> |
|
8193 <xsl:text> case "-": |
|
8194 </xsl:text> |
|
8195 <xsl:text> new_val = old_val - given_val; |
|
8196 </xsl:text> |
|
8197 <xsl:text> break; |
|
8198 </xsl:text> |
|
8199 <xsl:text> case "*": |
|
8200 </xsl:text> |
|
8201 <xsl:text> new_val = old_val * given_val; |
|
8202 </xsl:text> |
|
8203 <xsl:text> break; |
|
8204 </xsl:text> |
|
8205 <xsl:text> case "/": |
|
8206 </xsl:text> |
|
8207 <xsl:text> new_val = old_val / given_val; |
|
8208 </xsl:text> |
|
8209 <xsl:text> break; |
|
8210 </xsl:text> |
|
8211 <xsl:text> } |
|
8212 </xsl:text> |
|
8213 <xsl:text> return new_val; |
|
8214 </xsl:text> |
|
8215 <xsl:text>} |
|
8216 </xsl:text> |
|
8217 <xsl:text> |
|
8218 </xsl:text> |
|
8219 <xsl:text>var current_visible_page; |
|
8220 </xsl:text> |
|
8221 <xsl:text>var current_subscribed_page; |
|
8222 </xsl:text> |
|
8223 <xsl:text>var current_page_index; |
|
8224 </xsl:text> |
|
8225 <xsl:text>var page_node_local_index = hmi_local_index("page_node"); |
|
8226 </xsl:text> |
|
8227 <xsl:text> |
|
8228 </xsl:text> |
|
8229 <xsl:text>function toggleFullscreen() { |
|
8230 </xsl:text> |
|
8231 <xsl:text> let elem = document.documentElement; |
|
8232 </xsl:text> |
|
8233 <xsl:text> |
|
8234 </xsl:text> |
|
8235 <xsl:text> if (!document.fullscreenElement) { |
|
8236 </xsl:text> |
|
8237 <xsl:text> elem.requestFullscreen().catch(err => { |
|
8238 </xsl:text> |
|
8239 <xsl:text> console.log("Error attempting to enable full-screen mode: "+err.message+" ("+err.name+")"); |
|
8240 </xsl:text> |
|
8241 <xsl:text> }); |
|
8242 </xsl:text> |
|
8243 <xsl:text> } else { |
|
8244 </xsl:text> |
|
8245 <xsl:text> document.exitFullscreen(); |
|
8246 </xsl:text> |
|
8247 <xsl:text> } |
|
8248 </xsl:text> |
|
8249 <xsl:text>} |
|
8250 </xsl:text> |
|
8251 <xsl:text> |
|
8252 </xsl:text> |
|
8253 <xsl:text>function prepare_svg() { |
|
8254 </xsl:text> |
|
8255 <xsl:text> // prevents context menu from appearing on right click and long touch |
|
8256 </xsl:text> |
|
8257 <xsl:text> document.body.addEventListener('contextmenu', e => { |
|
8258 </xsl:text> |
|
8259 <xsl:text> toggleFullscreen(); |
|
8260 </xsl:text> |
|
8261 <xsl:text> e.preventDefault(); |
|
8262 </xsl:text> |
|
8263 <xsl:text> }); |
|
8264 </xsl:text> |
|
8265 <xsl:text> |
|
8266 </xsl:text> |
|
8267 <xsl:text> for(let eltid in detachable_elements){ |
|
8268 </xsl:text> |
|
8269 <xsl:text> let [element,parent] = detachable_elements[eltid]; |
|
8270 </xsl:text> |
|
8271 <xsl:text> parent.removeChild(element); |
|
8272 </xsl:text> |
|
8273 <xsl:text> } |
|
8274 </xsl:text> |
|
8275 <xsl:text>}; |
|
8276 </xsl:text> |
|
8277 <xsl:text> |
|
8278 </xsl:text> |
|
8279 <xsl:text>function switch_page(page_name, page_index) { |
|
8280 </xsl:text> |
|
8281 <xsl:text> if(current_subscribed_page != current_visible_page){ |
|
8282 </xsl:text> |
|
8283 <xsl:text> /* page switch already going */ |
|
8284 </xsl:text> |
|
8285 <xsl:text> /* TODO LOG ERROR */ |
|
8286 </xsl:text> |
|
8287 <xsl:text> return false; |
|
8288 </xsl:text> |
|
8289 <xsl:text> } |
|
8290 </xsl:text> |
|
8291 <xsl:text> |
|
8292 </xsl:text> |
|
8293 <xsl:text> if(page_name == undefined) |
|
8294 </xsl:text> |
|
8295 <xsl:text> page_name = current_subscribed_page; |
|
8296 </xsl:text> |
|
8297 <xsl:text> |
|
8298 </xsl:text> |
|
8299 <xsl:text> |
|
8300 </xsl:text> |
|
8301 <xsl:text> let old_desc = page_desc[current_subscribed_page]; |
|
8302 </xsl:text> |
|
8303 <xsl:text> let new_desc = page_desc[page_name]; |
|
8304 </xsl:text> |
|
8305 <xsl:text> |
|
8306 </xsl:text> |
|
8307 <xsl:text> if(new_desc == undefined){ |
|
8308 </xsl:text> |
|
8309 <xsl:text> /* TODO LOG ERROR */ |
|
8310 </xsl:text> |
|
8311 <xsl:text> return false; |
|
8312 </xsl:text> |
|
8313 <xsl:text> } |
|
8314 </xsl:text> |
|
8315 <xsl:text> |
|
8316 </xsl:text> |
|
8317 <xsl:text> if(page_index == undefined){ |
|
8318 </xsl:text> |
|
8319 <xsl:text> page_index = new_desc.page_index; |
|
8320 </xsl:text> |
|
8321 <xsl:text> } |
|
8322 </xsl:text> |
|
8323 <xsl:text> |
|
8324 </xsl:text> |
|
8325 <xsl:text> if(old_desc){ |
|
8326 </xsl:text> |
|
8327 <xsl:text> old_desc.widgets.map(([widget,relativeness])=>widget.unsub()); |
|
8328 </xsl:text> |
|
8329 <xsl:text> } |
|
8330 </xsl:text> |
|
8331 <xsl:text> const new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; |
|
8332 </xsl:text> |
|
8333 <xsl:text> |
|
8334 </xsl:text> |
|
8335 <xsl:text> const container_id = page_name + (page_index != undefined ? page_index : ""); |
|
8336 </xsl:text> |
|
8337 <xsl:text> |
|
8338 </xsl:text> |
|
8339 <xsl:text> new_desc.widgets.map(([widget,relativeness])=>widget.sub(new_offset,relativeness,container_id)); |
|
8340 </xsl:text> |
|
8341 <xsl:text> |
|
8342 </xsl:text> |
|
8343 <xsl:text> update_subscriptions(); |
|
8344 </xsl:text> |
|
8345 <xsl:text> |
|
8346 </xsl:text> |
|
8347 <xsl:text> current_subscribed_page = page_name; |
|
8348 </xsl:text> |
|
8349 <xsl:text> current_page_index = page_index; |
|
8350 </xsl:text> |
|
8351 <xsl:text> let page_node; |
|
8352 </xsl:text> |
|
8353 <xsl:text> if(page_index != undefined){ |
|
8354 </xsl:text> |
|
8355 <xsl:text> page_node = hmitree_paths[page_index]; |
|
8356 </xsl:text> |
|
8357 <xsl:text> }else{ |
|
8358 </xsl:text> |
|
8359 <xsl:text> page_node = ""; |
|
8360 </xsl:text> |
|
8361 <xsl:text> } |
|
8362 </xsl:text> |
|
8363 <xsl:text> apply_hmi_value(page_node_local_index, page_node); |
|
8364 </xsl:text> |
|
8365 <xsl:text> |
|
8366 </xsl:text> |
|
8367 <xsl:text> jumps_need_update = true; |
|
8368 </xsl:text> |
|
8369 <xsl:text> |
|
8370 </xsl:text> |
|
8371 <xsl:text> requestHMIAnimation(); |
|
8372 </xsl:text> |
|
8373 <xsl:text> jump_history.push([page_name, page_index]); |
|
8374 </xsl:text> |
|
8375 <xsl:text> if(jump_history.length > 42) |
|
8376 </xsl:text> |
|
8377 <xsl:text> jump_history.shift(); |
|
8378 </xsl:text> |
|
8379 <xsl:text> |
|
8380 </xsl:text> |
|
8381 <xsl:text> return true; |
|
8382 </xsl:text> |
|
8383 <xsl:text>}; |
|
8384 </xsl:text> |
|
8385 <xsl:text> |
|
8386 </xsl:text> |
|
8387 <xsl:text>function switch_visible_page(page_name) { |
|
8388 </xsl:text> |
|
8389 <xsl:text> |
|
8390 </xsl:text> |
|
8391 <xsl:text> let old_desc = page_desc[current_visible_page]; |
|
8392 </xsl:text> |
|
8393 <xsl:text> let new_desc = page_desc[page_name]; |
|
8394 </xsl:text> |
|
8395 <xsl:text> |
|
8396 </xsl:text> |
|
8397 <xsl:text> if(old_desc){ |
|
8398 </xsl:text> |
|
8399 <xsl:text> for(let eltid in old_desc.required_detachables){ |
|
8400 </xsl:text> |
|
8401 <xsl:text> if(!(eltid in new_desc.required_detachables)){ |
|
8402 </xsl:text> |
|
8403 <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; |
|
8404 </xsl:text> |
|
8405 <xsl:text> parent.removeChild(element); |
|
8406 </xsl:text> |
|
8407 <xsl:text> } |
|
8408 </xsl:text> |
|
8409 <xsl:text> } |
|
8410 </xsl:text> |
|
8411 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
8412 </xsl:text> |
|
8413 <xsl:text> if(!(eltid in old_desc.required_detachables)){ |
|
8414 </xsl:text> |
|
8415 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
8416 </xsl:text> |
|
8417 <xsl:text> parent.appendChild(element); |
|
8418 </xsl:text> |
|
8419 <xsl:text> } |
|
8420 </xsl:text> |
|
8421 <xsl:text> } |
|
8422 </xsl:text> |
|
8423 <xsl:text> }else{ |
|
8424 </xsl:text> |
|
8425 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
8426 </xsl:text> |
|
8427 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
8428 </xsl:text> |
|
8429 <xsl:text> parent.appendChild(element); |
|
8430 </xsl:text> |
|
8431 <xsl:text> } |
|
8432 </xsl:text> |
|
8433 <xsl:text> } |
|
8434 </xsl:text> |
|
8435 <xsl:text> |
|
8436 </xsl:text> |
|
8437 <xsl:text> svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); |
|
8438 </xsl:text> |
|
8439 <xsl:text> current_visible_page = page_name; |
|
8440 </xsl:text> |
|
8441 <xsl:text>}; |
|
8442 </xsl:text> |
|
8443 <xsl:text> |
|
8444 </xsl:text> |
|
8445 <xsl:text>// Once connection established |
|
8446 </xsl:text> |
|
8447 <xsl:text>ws.onopen = function (evt) { |
|
8448 </xsl:text> |
|
8449 <xsl:text> init_widgets(); |
|
8450 </xsl:text> |
|
8451 <xsl:text> send_reset(); |
|
8452 </xsl:text> |
|
8453 <xsl:text> // show main page |
|
8454 </xsl:text> |
|
8455 <xsl:text> prepare_svg(); |
|
8456 </xsl:text> |
|
8457 <xsl:text> switch_page(default_page); |
|
8458 </xsl:text> |
|
8459 <xsl:text>}; |
|
8460 </xsl:text> |
|
8461 <xsl:text> |
|
8462 </xsl:text> |
|
8463 <xsl:text>ws.onclose = function (evt) { |
|
8464 </xsl:text> |
|
8465 <xsl:text> // TODO : add visible notification while waiting for reload |
|
8466 </xsl:text> |
|
8467 <xsl:text> console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s."); |
|
8468 </xsl:text> |
|
8469 <xsl:text> // TODO : re-enable auto reload when not in debug |
|
8470 </xsl:text> |
|
8471 <xsl:text> //window.setTimeout(() => location.reload(true), 10000); |
|
8472 </xsl:text> |
|
8473 <xsl:text> alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+"."); |
|
8474 </xsl:text> |
|
8475 <xsl:text> |
|
8476 </xsl:text> |
|
8477 <xsl:text>}; |
|
8478 </xsl:text> |
|
8479 <xsl:text> |
|
8480 </xsl:text> |
|
8481 <xsl:text>const xmlns = "http://www.w3.org/2000/svg"; |
|
8482 </xsl:text> |
|
8483 <xsl:text>var edit_callback; |
|
8484 </xsl:text> |
|
8485 <xsl:text>const localtypes = {"PAGE_LOCAL":null, "HMI_LOCAL":null} |
|
8486 </xsl:text> |
|
8487 <xsl:text>function edit_value(path, valuetype, callback, initial) { |
|
8488 </xsl:text> |
|
8489 <xsl:text> if(valuetype in localtypes){ |
|
8490 </xsl:text> |
|
8491 <xsl:text> valuetype = (typeof initial) == "number" ? "HMI_REAL" : "HMI_STRING"; |
|
8492 </xsl:text> |
|
8493 <xsl:text> } |
|
8494 </xsl:text> |
|
8495 <xsl:text> let [keypadid, xcoord, ycoord] = keypads[valuetype]; |
|
8496 </xsl:text> |
|
8497 <xsl:text> edit_callback = callback; |
|
8498 </xsl:text> |
|
8499 <xsl:text> let widget = hmi_widgets[keypadid]; |
|
8500 </xsl:text> |
|
8501 <xsl:text> widget.start_edit(path, valuetype, callback, initial); |
|
8502 </xsl:text> |
|
8503 <xsl:text>}; |
|
8504 </xsl:text> |
|
8505 <xsl:text> |
|
8506 </xsl:text> |
|
8507 <xsl:text>var current_modal; /* TODO stack ?*/ |
|
8508 </xsl:text> |
|
8509 <xsl:text> |
|
8510 </xsl:text> |
|
8511 <xsl:text>function show_modal() { |
|
8512 </xsl:text> |
|
8513 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
8514 </xsl:text> |
|
8515 <xsl:text> |
|
8516 </xsl:text> |
|
8517 <xsl:text> tmpgrp = document.createElementNS(xmlns,"g"); |
|
8518 </xsl:text> |
|
8519 <xsl:text> tmpgrpattr = document.createAttribute("transform"); |
|
8520 </xsl:text> |
|
8521 <xsl:text> let [xcoord,ycoord] = this.coordinates; |
|
8522 </xsl:text> |
|
8523 <xsl:text> let [xdest,ydest] = page_desc[current_visible_page].bbox; |
|
8524 </xsl:text> |
|
8525 <xsl:text> tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")"; |
|
8526 </xsl:text> |
|
8527 <xsl:text> |
|
8528 </xsl:text> |
|
8529 <xsl:text> tmpgrp.setAttributeNode(tmpgrpattr); |
|
8530 </xsl:text> |
|
8531 <xsl:text> |
|
8532 </xsl:text> |
|
8533 <xsl:text> tmpgrp.appendChild(element); |
|
8534 </xsl:text> |
|
8535 <xsl:text> parent.appendChild(tmpgrp); |
|
8536 </xsl:text> |
|
8537 <xsl:text> |
|
8538 </xsl:text> |
|
8539 <xsl:text> current_modal = [this.element.id, tmpgrp]; |
|
8540 </xsl:text> |
|
8541 <xsl:text>}; |
|
8542 </xsl:text> |
|
8543 <xsl:text> |
|
8544 </xsl:text> |
|
8545 <xsl:text>function end_modal() { |
|
8546 </xsl:text> |
|
8547 <xsl:text> let [eltid, tmpgrp] = current_modal; |
|
8548 </xsl:text> |
|
8549 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
8550 </xsl:text> |
|
8551 <xsl:text> |
|
8552 </xsl:text> |
|
8553 <xsl:text> parent.removeChild(tmpgrp); |
|
8554 </xsl:text> |
|
8555 <xsl:text> |
|
8556 </xsl:text> |
|
8557 <xsl:text> current_modal = undefined; |
|
8558 </xsl:text> |
|
8559 <xsl:text>}; |
|
8560 </xsl:text> |
|
8561 <xsl:text> |
|
8562 </xsl:text> |
|
8563 </script> |
|
8564 </body> |
|
8565 </html> |
|
8566 </xsl:template> |
|
8567 </xsl:stylesheet> |