SVGHMI: Added HMI:VarInitPersistent to initialize persistent HMI_LOCAL and PAGE_LOCAL variables, stored as cookies in browser.
--- a/svghmi/gen_index_xhtml.xslt Tue Feb 09 07:41:24 2021 +0100
+++ b/svghmi/gen_index_xhtml.xslt Tue Feb 09 07:46:02 2021 +0100
@@ -192,12 +192,12 @@
</xsl:when>
</xsl:choose>
<xsl:choose>
- <xsl:when test="regexp:test($path,'^\.[a-zA-Z0-9_]+')">
+ <xsl:when test="regexp:test($path,'^\.[a-zA-Z0-9_]+$')">
<xsl:attribute name="type">
<xsl:text>PAGE_LOCAL</xsl:text>
</xsl:attribute>
</xsl:when>
- <xsl:when test="regexp:test($path,'^[a-zA-Z0-9_]+')">
+ <xsl:when test="regexp:test($path,'^[a-zA-Z0-9_]+$')">
<xsl:attribute name="type">
<xsl:text>HMI_LOCAL</xsl:text>
</xsl:attribute>
@@ -233,6 +233,10 @@
</xsl:if>
</xsl:template>
<xsl:variable name="_parsed_widgets">
+ <widget type="VarInitPersistent">
+ <arg value="0"/>
+ <path value="lang"/>
+ </widget>
<xsl:apply-templates mode="parselabel" select="$hmi_elements"/>
</xsl:variable>
<xsl:variable name="parsed_widgets" select="exsl:node-set($_parsed_widgets)"/>
@@ -972,7 +976,9 @@
<xsl:variable name="translations" select="ns:GetTranslations($translatable_strings)"/>
<xsl:text>var langs = [</xsl:text>
<xsl:for-each select="$translations/langs/lang">
+ <xsl:text>"</xsl:text>
<xsl:value-of select="."/>
+ <xsl:text>"</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
@@ -983,9 +989,18 @@
</xsl:text>
<xsl:for-each select="$translatable_texts">
<xsl:variable name="n" select="position()"/>
- <xsl:text> ["</xsl:text>
- <xsl:value-of select="@id"/>
- <xsl:text>",[</xsl:text>
+ <xsl:variable name="current_id" select="@id"/>
+ <xsl:variable name="text_unlinked_uses" select="$result_svg_ns//svg:text[@original = $current_id]/@id"/>
+ <xsl:text> [[</xsl:text>
+ <xsl:for-each select="@id | $text_unlinked_uses">
+ <xsl:text>id("</xsl:text>
+ <xsl:value-of select="."/>
+ <xsl:text>")</xsl:text>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>],[</xsl:text>
<xsl:for-each select="$translations/messages/msgid[$n]/msg">
<xsl:text>"</xsl:text>
<xsl:for-each select="line">
@@ -1126,11 +1141,13 @@
</xsl:text>
<xsl:text>var next_available_index = hmitree_types.length;
</xsl:text>
+ <xsl:text>let cookies = new Map(document.cookie.split("; ").map(s=>s.split("=")));
+</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>const local_defaults = {
</xsl:text>
- <xsl:for-each select="$parsed_widgets/widget[@type = 'VarInit']">
+ <xsl:for-each select="$parsed_widgets/widget[starts-with(@type,'VarInit')]">
<xsl:if test="count(path) != 1">
<xsl:message terminate="yes">
<xsl:text>VarInit </xsl:text>
@@ -1145,17 +1162,47 @@
<xsl:text> only applies to HMI variable.</xsl:text>
</xsl:message>
</xsl:if>
- <xsl:text>"</xsl:text>
+ <xsl:text> "</xsl:text>
<xsl:value-of select="path/@value"/>
<xsl:text>":</xsl:text>
- <xsl:value-of select="arg[1]/@value"/>
+ <xsl:choose>
+ <xsl:when test="@type = 'VarInitPersistent'">
+ <xsl:text>cookies.has("</xsl:text>
+ <xsl:value-of select="path/@value"/>
+ <xsl:text>")?cookies.get("</xsl:text>
+ <xsl:value-of select="path/@value"/>
+ <xsl:text>"):</xsl:text>
+ <xsl:value-of select="arg[1]/@value"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="arg[1]/@value"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>
+</xsl:text>
+ <xsl:if test="position()!=last()">
+ <xsl:text>,</xsl:text>
+ </xsl:if>
+ </xsl:for-each>
+ <xsl:text>};
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>const persistent_locals = new Set([
+</xsl:text>
+ <xsl:for-each select="$parsed_widgets/widget[@type='VarInitPersistent']">
+ <xsl:text> "</xsl:text>
+ <xsl:value-of select="path/@value"/>
+ <xsl:text>"</xsl:text>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
<xsl:text>
</xsl:text>
</xsl:for-each>
- <xsl:text>};
+ <xsl:text>]);
+</xsl:text>
+ <xsl:text>var persistent_indexes = new Map();
</xsl:text>
<xsl:text>var cache = hmitree_types.map(_ignored => undefined);
</xsl:text>
@@ -1193,10 +1240,16 @@
</xsl:text>
<xsl:text> let defaultval = local_defaults[varname];
</xsl:text>
- <xsl:text> if(defaultval != undefined)
+ <xsl:text> if(defaultval != undefined) {
</xsl:text>
<xsl:text> cache[new_index] = defaultval;
</xsl:text>
+ <xsl:text> if(persistent_locals.has(varname))
+</xsl:text>
+ <xsl:text> persistent_indexes.set(new_index, varname);
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
<xsl:text> return new_index;
</xsl:text>
<xsl:text>}
@@ -1506,12 +1559,32 @@
</xsl:text>
<xsl:text> }
</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text> activate_activable(eltsub) {
+</xsl:text>
+ <xsl:text> eltsub.inactive.style.display = "none";
+</xsl:text>
+ <xsl:text> eltsub.active.style.display = "";
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text> inactivate_activable(eltsub) {
+</xsl:text>
+ <xsl:text> eltsub.active.style.display = "none";
+</xsl:text>
+ <xsl:text> eltsub.inactive.style.display = "";
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
<xsl:text>}
</xsl:text>
<xsl:text>
</xsl:text>
</xsl:template>
- <xsl:variable name="excluded_types" select="str:split('Page VarInit')"/>
+ <xsl:variable name="excluded_types" select="str:split('Page VarInit VarInitPersistent')"/>
<xsl:key name="TypesKey" match="widget" use="@type"/>
<declarations:hmi-classes/>
<xsl:template match="declarations:hmi-classes">
@@ -3825,6 +3898,8 @@
</xsl:text>
<xsl:text> highlight_selection(){
</xsl:text>
+ <xsl:text> if(this.last_selection == undefined) return;
+</xsl:text>
<xsl:text> let highlighted_row = this.last_selection - this.menu_offset;
</xsl:text>
<xsl:text> if(highlighted_row < 0) return;
@@ -5123,7 +5198,7 @@
</xsl:text>
<xsl:text> this._shift = this.shift;
</xsl:text>
- <xsl:text> (this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
+ <xsl:text> (this.shift?this.activate_activable:this.inactivate_activable)(this.Shift_sub);
</xsl:text>
<xsl:text> }
</xsl:text>
@@ -5131,7 +5206,7 @@
</xsl:text>
<xsl:text> this._caps = this.caps;
</xsl:text>
- <xsl:text> (this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
+ <xsl:text> (this.caps?this.activate_activable:this.inactivate_activable)(this.CapsLock_sub);
</xsl:text>
<xsl:text> }
</xsl:text>
@@ -6734,6 +6809,72 @@
</xsl:text>
<xsl:text>
</xsl:text>
+ <xsl:text>var translated = false;
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>function switch_langnum(langnum) {
+</xsl:text>
+ <xsl:text> if(langnum == current_lang) {
+</xsl:text>
+ <xsl:text> return;
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text> if (!translated) {
+</xsl:text>
+ <xsl:text> translated = true;
+</xsl:text>
+ <xsl:text> for (let translation of translations) {
+</xsl:text>
+ <xsl:text> let [objs] = translation;
+</xsl:text>
+ <xsl:text> translation.push(Array.prototype.map.call(objs[0].children, x=>x.textContent).join("\n"));
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text> for (let translation of translations) {
+</xsl:text>
+ <xsl:text> let [objs, msgs, orig] = translation;
+</xsl:text>
+ <xsl:text> let msg = langnum == 0 ? orig : msgs[langnum - 1];
+</xsl:text>
+ <xsl:text> for (let obj of objs) {
+</xsl:text>
+ <xsl:text> msg.split('\n').map((line,i) => {obj.children[i].textContent = line;});
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text> current_lang = langnum;
+</xsl:text>
+ <xsl:text>}
+</xsl:text>
+ <xsl:text>var lang_local_index = hmi_local_index("lang");
+</xsl:text>
+ <xsl:text>subscribers(lang_local_index).add({
+</xsl:text>
+ <xsl:text> indexes: [lang_local_index],
+</xsl:text>
+ <xsl:text> new_hmi_value: function(index, value, oldval) {
+</xsl:text>
+ <xsl:text> switch_langnum(value);
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text>});
+</xsl:text>
+ <xsl:text>var current_lang = 0;
+</xsl:text>
+ <xsl:text>switch_langnum(cache[lang_local_index]);
+</xsl:text>
<xsl:text>
</xsl:text>
<xsl:text>function update_subscriptions() {
@@ -6812,6 +6953,22 @@
</xsl:text>
<xsl:text> updates[index] = value;
</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text> if(persistent_indexes.has(index)){
+</xsl:text>
+ <xsl:text> let varname = persistent_indexes.get(index);
+</xsl:text>
+ <xsl:text> console.log(varname+"="+value+"; max-age=3153600000");
+</xsl:text>
+ <xsl:text> document.cookie = varname+"="+value+"; max-age=3153600000";
+</xsl:text>
+ <xsl:text> }
+</xsl:text>
+ <xsl:text>
+</xsl:text>
+ <xsl:text>
+</xsl:text>
<xsl:text> requestHMIAnimation();
</xsl:text>
<xsl:text> return;
@@ -6930,28 +7087,6 @@
</xsl:text>
<xsl:text>
</xsl:text>
- <xsl:text>/*
-</xsl:text>
- <xsl:text>function change_hmi_value(index, opstr) {
-</xsl:text>
- <xsl:text> let old_val = cache[index];
-</xsl:text>
- <xsl:text> let new_val = eval_operation_string(old_val, opstr);
-</xsl:text>
- <xsl:text> if(new_val != undefined && old_val != new_val)
-</xsl:text>
- <xsl:text> send_hmi_value(index, new_val);
-</xsl:text>
- <xsl:text> // TODO else raise
-</xsl:text>
- <xsl:text> return new_val;
-</xsl:text>
- <xsl:text>}
-</xsl:text>
- <xsl:text>*/
-</xsl:text>
- <xsl:text>
-</xsl:text>
<xsl:text>var current_visible_page;
</xsl:text>
<xsl:text>var current_subscribed_page;
@@ -7256,34 +7391,6 @@
</xsl:text>
<xsl:text>
</xsl:text>
- <xsl:text>function widget_active_activable(eltsub) {
-</xsl:text>
- <xsl:text> if(eltsub.inactive_style === undefined)
-</xsl:text>
- <xsl:text> eltsub.inactive_style = eltsub.inactive.getAttribute("style");
-</xsl:text>
- <xsl:text> eltsub.inactive.setAttribute("style", "display:none");
-</xsl:text>
- <xsl:text> if(eltsub.active_style !== undefined)
-</xsl:text>
- <xsl:text> eltsub.active.setAttribute("style", eltsub.active_style);
-</xsl:text>
- <xsl:text>};
-</xsl:text>
- <xsl:text>function widget_inactive_activable(eltsub) {
-</xsl:text>
- <xsl:text> if(eltsub.active_style === undefined)
-</xsl:text>
- <xsl:text> eltsub.active_style = eltsub.active.getAttribute("style");
-</xsl:text>
- <xsl:text> eltsub.active.setAttribute("style", "display:none");
-</xsl:text>
- <xsl:text> if(eltsub.inactive_style !== undefined)
-</xsl:text>
- <xsl:text> eltsub.inactive.setAttribute("style", eltsub.inactive_style);
-</xsl:text>
- <xsl:text>};
-</xsl:text>
</script>
</body>
</html>
--- a/svghmi/svghmi.js Tue Feb 09 07:41:24 2021 +0100
+++ b/svghmi/svghmi.js Tue Feb 09 07:46:02 2021 +0100
@@ -243,6 +243,13 @@
function send_hmi_value(index, value) {
if(index > last_remote_index){
updates[index] = value;
+
+ if(persistent_indexes.has(index)){
+ let varname = persistent_indexes.get(index);
+ console.log(varname+"="+value+"; max-age=3153600000");
+ document.cookie = varname+"="+value+"; max-age=3153600000";
+ }
+
requestHMIAnimation();
return;
}
--- a/svghmi/widgets_common.ysl2 Tue Feb 09 07:41:24 2021 +0100
+++ b/svghmi/widgets_common.ysl2 Tue Feb 09 07:46:02 2021 +0100
@@ -68,16 +68,32 @@
let hmi_locals = {};
var last_remote_index = hmitree_types.length - 1;
var next_available_index = hmitree_types.length;
+ let cookies = new Map(document.cookie.split("; ").map(s=>s.split("=")));
const local_defaults = {
||
- foreach "$parsed_widgets/widget[@type = 'VarInit']"{
+ foreach "$parsed_widgets/widget[starts-with(@type,'VarInit')]"{
if "count(path) != 1" error > VarInit «@id» must have only one variable given.
if "path/@type != 'PAGE_LOCAL' and path/@type != 'HMI_LOCAL'" error > VarInit «@id» only applies to HMI variable.
- | "«path/@value»":«arg[1]/@value»`if "position()!=last()" > ,`
+ > "«path/@value»":
+ choose {
+ when "@type = 'VarInitPersistent'" > cookies.has("«path/@value»")?cookies.get("«path/@value»"):«arg[1]/@value»
+ otherwise > «arg[1]/@value»
+ }
+ > \n
+ if "position()!=last()" > ,
}
||
};
+
+ const persistent_locals = new Set([
+ ||
+ foreach "$parsed_widgets/widget[@type='VarInitPersistent']"{
+ | "«path/@value»"`if "position()!=last()" > ,`
+ }
+ ||
+ ]);
+ var persistent_indexes = new Map();
var cache = hmitree_types.map(_ignored => undefined);
function page_local_index(varname, pagename){
@@ -96,8 +112,11 @@
pagevars[varname] = new_index;
}
let defaultval = local_defaults[varname];
- if(defaultval != undefined)
+ if(defaultval != undefined) {
cache[new_index] = defaultval;
+ if(persistent_locals.has(varname))
+ persistent_indexes.set(new_index, varname);
+ }
return new_index;
}
@@ -265,7 +284,7 @@
||
}
-const "excluded_types", "str:split('Page VarInit')";
+const "excluded_types", "str:split('Page VarInit VarInitPersistent')";
// Key to filter unique types
key "TypesKey", "widget", "@type";