2078 </xsl:text> |
2194 </xsl:text> |
2079 </xsl:for-each> |
2195 </xsl:for-each> |
2080 <xsl:text> ], |
2196 <xsl:text> ], |
2081 </xsl:text> |
2197 </xsl:text> |
2082 </xsl:template> |
2198 </xsl:template> |
2083 <xsl:template name="scripts"> |
|
2084 <xsl:text> |
|
2085 </xsl:text> |
|
2086 <xsl:text>id = idstr => document.getElementById(idstr); |
|
2087 </xsl:text> |
|
2088 <xsl:text> |
|
2089 </xsl:text> |
|
2090 <xsl:apply-templates select="document('')/*/preamble:*"/> |
|
2091 <xsl:text>var hmi_hash = [</xsl:text> |
|
2092 <xsl:value-of select="$hmitree/@hash"/> |
|
2093 <xsl:text>]; |
|
2094 </xsl:text> |
|
2095 <xsl:text> |
|
2096 </xsl:text> |
|
2097 <xsl:text>var heartbeat_index = </xsl:text> |
|
2098 <xsl:value-of select="$indexed_hmitree/*[@hmipath = '/HEARTBEAT']/@index"/> |
|
2099 <xsl:text>; |
|
2100 </xsl:text> |
|
2101 <xsl:text> |
|
2102 </xsl:text> |
|
2103 <xsl:text>var hmitree_types = [ |
|
2104 </xsl:text> |
|
2105 <xsl:for-each select="$indexed_hmitree/*"> |
|
2106 <xsl:text> /* </xsl:text> |
|
2107 <xsl:value-of select="@index"/> |
|
2108 <xsl:text> </xsl:text> |
|
2109 <xsl:value-of select="@hmipath"/> |
|
2110 <xsl:text> */ "</xsl:text> |
|
2111 <xsl:value-of select="substring(local-name(), 5)"/> |
|
2112 <xsl:text>"</xsl:text> |
|
2113 <xsl:if test="position()!=last()"> |
|
2114 <xsl:text>,</xsl:text> |
|
2115 </xsl:if> |
|
2116 <xsl:text> |
|
2117 </xsl:text> |
|
2118 </xsl:for-each> |
|
2119 <xsl:text>] |
|
2120 </xsl:text> |
|
2121 <xsl:text> |
|
2122 </xsl:text> |
|
2123 <xsl:text>var detachable_elements = { |
|
2124 </xsl:text> |
|
2125 <xsl:for-each select="$detachable_elements"> |
|
2126 <xsl:text> "</xsl:text> |
|
2127 <xsl:value-of select="@id"/> |
|
2128 <xsl:text>":[id("</xsl:text> |
|
2129 <xsl:value-of select="@id"/> |
|
2130 <xsl:text>"), id("</xsl:text> |
|
2131 <xsl:value-of select="../@id"/> |
|
2132 <xsl:text>")]</xsl:text> |
|
2133 <xsl:if test="position()!=last()"> |
|
2134 <xsl:text>,</xsl:text> |
|
2135 </xsl:if> |
|
2136 <xsl:text> |
|
2137 </xsl:text> |
|
2138 </xsl:for-each> |
|
2139 <xsl:text>} |
|
2140 </xsl:text> |
|
2141 <xsl:text> |
|
2142 </xsl:text> |
|
2143 <xsl:text>var page_desc = { |
|
2144 </xsl:text> |
|
2145 <xsl:apply-templates mode="page_desc" select="$hmi_pages"/> |
|
2146 <xsl:text>} |
|
2147 </xsl:text> |
|
2148 <xsl:text>var keypads = { |
|
2149 </xsl:text> |
|
2150 <xsl:for-each select="$keypads_descs"> |
|
2151 <xsl:variable name="keypad_id" select="@id"/> |
|
2152 <xsl:for-each select="arg"> |
|
2153 <xsl:variable name="g" select="$geometry[@Id = $keypad_id]"/> |
|
2154 <xsl:text> "</xsl:text> |
|
2155 <xsl:value-of select="@value"/> |
|
2156 <xsl:text>":["</xsl:text> |
|
2157 <xsl:value-of select="$keypad_id"/> |
|
2158 <xsl:text>", </xsl:text> |
|
2159 <xsl:value-of select="$g/@x"/> |
|
2160 <xsl:text>, </xsl:text> |
|
2161 <xsl:value-of select="$g/@y"/> |
|
2162 <xsl:text>], |
|
2163 </xsl:text> |
|
2164 </xsl:for-each> |
|
2165 </xsl:for-each> |
|
2166 <xsl:text>} |
|
2167 </xsl:text> |
|
2168 <xsl:text> |
|
2169 </xsl:text> |
|
2170 <xsl:text>var default_page = "</xsl:text> |
|
2171 <xsl:value-of select="$default_page"/> |
|
2172 <xsl:text>"; |
|
2173 </xsl:text> |
|
2174 <xsl:text>var svg_root = id("</xsl:text> |
|
2175 <xsl:value-of select="/svg:svg/@id"/> |
|
2176 <xsl:text>"); |
|
2177 </xsl:text> |
|
2178 <xsl:text>// svghmi.js |
|
2179 </xsl:text> |
|
2180 <xsl:text> |
|
2181 </xsl:text> |
|
2182 <xsl:text>var cache = hmitree_types.map(_ignored => undefined); |
|
2183 </xsl:text> |
|
2184 <xsl:text>var updates = {}; |
|
2185 </xsl:text> |
|
2186 <xsl:text>var need_cache_apply = []; |
|
2187 </xsl:text> |
|
2188 <xsl:text>var jumps_need_update = false; |
|
2189 </xsl:text> |
|
2190 <xsl:text>var jump_history = [[default_page, undefined]]; |
|
2191 </xsl:text> |
|
2192 <xsl:text> |
|
2193 </xsl:text> |
|
2194 <xsl:text>function dispatch_value_to_widget(widget, index, value, oldval) { |
|
2195 </xsl:text> |
|
2196 <xsl:text> try { |
|
2197 </xsl:text> |
|
2198 <xsl:text> let idx = widget.offset ? index - widget.offset : index; |
|
2199 </xsl:text> |
|
2200 <xsl:text> let idxidx = widget.indexes.indexOf(idx); |
|
2201 </xsl:text> |
|
2202 <xsl:text> let d = widget.dispatch; |
|
2203 </xsl:text> |
|
2204 <xsl:text> if(typeof(d) == "function" && idxidx == 0){ |
|
2205 </xsl:text> |
|
2206 <xsl:text> d.call(widget, value, oldval); |
|
2207 </xsl:text> |
|
2208 <xsl:text> } |
|
2209 </xsl:text> |
|
2210 <xsl:text> else if(typeof(d) == "object" && d.length >= idxidx){ |
|
2211 </xsl:text> |
|
2212 <xsl:text> d[idxidx].call(widget, value, oldval); |
|
2213 </xsl:text> |
|
2214 <xsl:text> } |
|
2215 </xsl:text> |
|
2216 <xsl:text> /* else dispatch_0, ..., dispatch_n ? */ |
|
2217 </xsl:text> |
|
2218 <xsl:text> /*else { |
|
2219 </xsl:text> |
|
2220 <xsl:text> throw new Error("Dunno how to dispatch to widget at index = " + index); |
|
2221 </xsl:text> |
|
2222 <xsl:text> }*/ |
|
2223 </xsl:text> |
|
2224 <xsl:text> } catch(err) { |
|
2225 </xsl:text> |
|
2226 <xsl:text> console.log(err); |
|
2227 </xsl:text> |
|
2228 <xsl:text> } |
|
2229 </xsl:text> |
|
2230 <xsl:text>} |
|
2231 </xsl:text> |
|
2232 <xsl:text> |
|
2233 </xsl:text> |
|
2234 <xsl:text>function dispatch_value(index, value) { |
|
2235 </xsl:text> |
|
2236 <xsl:text> let widgets = subscribers[index]; |
|
2237 </xsl:text> |
|
2238 <xsl:text> |
|
2239 </xsl:text> |
|
2240 <xsl:text> let oldval = cache[index]; |
|
2241 </xsl:text> |
|
2242 <xsl:text> cache[index] = value; |
|
2243 </xsl:text> |
|
2244 <xsl:text> |
|
2245 </xsl:text> |
|
2246 <xsl:text> if(widgets.size > 0) { |
|
2247 </xsl:text> |
|
2248 <xsl:text> for(let widget of widgets){ |
|
2249 </xsl:text> |
|
2250 <xsl:text> dispatch_value_to_widget(widget, index, value, oldval); |
|
2251 </xsl:text> |
|
2252 <xsl:text> } |
|
2253 </xsl:text> |
|
2254 <xsl:text> } |
|
2255 </xsl:text> |
|
2256 <xsl:text>}; |
|
2257 </xsl:text> |
|
2258 <xsl:text> |
|
2259 </xsl:text> |
|
2260 <xsl:text>function init_widgets() { |
|
2261 </xsl:text> |
|
2262 <xsl:text> Object.keys(hmi_widgets).forEach(function(id) { |
|
2263 </xsl:text> |
|
2264 <xsl:text> let widget = hmi_widgets[id]; |
|
2265 </xsl:text> |
|
2266 <xsl:text> let init = widget.init; |
|
2267 </xsl:text> |
|
2268 <xsl:text> if(typeof(init) == "function"){ |
|
2269 </xsl:text> |
|
2270 <xsl:text> try { |
|
2271 </xsl:text> |
|
2272 <xsl:text> init.call(widget); |
|
2273 </xsl:text> |
|
2274 <xsl:text> } catch(err) { |
|
2275 </xsl:text> |
|
2276 <xsl:text> console.log(err); |
|
2277 </xsl:text> |
|
2278 <xsl:text> } |
|
2279 </xsl:text> |
|
2280 <xsl:text> } |
|
2281 </xsl:text> |
|
2282 <xsl:text> }); |
|
2283 </xsl:text> |
|
2284 <xsl:text>}; |
|
2285 </xsl:text> |
|
2286 <xsl:text> |
|
2287 </xsl:text> |
|
2288 <xsl:text>// Open WebSocket to relative "/ws" address |
|
2289 </xsl:text> |
|
2290 <xsl:text>var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); |
|
2291 </xsl:text> |
|
2292 <xsl:text>ws.binaryType = 'arraybuffer'; |
|
2293 </xsl:text> |
|
2294 <xsl:text> |
|
2295 </xsl:text> |
|
2296 <xsl:text>const dvgetters = { |
|
2297 </xsl:text> |
|
2298 <xsl:text> INT: (dv,offset) => [dv.getInt16(offset, true), 2], |
|
2299 </xsl:text> |
|
2300 <xsl:text> BOOL: (dv,offset) => [dv.getInt8(offset, true), 1], |
|
2301 </xsl:text> |
|
2302 <xsl:text> NODE: (dv,offset) => [dv.getInt8(offset, true), 1], |
|
2303 </xsl:text> |
|
2304 <xsl:text> STRING: (dv, offset) => { |
|
2305 </xsl:text> |
|
2306 <xsl:text> size = dv.getInt8(offset); |
|
2307 </xsl:text> |
|
2308 <xsl:text> return [ |
|
2309 </xsl:text> |
|
2310 <xsl:text> String.fromCharCode.apply(null, new Uint8Array( |
|
2311 </xsl:text> |
|
2312 <xsl:text> dv.buffer, /* original buffer */ |
|
2313 </xsl:text> |
|
2314 <xsl:text> offset + 1, /* string starts after size*/ |
|
2315 </xsl:text> |
|
2316 <xsl:text> size /* size of string */ |
|
2317 </xsl:text> |
|
2318 <xsl:text> )), size + 1]; /* total increment */ |
|
2319 </xsl:text> |
|
2320 <xsl:text> } |
|
2321 </xsl:text> |
|
2322 <xsl:text>}; |
|
2323 </xsl:text> |
|
2324 <xsl:text> |
|
2325 </xsl:text> |
|
2326 <xsl:text>// Apply updates recieved through ws.onmessage to subscribed widgets |
|
2327 </xsl:text> |
|
2328 <xsl:text>function apply_updates() { |
|
2329 </xsl:text> |
|
2330 <xsl:text> for(let index in updates){ |
|
2331 </xsl:text> |
|
2332 <xsl:text> // serving as a key, index becomes a string |
|
2333 </xsl:text> |
|
2334 <xsl:text> // -> pass Number(index) instead |
|
2335 </xsl:text> |
|
2336 <xsl:text> dispatch_value(Number(index), updates[index]); |
|
2337 </xsl:text> |
|
2338 <xsl:text> delete updates[index]; |
|
2339 </xsl:text> |
|
2340 <xsl:text> } |
|
2341 </xsl:text> |
|
2342 <xsl:text>} |
|
2343 </xsl:text> |
|
2344 <xsl:text> |
|
2345 </xsl:text> |
|
2346 <xsl:text>// Called on requestAnimationFrame, modifies DOM |
|
2347 </xsl:text> |
|
2348 <xsl:text>var requestAnimationFrameID = null; |
|
2349 </xsl:text> |
|
2350 <xsl:text>function animate() { |
|
2351 </xsl:text> |
|
2352 <xsl:text> // Do the page swith if any one pending |
|
2353 </xsl:text> |
|
2354 <xsl:text> if(current_subscribed_page != current_visible_page){ |
|
2355 </xsl:text> |
|
2356 <xsl:text> switch_visible_page(current_subscribed_page); |
|
2357 </xsl:text> |
|
2358 <xsl:text> } |
|
2359 </xsl:text> |
|
2360 <xsl:text> |
|
2361 </xsl:text> |
|
2362 <xsl:text> while(widget = need_cache_apply.pop()){ |
|
2363 </xsl:text> |
|
2364 <xsl:text> widget.apply_cache(); |
|
2365 </xsl:text> |
|
2366 <xsl:text> } |
|
2367 </xsl:text> |
|
2368 <xsl:text> |
|
2369 </xsl:text> |
|
2370 <xsl:text> if(jumps_need_update) update_jumps(); |
|
2371 </xsl:text> |
|
2372 <xsl:text> |
|
2373 </xsl:text> |
|
2374 <xsl:text> apply_updates(); |
|
2375 </xsl:text> |
|
2376 <xsl:text> requestAnimationFrameID = null; |
|
2377 </xsl:text> |
|
2378 <xsl:text>} |
|
2379 </xsl:text> |
|
2380 <xsl:text> |
|
2381 </xsl:text> |
|
2382 <xsl:text>function requestHMIAnimation() { |
|
2383 </xsl:text> |
|
2384 <xsl:text> if(requestAnimationFrameID == null){ |
|
2385 </xsl:text> |
|
2386 <xsl:text> requestAnimationFrameID = window.requestAnimationFrame(animate); |
|
2387 </xsl:text> |
|
2388 <xsl:text> } |
|
2389 </xsl:text> |
|
2390 <xsl:text>} |
|
2391 </xsl:text> |
|
2392 <xsl:text> |
|
2393 </xsl:text> |
|
2394 <xsl:text>// Message reception handler |
|
2395 </xsl:text> |
|
2396 <xsl:text>// Hash is verified and HMI values updates resulting from binary parsing |
|
2397 </xsl:text> |
|
2398 <xsl:text>// are stored until browser can compute next frame, DOM is left untouched |
|
2399 </xsl:text> |
|
2400 <xsl:text>ws.onmessage = function (evt) { |
|
2401 </xsl:text> |
|
2402 <xsl:text> |
|
2403 </xsl:text> |
|
2404 <xsl:text> let data = evt.data; |
|
2405 </xsl:text> |
|
2406 <xsl:text> let dv = new DataView(data); |
|
2407 </xsl:text> |
|
2408 <xsl:text> let i = 0; |
|
2409 </xsl:text> |
|
2410 <xsl:text> try { |
|
2411 </xsl:text> |
|
2412 <xsl:text> for(let hash_int of hmi_hash) { |
|
2413 </xsl:text> |
|
2414 <xsl:text> if(hash_int != dv.getUint8(i)){ |
|
2415 </xsl:text> |
|
2416 <xsl:text> throw new Error("Hash doesn't match"); |
|
2417 </xsl:text> |
|
2418 <xsl:text> }; |
|
2419 </xsl:text> |
|
2420 <xsl:text> i++; |
|
2421 </xsl:text> |
|
2422 <xsl:text> }; |
|
2423 </xsl:text> |
|
2424 <xsl:text> |
|
2425 </xsl:text> |
|
2426 <xsl:text> while(i < data.byteLength){ |
|
2427 </xsl:text> |
|
2428 <xsl:text> let index = dv.getUint32(i, true); |
|
2429 </xsl:text> |
|
2430 <xsl:text> i += 4; |
|
2431 </xsl:text> |
|
2432 <xsl:text> let iectype = hmitree_types[index]; |
|
2433 </xsl:text> |
|
2434 <xsl:text> if(iectype != undefined){ |
|
2435 </xsl:text> |
|
2436 <xsl:text> let dvgetter = dvgetters[iectype]; |
|
2437 </xsl:text> |
|
2438 <xsl:text> let [value, bytesize] = dvgetter(dv,i); |
|
2439 </xsl:text> |
|
2440 <xsl:text> updates[index] = value; |
|
2441 </xsl:text> |
|
2442 <xsl:text> i += bytesize; |
|
2443 </xsl:text> |
|
2444 <xsl:text> } else { |
|
2445 </xsl:text> |
|
2446 <xsl:text> throw new Error("Unknown index "+index); |
|
2447 </xsl:text> |
|
2448 <xsl:text> } |
|
2449 </xsl:text> |
|
2450 <xsl:text> }; |
|
2451 </xsl:text> |
|
2452 <xsl:text> // register for rendering on next frame, since there are updates |
|
2453 </xsl:text> |
|
2454 <xsl:text> requestHMIAnimation(); |
|
2455 </xsl:text> |
|
2456 <xsl:text> } catch(err) { |
|
2457 </xsl:text> |
|
2458 <xsl:text> // 1003 is for "Unsupported Data" |
|
2459 </xsl:text> |
|
2460 <xsl:text> // ws.close(1003, err.message); |
|
2461 </xsl:text> |
|
2462 <xsl:text> |
|
2463 </xsl:text> |
|
2464 <xsl:text> // TODO : remove debug alert ? |
|
2465 </xsl:text> |
|
2466 <xsl:text> alert("Error : "+err.message+"\nHMI will be reloaded."); |
|
2467 </xsl:text> |
|
2468 <xsl:text> |
|
2469 </xsl:text> |
|
2470 <xsl:text> // force reload ignoring cache |
|
2471 </xsl:text> |
|
2472 <xsl:text> location.reload(true); |
|
2473 </xsl:text> |
|
2474 <xsl:text> } |
|
2475 </xsl:text> |
|
2476 <xsl:text>}; |
|
2477 </xsl:text> |
|
2478 <xsl:text> |
|
2479 </xsl:text> |
|
2480 <xsl:text> |
|
2481 </xsl:text> |
|
2482 <xsl:text>function send_blob(data) { |
|
2483 </xsl:text> |
|
2484 <xsl:text> if(data.length > 0) { |
|
2485 </xsl:text> |
|
2486 <xsl:text> ws.send(new Blob([new Uint8Array(hmi_hash)].concat(data))); |
|
2487 </xsl:text> |
|
2488 <xsl:text> }; |
|
2489 </xsl:text> |
|
2490 <xsl:text>}; |
|
2491 </xsl:text> |
|
2492 <xsl:text> |
|
2493 </xsl:text> |
|
2494 <xsl:text>const typedarray_types = { |
|
2495 </xsl:text> |
|
2496 <xsl:text> INT: (number) => new Int16Array([number]), |
|
2497 </xsl:text> |
|
2498 <xsl:text> BOOL: (truth) => new Int16Array([truth]), |
|
2499 </xsl:text> |
|
2500 <xsl:text> NODE: (truth) => new Int16Array([truth]), |
|
2501 </xsl:text> |
|
2502 <xsl:text> STRING: (str) => { |
|
2503 </xsl:text> |
|
2504 <xsl:text> // beremiz default string max size is 128 |
|
2505 </xsl:text> |
|
2506 <xsl:text> str = str.slice(0,128); |
|
2507 </xsl:text> |
|
2508 <xsl:text> binary = new Uint8Array(str.length + 1); |
|
2509 </xsl:text> |
|
2510 <xsl:text> binary[0] = str.length; |
|
2511 </xsl:text> |
|
2512 <xsl:text> for(var i = 0; i < str.length; i++){ |
|
2513 </xsl:text> |
|
2514 <xsl:text> binary[i+1] = str.charCodeAt(i); |
|
2515 </xsl:text> |
|
2516 <xsl:text> } |
|
2517 </xsl:text> |
|
2518 <xsl:text> return binary; |
|
2519 </xsl:text> |
|
2520 <xsl:text> } |
|
2521 </xsl:text> |
|
2522 <xsl:text> /* TODO */ |
|
2523 </xsl:text> |
|
2524 <xsl:text>}; |
|
2525 </xsl:text> |
|
2526 <xsl:text> |
|
2527 </xsl:text> |
|
2528 <xsl:text>function send_reset() { |
|
2529 </xsl:text> |
|
2530 <xsl:text> send_blob(new Uint8Array([1])); /* reset = 1 */ |
|
2531 </xsl:text> |
|
2532 <xsl:text>}; |
|
2533 </xsl:text> |
|
2534 <xsl:text> |
|
2535 </xsl:text> |
|
2536 <xsl:text>// subscription state, as it should be in hmi server |
|
2537 </xsl:text> |
|
2538 <xsl:text>// hmitree indexed array of integers |
|
2539 </xsl:text> |
|
2540 <xsl:text>var subscriptions = hmitree_types.map(_ignored => 0); |
|
2541 </xsl:text> |
|
2542 <xsl:text> |
|
2543 </xsl:text> |
|
2544 <xsl:text>// subscription state as needed by widget now |
|
2545 </xsl:text> |
|
2546 <xsl:text>// hmitree indexed array of Sets of widgets objects |
|
2547 </xsl:text> |
|
2548 <xsl:text>var subscribers = hmitree_types.map(_ignored => new Set()); |
|
2549 </xsl:text> |
|
2550 <xsl:text> |
|
2551 </xsl:text> |
|
2552 <xsl:text>// artificially subscribe the watchdog widget to "/heartbeat" hmi variable |
|
2553 </xsl:text> |
|
2554 <xsl:text>// Since dispatch directly calls change_hmi_value, |
|
2555 </xsl:text> |
|
2556 <xsl:text>// PLC will periodically send variable at given frequency |
|
2557 </xsl:text> |
|
2558 <xsl:text>subscribers[heartbeat_index].add({ |
|
2559 </xsl:text> |
|
2560 <xsl:text> /* type: "Watchdog", */ |
|
2561 </xsl:text> |
|
2562 <xsl:text> frequency: 1, |
|
2563 </xsl:text> |
|
2564 <xsl:text> indexes: [heartbeat_index], |
|
2565 </xsl:text> |
|
2566 <xsl:text> dispatch: function(value) { |
|
2567 </xsl:text> |
|
2568 <xsl:text> change_hmi_value(heartbeat_index, "+1"); |
|
2569 </xsl:text> |
|
2570 <xsl:text> } |
|
2571 </xsl:text> |
|
2572 <xsl:text>}); |
|
2573 </xsl:text> |
|
2574 <xsl:text> |
|
2575 </xsl:text> |
|
2576 <xsl:text>function update_subscriptions() { |
|
2577 </xsl:text> |
|
2578 <xsl:text> let delta = []; |
|
2579 </xsl:text> |
|
2580 <xsl:text> for(let index = 0; index < subscribers.length; index++){ |
|
2581 </xsl:text> |
|
2582 <xsl:text> let widgets = subscribers[index]; |
|
2583 </xsl:text> |
|
2584 <xsl:text> |
|
2585 </xsl:text> |
|
2586 <xsl:text> // periods are in ms |
|
2587 </xsl:text> |
|
2588 <xsl:text> let previous_period = subscriptions[index]; |
|
2589 </xsl:text> |
|
2590 <xsl:text> |
|
2591 </xsl:text> |
|
2592 <xsl:text> // subscribing with a zero period is unsubscribing |
|
2593 </xsl:text> |
|
2594 <xsl:text> let new_period = 0; |
|
2595 </xsl:text> |
|
2596 <xsl:text> if(widgets.size > 0) { |
|
2597 </xsl:text> |
|
2598 <xsl:text> let maxfreq = 0; |
|
2599 </xsl:text> |
|
2600 <xsl:text> for(let widget of widgets) |
|
2601 </xsl:text> |
|
2602 <xsl:text> if(maxfreq < widget.frequency) |
|
2603 </xsl:text> |
|
2604 <xsl:text> maxfreq = widget.frequency; |
|
2605 </xsl:text> |
|
2606 <xsl:text> |
|
2607 </xsl:text> |
|
2608 <xsl:text> if(maxfreq != 0) |
|
2609 </xsl:text> |
|
2610 <xsl:text> new_period = 1000/maxfreq; |
|
2611 </xsl:text> |
|
2612 <xsl:text> } |
|
2613 </xsl:text> |
|
2614 <xsl:text> |
|
2615 </xsl:text> |
|
2616 <xsl:text> if(previous_period != new_period) { |
|
2617 </xsl:text> |
|
2618 <xsl:text> subscriptions[index] = new_period; |
|
2619 </xsl:text> |
|
2620 <xsl:text> delta.push( |
|
2621 </xsl:text> |
|
2622 <xsl:text> new Uint8Array([2]), /* subscribe = 2 */ |
|
2623 </xsl:text> |
|
2624 <xsl:text> new Uint32Array([index]), |
|
2625 </xsl:text> |
|
2626 <xsl:text> new Uint16Array([new_period])); |
|
2627 </xsl:text> |
|
2628 <xsl:text> } |
|
2629 </xsl:text> |
|
2630 <xsl:text> } |
|
2631 </xsl:text> |
|
2632 <xsl:text> send_blob(delta); |
|
2633 </xsl:text> |
|
2634 <xsl:text>}; |
|
2635 </xsl:text> |
|
2636 <xsl:text> |
|
2637 </xsl:text> |
|
2638 <xsl:text>function send_hmi_value(index, value) { |
|
2639 </xsl:text> |
|
2640 <xsl:text> let iectype = hmitree_types[index]; |
|
2641 </xsl:text> |
|
2642 <xsl:text> let tobinary = typedarray_types[iectype]; |
|
2643 </xsl:text> |
|
2644 <xsl:text> send_blob([ |
|
2645 </xsl:text> |
|
2646 <xsl:text> new Uint8Array([0]), /* setval = 0 */ |
|
2647 </xsl:text> |
|
2648 <xsl:text> new Uint32Array([index]), |
|
2649 </xsl:text> |
|
2650 <xsl:text> tobinary(value)]); |
|
2651 </xsl:text> |
|
2652 <xsl:text> |
|
2653 </xsl:text> |
|
2654 <xsl:text> // DON'T DO THAT unless read_iterator in svghmi.c modifies wbuf as well, not only rbuf |
|
2655 </xsl:text> |
|
2656 <xsl:text> // cache[index] = value; |
|
2657 </xsl:text> |
|
2658 <xsl:text>}; |
|
2659 </xsl:text> |
|
2660 <xsl:text> |
|
2661 </xsl:text> |
|
2662 <xsl:text>function apply_hmi_value(index, new_val) { |
|
2663 </xsl:text> |
|
2664 <xsl:text> let old_val = cache[index] |
|
2665 </xsl:text> |
|
2666 <xsl:text> if(new_val != undefined && old_val != new_val) |
|
2667 </xsl:text> |
|
2668 <xsl:text> send_hmi_value(index, new_val); |
|
2669 </xsl:text> |
|
2670 <xsl:text> return new_val; |
|
2671 </xsl:text> |
|
2672 <xsl:text>} |
|
2673 </xsl:text> |
|
2674 <xsl:text> |
|
2675 </xsl:text> |
|
2676 <xsl:text>function change_hmi_value(index, opstr) { |
|
2677 </xsl:text> |
|
2678 <xsl:text> let op = opstr[0]; |
|
2679 </xsl:text> |
|
2680 <xsl:text> let given_val = opstr.slice(1); |
|
2681 </xsl:text> |
|
2682 <xsl:text> let old_val = cache[index] |
|
2683 </xsl:text> |
|
2684 <xsl:text> let new_val; |
|
2685 </xsl:text> |
|
2686 <xsl:text> switch(op){ |
|
2687 </xsl:text> |
|
2688 <xsl:text> case "=": |
|
2689 </xsl:text> |
|
2690 <xsl:text> eval("new_val"+opstr); |
|
2691 </xsl:text> |
|
2692 <xsl:text> break; |
|
2693 </xsl:text> |
|
2694 <xsl:text> case "+": |
|
2695 </xsl:text> |
|
2696 <xsl:text> case "-": |
|
2697 </xsl:text> |
|
2698 <xsl:text> case "*": |
|
2699 </xsl:text> |
|
2700 <xsl:text> case "/": |
|
2701 </xsl:text> |
|
2702 <xsl:text> if(old_val != undefined) |
|
2703 </xsl:text> |
|
2704 <xsl:text> new_val = eval("old_val"+opstr); |
|
2705 </xsl:text> |
|
2706 <xsl:text> break; |
|
2707 </xsl:text> |
|
2708 <xsl:text> } |
|
2709 </xsl:text> |
|
2710 <xsl:text> if(new_val != undefined && old_val != new_val) |
|
2711 </xsl:text> |
|
2712 <xsl:text> send_hmi_value(index, new_val); |
|
2713 </xsl:text> |
|
2714 <xsl:text> return new_val; |
|
2715 </xsl:text> |
|
2716 <xsl:text>} |
|
2717 </xsl:text> |
|
2718 <xsl:text> |
|
2719 </xsl:text> |
|
2720 <xsl:text>var current_visible_page; |
|
2721 </xsl:text> |
|
2722 <xsl:text>var current_subscribed_page; |
|
2723 </xsl:text> |
|
2724 <xsl:text>var current_page_index; |
|
2725 </xsl:text> |
|
2726 <xsl:text> |
|
2727 </xsl:text> |
|
2728 <xsl:text>function prepare_svg() { |
|
2729 </xsl:text> |
|
2730 <xsl:text> for(let eltid in detachable_elements){ |
|
2731 </xsl:text> |
|
2732 <xsl:text> let [element,parent] = detachable_elements[eltid]; |
|
2733 </xsl:text> |
|
2734 <xsl:text> parent.removeChild(element); |
|
2735 </xsl:text> |
|
2736 <xsl:text> } |
|
2737 </xsl:text> |
|
2738 <xsl:text>}; |
|
2739 </xsl:text> |
|
2740 <xsl:text> |
|
2741 </xsl:text> |
|
2742 <xsl:text>function switch_page(page_name, page_index) { |
|
2743 </xsl:text> |
|
2744 <xsl:text> if(current_subscribed_page != current_visible_page){ |
|
2745 </xsl:text> |
|
2746 <xsl:text> /* page switch already going */ |
|
2747 </xsl:text> |
|
2748 <xsl:text> /* TODO LOG ERROR */ |
|
2749 </xsl:text> |
|
2750 <xsl:text> return false; |
|
2751 </xsl:text> |
|
2752 <xsl:text> } |
|
2753 </xsl:text> |
|
2754 <xsl:text> |
|
2755 </xsl:text> |
|
2756 <xsl:text> if(page_name == undefined) |
|
2757 </xsl:text> |
|
2758 <xsl:text> page_name = current_subscribed_page; |
|
2759 </xsl:text> |
|
2760 <xsl:text> |
|
2761 </xsl:text> |
|
2762 <xsl:text> |
|
2763 </xsl:text> |
|
2764 <xsl:text> let old_desc = page_desc[current_subscribed_page]; |
|
2765 </xsl:text> |
|
2766 <xsl:text> let new_desc = page_desc[page_name]; |
|
2767 </xsl:text> |
|
2768 <xsl:text> |
|
2769 </xsl:text> |
|
2770 <xsl:text> if(new_desc == undefined){ |
|
2771 </xsl:text> |
|
2772 <xsl:text> /* TODO LOG ERROR */ |
|
2773 </xsl:text> |
|
2774 <xsl:text> return false; |
|
2775 </xsl:text> |
|
2776 <xsl:text> } |
|
2777 </xsl:text> |
|
2778 <xsl:text> |
|
2779 </xsl:text> |
|
2780 <xsl:text> if(page_index == undefined){ |
|
2781 </xsl:text> |
|
2782 <xsl:text> page_index = new_desc.page_index; |
|
2783 </xsl:text> |
|
2784 <xsl:text> } |
|
2785 </xsl:text> |
|
2786 <xsl:text> |
|
2787 </xsl:text> |
|
2788 <xsl:text> if(old_desc){ |
|
2789 </xsl:text> |
|
2790 <xsl:text> old_desc.absolute_widgets.map(w=>w.unsub()); |
|
2791 </xsl:text> |
|
2792 <xsl:text> old_desc.relative_widgets.map(w=>w.unsub()); |
|
2793 </xsl:text> |
|
2794 <xsl:text> } |
|
2795 </xsl:text> |
|
2796 <xsl:text> new_desc.absolute_widgets.map(w=>w.sub()); |
|
2797 </xsl:text> |
|
2798 <xsl:text> var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; |
|
2799 </xsl:text> |
|
2800 <xsl:text> new_desc.relative_widgets.map(w=>w.sub(new_offset)); |
|
2801 </xsl:text> |
|
2802 <xsl:text> |
|
2803 </xsl:text> |
|
2804 <xsl:text> update_subscriptions(); |
|
2805 </xsl:text> |
|
2806 <xsl:text> |
|
2807 </xsl:text> |
|
2808 <xsl:text> current_subscribed_page = page_name; |
|
2809 </xsl:text> |
|
2810 <xsl:text> current_page_index = page_index; |
|
2811 </xsl:text> |
|
2812 <xsl:text> |
|
2813 </xsl:text> |
|
2814 <xsl:text> jumps_need_update = true; |
|
2815 </xsl:text> |
|
2816 <xsl:text> |
|
2817 </xsl:text> |
|
2818 <xsl:text> requestHMIAnimation(); |
|
2819 </xsl:text> |
|
2820 <xsl:text> |
|
2821 </xsl:text> |
|
2822 <xsl:text> jump_history.push([page_name, page_index]); |
|
2823 </xsl:text> |
|
2824 <xsl:text> if(jump_history.length > 42) |
|
2825 </xsl:text> |
|
2826 <xsl:text> jump_history.shift(); |
|
2827 </xsl:text> |
|
2828 <xsl:text> |
|
2829 </xsl:text> |
|
2830 <xsl:text> return true; |
|
2831 </xsl:text> |
|
2832 <xsl:text>}; |
|
2833 </xsl:text> |
|
2834 <xsl:text> |
|
2835 </xsl:text> |
|
2836 <xsl:text>function* chain(a,b){ |
|
2837 </xsl:text> |
|
2838 <xsl:text> yield* a; |
|
2839 </xsl:text> |
|
2840 <xsl:text> yield* b; |
|
2841 </xsl:text> |
|
2842 <xsl:text>}; |
|
2843 </xsl:text> |
|
2844 <xsl:text> |
|
2845 </xsl:text> |
|
2846 <xsl:text>function unsubscribe(){ |
|
2847 </xsl:text> |
|
2848 <xsl:text> /* remove subsribers */ |
|
2849 </xsl:text> |
|
2850 <xsl:text> for(let index of this.indexes){ |
|
2851 </xsl:text> |
|
2852 <xsl:text> let idx = index + this.offset; |
|
2853 </xsl:text> |
|
2854 <xsl:text> subscribers[idx].delete(this); |
|
2855 </xsl:text> |
|
2856 <xsl:text> } |
|
2857 </xsl:text> |
|
2858 <xsl:text> this.offset = 0; |
|
2859 </xsl:text> |
|
2860 <xsl:text>} |
|
2861 </xsl:text> |
|
2862 <xsl:text> |
|
2863 </xsl:text> |
|
2864 <xsl:text>function subscribe(new_offset=0){ |
|
2865 </xsl:text> |
|
2866 <xsl:text> /* set the offset because relative */ |
|
2867 </xsl:text> |
|
2868 <xsl:text> this.offset = new_offset; |
|
2869 </xsl:text> |
|
2870 <xsl:text> /* add this's subsribers */ |
|
2871 </xsl:text> |
|
2872 <xsl:text> for(let index of this.indexes){ |
|
2873 </xsl:text> |
|
2874 <xsl:text> subscribers[index + new_offset].add(this); |
|
2875 </xsl:text> |
|
2876 <xsl:text> } |
|
2877 </xsl:text> |
|
2878 <xsl:text> need_cache_apply.push(this); |
|
2879 </xsl:text> |
|
2880 <xsl:text>} |
|
2881 </xsl:text> |
|
2882 <xsl:text> |
|
2883 </xsl:text> |
|
2884 <xsl:text>function foreach_unsubscribe(){ |
|
2885 </xsl:text> |
|
2886 <xsl:text> for(let item of this.items){ |
|
2887 </xsl:text> |
|
2888 <xsl:text> for(let widget of item) { |
|
2889 </xsl:text> |
|
2890 <xsl:text> unsubscribe.call(widget); |
|
2891 </xsl:text> |
|
2892 <xsl:text> } |
|
2893 </xsl:text> |
|
2894 <xsl:text> } |
|
2895 </xsl:text> |
|
2896 <xsl:text> this.offset = 0; |
|
2897 </xsl:text> |
|
2898 <xsl:text>} |
|
2899 </xsl:text> |
|
2900 <xsl:text> |
|
2901 </xsl:text> |
|
2902 <xsl:text>function foreach_widgets_do(new_offset, todo){ |
|
2903 </xsl:text> |
|
2904 <xsl:text> this.offset = new_offset; |
|
2905 </xsl:text> |
|
2906 <xsl:text> for(let i = 0; i < this.items.length; i++) { |
|
2907 </xsl:text> |
|
2908 <xsl:text> let item = this.items[i]; |
|
2909 </xsl:text> |
|
2910 <xsl:text> let orig_item_index = this.index_pool[i]; |
|
2911 </xsl:text> |
|
2912 <xsl:text> let item_index = this.index_pool[i+this.item_offset]; |
|
2913 </xsl:text> |
|
2914 <xsl:text> let item_index_offset = item_index - orig_item_index; |
|
2915 </xsl:text> |
|
2916 <xsl:text> for(let widget of item) { |
|
2917 </xsl:text> |
|
2918 <xsl:text> todo.call(widget, new_offset + item_index_offset); |
|
2919 </xsl:text> |
|
2920 <xsl:text> } |
|
2921 </xsl:text> |
|
2922 <xsl:text> } |
|
2923 </xsl:text> |
|
2924 <xsl:text>} |
|
2925 </xsl:text> |
|
2926 <xsl:text> |
|
2927 </xsl:text> |
|
2928 <xsl:text>function foreach_subscribe(new_offset=0){ |
|
2929 </xsl:text> |
|
2930 <xsl:text> foreach_widgets_do.call(this, new_offset, subscribe); |
|
2931 </xsl:text> |
|
2932 <xsl:text>} |
|
2933 </xsl:text> |
|
2934 <xsl:text> |
|
2935 </xsl:text> |
|
2936 <xsl:text>function widget_apply_cache() { |
|
2937 </xsl:text> |
|
2938 <xsl:text> for(let index of this.indexes){ |
|
2939 </xsl:text> |
|
2940 <xsl:text> /* dispatch current cache in newly opened page widgets */ |
|
2941 </xsl:text> |
|
2942 <xsl:text> let realindex = index+this.offset; |
|
2943 </xsl:text> |
|
2944 <xsl:text> let cached_val = cache[realindex]; |
|
2945 </xsl:text> |
|
2946 <xsl:text> if(cached_val != undefined) |
|
2947 </xsl:text> |
|
2948 <xsl:text> dispatch_value_to_widget(this, realindex, cached_val, cached_val); |
|
2949 </xsl:text> |
|
2950 <xsl:text> } |
|
2951 </xsl:text> |
|
2952 <xsl:text>} |
|
2953 </xsl:text> |
|
2954 <xsl:text> |
|
2955 </xsl:text> |
|
2956 <xsl:text>function foreach_apply_cache() { |
|
2957 </xsl:text> |
|
2958 <xsl:text> foreach_widgets_do.call(this, this.offset, widget_apply_cache); |
|
2959 </xsl:text> |
|
2960 <xsl:text>} |
|
2961 </xsl:text> |
|
2962 <xsl:text> |
|
2963 </xsl:text> |
|
2964 <xsl:text>function foreach_onclick(opstr, evt) { |
|
2965 </xsl:text> |
|
2966 <xsl:text> new_item_offset = eval(String(this.item_offset)+opstr) |
|
2967 </xsl:text> |
|
2968 <xsl:text> if(new_item_offset + this.items.length > this.index_pool.length) { |
|
2969 </xsl:text> |
|
2970 <xsl:text> if(this.item_offset + this.items.length == this.index_pool.length) |
|
2971 </xsl:text> |
|
2972 <xsl:text> new_item_offset = 0; |
|
2973 </xsl:text> |
|
2974 <xsl:text> else |
|
2975 </xsl:text> |
|
2976 <xsl:text> new_item_offset = this.index_pool.length - this.items.length; |
|
2977 </xsl:text> |
|
2978 <xsl:text> } else if(new_item_offset < 0) { |
|
2979 </xsl:text> |
|
2980 <xsl:text> if(this.item_offset == 0) |
|
2981 </xsl:text> |
|
2982 <xsl:text> new_item_offset = this.index_pool.length - this.items.length; |
|
2983 </xsl:text> |
|
2984 <xsl:text> else |
|
2985 </xsl:text> |
|
2986 <xsl:text> new_item_offset = 0; |
|
2987 </xsl:text> |
|
2988 <xsl:text> } |
|
2989 </xsl:text> |
|
2990 <xsl:text> this.item_offset = new_item_offset; |
|
2991 </xsl:text> |
|
2992 <xsl:text> off = this.offset; |
|
2993 </xsl:text> |
|
2994 <xsl:text> foreach_unsubscribe.call(this); |
|
2995 </xsl:text> |
|
2996 <xsl:text> foreach_subscribe.call(this,off); |
|
2997 </xsl:text> |
|
2998 <xsl:text> update_subscriptions(); |
|
2999 </xsl:text> |
|
3000 <xsl:text> need_cache_apply.push(this); |
|
3001 </xsl:text> |
|
3002 <xsl:text> jumps_need_update = true; |
|
3003 </xsl:text> |
|
3004 <xsl:text> requestHMIAnimation(); |
|
3005 </xsl:text> |
|
3006 <xsl:text>} |
|
3007 </xsl:text> |
|
3008 <xsl:text> |
|
3009 </xsl:text> |
|
3010 <xsl:text> |
|
3011 </xsl:text> |
|
3012 <xsl:text>function switch_visible_page(page_name) { |
|
3013 </xsl:text> |
|
3014 <xsl:text> |
|
3015 </xsl:text> |
|
3016 <xsl:text> let old_desc = page_desc[current_visible_page]; |
|
3017 </xsl:text> |
|
3018 <xsl:text> let new_desc = page_desc[page_name]; |
|
3019 </xsl:text> |
|
3020 <xsl:text> |
|
3021 </xsl:text> |
|
3022 <xsl:text> if(old_desc){ |
|
3023 </xsl:text> |
|
3024 <xsl:text> for(let eltid in old_desc.required_detachables){ |
|
3025 </xsl:text> |
|
3026 <xsl:text> if(!(eltid in new_desc.required_detachables)){ |
|
3027 </xsl:text> |
|
3028 <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; |
|
3029 </xsl:text> |
|
3030 <xsl:text> parent.removeChild(element); |
|
3031 </xsl:text> |
|
3032 <xsl:text> } |
|
3033 </xsl:text> |
|
3034 <xsl:text> } |
|
3035 </xsl:text> |
|
3036 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
3037 </xsl:text> |
|
3038 <xsl:text> if(!(eltid in old_desc.required_detachables)){ |
|
3039 </xsl:text> |
|
3040 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
3041 </xsl:text> |
|
3042 <xsl:text> parent.appendChild(element); |
|
3043 </xsl:text> |
|
3044 <xsl:text> } |
|
3045 </xsl:text> |
|
3046 <xsl:text> } |
|
3047 </xsl:text> |
|
3048 <xsl:text> }else{ |
|
3049 </xsl:text> |
|
3050 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
3051 </xsl:text> |
|
3052 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
3053 </xsl:text> |
|
3054 <xsl:text> parent.appendChild(element); |
|
3055 </xsl:text> |
|
3056 <xsl:text> } |
|
3057 </xsl:text> |
|
3058 <xsl:text> } |
|
3059 </xsl:text> |
|
3060 <xsl:text> |
|
3061 </xsl:text> |
|
3062 <xsl:text> svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); |
|
3063 </xsl:text> |
|
3064 <xsl:text> current_visible_page = page_name; |
|
3065 </xsl:text> |
|
3066 <xsl:text>}; |
|
3067 </xsl:text> |
|
3068 <xsl:text> |
|
3069 </xsl:text> |
|
3070 <xsl:text>function update_jumps() { |
|
3071 </xsl:text> |
|
3072 <xsl:text> page_desc[current_visible_page].jumps.map(w=>w.notify_page_change(current_visible_page,current_page_index)); |
|
3073 </xsl:text> |
|
3074 <xsl:text> jumps_need_update = false; |
|
3075 </xsl:text> |
|
3076 <xsl:text>}; |
|
3077 </xsl:text> |
|
3078 <xsl:text> |
|
3079 </xsl:text> |
|
3080 <xsl:text> |
|
3081 </xsl:text> |
|
3082 <xsl:text>// Once connection established |
|
3083 </xsl:text> |
|
3084 <xsl:text>ws.onopen = function (evt) { |
|
3085 </xsl:text> |
|
3086 <xsl:text> init_widgets(); |
|
3087 </xsl:text> |
|
3088 <xsl:text> send_reset(); |
|
3089 </xsl:text> |
|
3090 <xsl:text> // show main page |
|
3091 </xsl:text> |
|
3092 <xsl:text> prepare_svg(); |
|
3093 </xsl:text> |
|
3094 <xsl:text> switch_page(default_page); |
|
3095 </xsl:text> |
|
3096 <xsl:text>}; |
|
3097 </xsl:text> |
|
3098 <xsl:text> |
|
3099 </xsl:text> |
|
3100 <xsl:text>ws.onclose = function (evt) { |
|
3101 </xsl:text> |
|
3102 <xsl:text> // TODO : add visible notification while waiting for reload |
|
3103 </xsl:text> |
|
3104 <xsl:text> console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s."); |
|
3105 </xsl:text> |
|
3106 <xsl:text> // TODO : re-enable auto reload when not in debug |
|
3107 </xsl:text> |
|
3108 <xsl:text> //window.setTimeout(() => location.reload(true), 10000); |
|
3109 </xsl:text> |
|
3110 <xsl:text> alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+"."); |
|
3111 </xsl:text> |
|
3112 <xsl:text> |
|
3113 </xsl:text> |
|
3114 <xsl:text>}; |
|
3115 </xsl:text> |
|
3116 <xsl:text> |
|
3117 </xsl:text> |
|
3118 <xsl:text>var xmlns = "http://www.w3.org/2000/svg"; |
|
3119 </xsl:text> |
|
3120 <xsl:text>var edit_callback; |
|
3121 </xsl:text> |
|
3122 <xsl:text>function edit_value(path, valuetype, callback, initial) { |
|
3123 </xsl:text> |
|
3124 <xsl:text> |
|
3125 </xsl:text> |
|
3126 <xsl:text> let [keypadid, xcoord, ycoord] = keypads[valuetype]; |
|
3127 </xsl:text> |
|
3128 <xsl:text> console.log('XXX TODO : Edit value', path, valuetype, callback, initial, keypadid); |
|
3129 </xsl:text> |
|
3130 <xsl:text> edit_callback = callback; |
|
3131 </xsl:text> |
|
3132 <xsl:text> let widget = hmi_widgets[keypadid]; |
|
3133 </xsl:text> |
|
3134 <xsl:text> widget.start_edit(path, valuetype, callback, initial); |
|
3135 </xsl:text> |
|
3136 <xsl:text>}; |
|
3137 </xsl:text> |
|
3138 <xsl:text> |
|
3139 </xsl:text> |
|
3140 <xsl:text>var current_modal; /* TODO stack ?*/ |
|
3141 </xsl:text> |
|
3142 <xsl:text> |
|
3143 </xsl:text> |
|
3144 <xsl:text>function show_modal() { |
|
3145 </xsl:text> |
|
3146 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
3147 </xsl:text> |
|
3148 <xsl:text> |
|
3149 </xsl:text> |
|
3150 <xsl:text> tmpgrp = document.createElementNS(xmlns,"g"); |
|
3151 </xsl:text> |
|
3152 <xsl:text> tmpgrpattr = document.createAttribute("transform"); |
|
3153 </xsl:text> |
|
3154 <xsl:text> |
|
3155 </xsl:text> |
|
3156 <xsl:text> let [xcoord,ycoord] = this.coordinates; |
|
3157 </xsl:text> |
|
3158 <xsl:text> let [xdest,ydest] = page_desc[current_visible_page].bbox; |
|
3159 </xsl:text> |
|
3160 <xsl:text> tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")"; |
|
3161 </xsl:text> |
|
3162 <xsl:text> tmpgrp.setAttributeNode(tmpgrpattr); |
|
3163 </xsl:text> |
|
3164 <xsl:text> |
|
3165 </xsl:text> |
|
3166 <xsl:text> tmpgrp.appendChild(element); |
|
3167 </xsl:text> |
|
3168 <xsl:text> parent.appendChild(tmpgrp); |
|
3169 </xsl:text> |
|
3170 <xsl:text> |
|
3171 </xsl:text> |
|
3172 <xsl:text> current_modal = [this.element.id, tmpgrp]; |
|
3173 </xsl:text> |
|
3174 <xsl:text>}; |
|
3175 </xsl:text> |
|
3176 <xsl:text> |
|
3177 </xsl:text> |
|
3178 <xsl:text>function end_modal() { |
|
3179 </xsl:text> |
|
3180 <xsl:text> let [eltid, tmpgrp] = current_modal; |
|
3181 </xsl:text> |
|
3182 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
3183 </xsl:text> |
|
3184 <xsl:text> |
|
3185 </xsl:text> |
|
3186 <xsl:text> parent.removeChild(tmpgrp); |
|
3187 </xsl:text> |
|
3188 <xsl:text> |
|
3189 </xsl:text> |
|
3190 <xsl:text> current_modal = undefined; |
|
3191 </xsl:text> |
|
3192 <xsl:text>}; |
|
3193 </xsl:text> |
|
3194 <xsl:text> |
|
3195 </xsl:text> |
|
3196 <xsl:text>function widget_active_activable(eltsub) { |
|
3197 </xsl:text> |
|
3198 <xsl:text> if(eltsub.inactive_style === undefined) |
|
3199 </xsl:text> |
|
3200 <xsl:text> eltsub.inactive_style = eltsub.inactive.getAttribute("style"); |
|
3201 </xsl:text> |
|
3202 <xsl:text> eltsub.inactive.setAttribute("style", "display:none"); |
|
3203 </xsl:text> |
|
3204 <xsl:text> if(eltsub.active_style !== undefined) |
|
3205 </xsl:text> |
|
3206 <xsl:text> eltsub.active.setAttribute("style", eltsub.active_style); |
|
3207 </xsl:text> |
|
3208 <xsl:text> console.log("active", eltsub); |
|
3209 </xsl:text> |
|
3210 <xsl:text>}; |
|
3211 </xsl:text> |
|
3212 <xsl:text>function widget_inactive_activable(eltsub) { |
|
3213 </xsl:text> |
|
3214 <xsl:text> if(eltsub.active_style === undefined) |
|
3215 </xsl:text> |
|
3216 <xsl:text> eltsub.active_style = eltsub.active.getAttribute("style"); |
|
3217 </xsl:text> |
|
3218 <xsl:text> eltsub.active.setAttribute("style", "display:none"); |
|
3219 </xsl:text> |
|
3220 <xsl:text> if(eltsub.inactive_style !== undefined) |
|
3221 </xsl:text> |
|
3222 <xsl:text> eltsub.inactive.setAttribute("style", eltsub.inactive_style); |
|
3223 </xsl:text> |
|
3224 <xsl:text> console.log("inactive", eltsub); |
|
3225 </xsl:text> |
|
3226 <xsl:text>}; |
|
3227 </xsl:text> |
|
3228 <xsl:apply-templates select="document('')/*/epilogue:*"/> |
|
3229 </xsl:template> |
|
3230 <xsl:template match="/"> |
2199 <xsl:template match="/"> |
3231 <xsl:comment> |
2200 <xsl:comment> |
3232 <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text> |
2201 <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text> |
3233 </xsl:comment> |
2202 </xsl:comment> |
3234 <xsl:for-each select="document('')/*/debug:*"> |
2203 <xsl:for-each select="document('')/*/debug:*"> |
3242 <html xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/1999/xhtml"> |
2211 <html xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/1999/xhtml"> |
3243 <head/> |
2212 <head/> |
3244 <body style="margin:0;overflow:hidden;"> |
2213 <body style="margin:0;overflow:hidden;"> |
3245 <xsl:copy-of select="$result_svg"/> |
2214 <xsl:copy-of select="$result_svg"/> |
3246 <script> |
2215 <script> |
3247 <xsl:call-template name="scripts"/> |
2216 <xsl:apply-templates select="document('')/*/preamble:*"/> |
|
2217 <xsl:apply-templates select="document('')/*/epilogue:*"/> |
|
2218 <xsl:text>// svghmi.js |
|
2219 </xsl:text> |
|
2220 <xsl:text> |
|
2221 </xsl:text> |
|
2222 <xsl:text>var cache = hmitree_types.map(_ignored => undefined); |
|
2223 </xsl:text> |
|
2224 <xsl:text>var updates = {}; |
|
2225 </xsl:text> |
|
2226 <xsl:text>var need_cache_apply = []; |
|
2227 </xsl:text> |
|
2228 <xsl:text>var jumps_need_update = false; |
|
2229 </xsl:text> |
|
2230 <xsl:text>var jump_history = [[default_page, undefined]]; |
|
2231 </xsl:text> |
|
2232 <xsl:text> |
|
2233 </xsl:text> |
|
2234 <xsl:text>function dispatch_value_to_widget(widget, index, value, oldval) { |
|
2235 </xsl:text> |
|
2236 <xsl:text> try { |
|
2237 </xsl:text> |
|
2238 <xsl:text> let idx = widget.offset ? index - widget.offset : index; |
|
2239 </xsl:text> |
|
2240 <xsl:text> let idxidx = widget.indexes.indexOf(idx); |
|
2241 </xsl:text> |
|
2242 <xsl:text> let d = widget.dispatch; |
|
2243 </xsl:text> |
|
2244 <xsl:text> if(typeof(d) == "function" && idxidx == 0){ |
|
2245 </xsl:text> |
|
2246 <xsl:text> d.call(widget, value, oldval); |
|
2247 </xsl:text> |
|
2248 <xsl:text> } |
|
2249 </xsl:text> |
|
2250 <xsl:text> else if(typeof(d) == "object" && d.length >= idxidx){ |
|
2251 </xsl:text> |
|
2252 <xsl:text> d[idxidx].call(widget, value, oldval); |
|
2253 </xsl:text> |
|
2254 <xsl:text> } |
|
2255 </xsl:text> |
|
2256 <xsl:text> /* else dispatch_0, ..., dispatch_n ? */ |
|
2257 </xsl:text> |
|
2258 <xsl:text> /*else { |
|
2259 </xsl:text> |
|
2260 <xsl:text> throw new Error("Dunno how to dispatch to widget at index = " + index); |
|
2261 </xsl:text> |
|
2262 <xsl:text> }*/ |
|
2263 </xsl:text> |
|
2264 <xsl:text> } catch(err) { |
|
2265 </xsl:text> |
|
2266 <xsl:text> console.log(err); |
|
2267 </xsl:text> |
|
2268 <xsl:text> } |
|
2269 </xsl:text> |
|
2270 <xsl:text>} |
|
2271 </xsl:text> |
|
2272 <xsl:text> |
|
2273 </xsl:text> |
|
2274 <xsl:text>function dispatch_value(index, value) { |
|
2275 </xsl:text> |
|
2276 <xsl:text> let widgets = subscribers[index]; |
|
2277 </xsl:text> |
|
2278 <xsl:text> |
|
2279 </xsl:text> |
|
2280 <xsl:text> let oldval = cache[index]; |
|
2281 </xsl:text> |
|
2282 <xsl:text> cache[index] = value; |
|
2283 </xsl:text> |
|
2284 <xsl:text> |
|
2285 </xsl:text> |
|
2286 <xsl:text> if(widgets.size > 0) { |
|
2287 </xsl:text> |
|
2288 <xsl:text> for(let widget of widgets){ |
|
2289 </xsl:text> |
|
2290 <xsl:text> dispatch_value_to_widget(widget, index, value, oldval); |
|
2291 </xsl:text> |
|
2292 <xsl:text> } |
|
2293 </xsl:text> |
|
2294 <xsl:text> } |
|
2295 </xsl:text> |
|
2296 <xsl:text>}; |
|
2297 </xsl:text> |
|
2298 <xsl:text> |
|
2299 </xsl:text> |
|
2300 <xsl:text>function init_widgets() { |
|
2301 </xsl:text> |
|
2302 <xsl:text> Object.keys(hmi_widgets).forEach(function(id) { |
|
2303 </xsl:text> |
|
2304 <xsl:text> let widget = hmi_widgets[id]; |
|
2305 </xsl:text> |
|
2306 <xsl:text> let init = widget.init; |
|
2307 </xsl:text> |
|
2308 <xsl:text> if(typeof(init) == "function"){ |
|
2309 </xsl:text> |
|
2310 <xsl:text> try { |
|
2311 </xsl:text> |
|
2312 <xsl:text> init.call(widget); |
|
2313 </xsl:text> |
|
2314 <xsl:text> } catch(err) { |
|
2315 </xsl:text> |
|
2316 <xsl:text> console.log(err); |
|
2317 </xsl:text> |
|
2318 <xsl:text> } |
|
2319 </xsl:text> |
|
2320 <xsl:text> } |
|
2321 </xsl:text> |
|
2322 <xsl:text> }); |
|
2323 </xsl:text> |
|
2324 <xsl:text>}; |
|
2325 </xsl:text> |
|
2326 <xsl:text> |
|
2327 </xsl:text> |
|
2328 <xsl:text>// Open WebSocket to relative "/ws" address |
|
2329 </xsl:text> |
|
2330 <xsl:text>var ws = new WebSocket(window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')); |
|
2331 </xsl:text> |
|
2332 <xsl:text>ws.binaryType = 'arraybuffer'; |
|
2333 </xsl:text> |
|
2334 <xsl:text> |
|
2335 </xsl:text> |
|
2336 <xsl:text>const dvgetters = { |
|
2337 </xsl:text> |
|
2338 <xsl:text> INT: (dv,offset) => [dv.getInt16(offset, true), 2], |
|
2339 </xsl:text> |
|
2340 <xsl:text> BOOL: (dv,offset) => [dv.getInt8(offset, true), 1], |
|
2341 </xsl:text> |
|
2342 <xsl:text> NODE: (dv,offset) => [dv.getInt8(offset, true), 1], |
|
2343 </xsl:text> |
|
2344 <xsl:text> STRING: (dv, offset) => { |
|
2345 </xsl:text> |
|
2346 <xsl:text> size = dv.getInt8(offset); |
|
2347 </xsl:text> |
|
2348 <xsl:text> return [ |
|
2349 </xsl:text> |
|
2350 <xsl:text> String.fromCharCode.apply(null, new Uint8Array( |
|
2351 </xsl:text> |
|
2352 <xsl:text> dv.buffer, /* original buffer */ |
|
2353 </xsl:text> |
|
2354 <xsl:text> offset + 1, /* string starts after size*/ |
|
2355 </xsl:text> |
|
2356 <xsl:text> size /* size of string */ |
|
2357 </xsl:text> |
|
2358 <xsl:text> )), size + 1]; /* total increment */ |
|
2359 </xsl:text> |
|
2360 <xsl:text> } |
|
2361 </xsl:text> |
|
2362 <xsl:text>}; |
|
2363 </xsl:text> |
|
2364 <xsl:text> |
|
2365 </xsl:text> |
|
2366 <xsl:text>// Apply updates recieved through ws.onmessage to subscribed widgets |
|
2367 </xsl:text> |
|
2368 <xsl:text>function apply_updates() { |
|
2369 </xsl:text> |
|
2370 <xsl:text> for(let index in updates){ |
|
2371 </xsl:text> |
|
2372 <xsl:text> // serving as a key, index becomes a string |
|
2373 </xsl:text> |
|
2374 <xsl:text> // -> pass Number(index) instead |
|
2375 </xsl:text> |
|
2376 <xsl:text> dispatch_value(Number(index), updates[index]); |
|
2377 </xsl:text> |
|
2378 <xsl:text> delete updates[index]; |
|
2379 </xsl:text> |
|
2380 <xsl:text> } |
|
2381 </xsl:text> |
|
2382 <xsl:text>} |
|
2383 </xsl:text> |
|
2384 <xsl:text> |
|
2385 </xsl:text> |
|
2386 <xsl:text>// Called on requestAnimationFrame, modifies DOM |
|
2387 </xsl:text> |
|
2388 <xsl:text>var requestAnimationFrameID = null; |
|
2389 </xsl:text> |
|
2390 <xsl:text>function animate() { |
|
2391 </xsl:text> |
|
2392 <xsl:text> // Do the page swith if any one pending |
|
2393 </xsl:text> |
|
2394 <xsl:text> if(current_subscribed_page != current_visible_page){ |
|
2395 </xsl:text> |
|
2396 <xsl:text> switch_visible_page(current_subscribed_page); |
|
2397 </xsl:text> |
|
2398 <xsl:text> } |
|
2399 </xsl:text> |
|
2400 <xsl:text> |
|
2401 </xsl:text> |
|
2402 <xsl:text> while(widget = need_cache_apply.pop()){ |
|
2403 </xsl:text> |
|
2404 <xsl:text> widget.apply_cache(); |
|
2405 </xsl:text> |
|
2406 <xsl:text> } |
|
2407 </xsl:text> |
|
2408 <xsl:text> |
|
2409 </xsl:text> |
|
2410 <xsl:text> if(jumps_need_update) update_jumps(); |
|
2411 </xsl:text> |
|
2412 <xsl:text> |
|
2413 </xsl:text> |
|
2414 <xsl:text> apply_updates(); |
|
2415 </xsl:text> |
|
2416 <xsl:text> requestAnimationFrameID = null; |
|
2417 </xsl:text> |
|
2418 <xsl:text>} |
|
2419 </xsl:text> |
|
2420 <xsl:text> |
|
2421 </xsl:text> |
|
2422 <xsl:text>function requestHMIAnimation() { |
|
2423 </xsl:text> |
|
2424 <xsl:text> if(requestAnimationFrameID == null){ |
|
2425 </xsl:text> |
|
2426 <xsl:text> requestAnimationFrameID = window.requestAnimationFrame(animate); |
|
2427 </xsl:text> |
|
2428 <xsl:text> } |
|
2429 </xsl:text> |
|
2430 <xsl:text>} |
|
2431 </xsl:text> |
|
2432 <xsl:text> |
|
2433 </xsl:text> |
|
2434 <xsl:text>// Message reception handler |
|
2435 </xsl:text> |
|
2436 <xsl:text>// Hash is verified and HMI values updates resulting from binary parsing |
|
2437 </xsl:text> |
|
2438 <xsl:text>// are stored until browser can compute next frame, DOM is left untouched |
|
2439 </xsl:text> |
|
2440 <xsl:text>ws.onmessage = function (evt) { |
|
2441 </xsl:text> |
|
2442 <xsl:text> |
|
2443 </xsl:text> |
|
2444 <xsl:text> let data = evt.data; |
|
2445 </xsl:text> |
|
2446 <xsl:text> let dv = new DataView(data); |
|
2447 </xsl:text> |
|
2448 <xsl:text> let i = 0; |
|
2449 </xsl:text> |
|
2450 <xsl:text> try { |
|
2451 </xsl:text> |
|
2452 <xsl:text> for(let hash_int of hmi_hash) { |
|
2453 </xsl:text> |
|
2454 <xsl:text> if(hash_int != dv.getUint8(i)){ |
|
2455 </xsl:text> |
|
2456 <xsl:text> throw new Error("Hash doesn't match"); |
|
2457 </xsl:text> |
|
2458 <xsl:text> }; |
|
2459 </xsl:text> |
|
2460 <xsl:text> i++; |
|
2461 </xsl:text> |
|
2462 <xsl:text> }; |
|
2463 </xsl:text> |
|
2464 <xsl:text> |
|
2465 </xsl:text> |
|
2466 <xsl:text> while(i < data.byteLength){ |
|
2467 </xsl:text> |
|
2468 <xsl:text> let index = dv.getUint32(i, true); |
|
2469 </xsl:text> |
|
2470 <xsl:text> i += 4; |
|
2471 </xsl:text> |
|
2472 <xsl:text> let iectype = hmitree_types[index]; |
|
2473 </xsl:text> |
|
2474 <xsl:text> if(iectype != undefined){ |
|
2475 </xsl:text> |
|
2476 <xsl:text> let dvgetter = dvgetters[iectype]; |
|
2477 </xsl:text> |
|
2478 <xsl:text> let [value, bytesize] = dvgetter(dv,i); |
|
2479 </xsl:text> |
|
2480 <xsl:text> updates[index] = value; |
|
2481 </xsl:text> |
|
2482 <xsl:text> i += bytesize; |
|
2483 </xsl:text> |
|
2484 <xsl:text> } else { |
|
2485 </xsl:text> |
|
2486 <xsl:text> throw new Error("Unknown index "+index); |
|
2487 </xsl:text> |
|
2488 <xsl:text> } |
|
2489 </xsl:text> |
|
2490 <xsl:text> }; |
|
2491 </xsl:text> |
|
2492 <xsl:text> // register for rendering on next frame, since there are updates |
|
2493 </xsl:text> |
|
2494 <xsl:text> requestHMIAnimation(); |
|
2495 </xsl:text> |
|
2496 <xsl:text> } catch(err) { |
|
2497 </xsl:text> |
|
2498 <xsl:text> // 1003 is for "Unsupported Data" |
|
2499 </xsl:text> |
|
2500 <xsl:text> // ws.close(1003, err.message); |
|
2501 </xsl:text> |
|
2502 <xsl:text> |
|
2503 </xsl:text> |
|
2504 <xsl:text> // TODO : remove debug alert ? |
|
2505 </xsl:text> |
|
2506 <xsl:text> alert("Error : "+err.message+"\nHMI will be reloaded."); |
|
2507 </xsl:text> |
|
2508 <xsl:text> |
|
2509 </xsl:text> |
|
2510 <xsl:text> // force reload ignoring cache |
|
2511 </xsl:text> |
|
2512 <xsl:text> location.reload(true); |
|
2513 </xsl:text> |
|
2514 <xsl:text> } |
|
2515 </xsl:text> |
|
2516 <xsl:text>}; |
|
2517 </xsl:text> |
|
2518 <xsl:text> |
|
2519 </xsl:text> |
|
2520 <xsl:text> |
|
2521 </xsl:text> |
|
2522 <xsl:text>function send_blob(data) { |
|
2523 </xsl:text> |
|
2524 <xsl:text> if(data.length > 0) { |
|
2525 </xsl:text> |
|
2526 <xsl:text> ws.send(new Blob([new Uint8Array(hmi_hash)].concat(data))); |
|
2527 </xsl:text> |
|
2528 <xsl:text> }; |
|
2529 </xsl:text> |
|
2530 <xsl:text>}; |
|
2531 </xsl:text> |
|
2532 <xsl:text> |
|
2533 </xsl:text> |
|
2534 <xsl:text>const typedarray_types = { |
|
2535 </xsl:text> |
|
2536 <xsl:text> INT: (number) => new Int16Array([number]), |
|
2537 </xsl:text> |
|
2538 <xsl:text> BOOL: (truth) => new Int16Array([truth]), |
|
2539 </xsl:text> |
|
2540 <xsl:text> NODE: (truth) => new Int16Array([truth]), |
|
2541 </xsl:text> |
|
2542 <xsl:text> STRING: (str) => { |
|
2543 </xsl:text> |
|
2544 <xsl:text> // beremiz default string max size is 128 |
|
2545 </xsl:text> |
|
2546 <xsl:text> str = str.slice(0,128); |
|
2547 </xsl:text> |
|
2548 <xsl:text> binary = new Uint8Array(str.length + 1); |
|
2549 </xsl:text> |
|
2550 <xsl:text> binary[0] = str.length; |
|
2551 </xsl:text> |
|
2552 <xsl:text> for(var i = 0; i < str.length; i++){ |
|
2553 </xsl:text> |
|
2554 <xsl:text> binary[i+1] = str.charCodeAt(i); |
|
2555 </xsl:text> |
|
2556 <xsl:text> } |
|
2557 </xsl:text> |
|
2558 <xsl:text> return binary; |
|
2559 </xsl:text> |
|
2560 <xsl:text> } |
|
2561 </xsl:text> |
|
2562 <xsl:text> /* TODO */ |
|
2563 </xsl:text> |
|
2564 <xsl:text>}; |
|
2565 </xsl:text> |
|
2566 <xsl:text> |
|
2567 </xsl:text> |
|
2568 <xsl:text>function send_reset() { |
|
2569 </xsl:text> |
|
2570 <xsl:text> send_blob(new Uint8Array([1])); /* reset = 1 */ |
|
2571 </xsl:text> |
|
2572 <xsl:text>}; |
|
2573 </xsl:text> |
|
2574 <xsl:text> |
|
2575 </xsl:text> |
|
2576 <xsl:text>// subscription state, as it should be in hmi server |
|
2577 </xsl:text> |
|
2578 <xsl:text>// hmitree indexed array of integers |
|
2579 </xsl:text> |
|
2580 <xsl:text>var subscriptions = hmitree_types.map(_ignored => 0); |
|
2581 </xsl:text> |
|
2582 <xsl:text> |
|
2583 </xsl:text> |
|
2584 <xsl:text>// subscription state as needed by widget now |
|
2585 </xsl:text> |
|
2586 <xsl:text>// hmitree indexed array of Sets of widgets objects |
|
2587 </xsl:text> |
|
2588 <xsl:text>var subscribers = hmitree_types.map(_ignored => new Set()); |
|
2589 </xsl:text> |
|
2590 <xsl:text> |
|
2591 </xsl:text> |
|
2592 <xsl:text>// artificially subscribe the watchdog widget to "/heartbeat" hmi variable |
|
2593 </xsl:text> |
|
2594 <xsl:text>// Since dispatch directly calls change_hmi_value, |
|
2595 </xsl:text> |
|
2596 <xsl:text>// PLC will periodically send variable at given frequency |
|
2597 </xsl:text> |
|
2598 <xsl:text>subscribers[heartbeat_index].add({ |
|
2599 </xsl:text> |
|
2600 <xsl:text> /* type: "Watchdog", */ |
|
2601 </xsl:text> |
|
2602 <xsl:text> frequency: 1, |
|
2603 </xsl:text> |
|
2604 <xsl:text> indexes: [heartbeat_index], |
|
2605 </xsl:text> |
|
2606 <xsl:text> dispatch: function(value) { |
|
2607 </xsl:text> |
|
2608 <xsl:text> change_hmi_value(heartbeat_index, "+1"); |
|
2609 </xsl:text> |
|
2610 <xsl:text> } |
|
2611 </xsl:text> |
|
2612 <xsl:text>}); |
|
2613 </xsl:text> |
|
2614 <xsl:text> |
|
2615 </xsl:text> |
|
2616 <xsl:text>function update_subscriptions() { |
|
2617 </xsl:text> |
|
2618 <xsl:text> let delta = []; |
|
2619 </xsl:text> |
|
2620 <xsl:text> for(let index = 0; index < subscribers.length; index++){ |
|
2621 </xsl:text> |
|
2622 <xsl:text> let widgets = subscribers[index]; |
|
2623 </xsl:text> |
|
2624 <xsl:text> |
|
2625 </xsl:text> |
|
2626 <xsl:text> // periods are in ms |
|
2627 </xsl:text> |
|
2628 <xsl:text> let previous_period = subscriptions[index]; |
|
2629 </xsl:text> |
|
2630 <xsl:text> |
|
2631 </xsl:text> |
|
2632 <xsl:text> // subscribing with a zero period is unsubscribing |
|
2633 </xsl:text> |
|
2634 <xsl:text> let new_period = 0; |
|
2635 </xsl:text> |
|
2636 <xsl:text> if(widgets.size > 0) { |
|
2637 </xsl:text> |
|
2638 <xsl:text> let maxfreq = 0; |
|
2639 </xsl:text> |
|
2640 <xsl:text> for(let widget of widgets) |
|
2641 </xsl:text> |
|
2642 <xsl:text> if(maxfreq < widget.frequency) |
|
2643 </xsl:text> |
|
2644 <xsl:text> maxfreq = widget.frequency; |
|
2645 </xsl:text> |
|
2646 <xsl:text> |
|
2647 </xsl:text> |
|
2648 <xsl:text> if(maxfreq != 0) |
|
2649 </xsl:text> |
|
2650 <xsl:text> new_period = 1000/maxfreq; |
|
2651 </xsl:text> |
|
2652 <xsl:text> } |
|
2653 </xsl:text> |
|
2654 <xsl:text> |
|
2655 </xsl:text> |
|
2656 <xsl:text> if(previous_period != new_period) { |
|
2657 </xsl:text> |
|
2658 <xsl:text> subscriptions[index] = new_period; |
|
2659 </xsl:text> |
|
2660 <xsl:text> delta.push( |
|
2661 </xsl:text> |
|
2662 <xsl:text> new Uint8Array([2]), /* subscribe = 2 */ |
|
2663 </xsl:text> |
|
2664 <xsl:text> new Uint32Array([index]), |
|
2665 </xsl:text> |
|
2666 <xsl:text> new Uint16Array([new_period])); |
|
2667 </xsl:text> |
|
2668 <xsl:text> } |
|
2669 </xsl:text> |
|
2670 <xsl:text> } |
|
2671 </xsl:text> |
|
2672 <xsl:text> send_blob(delta); |
|
2673 </xsl:text> |
|
2674 <xsl:text>}; |
|
2675 </xsl:text> |
|
2676 <xsl:text> |
|
2677 </xsl:text> |
|
2678 <xsl:text>function send_hmi_value(index, value) { |
|
2679 </xsl:text> |
|
2680 <xsl:text> let iectype = hmitree_types[index]; |
|
2681 </xsl:text> |
|
2682 <xsl:text> let tobinary = typedarray_types[iectype]; |
|
2683 </xsl:text> |
|
2684 <xsl:text> send_blob([ |
|
2685 </xsl:text> |
|
2686 <xsl:text> new Uint8Array([0]), /* setval = 0 */ |
|
2687 </xsl:text> |
|
2688 <xsl:text> new Uint32Array([index]), |
|
2689 </xsl:text> |
|
2690 <xsl:text> tobinary(value)]); |
|
2691 </xsl:text> |
|
2692 <xsl:text> |
|
2693 </xsl:text> |
|
2694 <xsl:text> // DON'T DO THAT unless read_iterator in svghmi.c modifies wbuf as well, not only rbuf |
|
2695 </xsl:text> |
|
2696 <xsl:text> // cache[index] = value; |
|
2697 </xsl:text> |
|
2698 <xsl:text>}; |
|
2699 </xsl:text> |
|
2700 <xsl:text> |
|
2701 </xsl:text> |
|
2702 <xsl:text>function apply_hmi_value(index, new_val) { |
|
2703 </xsl:text> |
|
2704 <xsl:text> let old_val = cache[index] |
|
2705 </xsl:text> |
|
2706 <xsl:text> if(new_val != undefined && old_val != new_val) |
|
2707 </xsl:text> |
|
2708 <xsl:text> send_hmi_value(index, new_val); |
|
2709 </xsl:text> |
|
2710 <xsl:text> return new_val; |
|
2711 </xsl:text> |
|
2712 <xsl:text>} |
|
2713 </xsl:text> |
|
2714 <xsl:text> |
|
2715 </xsl:text> |
|
2716 <xsl:text>function change_hmi_value(index, opstr) { |
|
2717 </xsl:text> |
|
2718 <xsl:text> let op = opstr[0]; |
|
2719 </xsl:text> |
|
2720 <xsl:text> let given_val = opstr.slice(1); |
|
2721 </xsl:text> |
|
2722 <xsl:text> let old_val = cache[index] |
|
2723 </xsl:text> |
|
2724 <xsl:text> let new_val; |
|
2725 </xsl:text> |
|
2726 <xsl:text> switch(op){ |
|
2727 </xsl:text> |
|
2728 <xsl:text> case "=": |
|
2729 </xsl:text> |
|
2730 <xsl:text> eval("new_val"+opstr); |
|
2731 </xsl:text> |
|
2732 <xsl:text> break; |
|
2733 </xsl:text> |
|
2734 <xsl:text> case "+": |
|
2735 </xsl:text> |
|
2736 <xsl:text> case "-": |
|
2737 </xsl:text> |
|
2738 <xsl:text> case "*": |
|
2739 </xsl:text> |
|
2740 <xsl:text> case "/": |
|
2741 </xsl:text> |
|
2742 <xsl:text> if(old_val != undefined) |
|
2743 </xsl:text> |
|
2744 <xsl:text> new_val = eval("old_val"+opstr); |
|
2745 </xsl:text> |
|
2746 <xsl:text> break; |
|
2747 </xsl:text> |
|
2748 <xsl:text> } |
|
2749 </xsl:text> |
|
2750 <xsl:text> if(new_val != undefined && old_val != new_val) |
|
2751 </xsl:text> |
|
2752 <xsl:text> send_hmi_value(index, new_val); |
|
2753 </xsl:text> |
|
2754 <xsl:text> return new_val; |
|
2755 </xsl:text> |
|
2756 <xsl:text>} |
|
2757 </xsl:text> |
|
2758 <xsl:text> |
|
2759 </xsl:text> |
|
2760 <xsl:text>var current_visible_page; |
|
2761 </xsl:text> |
|
2762 <xsl:text>var current_subscribed_page; |
|
2763 </xsl:text> |
|
2764 <xsl:text>var current_page_index; |
|
2765 </xsl:text> |
|
2766 <xsl:text> |
|
2767 </xsl:text> |
|
2768 <xsl:text>function prepare_svg() { |
|
2769 </xsl:text> |
|
2770 <xsl:text> for(let eltid in detachable_elements){ |
|
2771 </xsl:text> |
|
2772 <xsl:text> let [element,parent] = detachable_elements[eltid]; |
|
2773 </xsl:text> |
|
2774 <xsl:text> parent.removeChild(element); |
|
2775 </xsl:text> |
|
2776 <xsl:text> } |
|
2777 </xsl:text> |
|
2778 <xsl:text>}; |
|
2779 </xsl:text> |
|
2780 <xsl:text> |
|
2781 </xsl:text> |
|
2782 <xsl:text>function switch_page(page_name, page_index) { |
|
2783 </xsl:text> |
|
2784 <xsl:text> if(current_subscribed_page != current_visible_page){ |
|
2785 </xsl:text> |
|
2786 <xsl:text> /* page switch already going */ |
|
2787 </xsl:text> |
|
2788 <xsl:text> /* TODO LOG ERROR */ |
|
2789 </xsl:text> |
|
2790 <xsl:text> return false; |
|
2791 </xsl:text> |
|
2792 <xsl:text> } |
|
2793 </xsl:text> |
|
2794 <xsl:text> |
|
2795 </xsl:text> |
|
2796 <xsl:text> if(page_name == undefined) |
|
2797 </xsl:text> |
|
2798 <xsl:text> page_name = current_subscribed_page; |
|
2799 </xsl:text> |
|
2800 <xsl:text> |
|
2801 </xsl:text> |
|
2802 <xsl:text> |
|
2803 </xsl:text> |
|
2804 <xsl:text> let old_desc = page_desc[current_subscribed_page]; |
|
2805 </xsl:text> |
|
2806 <xsl:text> let new_desc = page_desc[page_name]; |
|
2807 </xsl:text> |
|
2808 <xsl:text> |
|
2809 </xsl:text> |
|
2810 <xsl:text> if(new_desc == undefined){ |
|
2811 </xsl:text> |
|
2812 <xsl:text> /* TODO LOG ERROR */ |
|
2813 </xsl:text> |
|
2814 <xsl:text> return false; |
|
2815 </xsl:text> |
|
2816 <xsl:text> } |
|
2817 </xsl:text> |
|
2818 <xsl:text> |
|
2819 </xsl:text> |
|
2820 <xsl:text> if(page_index == undefined){ |
|
2821 </xsl:text> |
|
2822 <xsl:text> page_index = new_desc.page_index; |
|
2823 </xsl:text> |
|
2824 <xsl:text> } |
|
2825 </xsl:text> |
|
2826 <xsl:text> |
|
2827 </xsl:text> |
|
2828 <xsl:text> if(old_desc){ |
|
2829 </xsl:text> |
|
2830 <xsl:text> old_desc.absolute_widgets.map(w=>w.unsub()); |
|
2831 </xsl:text> |
|
2832 <xsl:text> old_desc.relative_widgets.map(w=>w.unsub()); |
|
2833 </xsl:text> |
|
2834 <xsl:text> } |
|
2835 </xsl:text> |
|
2836 <xsl:text> new_desc.absolute_widgets.map(w=>w.sub()); |
|
2837 </xsl:text> |
|
2838 <xsl:text> var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; |
|
2839 </xsl:text> |
|
2840 <xsl:text> new_desc.relative_widgets.map(w=>w.sub(new_offset)); |
|
2841 </xsl:text> |
|
2842 <xsl:text> |
|
2843 </xsl:text> |
|
2844 <xsl:text> update_subscriptions(); |
|
2845 </xsl:text> |
|
2846 <xsl:text> |
|
2847 </xsl:text> |
|
2848 <xsl:text> current_subscribed_page = page_name; |
|
2849 </xsl:text> |
|
2850 <xsl:text> current_page_index = page_index; |
|
2851 </xsl:text> |
|
2852 <xsl:text> |
|
2853 </xsl:text> |
|
2854 <xsl:text> jumps_need_update = true; |
|
2855 </xsl:text> |
|
2856 <xsl:text> |
|
2857 </xsl:text> |
|
2858 <xsl:text> requestHMIAnimation(); |
|
2859 </xsl:text> |
|
2860 <xsl:text> |
|
2861 </xsl:text> |
|
2862 <xsl:text> jump_history.push([page_name, page_index]); |
|
2863 </xsl:text> |
|
2864 <xsl:text> if(jump_history.length > 42) |
|
2865 </xsl:text> |
|
2866 <xsl:text> jump_history.shift(); |
|
2867 </xsl:text> |
|
2868 <xsl:text> |
|
2869 </xsl:text> |
|
2870 <xsl:text> return true; |
|
2871 </xsl:text> |
|
2872 <xsl:text>}; |
|
2873 </xsl:text> |
|
2874 <xsl:text> |
|
2875 </xsl:text> |
|
2876 <xsl:text>function* chain(a,b){ |
|
2877 </xsl:text> |
|
2878 <xsl:text> yield* a; |
|
2879 </xsl:text> |
|
2880 <xsl:text> yield* b; |
|
2881 </xsl:text> |
|
2882 <xsl:text>}; |
|
2883 </xsl:text> |
|
2884 <xsl:text> |
|
2885 </xsl:text> |
|
2886 <xsl:text>function unsubscribe(){ |
|
2887 </xsl:text> |
|
2888 <xsl:text> /* remove subsribers */ |
|
2889 </xsl:text> |
|
2890 <xsl:text> for(let index of this.indexes){ |
|
2891 </xsl:text> |
|
2892 <xsl:text> let idx = index + this.offset; |
|
2893 </xsl:text> |
|
2894 <xsl:text> subscribers[idx].delete(this); |
|
2895 </xsl:text> |
|
2896 <xsl:text> } |
|
2897 </xsl:text> |
|
2898 <xsl:text> this.offset = 0; |
|
2899 </xsl:text> |
|
2900 <xsl:text>} |
|
2901 </xsl:text> |
|
2902 <xsl:text> |
|
2903 </xsl:text> |
|
2904 <xsl:text>function subscribe(new_offset=0){ |
|
2905 </xsl:text> |
|
2906 <xsl:text> /* set the offset because relative */ |
|
2907 </xsl:text> |
|
2908 <xsl:text> this.offset = new_offset; |
|
2909 </xsl:text> |
|
2910 <xsl:text> /* add this's subsribers */ |
|
2911 </xsl:text> |
|
2912 <xsl:text> for(let index of this.indexes){ |
|
2913 </xsl:text> |
|
2914 <xsl:text> subscribers[index + new_offset].add(this); |
|
2915 </xsl:text> |
|
2916 <xsl:text> } |
|
2917 </xsl:text> |
|
2918 <xsl:text> need_cache_apply.push(this); |
|
2919 </xsl:text> |
|
2920 <xsl:text>} |
|
2921 </xsl:text> |
|
2922 <xsl:text> |
|
2923 </xsl:text> |
|
2924 <xsl:text>function foreach_unsubscribe(){ |
|
2925 </xsl:text> |
|
2926 <xsl:text> for(let item of this.items){ |
|
2927 </xsl:text> |
|
2928 <xsl:text> for(let widget of item) { |
|
2929 </xsl:text> |
|
2930 <xsl:text> unsubscribe.call(widget); |
|
2931 </xsl:text> |
|
2932 <xsl:text> } |
|
2933 </xsl:text> |
|
2934 <xsl:text> } |
|
2935 </xsl:text> |
|
2936 <xsl:text> this.offset = 0; |
|
2937 </xsl:text> |
|
2938 <xsl:text>} |
|
2939 </xsl:text> |
|
2940 <xsl:text> |
|
2941 </xsl:text> |
|
2942 <xsl:text>function foreach_widgets_do(new_offset, todo){ |
|
2943 </xsl:text> |
|
2944 <xsl:text> this.offset = new_offset; |
|
2945 </xsl:text> |
|
2946 <xsl:text> for(let i = 0; i < this.items.length; i++) { |
|
2947 </xsl:text> |
|
2948 <xsl:text> let item = this.items[i]; |
|
2949 </xsl:text> |
|
2950 <xsl:text> let orig_item_index = this.index_pool[i]; |
|
2951 </xsl:text> |
|
2952 <xsl:text> let item_index = this.index_pool[i+this.item_offset]; |
|
2953 </xsl:text> |
|
2954 <xsl:text> let item_index_offset = item_index - orig_item_index; |
|
2955 </xsl:text> |
|
2956 <xsl:text> for(let widget of item) { |
|
2957 </xsl:text> |
|
2958 <xsl:text> todo.call(widget, new_offset + item_index_offset); |
|
2959 </xsl:text> |
|
2960 <xsl:text> } |
|
2961 </xsl:text> |
|
2962 <xsl:text> } |
|
2963 </xsl:text> |
|
2964 <xsl:text>} |
|
2965 </xsl:text> |
|
2966 <xsl:text> |
|
2967 </xsl:text> |
|
2968 <xsl:text>function foreach_subscribe(new_offset=0){ |
|
2969 </xsl:text> |
|
2970 <xsl:text> foreach_widgets_do.call(this, new_offset, subscribe); |
|
2971 </xsl:text> |
|
2972 <xsl:text>} |
|
2973 </xsl:text> |
|
2974 <xsl:text> |
|
2975 </xsl:text> |
|
2976 <xsl:text>function widget_apply_cache() { |
|
2977 </xsl:text> |
|
2978 <xsl:text> for(let index of this.indexes){ |
|
2979 </xsl:text> |
|
2980 <xsl:text> /* dispatch current cache in newly opened page widgets */ |
|
2981 </xsl:text> |
|
2982 <xsl:text> let realindex = index+this.offset; |
|
2983 </xsl:text> |
|
2984 <xsl:text> let cached_val = cache[realindex]; |
|
2985 </xsl:text> |
|
2986 <xsl:text> if(cached_val != undefined) |
|
2987 </xsl:text> |
|
2988 <xsl:text> dispatch_value_to_widget(this, realindex, cached_val, cached_val); |
|
2989 </xsl:text> |
|
2990 <xsl:text> } |
|
2991 </xsl:text> |
|
2992 <xsl:text>} |
|
2993 </xsl:text> |
|
2994 <xsl:text> |
|
2995 </xsl:text> |
|
2996 <xsl:text>function foreach_apply_cache() { |
|
2997 </xsl:text> |
|
2998 <xsl:text> foreach_widgets_do.call(this, this.offset, widget_apply_cache); |
|
2999 </xsl:text> |
|
3000 <xsl:text>} |
|
3001 </xsl:text> |
|
3002 <xsl:text> |
|
3003 </xsl:text> |
|
3004 <xsl:text>function foreach_onclick(opstr, evt) { |
|
3005 </xsl:text> |
|
3006 <xsl:text> new_item_offset = eval(String(this.item_offset)+opstr) |
|
3007 </xsl:text> |
|
3008 <xsl:text> if(new_item_offset + this.items.length > this.index_pool.length) { |
|
3009 </xsl:text> |
|
3010 <xsl:text> if(this.item_offset + this.items.length == this.index_pool.length) |
|
3011 </xsl:text> |
|
3012 <xsl:text> new_item_offset = 0; |
|
3013 </xsl:text> |
|
3014 <xsl:text> else |
|
3015 </xsl:text> |
|
3016 <xsl:text> new_item_offset = this.index_pool.length - this.items.length; |
|
3017 </xsl:text> |
|
3018 <xsl:text> } else if(new_item_offset < 0) { |
|
3019 </xsl:text> |
|
3020 <xsl:text> if(this.item_offset == 0) |
|
3021 </xsl:text> |
|
3022 <xsl:text> new_item_offset = this.index_pool.length - this.items.length; |
|
3023 </xsl:text> |
|
3024 <xsl:text> else |
|
3025 </xsl:text> |
|
3026 <xsl:text> new_item_offset = 0; |
|
3027 </xsl:text> |
|
3028 <xsl:text> } |
|
3029 </xsl:text> |
|
3030 <xsl:text> this.item_offset = new_item_offset; |
|
3031 </xsl:text> |
|
3032 <xsl:text> off = this.offset; |
|
3033 </xsl:text> |
|
3034 <xsl:text> foreach_unsubscribe.call(this); |
|
3035 </xsl:text> |
|
3036 <xsl:text> foreach_subscribe.call(this,off); |
|
3037 </xsl:text> |
|
3038 <xsl:text> update_subscriptions(); |
|
3039 </xsl:text> |
|
3040 <xsl:text> need_cache_apply.push(this); |
|
3041 </xsl:text> |
|
3042 <xsl:text> jumps_need_update = true; |
|
3043 </xsl:text> |
|
3044 <xsl:text> requestHMIAnimation(); |
|
3045 </xsl:text> |
|
3046 <xsl:text>} |
|
3047 </xsl:text> |
|
3048 <xsl:text> |
|
3049 </xsl:text> |
|
3050 <xsl:text> |
|
3051 </xsl:text> |
|
3052 <xsl:text>function switch_visible_page(page_name) { |
|
3053 </xsl:text> |
|
3054 <xsl:text> |
|
3055 </xsl:text> |
|
3056 <xsl:text> let old_desc = page_desc[current_visible_page]; |
|
3057 </xsl:text> |
|
3058 <xsl:text> let new_desc = page_desc[page_name]; |
|
3059 </xsl:text> |
|
3060 <xsl:text> |
|
3061 </xsl:text> |
|
3062 <xsl:text> if(old_desc){ |
|
3063 </xsl:text> |
|
3064 <xsl:text> for(let eltid in old_desc.required_detachables){ |
|
3065 </xsl:text> |
|
3066 <xsl:text> if(!(eltid in new_desc.required_detachables)){ |
|
3067 </xsl:text> |
|
3068 <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; |
|
3069 </xsl:text> |
|
3070 <xsl:text> parent.removeChild(element); |
|
3071 </xsl:text> |
|
3072 <xsl:text> } |
|
3073 </xsl:text> |
|
3074 <xsl:text> } |
|
3075 </xsl:text> |
|
3076 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
3077 </xsl:text> |
|
3078 <xsl:text> if(!(eltid in old_desc.required_detachables)){ |
|
3079 </xsl:text> |
|
3080 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
3081 </xsl:text> |
|
3082 <xsl:text> parent.appendChild(element); |
|
3083 </xsl:text> |
|
3084 <xsl:text> } |
|
3085 </xsl:text> |
|
3086 <xsl:text> } |
|
3087 </xsl:text> |
|
3088 <xsl:text> }else{ |
|
3089 </xsl:text> |
|
3090 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
3091 </xsl:text> |
|
3092 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
3093 </xsl:text> |
|
3094 <xsl:text> parent.appendChild(element); |
|
3095 </xsl:text> |
|
3096 <xsl:text> } |
|
3097 </xsl:text> |
|
3098 <xsl:text> } |
|
3099 </xsl:text> |
|
3100 <xsl:text> |
|
3101 </xsl:text> |
|
3102 <xsl:text> svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); |
|
3103 </xsl:text> |
|
3104 <xsl:text> current_visible_page = page_name; |
|
3105 </xsl:text> |
|
3106 <xsl:text>}; |
|
3107 </xsl:text> |
|
3108 <xsl:text> |
|
3109 </xsl:text> |
|
3110 <xsl:text>function update_jumps() { |
|
3111 </xsl:text> |
|
3112 <xsl:text> page_desc[current_visible_page].jumps.map(w=>w.notify_page_change(current_visible_page,current_page_index)); |
|
3113 </xsl:text> |
|
3114 <xsl:text> jumps_need_update = false; |
|
3115 </xsl:text> |
|
3116 <xsl:text>}; |
|
3117 </xsl:text> |
|
3118 <xsl:text> |
|
3119 </xsl:text> |
|
3120 <xsl:text> |
|
3121 </xsl:text> |
|
3122 <xsl:text>// Once connection established |
|
3123 </xsl:text> |
|
3124 <xsl:text>ws.onopen = function (evt) { |
|
3125 </xsl:text> |
|
3126 <xsl:text> init_widgets(); |
|
3127 </xsl:text> |
|
3128 <xsl:text> send_reset(); |
|
3129 </xsl:text> |
|
3130 <xsl:text> // show main page |
|
3131 </xsl:text> |
|
3132 <xsl:text> prepare_svg(); |
|
3133 </xsl:text> |
|
3134 <xsl:text> switch_page(default_page); |
|
3135 </xsl:text> |
|
3136 <xsl:text>}; |
|
3137 </xsl:text> |
|
3138 <xsl:text> |
|
3139 </xsl:text> |
|
3140 <xsl:text>ws.onclose = function (evt) { |
|
3141 </xsl:text> |
|
3142 <xsl:text> // TODO : add visible notification while waiting for reload |
|
3143 </xsl:text> |
|
3144 <xsl:text> console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s."); |
|
3145 </xsl:text> |
|
3146 <xsl:text> // TODO : re-enable auto reload when not in debug |
|
3147 </xsl:text> |
|
3148 <xsl:text> //window.setTimeout(() => location.reload(true), 10000); |
|
3149 </xsl:text> |
|
3150 <xsl:text> alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+"."); |
|
3151 </xsl:text> |
|
3152 <xsl:text> |
|
3153 </xsl:text> |
|
3154 <xsl:text>}; |
|
3155 </xsl:text> |
|
3156 <xsl:text> |
|
3157 </xsl:text> |
|
3158 <xsl:text>var xmlns = "http://www.w3.org/2000/svg"; |
|
3159 </xsl:text> |
|
3160 <xsl:text>var edit_callback; |
|
3161 </xsl:text> |
|
3162 <xsl:text>function edit_value(path, valuetype, callback, initial) { |
|
3163 </xsl:text> |
|
3164 <xsl:text> |
|
3165 </xsl:text> |
|
3166 <xsl:text> let [keypadid, xcoord, ycoord] = keypads[valuetype]; |
|
3167 </xsl:text> |
|
3168 <xsl:text> console.log('XXX TODO : Edit value', path, valuetype, callback, initial, keypadid); |
|
3169 </xsl:text> |
|
3170 <xsl:text> edit_callback = callback; |
|
3171 </xsl:text> |
|
3172 <xsl:text> let widget = hmi_widgets[keypadid]; |
|
3173 </xsl:text> |
|
3174 <xsl:text> widget.start_edit(path, valuetype, callback, initial); |
|
3175 </xsl:text> |
|
3176 <xsl:text>}; |
|
3177 </xsl:text> |
|
3178 <xsl:text> |
|
3179 </xsl:text> |
|
3180 <xsl:text>var current_modal; /* TODO stack ?*/ |
|
3181 </xsl:text> |
|
3182 <xsl:text> |
|
3183 </xsl:text> |
|
3184 <xsl:text>function show_modal() { |
|
3185 </xsl:text> |
|
3186 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
3187 </xsl:text> |
|
3188 <xsl:text> |
|
3189 </xsl:text> |
|
3190 <xsl:text> tmpgrp = document.createElementNS(xmlns,"g"); |
|
3191 </xsl:text> |
|
3192 <xsl:text> tmpgrpattr = document.createAttribute("transform"); |
|
3193 </xsl:text> |
|
3194 <xsl:text> |
|
3195 </xsl:text> |
|
3196 <xsl:text> let [xcoord,ycoord] = this.coordinates; |
|
3197 </xsl:text> |
|
3198 <xsl:text> let [xdest,ydest] = page_desc[current_visible_page].bbox; |
|
3199 </xsl:text> |
|
3200 <xsl:text> tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")"; |
|
3201 </xsl:text> |
|
3202 <xsl:text> tmpgrp.setAttributeNode(tmpgrpattr); |
|
3203 </xsl:text> |
|
3204 <xsl:text> |
|
3205 </xsl:text> |
|
3206 <xsl:text> tmpgrp.appendChild(element); |
|
3207 </xsl:text> |
|
3208 <xsl:text> parent.appendChild(tmpgrp); |
|
3209 </xsl:text> |
|
3210 <xsl:text> |
|
3211 </xsl:text> |
|
3212 <xsl:text> current_modal = [this.element.id, tmpgrp]; |
|
3213 </xsl:text> |
|
3214 <xsl:text>}; |
|
3215 </xsl:text> |
|
3216 <xsl:text> |
|
3217 </xsl:text> |
|
3218 <xsl:text>function end_modal() { |
|
3219 </xsl:text> |
|
3220 <xsl:text> let [eltid, tmpgrp] = current_modal; |
|
3221 </xsl:text> |
|
3222 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
3223 </xsl:text> |
|
3224 <xsl:text> |
|
3225 </xsl:text> |
|
3226 <xsl:text> parent.removeChild(tmpgrp); |
|
3227 </xsl:text> |
|
3228 <xsl:text> |
|
3229 </xsl:text> |
|
3230 <xsl:text> current_modal = undefined; |
|
3231 </xsl:text> |
|
3232 <xsl:text>}; |
|
3233 </xsl:text> |
|
3234 <xsl:text> |
|
3235 </xsl:text> |
|
3236 <xsl:text>function widget_active_activable(eltsub) { |
|
3237 </xsl:text> |
|
3238 <xsl:text> if(eltsub.inactive_style === undefined) |
|
3239 </xsl:text> |
|
3240 <xsl:text> eltsub.inactive_style = eltsub.inactive.getAttribute("style"); |
|
3241 </xsl:text> |
|
3242 <xsl:text> eltsub.inactive.setAttribute("style", "display:none"); |
|
3243 </xsl:text> |
|
3244 <xsl:text> if(eltsub.active_style !== undefined) |
|
3245 </xsl:text> |
|
3246 <xsl:text> eltsub.active.setAttribute("style", eltsub.active_style); |
|
3247 </xsl:text> |
|
3248 <xsl:text> console.log("active", eltsub); |
|
3249 </xsl:text> |
|
3250 <xsl:text>}; |
|
3251 </xsl:text> |
|
3252 <xsl:text>function widget_inactive_activable(eltsub) { |
|
3253 </xsl:text> |
|
3254 <xsl:text> if(eltsub.active_style === undefined) |
|
3255 </xsl:text> |
|
3256 <xsl:text> eltsub.active_style = eltsub.active.getAttribute("style"); |
|
3257 </xsl:text> |
|
3258 <xsl:text> eltsub.active.setAttribute("style", "display:none"); |
|
3259 </xsl:text> |
|
3260 <xsl:text> if(eltsub.inactive_style !== undefined) |
|
3261 </xsl:text> |
|
3262 <xsl:text> eltsub.inactive.setAttribute("style", eltsub.inactive_style); |
|
3263 </xsl:text> |
|
3264 <xsl:text> console.log("inactive", eltsub); |
|
3265 </xsl:text> |
|
3266 <xsl:text>}; |
|
3267 </xsl:text> |
3248 </script> |
3268 </script> |
3249 </body> |
3269 </body> |
3250 </html> |
3270 </html> |
3251 </xsl:template> |
3271 </xsl:template> |
3252 </xsl:stylesheet> |
3272 </xsl:stylesheet> |