10497 </xsl:text> |
10536 </xsl:text> |
10498 <xsl:text>var requestAnimationFrameID = null; |
10537 <xsl:text>var requestAnimationFrameID = null; |
10499 </xsl:text> |
10538 </xsl:text> |
10500 <xsl:text>function animate() { |
10539 <xsl:text>function animate() { |
10501 </xsl:text> |
10540 </xsl:text> |
10502 <xsl:text> // Do the page swith if any one pending |
10541 <xsl:text> let rearm = true; |
10503 </xsl:text> |
10542 </xsl:text> |
10504 <xsl:text> if(current_subscribed_page != current_visible_page){ |
10543 <xsl:text> do{ |
10505 </xsl:text> |
10544 </xsl:text> |
10506 <xsl:text> switch_visible_page(current_subscribed_page); |
10545 <xsl:text> if(page_fading == "pending" || page_fading == "forced"){ |
|
10546 </xsl:text> |
|
10547 <xsl:text> if(page_fading == "pending") |
|
10548 </xsl:text> |
|
10549 <xsl:text> svg_root.classList.add("fade-out-page"); |
|
10550 </xsl:text> |
|
10551 <xsl:text> page_fading = "in_progress"; |
|
10552 </xsl:text> |
|
10553 <xsl:text> if(page_fading_args.length) |
|
10554 </xsl:text> |
|
10555 <xsl:text> setTimeout(function(){ |
|
10556 </xsl:text> |
|
10557 <xsl:text> switch_page(...page_fading_args); |
|
10558 </xsl:text> |
|
10559 <xsl:text> },1); |
|
10560 </xsl:text> |
|
10561 <xsl:text> break; |
|
10562 </xsl:text> |
|
10563 <xsl:text> } |
|
10564 </xsl:text> |
|
10565 <xsl:text> |
|
10566 </xsl:text> |
|
10567 <xsl:text> // Do the page swith if pending |
|
10568 </xsl:text> |
|
10569 <xsl:text> if(page_switch_in_progress){ |
|
10570 </xsl:text> |
|
10571 <xsl:text> if(current_subscribed_page != current_visible_page){ |
|
10572 </xsl:text> |
|
10573 <xsl:text> switch_visible_page(current_subscribed_page); |
|
10574 </xsl:text> |
|
10575 <xsl:text> } |
|
10576 </xsl:text> |
|
10577 <xsl:text> |
|
10578 </xsl:text> |
|
10579 <xsl:text> page_switch_in_progress = false; |
|
10580 </xsl:text> |
|
10581 <xsl:text> |
|
10582 </xsl:text> |
|
10583 <xsl:text> if(page_fading == "in_progress"){ |
|
10584 </xsl:text> |
|
10585 <xsl:text> svg_root.classList.remove("fade-out-page"); |
|
10586 </xsl:text> |
|
10587 <xsl:text> page_fading = "off"; |
|
10588 </xsl:text> |
|
10589 <xsl:text> } |
|
10590 </xsl:text> |
|
10591 <xsl:text> } |
|
10592 </xsl:text> |
|
10593 <xsl:text> |
|
10594 </xsl:text> |
|
10595 <xsl:text> while(widget = need_cache_apply.pop()){ |
|
10596 </xsl:text> |
|
10597 <xsl:text> widget.apply_cache(); |
|
10598 </xsl:text> |
|
10599 <xsl:text> } |
|
10600 </xsl:text> |
|
10601 <xsl:text> |
|
10602 </xsl:text> |
|
10603 <xsl:text> if(jumps_need_update) update_jumps(); |
|
10604 </xsl:text> |
|
10605 <xsl:text> |
|
10606 </xsl:text> |
|
10607 <xsl:text> apply_updates(); |
|
10608 </xsl:text> |
|
10609 <xsl:text> |
|
10610 </xsl:text> |
|
10611 <xsl:text> pending_widget_animates.forEach(widget => widget._animate()); |
|
10612 </xsl:text> |
|
10613 <xsl:text> pending_widget_animates = []; |
|
10614 </xsl:text> |
|
10615 <xsl:text> rearm = false; |
|
10616 </xsl:text> |
|
10617 <xsl:text> } while(0); |
|
10618 </xsl:text> |
|
10619 <xsl:text> |
|
10620 </xsl:text> |
|
10621 <xsl:text> requestAnimationFrameID = null; |
|
10622 </xsl:text> |
|
10623 <xsl:text> |
|
10624 </xsl:text> |
|
10625 <xsl:text> if(rearm) requestHMIAnimation(); |
|
10626 </xsl:text> |
|
10627 <xsl:text>} |
|
10628 </xsl:text> |
|
10629 <xsl:text> |
|
10630 </xsl:text> |
|
10631 <xsl:text>function requestHMIAnimation() { |
|
10632 </xsl:text> |
|
10633 <xsl:text> if(requestAnimationFrameID == null){ |
|
10634 </xsl:text> |
|
10635 <xsl:text> requestAnimationFrameID = window.requestAnimationFrame(animate); |
10507 </xsl:text> |
10636 </xsl:text> |
10508 <xsl:text> } |
10637 <xsl:text> } |
10509 </xsl:text> |
10638 </xsl:text> |
10510 <xsl:text> |
10639 <xsl:text>} |
10511 </xsl:text> |
10640 </xsl:text> |
10512 <xsl:text> while(widget = need_cache_apply.pop()){ |
10641 <xsl:text> |
10513 </xsl:text> |
10642 </xsl:text> |
10514 <xsl:text> widget.apply_cache(); |
10643 <xsl:text>// Message reception handler |
|
10644 </xsl:text> |
|
10645 <xsl:text>// Hash is verified and HMI values updates resulting from binary parsing |
|
10646 </xsl:text> |
|
10647 <xsl:text>// are stored until browser can compute next frame, DOM is left untouched |
|
10648 </xsl:text> |
|
10649 <xsl:text>ws.onmessage = function (evt) { |
|
10650 </xsl:text> |
|
10651 <xsl:text> |
|
10652 </xsl:text> |
|
10653 <xsl:text> let data = evt.data; |
|
10654 </xsl:text> |
|
10655 <xsl:text> let dv = new DataView(data); |
|
10656 </xsl:text> |
|
10657 <xsl:text> let i = 0; |
|
10658 </xsl:text> |
|
10659 <xsl:text> try { |
|
10660 </xsl:text> |
|
10661 <xsl:text> for(let hash_int of hmi_hash) { |
|
10662 </xsl:text> |
|
10663 <xsl:text> if(hash_int != dv.getUint8(i)){ |
|
10664 </xsl:text> |
|
10665 <xsl:text> throw new Error("Hash doesn't match"); |
|
10666 </xsl:text> |
|
10667 <xsl:text> }; |
|
10668 </xsl:text> |
|
10669 <xsl:text> i++; |
|
10670 </xsl:text> |
|
10671 <xsl:text> }; |
|
10672 </xsl:text> |
|
10673 <xsl:text> |
|
10674 </xsl:text> |
|
10675 <xsl:text> while(i < data.byteLength){ |
|
10676 </xsl:text> |
|
10677 <xsl:text> let index = dv.getUint32(i, true); |
|
10678 </xsl:text> |
|
10679 <xsl:text> i += 4; |
|
10680 </xsl:text> |
|
10681 <xsl:text> let iectype = hmitree_types[index]; |
|
10682 </xsl:text> |
|
10683 <xsl:text> if(iectype != undefined){ |
|
10684 </xsl:text> |
|
10685 <xsl:text> let dvgetter = dvgetters[iectype]; |
|
10686 </xsl:text> |
|
10687 <xsl:text> let [value, bytesize] = dvgetter(dv,i); |
|
10688 </xsl:text> |
|
10689 <xsl:text> updates.set(index, value); |
|
10690 </xsl:text> |
|
10691 <xsl:text> i += bytesize; |
|
10692 </xsl:text> |
|
10693 <xsl:text> } else { |
|
10694 </xsl:text> |
|
10695 <xsl:text> throw new Error("Unknown index "+index); |
|
10696 </xsl:text> |
|
10697 <xsl:text> } |
|
10698 </xsl:text> |
|
10699 <xsl:text> }; |
|
10700 </xsl:text> |
|
10701 <xsl:text> // register for rendering on next frame, since there are updates |
|
10702 </xsl:text> |
|
10703 <xsl:text> requestHMIAnimation(); |
|
10704 </xsl:text> |
|
10705 <xsl:text> } catch(err) { |
|
10706 </xsl:text> |
|
10707 <xsl:text> // 1003 is for "Unsupported Data" |
|
10708 </xsl:text> |
|
10709 <xsl:text> // ws.close(1003, err.message); |
|
10710 </xsl:text> |
|
10711 <xsl:text> |
|
10712 </xsl:text> |
|
10713 <xsl:text> // TODO : remove debug alert ? |
|
10714 </xsl:text> |
|
10715 <xsl:text> alert("Error : "+err.message+"\nHMI will be reloaded."); |
|
10716 </xsl:text> |
|
10717 <xsl:text> |
|
10718 </xsl:text> |
|
10719 <xsl:text> // force reload ignoring cache |
|
10720 </xsl:text> |
|
10721 <xsl:text> location.reload(true); |
10515 </xsl:text> |
10722 </xsl:text> |
10516 <xsl:text> } |
10723 <xsl:text> } |
10517 </xsl:text> |
10724 </xsl:text> |
10518 <xsl:text> |
10725 <xsl:text>}; |
10519 </xsl:text> |
10726 </xsl:text> |
10520 <xsl:text> if(jumps_need_update) update_jumps(); |
10727 <xsl:text> |
10521 </xsl:text> |
10728 </xsl:text> |
10522 <xsl:text> |
10729 <xsl:text>hmi_hash_u8 = new Uint8Array(hmi_hash); |
10523 </xsl:text> |
10730 </xsl:text> |
10524 <xsl:text> apply_updates(); |
10731 <xsl:text> |
10525 </xsl:text> |
10732 </xsl:text> |
10526 <xsl:text> |
10733 <xsl:text>function send_blob(data) { |
10527 </xsl:text> |
10734 </xsl:text> |
10528 <xsl:text> pending_widget_animates.forEach(widget => widget._animate()); |
10735 <xsl:text> if(data.length > 0) { |
10529 </xsl:text> |
10736 </xsl:text> |
10530 <xsl:text> pending_widget_animates = []; |
10737 <xsl:text> ws.send(new Blob([hmi_hash_u8].concat(data))); |
10531 </xsl:text> |
10738 </xsl:text> |
10532 <xsl:text> |
10739 <xsl:text> }; |
10533 </xsl:text> |
10740 </xsl:text> |
10534 <xsl:text> requestAnimationFrameID = null; |
10741 <xsl:text>}; |
|
10742 </xsl:text> |
|
10743 <xsl:text> |
|
10744 </xsl:text> |
|
10745 <xsl:text>const typedarray_types = { |
|
10746 </xsl:text> |
|
10747 <xsl:text> INT: (number) => new Int16Array([number]), |
|
10748 </xsl:text> |
|
10749 <xsl:text> BOOL: (truth) => new Int16Array([truth]), |
|
10750 </xsl:text> |
|
10751 <xsl:text> NODE: (truth) => new Int16Array([truth]), |
|
10752 </xsl:text> |
|
10753 <xsl:text> REAL: (number) => new Float32Array([number]), |
|
10754 </xsl:text> |
|
10755 <xsl:text> STRING: (str) => { |
|
10756 </xsl:text> |
|
10757 <xsl:text> // beremiz default string max size is 128 |
|
10758 </xsl:text> |
|
10759 <xsl:text> str = str.slice(0,128); |
|
10760 </xsl:text> |
|
10761 <xsl:text> binary = new Uint8Array(str.length + 1); |
|
10762 </xsl:text> |
|
10763 <xsl:text> binary[0] = str.length; |
|
10764 </xsl:text> |
|
10765 <xsl:text> for(let i = 0; i < str.length; i++){ |
|
10766 </xsl:text> |
|
10767 <xsl:text> binary[i+1] = str.charCodeAt(i); |
|
10768 </xsl:text> |
|
10769 <xsl:text> } |
|
10770 </xsl:text> |
|
10771 <xsl:text> return binary; |
|
10772 </xsl:text> |
|
10773 <xsl:text> } |
|
10774 </xsl:text> |
|
10775 <xsl:text> /* TODO */ |
|
10776 </xsl:text> |
|
10777 <xsl:text>}; |
|
10778 </xsl:text> |
|
10779 <xsl:text> |
|
10780 </xsl:text> |
|
10781 <xsl:text>function send_reset() { |
|
10782 </xsl:text> |
|
10783 <xsl:text> send_blob(new Uint8Array([1])); /* reset = 1 */ |
|
10784 </xsl:text> |
|
10785 <xsl:text>}; |
|
10786 </xsl:text> |
|
10787 <xsl:text> |
|
10788 </xsl:text> |
|
10789 <xsl:text>var subscriptions = []; |
|
10790 </xsl:text> |
|
10791 <xsl:text> |
|
10792 </xsl:text> |
|
10793 <xsl:text>function subscribers(index) { |
|
10794 </xsl:text> |
|
10795 <xsl:text> let entry = subscriptions[index]; |
|
10796 </xsl:text> |
|
10797 <xsl:text> let res; |
|
10798 </xsl:text> |
|
10799 <xsl:text> if(entry == undefined){ |
|
10800 </xsl:text> |
|
10801 <xsl:text> res = new Set(); |
|
10802 </xsl:text> |
|
10803 <xsl:text> subscriptions[index] = [res,0]; |
|
10804 </xsl:text> |
|
10805 <xsl:text> }else{ |
|
10806 </xsl:text> |
|
10807 <xsl:text> [res, _ign] = entry; |
|
10808 </xsl:text> |
|
10809 <xsl:text> } |
|
10810 </xsl:text> |
|
10811 <xsl:text> return res |
10535 </xsl:text> |
10812 </xsl:text> |
10536 <xsl:text>} |
10813 <xsl:text>} |
10537 </xsl:text> |
10814 </xsl:text> |
10538 <xsl:text> |
10815 <xsl:text> |
10539 </xsl:text> |
10816 </xsl:text> |
10540 <xsl:text>function requestHMIAnimation() { |
10817 <xsl:text>function get_subscription_period(index) { |
10541 </xsl:text> |
10818 </xsl:text> |
10542 <xsl:text> if(requestAnimationFrameID == null){ |
10819 <xsl:text> let entry = subscriptions[index]; |
10543 </xsl:text> |
10820 </xsl:text> |
10544 <xsl:text> requestAnimationFrameID = window.requestAnimationFrame(animate); |
10821 <xsl:text> if(entry == undefined) |
|
10822 </xsl:text> |
|
10823 <xsl:text> return 0; |
|
10824 </xsl:text> |
|
10825 <xsl:text> let [_ign, period] = entry; |
|
10826 </xsl:text> |
|
10827 <xsl:text> return period; |
|
10828 </xsl:text> |
|
10829 <xsl:text>} |
|
10830 </xsl:text> |
|
10831 <xsl:text> |
|
10832 </xsl:text> |
|
10833 <xsl:text>function set_subscription_period(index, period) { |
|
10834 </xsl:text> |
|
10835 <xsl:text> let entry = subscriptions[index]; |
|
10836 </xsl:text> |
|
10837 <xsl:text> if(entry == undefined){ |
|
10838 </xsl:text> |
|
10839 <xsl:text> subscriptions[index] = [new Set(), period]; |
|
10840 </xsl:text> |
|
10841 <xsl:text> } else { |
|
10842 </xsl:text> |
|
10843 <xsl:text> entry[1] = period; |
10545 </xsl:text> |
10844 </xsl:text> |
10546 <xsl:text> } |
10845 <xsl:text> } |
10547 </xsl:text> |
10846 </xsl:text> |
10548 <xsl:text>} |
10847 <xsl:text>} |
10549 </xsl:text> |
10848 </xsl:text> |
10550 <xsl:text> |
10849 <xsl:text> |
10551 </xsl:text> |
10850 </xsl:text> |
10552 <xsl:text>// Message reception handler |
10851 <xsl:text>if(has_watchdog){ |
10553 </xsl:text> |
10852 </xsl:text> |
10554 <xsl:text>// Hash is verified and HMI values updates resulting from binary parsing |
10853 <xsl:text> // artificially subscribe the watchdog widget to "/heartbeat" hmi variable |
10555 </xsl:text> |
10854 </xsl:text> |
10556 <xsl:text>// are stored until browser can compute next frame, DOM is left untouched |
10855 <xsl:text> // Since dispatch directly calls change_hmi_value, |
10557 </xsl:text> |
10856 </xsl:text> |
10558 <xsl:text>ws.onmessage = function (evt) { |
10857 <xsl:text> // PLC will periodically send variable at given frequency |
10559 </xsl:text> |
10858 </xsl:text> |
10560 <xsl:text> |
10859 <xsl:text> subscribers(heartbeat_index).add({ |
10561 </xsl:text> |
10860 </xsl:text> |
10562 <xsl:text> let data = evt.data; |
10861 <xsl:text> /* type: "Watchdog", */ |
10563 </xsl:text> |
10862 </xsl:text> |
10564 <xsl:text> let dv = new DataView(data); |
10863 <xsl:text> frequency: 1, |
10565 </xsl:text> |
10864 </xsl:text> |
10566 <xsl:text> let i = 0; |
10865 <xsl:text> indexes: [heartbeat_index], |
10567 </xsl:text> |
10866 </xsl:text> |
10568 <xsl:text> try { |
10867 <xsl:text> new_hmi_value: function(index, value, oldval) { |
10569 </xsl:text> |
10868 </xsl:text> |
10570 <xsl:text> for(let hash_int of hmi_hash) { |
10869 <xsl:text> apply_hmi_value(heartbeat_index, value+1); |
10571 </xsl:text> |
10870 </xsl:text> |
10572 <xsl:text> if(hash_int != dv.getUint8(i)){ |
10871 <xsl:text> } |
10573 </xsl:text> |
10872 </xsl:text> |
10574 <xsl:text> throw new Error("Hash doesn't match"); |
10873 <xsl:text> }); |
10575 </xsl:text> |
10874 </xsl:text> |
10576 <xsl:text> }; |
10875 <xsl:text>} |
10577 </xsl:text> |
10876 </xsl:text> |
10578 <xsl:text> i++; |
10877 <xsl:text> |
10579 </xsl:text> |
10878 </xsl:text> |
10580 <xsl:text> }; |
10879 <xsl:text> |
10581 </xsl:text> |
10880 </xsl:text> |
10582 <xsl:text> |
10881 <xsl:text>var page_fading = "off"; |
10583 </xsl:text> |
10882 </xsl:text> |
10584 <xsl:text> while(i < data.byteLength){ |
10883 <xsl:text>var page_fading_args = "off"; |
10585 </xsl:text> |
10884 </xsl:text> |
10586 <xsl:text> let index = dv.getUint32(i, true); |
10885 <xsl:text>function fading_page_switch(...args){ |
10587 </xsl:text> |
10886 </xsl:text> |
10588 <xsl:text> i += 4; |
10887 <xsl:text> if(page_fading == "in_progress") |
10589 </xsl:text> |
10888 </xsl:text> |
10590 <xsl:text> let iectype = hmitree_types[index]; |
10889 <xsl:text> page_fading = "forced"; |
10591 </xsl:text> |
10890 </xsl:text> |
10592 <xsl:text> if(iectype != undefined){ |
10891 <xsl:text> else |
10593 </xsl:text> |
10892 </xsl:text> |
10594 <xsl:text> let dvgetter = dvgetters[iectype]; |
10893 <xsl:text> page_fading = "pending"; |
10595 </xsl:text> |
10894 </xsl:text> |
10596 <xsl:text> let [value, bytesize] = dvgetter(dv,i); |
10895 <xsl:text> page_fading_args = args; |
10597 </xsl:text> |
10896 </xsl:text> |
10598 <xsl:text> updates.set(index, value); |
10897 <xsl:text> |
10599 </xsl:text> |
10898 </xsl:text> |
10600 <xsl:text> i += bytesize; |
10899 <xsl:text> requestHMIAnimation(); |
10601 </xsl:text> |
10900 </xsl:text> |
10602 <xsl:text> } else { |
10901 <xsl:text> |
10603 </xsl:text> |
10902 </xsl:text> |
10604 <xsl:text> throw new Error("Unknown index "+index); |
10903 <xsl:text>} |
|
10904 </xsl:text> |
|
10905 <xsl:text>document.body.style.backgroundColor = "black"; |
|
10906 </xsl:text> |
|
10907 <xsl:text> |
|
10908 </xsl:text> |
|
10909 <xsl:text>// subscribe to per instance current page hmi variable |
|
10910 </xsl:text> |
|
10911 <xsl:text>// PLC must prefix page name with "!" for page switch to happen |
|
10912 </xsl:text> |
|
10913 <xsl:text>subscribers(current_page_var_index).add({ |
|
10914 </xsl:text> |
|
10915 <xsl:text> frequency: 1, |
|
10916 </xsl:text> |
|
10917 <xsl:text> indexes: [current_page_var_index], |
|
10918 </xsl:text> |
|
10919 <xsl:text> new_hmi_value: function(index, value, oldval) { |
|
10920 </xsl:text> |
|
10921 <xsl:text> if(value.startsWith("!")) |
|
10922 </xsl:text> |
|
10923 <xsl:text> fading_page_switch(value.slice(1)); |
|
10924 </xsl:text> |
|
10925 <xsl:text> } |
|
10926 </xsl:text> |
|
10927 <xsl:text>}); |
|
10928 </xsl:text> |
|
10929 <xsl:text> |
|
10930 </xsl:text> |
|
10931 <xsl:text>function svg_text_to_multiline(elt) { |
|
10932 </xsl:text> |
|
10933 <xsl:text> return(Array.prototype.map.call(elt.children, x=>x.textContent).join("\n")); |
|
10934 </xsl:text> |
|
10935 <xsl:text>} |
|
10936 </xsl:text> |
|
10937 <xsl:text> |
|
10938 </xsl:text> |
|
10939 <xsl:text>function multiline_to_svg_text(elt, str, blank) { |
|
10940 </xsl:text> |
|
10941 <xsl:text> str.split('\n').map((line,i) => {elt.children[i].textContent = blank?"":line;}); |
|
10942 </xsl:text> |
|
10943 <xsl:text>} |
|
10944 </xsl:text> |
|
10945 <xsl:text> |
|
10946 </xsl:text> |
|
10947 <xsl:text>function switch_langnum(langnum) { |
|
10948 </xsl:text> |
|
10949 <xsl:text> langnum = Math.max(0, Math.min(langs.length - 1, langnum)); |
|
10950 </xsl:text> |
|
10951 <xsl:text> |
|
10952 </xsl:text> |
|
10953 <xsl:text> for (let translation of translations) { |
|
10954 </xsl:text> |
|
10955 <xsl:text> let [objs, msgs] = translation; |
|
10956 </xsl:text> |
|
10957 <xsl:text> let msg = msgs[langnum]; |
|
10958 </xsl:text> |
|
10959 <xsl:text> for (let obj of objs) { |
|
10960 </xsl:text> |
|
10961 <xsl:text> multiline_to_svg_text(obj, msg); |
|
10962 </xsl:text> |
|
10963 <xsl:text> obj.setAttribute("lang",langnum); |
|
10964 </xsl:text> |
|
10965 <xsl:text> } |
|
10966 </xsl:text> |
|
10967 <xsl:text> } |
|
10968 </xsl:text> |
|
10969 <xsl:text> return langnum; |
|
10970 </xsl:text> |
|
10971 <xsl:text>} |
|
10972 </xsl:text> |
|
10973 <xsl:text> |
|
10974 </xsl:text> |
|
10975 <xsl:text>// backup original texts |
|
10976 </xsl:text> |
|
10977 <xsl:text>for (let translation of translations) { |
|
10978 </xsl:text> |
|
10979 <xsl:text> let [objs, msgs] = translation; |
|
10980 </xsl:text> |
|
10981 <xsl:text> msgs.unshift(svg_text_to_multiline(objs[0])); |
|
10982 </xsl:text> |
|
10983 <xsl:text>} |
|
10984 </xsl:text> |
|
10985 <xsl:text> |
|
10986 </xsl:text> |
|
10987 <xsl:text>var lang_local_index = hmi_local_index("lang"); |
|
10988 </xsl:text> |
|
10989 <xsl:text>var langcode_local_index = hmi_local_index("lang_code"); |
|
10990 </xsl:text> |
|
10991 <xsl:text>var langname_local_index = hmi_local_index("lang_name"); |
|
10992 </xsl:text> |
|
10993 <xsl:text>subscribers(lang_local_index).add({ |
|
10994 </xsl:text> |
|
10995 <xsl:text> indexes: [lang_local_index], |
|
10996 </xsl:text> |
|
10997 <xsl:text> new_hmi_value: function(index, value, oldval) { |
|
10998 </xsl:text> |
|
10999 <xsl:text> let current_lang = switch_langnum(value); |
|
11000 </xsl:text> |
|
11001 <xsl:text> let [langname,langcode] = langs[current_lang]; |
|
11002 </xsl:text> |
|
11003 <xsl:text> apply_hmi_value(langcode_local_index, langcode); |
|
11004 </xsl:text> |
|
11005 <xsl:text> apply_hmi_value(langname_local_index, langname); |
|
11006 </xsl:text> |
|
11007 <xsl:text> switch_page(); |
|
11008 </xsl:text> |
|
11009 <xsl:text> } |
|
11010 </xsl:text> |
|
11011 <xsl:text>}); |
|
11012 </xsl:text> |
|
11013 <xsl:text> |
|
11014 </xsl:text> |
|
11015 <xsl:text>// returns en_US, fr_FR or en_UK depending on selected language |
|
11016 </xsl:text> |
|
11017 <xsl:text>function get_current_lang_code(){ |
|
11018 </xsl:text> |
|
11019 <xsl:text> return cache[langcode_local_index]; |
|
11020 </xsl:text> |
|
11021 <xsl:text>} |
|
11022 </xsl:text> |
|
11023 <xsl:text> |
|
11024 </xsl:text> |
|
11025 <xsl:text>function setup_lang(){ |
|
11026 </xsl:text> |
|
11027 <xsl:text> let current_lang = cache[lang_local_index]; |
|
11028 </xsl:text> |
|
11029 <xsl:text> let new_lang = switch_langnum(current_lang); |
|
11030 </xsl:text> |
|
11031 <xsl:text> if(current_lang != new_lang){ |
|
11032 </xsl:text> |
|
11033 <xsl:text> apply_hmi_value(lang_local_index, new_lang); |
|
11034 </xsl:text> |
|
11035 <xsl:text> } |
|
11036 </xsl:text> |
|
11037 <xsl:text>} |
|
11038 </xsl:text> |
|
11039 <xsl:text> |
|
11040 </xsl:text> |
|
11041 <xsl:text>setup_lang(); |
|
11042 </xsl:text> |
|
11043 <xsl:text> |
|
11044 </xsl:text> |
|
11045 <xsl:text>function update_subscriptions() { |
|
11046 </xsl:text> |
|
11047 <xsl:text> let delta = []; |
|
11048 </xsl:text> |
|
11049 <xsl:text> for(let index in subscriptions){ |
|
11050 </xsl:text> |
|
11051 <xsl:text> let widgets = subscribers(index); |
|
11052 </xsl:text> |
|
11053 <xsl:text> |
|
11054 </xsl:text> |
|
11055 <xsl:text> // periods are in ms |
|
11056 </xsl:text> |
|
11057 <xsl:text> let previous_period = get_subscription_period(index); |
|
11058 </xsl:text> |
|
11059 <xsl:text> |
|
11060 </xsl:text> |
|
11061 <xsl:text> // subscribing with a zero period is unsubscribing |
|
11062 </xsl:text> |
|
11063 <xsl:text> let new_period = 0; |
|
11064 </xsl:text> |
|
11065 <xsl:text> if(widgets.size > 0) { |
|
11066 </xsl:text> |
|
11067 <xsl:text> let maxfreq = 0; |
|
11068 </xsl:text> |
|
11069 <xsl:text> for(let widget of widgets){ |
|
11070 </xsl:text> |
|
11071 <xsl:text> let wf = widget.frequency; |
|
11072 </xsl:text> |
|
11073 <xsl:text> if(wf != undefined && maxfreq < wf) |
|
11074 </xsl:text> |
|
11075 <xsl:text> maxfreq = wf; |
10605 </xsl:text> |
11076 </xsl:text> |
10606 <xsl:text> } |
11077 <xsl:text> } |
10607 </xsl:text> |
11078 </xsl:text> |
10608 <xsl:text> }; |
11079 <xsl:text> |
10609 </xsl:text> |
11080 </xsl:text> |
10610 <xsl:text> // register for rendering on next frame, since there are updates |
11081 <xsl:text> if(maxfreq != 0) |
|
11082 </xsl:text> |
|
11083 <xsl:text> new_period = 1000/maxfreq; |
|
11084 </xsl:text> |
|
11085 <xsl:text> } |
|
11086 </xsl:text> |
|
11087 <xsl:text> |
|
11088 </xsl:text> |
|
11089 <xsl:text> if(previous_period != new_period) { |
|
11090 </xsl:text> |
|
11091 <xsl:text> set_subscription_period(index, new_period); |
|
11092 </xsl:text> |
|
11093 <xsl:text> if(index <= last_remote_index){ |
|
11094 </xsl:text> |
|
11095 <xsl:text> delta.push( |
|
11096 </xsl:text> |
|
11097 <xsl:text> new Uint8Array([2]), /* subscribe = 2 */ |
|
11098 </xsl:text> |
|
11099 <xsl:text> new Uint32Array([index]), |
|
11100 </xsl:text> |
|
11101 <xsl:text> new Uint16Array([new_period])); |
|
11102 </xsl:text> |
|
11103 <xsl:text> } |
|
11104 </xsl:text> |
|
11105 <xsl:text> } |
|
11106 </xsl:text> |
|
11107 <xsl:text> } |
|
11108 </xsl:text> |
|
11109 <xsl:text> send_blob(delta); |
|
11110 </xsl:text> |
|
11111 <xsl:text>}; |
|
11112 </xsl:text> |
|
11113 <xsl:text> |
|
11114 </xsl:text> |
|
11115 <xsl:text>function send_hmi_value(index, value) { |
|
11116 </xsl:text> |
|
11117 <xsl:text> if(index > last_remote_index){ |
|
11118 </xsl:text> |
|
11119 <xsl:text> updates.set(index, value); |
|
11120 </xsl:text> |
|
11121 <xsl:text> |
|
11122 </xsl:text> |
|
11123 <xsl:text> if(persistent_indexes.has(index)){ |
|
11124 </xsl:text> |
|
11125 <xsl:text> let varname = persistent_indexes.get(index); |
|
11126 </xsl:text> |
|
11127 <xsl:text> document.cookie = varname+"="+value+"; max-age=3153600000"; |
|
11128 </xsl:text> |
|
11129 <xsl:text> } |
|
11130 </xsl:text> |
|
11131 <xsl:text> |
10611 </xsl:text> |
11132 </xsl:text> |
10612 <xsl:text> requestHMIAnimation(); |
11133 <xsl:text> requestHMIAnimation(); |
10613 </xsl:text> |
11134 </xsl:text> |
10614 <xsl:text> } catch(err) { |
11135 <xsl:text> return; |
10615 </xsl:text> |
|
10616 <xsl:text> // 1003 is for "Unsupported Data" |
|
10617 </xsl:text> |
|
10618 <xsl:text> // ws.close(1003, err.message); |
|
10619 </xsl:text> |
|
10620 <xsl:text> |
|
10621 </xsl:text> |
|
10622 <xsl:text> // TODO : remove debug alert ? |
|
10623 </xsl:text> |
|
10624 <xsl:text> alert("Error : "+err.message+"\nHMI will be reloaded."); |
|
10625 </xsl:text> |
|
10626 <xsl:text> |
|
10627 </xsl:text> |
|
10628 <xsl:text> // force reload ignoring cache |
|
10629 </xsl:text> |
|
10630 <xsl:text> location.reload(true); |
|
10631 </xsl:text> |
11136 </xsl:text> |
10632 <xsl:text> } |
11137 <xsl:text> } |
10633 </xsl:text> |
11138 </xsl:text> |
|
11139 <xsl:text> |
|
11140 </xsl:text> |
|
11141 <xsl:text> let iectype = hmitree_types[index]; |
|
11142 </xsl:text> |
|
11143 <xsl:text> let tobinary = typedarray_types[iectype]; |
|
11144 </xsl:text> |
|
11145 <xsl:text> send_blob([ |
|
11146 </xsl:text> |
|
11147 <xsl:text> new Uint8Array([0]), /* setval = 0 */ |
|
11148 </xsl:text> |
|
11149 <xsl:text> new Uint32Array([index]), |
|
11150 </xsl:text> |
|
11151 <xsl:text> tobinary(value)]); |
|
11152 </xsl:text> |
|
11153 <xsl:text> |
|
11154 </xsl:text> |
|
11155 <xsl:text> // DON'T DO THAT unless read_iterator in svghmi.c modifies wbuf as well, not only rbuf |
|
11156 </xsl:text> |
|
11157 <xsl:text> // cache[index] = value; |
|
11158 </xsl:text> |
10634 <xsl:text>}; |
11159 <xsl:text>}; |
10635 </xsl:text> |
11160 </xsl:text> |
10636 <xsl:text> |
11161 <xsl:text> |
10637 </xsl:text> |
11162 </xsl:text> |
10638 <xsl:text>hmi_hash_u8 = new Uint8Array(hmi_hash); |
11163 <xsl:text>function apply_hmi_value(index, new_val) { |
10639 </xsl:text> |
11164 </xsl:text> |
10640 <xsl:text> |
11165 <xsl:text> // Similarly to previous comment, taking decision to update based |
10641 </xsl:text> |
11166 </xsl:text> |
10642 <xsl:text>function send_blob(data) { |
11167 <xsl:text> // on cache content is bad and can lead to inconsistency |
10643 </xsl:text> |
11168 </xsl:text> |
10644 <xsl:text> if(data.length > 0) { |
11169 <xsl:text> /*let old_val = cache[index];*/ |
10645 </xsl:text> |
11170 </xsl:text> |
10646 <xsl:text> ws.send(new Blob([hmi_hash_u8].concat(data))); |
11171 <xsl:text> if(new_val != undefined /*&& old_val != new_val*/) |
10647 </xsl:text> |
11172 </xsl:text> |
10648 <xsl:text> }; |
11173 <xsl:text> send_hmi_value(index, new_val); |
|
11174 </xsl:text> |
|
11175 <xsl:text> return new_val; |
|
11176 </xsl:text> |
|
11177 <xsl:text>} |
|
11178 </xsl:text> |
|
11179 <xsl:text> |
|
11180 </xsl:text> |
|
11181 <xsl:text>const quotes = {"'":null, '"':null}; |
|
11182 </xsl:text> |
|
11183 <xsl:text> |
|
11184 </xsl:text> |
|
11185 <xsl:text>function eval_operation_string(old_val, opstr) { |
|
11186 </xsl:text> |
|
11187 <xsl:text> let op = opstr[0]; |
|
11188 </xsl:text> |
|
11189 <xsl:text> let given_val; |
|
11190 </xsl:text> |
|
11191 <xsl:text> if(opstr.length < 2) |
|
11192 </xsl:text> |
|
11193 <xsl:text> return undefined; |
|
11194 </xsl:text> |
|
11195 <xsl:text> if(opstr[1] in quotes){ |
|
11196 </xsl:text> |
|
11197 <xsl:text> if(opstr.length < 3) |
|
11198 </xsl:text> |
|
11199 <xsl:text> return undefined; |
|
11200 </xsl:text> |
|
11201 <xsl:text> if(opstr[opstr.length-1] == opstr[1]){ |
|
11202 </xsl:text> |
|
11203 <xsl:text> given_val = opstr.slice(2,opstr.length-1); |
|
11204 </xsl:text> |
|
11205 <xsl:text> } |
|
11206 </xsl:text> |
|
11207 <xsl:text> } else { |
|
11208 </xsl:text> |
|
11209 <xsl:text> given_val = Number(opstr.slice(1)); |
|
11210 </xsl:text> |
|
11211 <xsl:text> } |
|
11212 </xsl:text> |
|
11213 <xsl:text> let new_val; |
|
11214 </xsl:text> |
|
11215 <xsl:text> switch(op){ |
|
11216 </xsl:text> |
|
11217 <xsl:text> case "=": |
|
11218 </xsl:text> |
|
11219 <xsl:text> new_val = given_val; |
|
11220 </xsl:text> |
|
11221 <xsl:text> break; |
|
11222 </xsl:text> |
|
11223 <xsl:text> case "+": |
|
11224 </xsl:text> |
|
11225 <xsl:text> new_val = old_val + given_val; |
|
11226 </xsl:text> |
|
11227 <xsl:text> break; |
|
11228 </xsl:text> |
|
11229 <xsl:text> case "-": |
|
11230 </xsl:text> |
|
11231 <xsl:text> new_val = old_val - given_val; |
|
11232 </xsl:text> |
|
11233 <xsl:text> break; |
|
11234 </xsl:text> |
|
11235 <xsl:text> case "*": |
|
11236 </xsl:text> |
|
11237 <xsl:text> new_val = old_val * given_val; |
|
11238 </xsl:text> |
|
11239 <xsl:text> break; |
|
11240 </xsl:text> |
|
11241 <xsl:text> case "/": |
|
11242 </xsl:text> |
|
11243 <xsl:text> new_val = old_val / given_val; |
|
11244 </xsl:text> |
|
11245 <xsl:text> break; |
|
11246 </xsl:text> |
|
11247 <xsl:text> } |
|
11248 </xsl:text> |
|
11249 <xsl:text> return new_val; |
|
11250 </xsl:text> |
|
11251 <xsl:text>} |
|
11252 </xsl:text> |
|
11253 <xsl:text> |
|
11254 </xsl:text> |
|
11255 <xsl:text>var current_visible_page; |
|
11256 </xsl:text> |
|
11257 <xsl:text>var current_subscribed_page; |
|
11258 </xsl:text> |
|
11259 <xsl:text>var current_page_index; |
|
11260 </xsl:text> |
|
11261 <xsl:text>var page_node_local_index = hmi_local_index("page_node"); |
|
11262 </xsl:text> |
|
11263 <xsl:text>var page_switch_in_progress = false; |
|
11264 </xsl:text> |
|
11265 <xsl:text> |
|
11266 </xsl:text> |
|
11267 <xsl:text>function toggleFullscreen() { |
|
11268 </xsl:text> |
|
11269 <xsl:text> let elem = document.documentElement; |
|
11270 </xsl:text> |
|
11271 <xsl:text> |
|
11272 </xsl:text> |
|
11273 <xsl:text> if (!document.fullscreenElement) { |
|
11274 </xsl:text> |
|
11275 <xsl:text> elem.requestFullscreen().catch(err => { |
|
11276 </xsl:text> |
|
11277 <xsl:text> console.log("Error attempting to enable full-screen mode: "+err.message+" ("+err.name+")"); |
|
11278 </xsl:text> |
|
11279 <xsl:text> }); |
|
11280 </xsl:text> |
|
11281 <xsl:text> } else { |
|
11282 </xsl:text> |
|
11283 <xsl:text> document.exitFullscreen(); |
|
11284 </xsl:text> |
|
11285 <xsl:text> } |
|
11286 </xsl:text> |
|
11287 <xsl:text>} |
|
11288 </xsl:text> |
|
11289 <xsl:text> |
|
11290 </xsl:text> |
|
11291 <xsl:text>function prepare_svg() { |
|
11292 </xsl:text> |
|
11293 <xsl:text> // prevents context menu from appearing on right click and long touch |
|
11294 </xsl:text> |
|
11295 <xsl:text> document.body.addEventListener('contextmenu', e => { |
|
11296 </xsl:text> |
|
11297 <xsl:text> toggleFullscreen(); |
|
11298 </xsl:text> |
|
11299 <xsl:text> e.preventDefault(); |
|
11300 </xsl:text> |
|
11301 <xsl:text> }); |
|
11302 </xsl:text> |
|
11303 <xsl:text> |
|
11304 </xsl:text> |
|
11305 <xsl:text> for(let eltid in detachable_elements){ |
|
11306 </xsl:text> |
|
11307 <xsl:text> let [element,parent] = detachable_elements[eltid]; |
|
11308 </xsl:text> |
|
11309 <xsl:text> parent.removeChild(element); |
|
11310 </xsl:text> |
|
11311 <xsl:text> } |
10649 </xsl:text> |
11312 </xsl:text> |
10650 <xsl:text>}; |
11313 <xsl:text>}; |
10651 </xsl:text> |
11314 </xsl:text> |
10652 <xsl:text> |
11315 <xsl:text> |
10653 </xsl:text> |
11316 </xsl:text> |
10654 <xsl:text>const typedarray_types = { |
11317 <xsl:text>function switch_page(page_name, page_index) { |
10655 </xsl:text> |
11318 </xsl:text> |
10656 <xsl:text> INT: (number) => new Int16Array([number]), |
11319 <xsl:text> if(page_switch_in_progress){ |
10657 </xsl:text> |
11320 </xsl:text> |
10658 <xsl:text> BOOL: (truth) => new Int16Array([truth]), |
11321 <xsl:text> /* page switch already going */ |
10659 </xsl:text> |
11322 </xsl:text> |
10660 <xsl:text> NODE: (truth) => new Int16Array([truth]), |
11323 <xsl:text> /* TODO LOG ERROR */ |
10661 </xsl:text> |
11324 </xsl:text> |
10662 <xsl:text> REAL: (number) => new Float32Array([number]), |
11325 <xsl:text> return false; |
10663 </xsl:text> |
11326 </xsl:text> |
10664 <xsl:text> STRING: (str) => { |
11327 <xsl:text> } |
10665 </xsl:text> |
11328 </xsl:text> |
10666 <xsl:text> // beremiz default string max size is 128 |
11329 <xsl:text> page_switch_in_progress = true; |
10667 </xsl:text> |
11330 </xsl:text> |
10668 <xsl:text> str = str.slice(0,128); |
11331 <xsl:text> |
10669 </xsl:text> |
11332 </xsl:text> |
10670 <xsl:text> binary = new Uint8Array(str.length + 1); |
11333 <xsl:text> if(page_name == undefined) |
10671 </xsl:text> |
11334 </xsl:text> |
10672 <xsl:text> binary[0] = str.length; |
11335 <xsl:text> page_name = current_subscribed_page; |
10673 </xsl:text> |
11336 </xsl:text> |
10674 <xsl:text> for(let i = 0; i < str.length; i++){ |
11337 <xsl:text> else if(page_index == undefined){ |
10675 </xsl:text> |
11338 </xsl:text> |
10676 <xsl:text> binary[i+1] = str.charCodeAt(i); |
11339 <xsl:text> [page_name, page_index] = page_name.split('@') |
|
11340 </xsl:text> |
|
11341 <xsl:text> } |
|
11342 </xsl:text> |
|
11343 <xsl:text> |
|
11344 </xsl:text> |
|
11345 <xsl:text> let old_desc = page_desc[current_subscribed_page]; |
|
11346 </xsl:text> |
|
11347 <xsl:text> let new_desc = page_desc[page_name]; |
|
11348 </xsl:text> |
|
11349 <xsl:text> |
|
11350 </xsl:text> |
|
11351 <xsl:text> if(new_desc == undefined){ |
|
11352 </xsl:text> |
|
11353 <xsl:text> /* TODO LOG ERROR */ |
|
11354 </xsl:text> |
|
11355 <xsl:text> return false; |
|
11356 </xsl:text> |
|
11357 <xsl:text> } |
|
11358 </xsl:text> |
|
11359 <xsl:text> |
|
11360 </xsl:text> |
|
11361 <xsl:text> if(page_index == undefined) |
|
11362 </xsl:text> |
|
11363 <xsl:text> page_index = new_desc.page_index; |
|
11364 </xsl:text> |
|
11365 <xsl:text> else if(typeof(page_index) == "string") { |
|
11366 </xsl:text> |
|
11367 <xsl:text> let hmitree_node = hmitree_nodes[page_index]; |
|
11368 </xsl:text> |
|
11369 <xsl:text> if(hmitree_node !== undefined){ |
|
11370 </xsl:text> |
|
11371 <xsl:text> let [int_index, hmiclass] = hmitree_node; |
|
11372 </xsl:text> |
|
11373 <xsl:text> if(hmiclass == new_desc.page_class) |
|
11374 </xsl:text> |
|
11375 <xsl:text> page_index = int_index; |
|
11376 </xsl:text> |
|
11377 <xsl:text> else |
|
11378 </xsl:text> |
|
11379 <xsl:text> page_index = new_desc.page_index; |
|
11380 </xsl:text> |
|
11381 <xsl:text> } else { |
|
11382 </xsl:text> |
|
11383 <xsl:text> page_index = new_desc.page_index; |
10677 </xsl:text> |
11384 </xsl:text> |
10678 <xsl:text> } |
11385 <xsl:text> } |
10679 </xsl:text> |
11386 </xsl:text> |
10680 <xsl:text> return binary; |
|
10681 </xsl:text> |
|
10682 <xsl:text> } |
11387 <xsl:text> } |
10683 </xsl:text> |
11388 </xsl:text> |
10684 <xsl:text> /* TODO */ |
11389 <xsl:text> |
|
11390 </xsl:text> |
|
11391 <xsl:text> if(old_desc){ |
|
11392 </xsl:text> |
|
11393 <xsl:text> old_desc.widgets.map(([widget,relativeness])=>widget.unsub()); |
|
11394 </xsl:text> |
|
11395 <xsl:text> } |
|
11396 </xsl:text> |
|
11397 <xsl:text> const new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; |
|
11398 </xsl:text> |
|
11399 <xsl:text> |
|
11400 </xsl:text> |
|
11401 <xsl:text> const container_id = page_name + (page_index != undefined ? page_index : ""); |
|
11402 </xsl:text> |
|
11403 <xsl:text> |
|
11404 </xsl:text> |
|
11405 <xsl:text> new_desc.widgets.map(([widget,relativeness])=>widget.sub(new_offset,relativeness,container_id)); |
|
11406 </xsl:text> |
|
11407 <xsl:text> |
|
11408 </xsl:text> |
|
11409 <xsl:text> update_subscriptions(); |
|
11410 </xsl:text> |
|
11411 <xsl:text> |
|
11412 </xsl:text> |
|
11413 <xsl:text> current_subscribed_page = page_name; |
|
11414 </xsl:text> |
|
11415 <xsl:text> current_page_index = page_index; |
|
11416 </xsl:text> |
|
11417 <xsl:text> let page_node; |
|
11418 </xsl:text> |
|
11419 <xsl:text> if(page_index != undefined){ |
|
11420 </xsl:text> |
|
11421 <xsl:text> page_node = hmitree_paths[page_index]; |
|
11422 </xsl:text> |
|
11423 <xsl:text> }else{ |
|
11424 </xsl:text> |
|
11425 <xsl:text> page_node = ""; |
|
11426 </xsl:text> |
|
11427 <xsl:text> } |
|
11428 </xsl:text> |
|
11429 <xsl:text> apply_hmi_value(page_node_local_index, page_node); |
|
11430 </xsl:text> |
|
11431 <xsl:text> |
|
11432 </xsl:text> |
|
11433 <xsl:text> jumps_need_update = true; |
|
11434 </xsl:text> |
|
11435 <xsl:text> |
|
11436 </xsl:text> |
|
11437 <xsl:text> requestHMIAnimation(); |
|
11438 </xsl:text> |
|
11439 <xsl:text> jump_history.push([page_name, page_index]); |
|
11440 </xsl:text> |
|
11441 <xsl:text> if(jump_history.length > 42) |
|
11442 </xsl:text> |
|
11443 <xsl:text> jump_history.shift(); |
|
11444 </xsl:text> |
|
11445 <xsl:text> |
|
11446 </xsl:text> |
|
11447 <xsl:text> apply_hmi_value(current_page_var_index, page_index == undefined |
|
11448 </xsl:text> |
|
11449 <xsl:text> ? page_name |
|
11450 </xsl:text> |
|
11451 <xsl:text> : page_name + "@" + hmitree_paths[page_index]); |
|
11452 </xsl:text> |
|
11453 <xsl:text> |
|
11454 </xsl:text> |
|
11455 <xsl:text> return true; |
10685 </xsl:text> |
11456 </xsl:text> |
10686 <xsl:text>}; |
11457 <xsl:text>}; |
10687 </xsl:text> |
11458 </xsl:text> |
10688 <xsl:text> |
11459 <xsl:text> |
10689 </xsl:text> |
11460 </xsl:text> |
10690 <xsl:text>function send_reset() { |
11461 <xsl:text>function switch_visible_page(page_name) { |
10691 </xsl:text> |
11462 </xsl:text> |
10692 <xsl:text> send_blob(new Uint8Array([1])); /* reset = 1 */ |
11463 <xsl:text> |
|
11464 </xsl:text> |
|
11465 <xsl:text> let old_desc = page_desc[current_visible_page]; |
|
11466 </xsl:text> |
|
11467 <xsl:text> let new_desc = page_desc[page_name]; |
|
11468 </xsl:text> |
|
11469 <xsl:text> |
|
11470 </xsl:text> |
|
11471 <xsl:text> if(old_desc){ |
|
11472 </xsl:text> |
|
11473 <xsl:text> for(let eltid in old_desc.required_detachables){ |
|
11474 </xsl:text> |
|
11475 <xsl:text> if(!(eltid in new_desc.required_detachables)){ |
|
11476 </xsl:text> |
|
11477 <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; |
|
11478 </xsl:text> |
|
11479 <xsl:text> parent.removeChild(element); |
|
11480 </xsl:text> |
|
11481 <xsl:text> } |
|
11482 </xsl:text> |
|
11483 <xsl:text> } |
|
11484 </xsl:text> |
|
11485 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
11486 </xsl:text> |
|
11487 <xsl:text> if(!(eltid in old_desc.required_detachables)){ |
|
11488 </xsl:text> |
|
11489 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
11490 </xsl:text> |
|
11491 <xsl:text> parent.appendChild(element); |
|
11492 </xsl:text> |
|
11493 <xsl:text> } |
|
11494 </xsl:text> |
|
11495 <xsl:text> } |
|
11496 </xsl:text> |
|
11497 <xsl:text> }else{ |
|
11498 </xsl:text> |
|
11499 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
11500 </xsl:text> |
|
11501 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
11502 </xsl:text> |
|
11503 <xsl:text> parent.appendChild(element); |
|
11504 </xsl:text> |
|
11505 <xsl:text> } |
|
11506 </xsl:text> |
|
11507 <xsl:text> } |
|
11508 </xsl:text> |
|
11509 <xsl:text> |
|
11510 </xsl:text> |
|
11511 <xsl:text> svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); |
|
11512 </xsl:text> |
|
11513 <xsl:text> current_visible_page = page_name; |
10693 </xsl:text> |
11514 </xsl:text> |
10694 <xsl:text>}; |
11515 <xsl:text>}; |
10695 </xsl:text> |
11516 </xsl:text> |
10696 <xsl:text> |
11517 <xsl:text> |
10697 </xsl:text> |
11518 </xsl:text> |
10698 <xsl:text>var subscriptions = []; |
11519 <xsl:text>// Once connection established |
10699 </xsl:text> |
11520 </xsl:text> |
10700 <xsl:text> |
11521 <xsl:text>ws.onopen = function (evt) { |
10701 </xsl:text> |
11522 </xsl:text> |
10702 <xsl:text>function subscribers(index) { |
11523 <xsl:text> init_widgets(); |
10703 </xsl:text> |
11524 </xsl:text> |
10704 <xsl:text> let entry = subscriptions[index]; |
11525 <xsl:text> send_reset(); |
10705 </xsl:text> |
11526 </xsl:text> |
10706 <xsl:text> let res; |
11527 <xsl:text> // show main page |
10707 </xsl:text> |
11528 </xsl:text> |
10708 <xsl:text> if(entry == undefined){ |
11529 <xsl:text> prepare_svg(); |
10709 </xsl:text> |
11530 </xsl:text> |
10710 <xsl:text> res = new Set(); |
11531 <xsl:text> switch_page(default_page); |
10711 </xsl:text> |
11532 </xsl:text> |
10712 <xsl:text> subscriptions[index] = [res,0]; |
11533 <xsl:text>}; |
10713 </xsl:text> |
11534 </xsl:text> |
10714 <xsl:text> }else{ |
11535 <xsl:text> |
10715 </xsl:text> |
11536 </xsl:text> |
10716 <xsl:text> [res, _ign] = entry; |
11537 <xsl:text>ws.onclose = function (evt) { |
|
11538 </xsl:text> |
|
11539 <xsl:text> // TODO : add visible notification while waiting for reload |
|
11540 </xsl:text> |
|
11541 <xsl:text> console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s."); |
|
11542 </xsl:text> |
|
11543 <xsl:text> // TODO : re-enable auto reload when not in debug |
|
11544 </xsl:text> |
|
11545 <xsl:text> //window.setTimeout(() => location.reload(true), 10000); |
|
11546 </xsl:text> |
|
11547 <xsl:text> alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+"."); |
|
11548 </xsl:text> |
|
11549 <xsl:text> |
|
11550 </xsl:text> |
|
11551 <xsl:text>}; |
|
11552 </xsl:text> |
|
11553 <xsl:text> |
|
11554 </xsl:text> |
|
11555 <xsl:text>const xmlns = "http://www.w3.org/2000/svg"; |
|
11556 </xsl:text> |
|
11557 <xsl:text>var edit_callback; |
|
11558 </xsl:text> |
|
11559 <xsl:text>const localtypes = {"PAGE_LOCAL":null, "HMI_LOCAL":null} |
|
11560 </xsl:text> |
|
11561 <xsl:text>function edit_value(path, valuetype, callback, initial) { |
|
11562 </xsl:text> |
|
11563 <xsl:text> if(valuetype in localtypes){ |
|
11564 </xsl:text> |
|
11565 <xsl:text> valuetype = (typeof initial) == "number" ? "HMI_REAL" : "HMI_STRING"; |
10717 </xsl:text> |
11566 </xsl:text> |
10718 <xsl:text> } |
11567 <xsl:text> } |
10719 </xsl:text> |
11568 </xsl:text> |
10720 <xsl:text> return res |
11569 <xsl:text> let [keypadid, xcoord, ycoord] = keypads[valuetype]; |
10721 </xsl:text> |
11570 </xsl:text> |
10722 <xsl:text>} |
11571 <xsl:text> edit_callback = callback; |
10723 </xsl:text> |
11572 </xsl:text> |
10724 <xsl:text> |
11573 <xsl:text> let widget = hmi_widgets[keypadid]; |
10725 </xsl:text> |
11574 </xsl:text> |
10726 <xsl:text>function get_subscription_period(index) { |
11575 <xsl:text> widget.start_edit(path, valuetype, callback, initial); |
10727 </xsl:text> |
|
10728 <xsl:text> let entry = subscriptions[index]; |
|
10729 </xsl:text> |
|
10730 <xsl:text> if(entry == undefined) |
|
10731 </xsl:text> |
|
10732 <xsl:text> return 0; |
|
10733 </xsl:text> |
|
10734 <xsl:text> let [_ign, period] = entry; |
|
10735 </xsl:text> |
|
10736 <xsl:text> return period; |
|
10737 </xsl:text> |
|
10738 <xsl:text>} |
|
10739 </xsl:text> |
|
10740 <xsl:text> |
|
10741 </xsl:text> |
|
10742 <xsl:text>function set_subscription_period(index, period) { |
|
10743 </xsl:text> |
|
10744 <xsl:text> let entry = subscriptions[index]; |
|
10745 </xsl:text> |
|
10746 <xsl:text> if(entry == undefined){ |
|
10747 </xsl:text> |
|
10748 <xsl:text> subscriptions[index] = [new Set(), period]; |
|
10749 </xsl:text> |
|
10750 <xsl:text> } else { |
|
10751 </xsl:text> |
|
10752 <xsl:text> entry[1] = period; |
|
10753 </xsl:text> |
|
10754 <xsl:text> } |
|
10755 </xsl:text> |
|
10756 <xsl:text>} |
|
10757 </xsl:text> |
|
10758 <xsl:text> |
|
10759 </xsl:text> |
|
10760 <xsl:text>if(has_watchdog){ |
|
10761 </xsl:text> |
|
10762 <xsl:text> // artificially subscribe the watchdog widget to "/heartbeat" hmi variable |
|
10763 </xsl:text> |
|
10764 <xsl:text> // Since dispatch directly calls change_hmi_value, |
|
10765 </xsl:text> |
|
10766 <xsl:text> // PLC will periodically send variable at given frequency |
|
10767 </xsl:text> |
|
10768 <xsl:text> subscribers(heartbeat_index).add({ |
|
10769 </xsl:text> |
|
10770 <xsl:text> /* type: "Watchdog", */ |
|
10771 </xsl:text> |
|
10772 <xsl:text> frequency: 1, |
|
10773 </xsl:text> |
|
10774 <xsl:text> indexes: [heartbeat_index], |
|
10775 </xsl:text> |
|
10776 <xsl:text> new_hmi_value: function(index, value, oldval) { |
|
10777 </xsl:text> |
|
10778 <xsl:text> apply_hmi_value(heartbeat_index, value+1); |
|
10779 </xsl:text> |
|
10780 <xsl:text> } |
|
10781 </xsl:text> |
|
10782 <xsl:text> }); |
|
10783 </xsl:text> |
|
10784 <xsl:text>} |
|
10785 </xsl:text> |
|
10786 <xsl:text> |
|
10787 </xsl:text> |
|
10788 <xsl:text> |
|
10789 </xsl:text> |
|
10790 <xsl:text>var page_fading_in_progress = false; |
|
10791 </xsl:text> |
|
10792 <xsl:text>function fading_page_switch(...args){ |
|
10793 </xsl:text> |
|
10794 <xsl:text> svg_root.classList.add("fade-out-page"); |
|
10795 </xsl:text> |
|
10796 <xsl:text> page_fading_in_progress = true; |
|
10797 </xsl:text> |
|
10798 <xsl:text> |
|
10799 </xsl:text> |
|
10800 <xsl:text> setTimeout(function(){ |
|
10801 </xsl:text> |
|
10802 <xsl:text> switch_page(...args); |
|
10803 </xsl:text> |
|
10804 <xsl:text> },1); |
|
10805 </xsl:text> |
|
10806 <xsl:text>} |
|
10807 </xsl:text> |
|
10808 <xsl:text>document.body.style.backgroundColor = "black"; |
|
10809 </xsl:text> |
|
10810 <xsl:text> |
|
10811 </xsl:text> |
|
10812 <xsl:text>// subscribe to per instance current page hmi variable |
|
10813 </xsl:text> |
|
10814 <xsl:text>// PLC must prefix page name with "!" for page switch to happen |
|
10815 </xsl:text> |
|
10816 <xsl:text>subscribers(current_page_var_index).add({ |
|
10817 </xsl:text> |
|
10818 <xsl:text> frequency: 1, |
|
10819 </xsl:text> |
|
10820 <xsl:text> indexes: [current_page_var_index], |
|
10821 </xsl:text> |
|
10822 <xsl:text> new_hmi_value: function(index, value, oldval) { |
|
10823 </xsl:text> |
|
10824 <xsl:text> if(value.startsWith("!")) |
|
10825 </xsl:text> |
|
10826 <xsl:text> fading_page_switch(value.slice(1)); |
|
10827 </xsl:text> |
|
10828 <xsl:text> } |
|
10829 </xsl:text> |
|
10830 <xsl:text>}); |
|
10831 </xsl:text> |
|
10832 <xsl:text> |
|
10833 </xsl:text> |
|
10834 <xsl:text>function svg_text_to_multiline(elt) { |
|
10835 </xsl:text> |
|
10836 <xsl:text> return(Array.prototype.map.call(elt.children, x=>x.textContent).join("\n")); |
|
10837 </xsl:text> |
|
10838 <xsl:text>} |
|
10839 </xsl:text> |
|
10840 <xsl:text> |
|
10841 </xsl:text> |
|
10842 <xsl:text>function multiline_to_svg_text(elt, str, blank) { |
|
10843 </xsl:text> |
|
10844 <xsl:text> str.split('\n').map((line,i) => {elt.children[i].textContent = blank?"":line;}); |
|
10845 </xsl:text> |
|
10846 <xsl:text>} |
|
10847 </xsl:text> |
|
10848 <xsl:text> |
|
10849 </xsl:text> |
|
10850 <xsl:text>function switch_langnum(langnum) { |
|
10851 </xsl:text> |
|
10852 <xsl:text> langnum = Math.max(0, Math.min(langs.length - 1, langnum)); |
|
10853 </xsl:text> |
|
10854 <xsl:text> |
|
10855 </xsl:text> |
|
10856 <xsl:text> for (let translation of translations) { |
|
10857 </xsl:text> |
|
10858 <xsl:text> let [objs, msgs] = translation; |
|
10859 </xsl:text> |
|
10860 <xsl:text> let msg = msgs[langnum]; |
|
10861 </xsl:text> |
|
10862 <xsl:text> for (let obj of objs) { |
|
10863 </xsl:text> |
|
10864 <xsl:text> multiline_to_svg_text(obj, msg); |
|
10865 </xsl:text> |
|
10866 <xsl:text> obj.setAttribute("lang",langnum); |
|
10867 </xsl:text> |
|
10868 <xsl:text> } |
|
10869 </xsl:text> |
|
10870 <xsl:text> } |
|
10871 </xsl:text> |
|
10872 <xsl:text> return langnum; |
|
10873 </xsl:text> |
|
10874 <xsl:text>} |
|
10875 </xsl:text> |
|
10876 <xsl:text> |
|
10877 </xsl:text> |
|
10878 <xsl:text>// backup original texts |
|
10879 </xsl:text> |
|
10880 <xsl:text>for (let translation of translations) { |
|
10881 </xsl:text> |
|
10882 <xsl:text> let [objs, msgs] = translation; |
|
10883 </xsl:text> |
|
10884 <xsl:text> msgs.unshift(svg_text_to_multiline(objs[0])); |
|
10885 </xsl:text> |
|
10886 <xsl:text>} |
|
10887 </xsl:text> |
|
10888 <xsl:text> |
|
10889 </xsl:text> |
|
10890 <xsl:text>var lang_local_index = hmi_local_index("lang"); |
|
10891 </xsl:text> |
|
10892 <xsl:text>var langcode_local_index = hmi_local_index("lang_code"); |
|
10893 </xsl:text> |
|
10894 <xsl:text>var langname_local_index = hmi_local_index("lang_name"); |
|
10895 </xsl:text> |
|
10896 <xsl:text>subscribers(lang_local_index).add({ |
|
10897 </xsl:text> |
|
10898 <xsl:text> indexes: [lang_local_index], |
|
10899 </xsl:text> |
|
10900 <xsl:text> new_hmi_value: function(index, value, oldval) { |
|
10901 </xsl:text> |
|
10902 <xsl:text> let current_lang = switch_langnum(value); |
|
10903 </xsl:text> |
|
10904 <xsl:text> let [langname,langcode] = langs[current_lang]; |
|
10905 </xsl:text> |
|
10906 <xsl:text> apply_hmi_value(langcode_local_index, langcode); |
|
10907 </xsl:text> |
|
10908 <xsl:text> apply_hmi_value(langname_local_index, langname); |
|
10909 </xsl:text> |
|
10910 <xsl:text> switch_page(); |
|
10911 </xsl:text> |
|
10912 <xsl:text> } |
|
10913 </xsl:text> |
|
10914 <xsl:text>}); |
|
10915 </xsl:text> |
|
10916 <xsl:text> |
|
10917 </xsl:text> |
|
10918 <xsl:text>// returns en_US, fr_FR or en_UK depending on selected language |
|
10919 </xsl:text> |
|
10920 <xsl:text>function get_current_lang_code(){ |
|
10921 </xsl:text> |
|
10922 <xsl:text> return cache[langcode_local_index]; |
|
10923 </xsl:text> |
|
10924 <xsl:text>} |
|
10925 </xsl:text> |
|
10926 <xsl:text> |
|
10927 </xsl:text> |
|
10928 <xsl:text>function setup_lang(){ |
|
10929 </xsl:text> |
|
10930 <xsl:text> let current_lang = cache[lang_local_index]; |
|
10931 </xsl:text> |
|
10932 <xsl:text> let new_lang = switch_langnum(current_lang); |
|
10933 </xsl:text> |
|
10934 <xsl:text> if(current_lang != new_lang){ |
|
10935 </xsl:text> |
|
10936 <xsl:text> apply_hmi_value(lang_local_index, new_lang); |
|
10937 </xsl:text> |
|
10938 <xsl:text> } |
|
10939 </xsl:text> |
|
10940 <xsl:text>} |
|
10941 </xsl:text> |
|
10942 <xsl:text> |
|
10943 </xsl:text> |
|
10944 <xsl:text>setup_lang(); |
|
10945 </xsl:text> |
|
10946 <xsl:text> |
|
10947 </xsl:text> |
|
10948 <xsl:text>function update_subscriptions() { |
|
10949 </xsl:text> |
|
10950 <xsl:text> let delta = []; |
|
10951 </xsl:text> |
|
10952 <xsl:text> for(let index in subscriptions){ |
|
10953 </xsl:text> |
|
10954 <xsl:text> let widgets = subscribers(index); |
|
10955 </xsl:text> |
|
10956 <xsl:text> |
|
10957 </xsl:text> |
|
10958 <xsl:text> // periods are in ms |
|
10959 </xsl:text> |
|
10960 <xsl:text> let previous_period = get_subscription_period(index); |
|
10961 </xsl:text> |
|
10962 <xsl:text> |
|
10963 </xsl:text> |
|
10964 <xsl:text> // subscribing with a zero period is unsubscribing |
|
10965 </xsl:text> |
|
10966 <xsl:text> let new_period = 0; |
|
10967 </xsl:text> |
|
10968 <xsl:text> if(widgets.size > 0) { |
|
10969 </xsl:text> |
|
10970 <xsl:text> let maxfreq = 0; |
|
10971 </xsl:text> |
|
10972 <xsl:text> for(let widget of widgets){ |
|
10973 </xsl:text> |
|
10974 <xsl:text> let wf = widget.frequency; |
|
10975 </xsl:text> |
|
10976 <xsl:text> if(wf != undefined && maxfreq < wf) |
|
10977 </xsl:text> |
|
10978 <xsl:text> maxfreq = wf; |
|
10979 </xsl:text> |
|
10980 <xsl:text> } |
|
10981 </xsl:text> |
|
10982 <xsl:text> |
|
10983 </xsl:text> |
|
10984 <xsl:text> if(maxfreq != 0) |
|
10985 </xsl:text> |
|
10986 <xsl:text> new_period = 1000/maxfreq; |
|
10987 </xsl:text> |
|
10988 <xsl:text> } |
|
10989 </xsl:text> |
|
10990 <xsl:text> |
|
10991 </xsl:text> |
|
10992 <xsl:text> if(previous_period != new_period) { |
|
10993 </xsl:text> |
|
10994 <xsl:text> set_subscription_period(index, new_period); |
|
10995 </xsl:text> |
|
10996 <xsl:text> if(index <= last_remote_index){ |
|
10997 </xsl:text> |
|
10998 <xsl:text> delta.push( |
|
10999 </xsl:text> |
|
11000 <xsl:text> new Uint8Array([2]), /* subscribe = 2 */ |
|
11001 </xsl:text> |
|
11002 <xsl:text> new Uint32Array([index]), |
|
11003 </xsl:text> |
|
11004 <xsl:text> new Uint16Array([new_period])); |
|
11005 </xsl:text> |
|
11006 <xsl:text> } |
|
11007 </xsl:text> |
|
11008 <xsl:text> } |
|
11009 </xsl:text> |
|
11010 <xsl:text> } |
|
11011 </xsl:text> |
|
11012 <xsl:text> send_blob(delta); |
|
11013 </xsl:text> |
11576 </xsl:text> |
11014 <xsl:text>}; |
11577 <xsl:text>}; |
11015 </xsl:text> |
11578 </xsl:text> |
11016 <xsl:text> |
11579 <xsl:text> |
11017 </xsl:text> |
11580 </xsl:text> |
11018 <xsl:text>function send_hmi_value(index, value) { |
11581 <xsl:text>var current_modal; /* TODO stack ?*/ |
11019 </xsl:text> |
11582 </xsl:text> |
11020 <xsl:text> if(index > last_remote_index){ |
11583 <xsl:text> |
11021 </xsl:text> |
11584 </xsl:text> |
11022 <xsl:text> updates.set(index, value); |
11585 <xsl:text>function show_modal() { |
11023 </xsl:text> |
11586 </xsl:text> |
11024 <xsl:text> |
11587 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
11025 </xsl:text> |
11588 </xsl:text> |
11026 <xsl:text> if(persistent_indexes.has(index)){ |
11589 <xsl:text> |
11027 </xsl:text> |
11590 </xsl:text> |
11028 <xsl:text> let varname = persistent_indexes.get(index); |
11591 <xsl:text> tmpgrp = document.createElementNS(xmlns,"g"); |
11029 </xsl:text> |
11592 </xsl:text> |
11030 <xsl:text> document.cookie = varname+"="+value+"; max-age=3153600000"; |
11593 <xsl:text> tmpgrpattr = document.createAttribute("transform"); |
11031 </xsl:text> |
11594 </xsl:text> |
11032 <xsl:text> } |
11595 <xsl:text> let [xcoord,ycoord] = this.coordinates; |
11033 </xsl:text> |
11596 </xsl:text> |
11034 <xsl:text> |
11597 <xsl:text> let [xdest,ydest] = page_desc[current_visible_page].bbox; |
11035 </xsl:text> |
11598 </xsl:text> |
11036 <xsl:text> requestHMIAnimation(); |
11599 <xsl:text> tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")"; |
11037 </xsl:text> |
11600 </xsl:text> |
11038 <xsl:text> return; |
11601 <xsl:text> |
11039 </xsl:text> |
11602 </xsl:text> |
11040 <xsl:text> } |
11603 <xsl:text> tmpgrp.setAttributeNode(tmpgrpattr); |
11041 </xsl:text> |
11604 </xsl:text> |
11042 <xsl:text> |
11605 <xsl:text> |
11043 </xsl:text> |
11606 </xsl:text> |
11044 <xsl:text> let iectype = hmitree_types[index]; |
11607 <xsl:text> tmpgrp.appendChild(element); |
11045 </xsl:text> |
11608 </xsl:text> |
11046 <xsl:text> let tobinary = typedarray_types[iectype]; |
11609 <xsl:text> parent.appendChild(tmpgrp); |
11047 </xsl:text> |
11610 </xsl:text> |
11048 <xsl:text> send_blob([ |
11611 <xsl:text> |
11049 </xsl:text> |
11612 </xsl:text> |
11050 <xsl:text> new Uint8Array([0]), /* setval = 0 */ |
11613 <xsl:text> current_modal = [this.element.id, tmpgrp]; |
11051 </xsl:text> |
|
11052 <xsl:text> new Uint32Array([index]), |
|
11053 </xsl:text> |
|
11054 <xsl:text> tobinary(value)]); |
|
11055 </xsl:text> |
|
11056 <xsl:text> |
|
11057 </xsl:text> |
|
11058 <xsl:text> // DON'T DO THAT unless read_iterator in svghmi.c modifies wbuf as well, not only rbuf |
|
11059 </xsl:text> |
|
11060 <xsl:text> // cache[index] = value; |
|
11061 </xsl:text> |
11614 </xsl:text> |
11062 <xsl:text>}; |
11615 <xsl:text>}; |
11063 </xsl:text> |
11616 </xsl:text> |
11064 <xsl:text> |
11617 <xsl:text> |
11065 </xsl:text> |
11618 </xsl:text> |
11066 <xsl:text>function apply_hmi_value(index, new_val) { |
11619 <xsl:text>function end_modal() { |
11067 </xsl:text> |
11620 </xsl:text> |
11068 <xsl:text> // Similarly to previous comment, taking decision to update based |
11621 <xsl:text> let [eltid, tmpgrp] = current_modal; |
11069 </xsl:text> |
11622 </xsl:text> |
11070 <xsl:text> // on cache content is bad and can lead to inconsistency |
11623 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
11071 </xsl:text> |
11624 </xsl:text> |
11072 <xsl:text> /*let old_val = cache[index];*/ |
11625 <xsl:text> |
11073 </xsl:text> |
11626 </xsl:text> |
11074 <xsl:text> if(new_val != undefined /*&& old_val != new_val*/) |
11627 <xsl:text> parent.removeChild(tmpgrp); |
11075 </xsl:text> |
11628 </xsl:text> |
11076 <xsl:text> send_hmi_value(index, new_val); |
11629 <xsl:text> |
11077 </xsl:text> |
11630 </xsl:text> |
11078 <xsl:text> return new_val; |
11631 <xsl:text> current_modal = undefined; |
11079 </xsl:text> |
|
11080 <xsl:text>} |
|
11081 </xsl:text> |
|
11082 <xsl:text> |
|
11083 </xsl:text> |
|
11084 <xsl:text>const quotes = {"'":null, '"':null}; |
|
11085 </xsl:text> |
|
11086 <xsl:text> |
|
11087 </xsl:text> |
|
11088 <xsl:text>function eval_operation_string(old_val, opstr) { |
|
11089 </xsl:text> |
|
11090 <xsl:text> let op = opstr[0]; |
|
11091 </xsl:text> |
|
11092 <xsl:text> let given_val; |
|
11093 </xsl:text> |
|
11094 <xsl:text> if(opstr.length < 2) |
|
11095 </xsl:text> |
|
11096 <xsl:text> return undefined; |
|
11097 </xsl:text> |
|
11098 <xsl:text> if(opstr[1] in quotes){ |
|
11099 </xsl:text> |
|
11100 <xsl:text> if(opstr.length < 3) |
|
11101 </xsl:text> |
|
11102 <xsl:text> return undefined; |
|
11103 </xsl:text> |
|
11104 <xsl:text> if(opstr[opstr.length-1] == opstr[1]){ |
|
11105 </xsl:text> |
|
11106 <xsl:text> given_val = opstr.slice(2,opstr.length-1); |
|
11107 </xsl:text> |
|
11108 <xsl:text> } |
|
11109 </xsl:text> |
|
11110 <xsl:text> } else { |
|
11111 </xsl:text> |
|
11112 <xsl:text> given_val = Number(opstr.slice(1)); |
|
11113 </xsl:text> |
|
11114 <xsl:text> } |
|
11115 </xsl:text> |
|
11116 <xsl:text> let new_val; |
|
11117 </xsl:text> |
|
11118 <xsl:text> switch(op){ |
|
11119 </xsl:text> |
|
11120 <xsl:text> case "=": |
|
11121 </xsl:text> |
|
11122 <xsl:text> new_val = given_val; |
|
11123 </xsl:text> |
|
11124 <xsl:text> break; |
|
11125 </xsl:text> |
|
11126 <xsl:text> case "+": |
|
11127 </xsl:text> |
|
11128 <xsl:text> new_val = old_val + given_val; |
|
11129 </xsl:text> |
|
11130 <xsl:text> break; |
|
11131 </xsl:text> |
|
11132 <xsl:text> case "-": |
|
11133 </xsl:text> |
|
11134 <xsl:text> new_val = old_val - given_val; |
|
11135 </xsl:text> |
|
11136 <xsl:text> break; |
|
11137 </xsl:text> |
|
11138 <xsl:text> case "*": |
|
11139 </xsl:text> |
|
11140 <xsl:text> new_val = old_val * given_val; |
|
11141 </xsl:text> |
|
11142 <xsl:text> break; |
|
11143 </xsl:text> |
|
11144 <xsl:text> case "/": |
|
11145 </xsl:text> |
|
11146 <xsl:text> new_val = old_val / given_val; |
|
11147 </xsl:text> |
|
11148 <xsl:text> break; |
|
11149 </xsl:text> |
|
11150 <xsl:text> } |
|
11151 </xsl:text> |
|
11152 <xsl:text> return new_val; |
|
11153 </xsl:text> |
|
11154 <xsl:text>} |
|
11155 </xsl:text> |
|
11156 <xsl:text> |
|
11157 </xsl:text> |
|
11158 <xsl:text>var current_visible_page; |
|
11159 </xsl:text> |
|
11160 <xsl:text>var current_subscribed_page; |
|
11161 </xsl:text> |
|
11162 <xsl:text>var current_page_index; |
|
11163 </xsl:text> |
|
11164 <xsl:text>var page_node_local_index = hmi_local_index("page_node"); |
|
11165 </xsl:text> |
|
11166 <xsl:text> |
|
11167 </xsl:text> |
|
11168 <xsl:text>function toggleFullscreen() { |
|
11169 </xsl:text> |
|
11170 <xsl:text> let elem = document.documentElement; |
|
11171 </xsl:text> |
|
11172 <xsl:text> |
|
11173 </xsl:text> |
|
11174 <xsl:text> if (!document.fullscreenElement) { |
|
11175 </xsl:text> |
|
11176 <xsl:text> elem.requestFullscreen().catch(err => { |
|
11177 </xsl:text> |
|
11178 <xsl:text> console.log("Error attempting to enable full-screen mode: "+err.message+" ("+err.name+")"); |
|
11179 </xsl:text> |
|
11180 <xsl:text> }); |
|
11181 </xsl:text> |
|
11182 <xsl:text> } else { |
|
11183 </xsl:text> |
|
11184 <xsl:text> document.exitFullscreen(); |
|
11185 </xsl:text> |
|
11186 <xsl:text> } |
|
11187 </xsl:text> |
|
11188 <xsl:text>} |
|
11189 </xsl:text> |
|
11190 <xsl:text> |
|
11191 </xsl:text> |
|
11192 <xsl:text>function prepare_svg() { |
|
11193 </xsl:text> |
|
11194 <xsl:text> // prevents context menu from appearing on right click and long touch |
|
11195 </xsl:text> |
|
11196 <xsl:text> document.body.addEventListener('contextmenu', e => { |
|
11197 </xsl:text> |
|
11198 <xsl:text> toggleFullscreen(); |
|
11199 </xsl:text> |
|
11200 <xsl:text> e.preventDefault(); |
|
11201 </xsl:text> |
|
11202 <xsl:text> }); |
|
11203 </xsl:text> |
|
11204 <xsl:text> |
|
11205 </xsl:text> |
|
11206 <xsl:text> for(let eltid in detachable_elements){ |
|
11207 </xsl:text> |
|
11208 <xsl:text> let [element,parent] = detachable_elements[eltid]; |
|
11209 </xsl:text> |
|
11210 <xsl:text> parent.removeChild(element); |
|
11211 </xsl:text> |
|
11212 <xsl:text> } |
|
11213 </xsl:text> |
11632 </xsl:text> |
11214 <xsl:text>}; |
11633 <xsl:text>}; |
11215 </xsl:text> |
11634 </xsl:text> |
11216 <xsl:text> |
11635 <xsl:text> |
11217 </xsl:text> |
11636 </xsl:text> |
11218 <xsl:text>function switch_page(page_name, page_index) { |
11637 <xsl:text> |
11219 </xsl:text> |
11638 // |
11220 <xsl:text> if(current_subscribed_page != current_visible_page){ |
11639 // |
11221 </xsl:text> |
11640 // Declarations from SVG scripts (inkscape document properties) |
11222 <xsl:text> /* page switch already going */ |
11641 // |
11223 </xsl:text> |
11642 // |
11224 <xsl:text> /* TODO LOG ERROR */ |
11643 </xsl:text> |
11225 </xsl:text> |
11644 <xsl:for-each select="/svg:svg/svg:script"> |
11226 <xsl:text> return false; |
11645 <xsl:text> |
11227 </xsl:text> |
11646 </xsl:text> |
11228 <xsl:text> } |
11647 <xsl:text>/* </xsl:text> |
11229 </xsl:text> |
11648 <xsl:value-of select="@id"/> |
11230 <xsl:text> |
11649 <xsl:text> */ |
11231 </xsl:text> |
11650 </xsl:text> |
11232 <xsl:text> if(page_name == undefined) |
11651 <xsl:value-of select="text()"/> |
11233 </xsl:text> |
11652 <xsl:text> |
11234 <xsl:text> page_name = current_subscribed_page; |
11653 </xsl:text> |
11235 </xsl:text> |
11654 </xsl:for-each> |
11236 <xsl:text> else if(page_index == undefined){ |
|
11237 </xsl:text> |
|
11238 <xsl:text> [page_name, page_index] = page_name.split('@') |
|
11239 </xsl:text> |
|
11240 <xsl:text> } |
|
11241 </xsl:text> |
|
11242 <xsl:text> |
|
11243 </xsl:text> |
|
11244 <xsl:text> let old_desc = page_desc[current_subscribed_page]; |
|
11245 </xsl:text> |
|
11246 <xsl:text> let new_desc = page_desc[page_name]; |
|
11247 </xsl:text> |
|
11248 <xsl:text> |
|
11249 </xsl:text> |
|
11250 <xsl:text> if(new_desc == undefined){ |
|
11251 </xsl:text> |
|
11252 <xsl:text> /* TODO LOG ERROR */ |
|
11253 </xsl:text> |
|
11254 <xsl:text> return false; |
|
11255 </xsl:text> |
|
11256 <xsl:text> } |
|
11257 </xsl:text> |
|
11258 <xsl:text> |
|
11259 </xsl:text> |
|
11260 <xsl:text> if(page_index == undefined) |
|
11261 </xsl:text> |
|
11262 <xsl:text> page_index = new_desc.page_index; |
|
11263 </xsl:text> |
|
11264 <xsl:text> else if(typeof(page_index) == "string") { |
|
11265 </xsl:text> |
|
11266 <xsl:text> let hmitree_node = hmitree_nodes[page_index]; |
|
11267 </xsl:text> |
|
11268 <xsl:text> if(hmitree_node !== undefined){ |
|
11269 </xsl:text> |
|
11270 <xsl:text> let [int_index, hmiclass] = hmitree_node; |
|
11271 </xsl:text> |
|
11272 <xsl:text> if(hmiclass == new_desc.page_class) |
|
11273 </xsl:text> |
|
11274 <xsl:text> page_index = int_index; |
|
11275 </xsl:text> |
|
11276 <xsl:text> else |
|
11277 </xsl:text> |
|
11278 <xsl:text> page_index = new_desc.page_index; |
|
11279 </xsl:text> |
|
11280 <xsl:text> } else { |
|
11281 </xsl:text> |
|
11282 <xsl:text> page_index = new_desc.page_index; |
|
11283 </xsl:text> |
|
11284 <xsl:text> } |
|
11285 </xsl:text> |
|
11286 <xsl:text> } |
|
11287 </xsl:text> |
|
11288 <xsl:text> |
|
11289 </xsl:text> |
|
11290 <xsl:text> if(old_desc){ |
|
11291 </xsl:text> |
|
11292 <xsl:text> old_desc.widgets.map(([widget,relativeness])=>widget.unsub()); |
|
11293 </xsl:text> |
|
11294 <xsl:text> } |
|
11295 </xsl:text> |
|
11296 <xsl:text> const new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; |
|
11297 </xsl:text> |
|
11298 <xsl:text> |
|
11299 </xsl:text> |
|
11300 <xsl:text> const container_id = page_name + (page_index != undefined ? page_index : ""); |
|
11301 </xsl:text> |
|
11302 <xsl:text> |
|
11303 </xsl:text> |
|
11304 <xsl:text> new_desc.widgets.map(([widget,relativeness])=>widget.sub(new_offset,relativeness,container_id)); |
|
11305 </xsl:text> |
|
11306 <xsl:text> |
|
11307 </xsl:text> |
|
11308 <xsl:text> update_subscriptions(); |
|
11309 </xsl:text> |
|
11310 <xsl:text> |
|
11311 </xsl:text> |
|
11312 <xsl:text> current_subscribed_page = page_name; |
|
11313 </xsl:text> |
|
11314 <xsl:text> current_page_index = page_index; |
|
11315 </xsl:text> |
|
11316 <xsl:text> let page_node; |
|
11317 </xsl:text> |
|
11318 <xsl:text> if(page_index != undefined){ |
|
11319 </xsl:text> |
|
11320 <xsl:text> page_node = hmitree_paths[page_index]; |
|
11321 </xsl:text> |
|
11322 <xsl:text> }else{ |
|
11323 </xsl:text> |
|
11324 <xsl:text> page_node = ""; |
|
11325 </xsl:text> |
|
11326 <xsl:text> } |
|
11327 </xsl:text> |
|
11328 <xsl:text> apply_hmi_value(page_node_local_index, page_node); |
|
11329 </xsl:text> |
|
11330 <xsl:text> |
|
11331 </xsl:text> |
|
11332 <xsl:text> jumps_need_update = true; |
|
11333 </xsl:text> |
|
11334 <xsl:text> |
|
11335 </xsl:text> |
|
11336 <xsl:text> requestHMIAnimation(); |
|
11337 </xsl:text> |
|
11338 <xsl:text> jump_history.push([page_name, page_index]); |
|
11339 </xsl:text> |
|
11340 <xsl:text> if(jump_history.length > 42) |
|
11341 </xsl:text> |
|
11342 <xsl:text> jump_history.shift(); |
|
11343 </xsl:text> |
|
11344 <xsl:text> |
|
11345 </xsl:text> |
|
11346 <xsl:text> apply_hmi_value(current_page_var_index, page_index == undefined |
|
11347 </xsl:text> |
|
11348 <xsl:text> ? page_name |
|
11349 </xsl:text> |
|
11350 <xsl:text> : page_name + "@" + hmitree_paths[page_index]); |
|
11351 </xsl:text> |
|
11352 <xsl:text> |
|
11353 </xsl:text> |
|
11354 <xsl:text> return true; |
|
11355 </xsl:text> |
|
11356 <xsl:text>}; |
|
11357 </xsl:text> |
|
11358 <xsl:text> |
|
11359 </xsl:text> |
|
11360 <xsl:text>function switch_visible_page(page_name) { |
|
11361 </xsl:text> |
|
11362 <xsl:text> |
|
11363 </xsl:text> |
|
11364 <xsl:text> let old_desc = page_desc[current_visible_page]; |
|
11365 </xsl:text> |
|
11366 <xsl:text> let new_desc = page_desc[page_name]; |
|
11367 </xsl:text> |
|
11368 <xsl:text> |
|
11369 </xsl:text> |
|
11370 <xsl:text> if(old_desc){ |
|
11371 </xsl:text> |
|
11372 <xsl:text> for(let eltid in old_desc.required_detachables){ |
|
11373 </xsl:text> |
|
11374 <xsl:text> if(!(eltid in new_desc.required_detachables)){ |
|
11375 </xsl:text> |
|
11376 <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; |
|
11377 </xsl:text> |
|
11378 <xsl:text> parent.removeChild(element); |
|
11379 </xsl:text> |
|
11380 <xsl:text> } |
|
11381 </xsl:text> |
|
11382 <xsl:text> } |
|
11383 </xsl:text> |
|
11384 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
11385 </xsl:text> |
|
11386 <xsl:text> if(!(eltid in old_desc.required_detachables)){ |
|
11387 </xsl:text> |
|
11388 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
11389 </xsl:text> |
|
11390 <xsl:text> parent.appendChild(element); |
|
11391 </xsl:text> |
|
11392 <xsl:text> } |
|
11393 </xsl:text> |
|
11394 <xsl:text> } |
|
11395 </xsl:text> |
|
11396 <xsl:text> }else{ |
|
11397 </xsl:text> |
|
11398 <xsl:text> for(let eltid in new_desc.required_detachables){ |
|
11399 </xsl:text> |
|
11400 <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; |
|
11401 </xsl:text> |
|
11402 <xsl:text> parent.appendChild(element); |
|
11403 </xsl:text> |
|
11404 <xsl:text> } |
|
11405 </xsl:text> |
|
11406 <xsl:text> } |
|
11407 </xsl:text> |
|
11408 <xsl:text> |
|
11409 </xsl:text> |
|
11410 <xsl:text> svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); |
|
11411 </xsl:text> |
|
11412 <xsl:text> if(page_fading_in_progress) |
|
11413 </xsl:text> |
|
11414 <xsl:text> svg_root.classList.remove("fade-out-page"); |
|
11415 </xsl:text> |
|
11416 <xsl:text> page_fading_in_progress = false; |
|
11417 </xsl:text> |
|
11418 <xsl:text> current_visible_page = page_name; |
|
11419 </xsl:text> |
|
11420 <xsl:text>}; |
|
11421 </xsl:text> |
|
11422 <xsl:text> |
|
11423 </xsl:text> |
|
11424 <xsl:text>// Once connection established |
|
11425 </xsl:text> |
|
11426 <xsl:text>ws.onopen = function (evt) { |
|
11427 </xsl:text> |
|
11428 <xsl:text> init_widgets(); |
|
11429 </xsl:text> |
|
11430 <xsl:text> send_reset(); |
|
11431 </xsl:text> |
|
11432 <xsl:text> // show main page |
|
11433 </xsl:text> |
|
11434 <xsl:text> prepare_svg(); |
|
11435 </xsl:text> |
|
11436 <xsl:text> switch_page(default_page); |
|
11437 </xsl:text> |
|
11438 <xsl:text>}; |
|
11439 </xsl:text> |
|
11440 <xsl:text> |
|
11441 </xsl:text> |
|
11442 <xsl:text>ws.onclose = function (evt) { |
|
11443 </xsl:text> |
|
11444 <xsl:text> // TODO : add visible notification while waiting for reload |
|
11445 </xsl:text> |
|
11446 <xsl:text> console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s."); |
|
11447 </xsl:text> |
|
11448 <xsl:text> // TODO : re-enable auto reload when not in debug |
|
11449 </xsl:text> |
|
11450 <xsl:text> //window.setTimeout(() => location.reload(true), 10000); |
|
11451 </xsl:text> |
|
11452 <xsl:text> alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+"."); |
|
11453 </xsl:text> |
|
11454 <xsl:text> |
|
11455 </xsl:text> |
|
11456 <xsl:text>}; |
|
11457 </xsl:text> |
|
11458 <xsl:text> |
|
11459 </xsl:text> |
|
11460 <xsl:text>const xmlns = "http://www.w3.org/2000/svg"; |
|
11461 </xsl:text> |
|
11462 <xsl:text>var edit_callback; |
|
11463 </xsl:text> |
|
11464 <xsl:text>const localtypes = {"PAGE_LOCAL":null, "HMI_LOCAL":null} |
|
11465 </xsl:text> |
|
11466 <xsl:text>function edit_value(path, valuetype, callback, initial) { |
|
11467 </xsl:text> |
|
11468 <xsl:text> if(valuetype in localtypes){ |
|
11469 </xsl:text> |
|
11470 <xsl:text> valuetype = (typeof initial) == "number" ? "HMI_REAL" : "HMI_STRING"; |
|
11471 </xsl:text> |
|
11472 <xsl:text> } |
|
11473 </xsl:text> |
|
11474 <xsl:text> let [keypadid, xcoord, ycoord] = keypads[valuetype]; |
|
11475 </xsl:text> |
|
11476 <xsl:text> edit_callback = callback; |
|
11477 </xsl:text> |
|
11478 <xsl:text> let widget = hmi_widgets[keypadid]; |
|
11479 </xsl:text> |
|
11480 <xsl:text> widget.start_edit(path, valuetype, callback, initial); |
|
11481 </xsl:text> |
|
11482 <xsl:text>}; |
|
11483 </xsl:text> |
|
11484 <xsl:text> |
|
11485 </xsl:text> |
|
11486 <xsl:text>var current_modal; /* TODO stack ?*/ |
|
11487 </xsl:text> |
|
11488 <xsl:text> |
|
11489 </xsl:text> |
|
11490 <xsl:text>function show_modal() { |
|
11491 </xsl:text> |
|
11492 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
11493 </xsl:text> |
|
11494 <xsl:text> |
|
11495 </xsl:text> |
|
11496 <xsl:text> tmpgrp = document.createElementNS(xmlns,"g"); |
|
11497 </xsl:text> |
|
11498 <xsl:text> tmpgrpattr = document.createAttribute("transform"); |
|
11499 </xsl:text> |
|
11500 <xsl:text> let [xcoord,ycoord] = this.coordinates; |
|
11501 </xsl:text> |
|
11502 <xsl:text> let [xdest,ydest] = page_desc[current_visible_page].bbox; |
|
11503 </xsl:text> |
|
11504 <xsl:text> tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")"; |
|
11505 </xsl:text> |
|
11506 <xsl:text> |
|
11507 </xsl:text> |
|
11508 <xsl:text> tmpgrp.setAttributeNode(tmpgrpattr); |
|
11509 </xsl:text> |
|
11510 <xsl:text> |
|
11511 </xsl:text> |
|
11512 <xsl:text> tmpgrp.appendChild(element); |
|
11513 </xsl:text> |
|
11514 <xsl:text> parent.appendChild(tmpgrp); |
|
11515 </xsl:text> |
|
11516 <xsl:text> |
|
11517 </xsl:text> |
|
11518 <xsl:text> current_modal = [this.element.id, tmpgrp]; |
|
11519 </xsl:text> |
|
11520 <xsl:text>}; |
|
11521 </xsl:text> |
|
11522 <xsl:text> |
|
11523 </xsl:text> |
|
11524 <xsl:text>function end_modal() { |
|
11525 </xsl:text> |
|
11526 <xsl:text> let [eltid, tmpgrp] = current_modal; |
|
11527 </xsl:text> |
|
11528 <xsl:text> let [element, parent] = detachable_elements[this.element.id]; |
|
11529 </xsl:text> |
|
11530 <xsl:text> |
|
11531 </xsl:text> |
|
11532 <xsl:text> parent.removeChild(tmpgrp); |
|
11533 </xsl:text> |
|
11534 <xsl:text> |
|
11535 </xsl:text> |
|
11536 <xsl:text> current_modal = undefined; |
|
11537 </xsl:text> |
|
11538 <xsl:text>}; |
|
11539 </xsl:text> |
|
11540 <xsl:text> |
|
11541 </xsl:text> |
|
11542 </script> |
11655 </script> |
11543 </body> |
11656 </body> |
11544 </html> |
11657 </html> |
11545 </xsl:template> |
11658 </xsl:template> |
11546 </xsl:stylesheet> |
11659 </xsl:stylesheet> |