# HG changeset patch
# User Edouard Tisserant
# Date 1585054999 -3600
# Node ID 89c02b452717ff9c6d847d3aea16c33702836e6e
# Parent 4cf9ad35e6d0151217a9b130b0e141f774838fdd
SVGHMI: ForEach now has working (un)subscribe. Fixed PageSwitch that wasn't behaving when jumping to current page with another path.
diff -r 4cf9ad35e6d0 -r 89c02b452717 svghmi/gen_index_xhtml.xslt
--- a/svghmi/gen_index_xhtml.xslt Mon Mar 23 21:44:28 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt Tue Mar 24 14:03:19 2020 +0100
@@ -747,9 +747,7 @@
'].on_click(evt)");*/
- },
-
- items: [
+ this.items = [
@@ -758,7 +756,7 @@
- [ /* item="
+ [ /* item="
" path="
@@ -786,7 +784,7 @@
.
- hmi_widgets["
+ hmi_widgets["
"]
@@ -795,26 +793,30 @@
- ]
+ ]
,
- ],
+ ]
+
+ },
+
+ item_offset: 0,
sub: function(off){
- /*subscribe.call(this,off);*/
+ subscribe_foreach.call(this,off);
},
unsub: function(){
- /*unsubscribe.call(this);*/
+ unsubscribe_foreach.call(this);
},
@@ -1315,6 +1317,14 @@
}
+
+
+ if(current_subscribed_page_index != current_visible_page_index){
+
+ apply_cache();
+
+ }
+
apply_updates();
requestAnimationFrameID = null;
@@ -1649,6 +1659,10 @@
var current_subscribed_page;
+ var current_visible_page_index;
+
+ var current_subscribed_page_index;
+
function prepare_svg() {
@@ -1675,9 +1689,117 @@
return;
- } else if(page_name == current_visible_page){
-
- /* already in that page */
+ }
+
+
+
+ if(page_name == undefined)
+
+ page_name = current_subscribed_page;
+
+
+
+ switch_subscribed_page(page_name, page_index);
+
+ };
+
+
+
+ function* chain(a,b){
+
+ yield* a;
+
+ yield* b;
+
+ };
+
+
+
+ function unsubscribe(){
+
+ /* remove subsribers */
+
+ for(let index of this.indexes){
+
+ let idx = index + this.offset;
+
+ subscribers[idx].delete(this);
+
+ }
+
+ this.offset = 0;
+
+ }
+
+
+
+ function subscribe(new_offset=0){
+
+ /* set the offset because relative */
+
+ this.offset = new_offset;
+
+ /* add this's subsribers */
+
+ for(let index of this.indexes){
+
+ subscribers[index + new_offset].add(this);
+
+ }
+
+ }
+
+
+
+ function unsubscribe_foreach(){
+
+ for(let item of this.items){
+
+ for(let widget of item) {
+
+ unsubscribe.call(widget);
+
+ }
+
+ }
+
+ }
+
+
+
+ function subscribe_foreach(new_offset=0){
+
+ for(let i = 0; i < this.items.length; i++) {
+
+ let item = this.items[i];
+
+ let orig_item_index = this.index_pool[i];
+
+ let item_index = this.index_pool[i+this.item_offset];
+
+ let item_index_offset = item_index - orig_item_index;
+
+ for(let widget of item) {
+
+ subscribe.call(widget,new_offset + item_index_offset);
+
+ }
+
+ }
+
+ }
+
+
+
+ function switch_subscribed_page(page_name, page_index) {
+
+ let old_desc = page_desc[current_subscribed_page];
+
+ let new_desc = page_desc[page_name];
+
+
+
+ if(new_desc == undefined){
/* TODO LOG ERROR */
@@ -1685,229 +1807,171 @@
}
- switch_subscribed_page(page_name, page_index);
+
+
+ if(page_index == undefined){
+
+ page_index = new_desc.page_index;
+
+ }
+
+
+
+ if(old_desc){
+
+ old_desc.absolute_widgets.map(w=>w.unsub());
+
+ old_desc.relative_widgets.map(w=>w.unsub());
+
+ }
+
+ new_desc.absolute_widgets.map(w=>w.sub());
+
+ var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index;
+
+ new_desc.relative_widgets.map(w=>w.sub(new_offset));
+
+
+
+ update_subscriptions();
+
+
+
+ current_subscribed_page = page_name;
+
+ current_subscribed_page_index = page_index;
+
+
+
+ requestHMIAnimation();
+
+ }
+
+
+
+ function switch_visible_page(page_name) {
+
+
+
+ let old_desc = page_desc[current_visible_page];
+
+ let new_desc = page_desc[page_name];
+
+
+
+ if(old_desc){
+
+ for(let eltid in old_desc.required_detachables){
+
+ if(!(eltid in new_desc.required_detachables)){
+
+ let [element, parent] = old_desc.required_detachables[eltid];
+
+ parent.removeChild(element);
+
+ }
+
+ }
+
+ for(let eltid in new_desc.required_detachables){
+
+ if(!(eltid in old_desc.required_detachables)){
+
+ let [element, parent] = new_desc.required_detachables[eltid];
+
+ parent.appendChild(element);
+
+ }
+
+ }
+
+ }else{
+
+ for(let eltid in new_desc.required_detachables){
+
+ let [element, parent] = new_desc.required_detachables[eltid];
+
+ parent.appendChild(element);
+
+ }
+
+ }
+
+
+
+ svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
+
+ current_visible_page = page_name;
};
-
-
- function* chain(a,b){
-
- yield* a;
-
- yield* b;
+
+
+ function apply_cache() {
+
+ let new_desc = page_desc[current_visible_page];
+
+ for(let widget of chain(new_desc.absolute_widgets,new_desc.relative_widgets)){
+
+ for(let index of widget.indexes){
+
+ /* dispatch current cache in newly opened page widgets */
+
+ let realindex = index+widget.offset;
+
+ let cached_val = cache[realindex];
+
+ if(cached_val != undefined)
+
+ dispatch_value_to_widget(widget, realindex, cached_val, cached_val);
+
+ }
+
+ }
+
+ current_visible_page_index = current_subscribed_page_index;
+
+ }
+
+
+
+
+
+
+
+ // Once connection established
+
+ ws.onopen = function (evt) {
+
+ init_widgets();
+
+ send_reset();
+
+ // show main page
+
+ prepare_svg();
+
+ switch_page(default_page);
};
- function unsubscribe(){
-
- widget = this;
-
- /* remove subsribers */
-
- for(let index of widget.indexes){
-
- let idx = index + widget.offset;
-
- subscribers[idx].delete(widget);
-
- }
-
- widget.offset = 0;
-
- }
-
-
-
- function subscribe(new_offset=0){
-
- widget = this;
-
- /* set the offset because relative */
-
- widget.offset = new_offset;
-
- /* add widget's subsribers */
-
- for(let index of widget.indexes){
-
- subscribers[index + new_offset].add(widget);
-
- }
-
- }
-
-
-
- function switch_subscribed_page(page_name, page_index) {
-
- let old_desc = page_desc[current_subscribed_page];
-
- let new_desc = page_desc[page_name];
-
-
-
- if(new_desc == undefined){
-
- /* TODO LOG ERROR */
-
- return;
-
- }
-
-
-
- if(page_index == undefined){
-
- page_index = new_desc.page_index;
-
- }
-
-
-
- if(old_desc){
-
- old_desc.absolute_widgets.map(w=>w.unsub());
-
- old_desc.relative_widgets.map(w=>w.unsub());
-
- }
-
- new_desc.absolute_widgets.map(w=>w.sub());
-
- var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index;
-
- new_desc.relative_widgets.map(w=>w.sub(new_offset));
-
-
-
- update_subscriptions();
-
-
-
- current_subscribed_page = page_name;
-
-
-
- requestHMIAnimation();
-
- }
-
-
-
- function switch_visible_page(page_name) {
-
-
-
- let old_desc = page_desc[current_visible_page];
-
- let new_desc = page_desc[page_name];
-
-
-
- if(old_desc){
-
- for(let eltid in old_desc.required_detachables){
-
- if(!(eltid in new_desc.required_detachables)){
-
- let [element, parent] = old_desc.required_detachables[eltid];
-
- parent.removeChild(element);
-
- }
-
- }
-
- for(let eltid in new_desc.required_detachables){
-
- if(!(eltid in old_desc.required_detachables)){
-
- let [element, parent] = new_desc.required_detachables[eltid];
-
- parent.appendChild(element);
-
- }
-
- }
-
- }else{
-
- for(let eltid in new_desc.required_detachables){
-
- let [element, parent] = new_desc.required_detachables[eltid];
-
- parent.appendChild(element);
-
- }
-
- }
-
-
-
- for(let widget of chain(new_desc.absolute_widgets,new_desc.relative_widgets)){
-
- for(let index of widget.indexes){
-
- /* dispatch current cache in newly opened page widgets */
-
- let cached_val = cache[index];
-
- if(cached_val != undefined)
-
- dispatch_value_to_widget(widget, index, cached_val, cached_val);
-
- }
-
- }
-
-
-
- svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
-
- current_visible_page = page_name;
+ ws.onclose = function (evt) {
+
+ // TODO : add visible notification while waiting for reload
+
+ console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s.");
+
+ // TODO : re-enable auto reload when not in debug
+
+ //window.setTimeout(() => location.reload(true), 10000);
+
+ alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+".");
+
+
};
-
-
-
-
- // Once connection established
-
- ws.onopen = function (evt) {
-
- init_widgets();
-
- send_reset();
-
- // show main page
-
- prepare_svg();
-
- switch_page(default_page);
-
- };
-
-
-
- ws.onclose = function (evt) {
-
- // TODO : add visible notification while waiting for reload
-
- console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s.");
-
- // TODO : re-enable auto reload when not in debug
-
- //window.setTimeout(() => location.reload(true), 10000);
-
- alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+".");
-
-
-
- };
-
diff -r 4cf9ad35e6d0 -r 89c02b452717 svghmi/svghmi.js
--- a/svghmi/svghmi.js Mon Mar 23 21:44:28 2020 +0100
+++ b/svghmi/svghmi.js Tue Mar 24 14:03:19 2020 +0100
@@ -86,6 +86,10 @@
if(current_subscribed_page != current_visible_page){
switch_visible_page(current_subscribed_page);
}
+
+ if(current_subscribed_page_index != current_visible_page_index){
+ apply_cache();
+ }
apply_updates();
requestAnimationFrameID = null;
}
@@ -253,6 +257,8 @@
var current_visible_page;
var current_subscribed_page;
+var current_visible_page_index;
+var current_subscribed_page_index;
function prepare_svg() {
for(let eltid in detachable_elements){
@@ -266,11 +272,11 @@
/* page switch already going */
/* TODO LOG ERROR */
return;
- } else if(page_name == current_visible_page){
- /* already in that page */
- /* TODO LOG ERROR */
- return;
- }
+ }
+
+ if(page_name == undefined)
+ page_name = current_subscribed_page;
+
switch_subscribed_page(page_name, page_index);
};
@@ -280,22 +286,40 @@
};
function unsubscribe(){
- widget = this;
/* remove subsribers */
- for(let index of widget.indexes){
- let idx = index + widget.offset;
- subscribers[idx].delete(widget);
- }
- widget.offset = 0;
+ for(let index of this.indexes){
+ let idx = index + this.offset;
+ subscribers[idx].delete(this);
+ }
+ this.offset = 0;
}
function subscribe(new_offset=0){
- widget = this;
/* set the offset because relative */
- widget.offset = new_offset;
- /* add widget's subsribers */
- for(let index of widget.indexes){
- subscribers[index + new_offset].add(widget);
+ this.offset = new_offset;
+ /* add this's subsribers */
+ for(let index of this.indexes){
+ subscribers[index + new_offset].add(this);
+ }
+}
+
+function unsubscribe_foreach(){
+ for(let item of this.items){
+ for(let widget of item) {
+ unsubscribe.call(widget);
+ }
+ }
+}
+
+function subscribe_foreach(new_offset=0){
+ for(let i = 0; i < this.items.length; i++) {
+ let item = this.items[i];
+ let orig_item_index = this.index_pool[i];
+ let item_index = this.index_pool[i+this.item_offset];
+ let item_index_offset = item_index - orig_item_index;
+ for(let widget of item) {
+ subscribe.call(widget,new_offset + item_index_offset);
+ }
}
}
@@ -323,6 +347,7 @@
update_subscriptions();
current_subscribed_page = page_name;
+ current_subscribed_page_index = page_index;
requestHMIAnimation();
}
@@ -352,18 +377,24 @@
}
}
+ svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
+ current_visible_page = page_name;
+};
+
+function apply_cache() {
+ let new_desc = page_desc[current_visible_page];
for(let widget of chain(new_desc.absolute_widgets,new_desc.relative_widgets)){
for(let index of widget.indexes){
/* dispatch current cache in newly opened page widgets */
- let cached_val = cache[index];
+ let realindex = index+widget.offset;
+ let cached_val = cache[realindex];
if(cached_val != undefined)
- dispatch_value_to_widget(widget, index, cached_val, cached_val);
- }
- }
-
- svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
- current_visible_page = page_name;
-};
+ dispatch_value_to_widget(widget, realindex, cached_val, cached_val);
+ }
+ }
+ current_visible_page_index = current_subscribed_page_index;
+}
+
// Once connection established
diff -r 4cf9ad35e6d0 -r 89c02b452717 svghmi/widget_foreach.ysl2
--- a/svghmi/widget_foreach.ysl2 Mon Mar 23 21:44:28 2020 +0100
+++ b/svghmi/widget_foreach.ysl2 Tue Mar 24 14:03:19 2020 +0100
@@ -25,9 +25,8 @@
| ],
| init: function() {
| /* TODO elt.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_click(evt)");*/
- | },
- | items: [
+ | this.items = [
const "items_regex","concat('^',$prefix,'[0-9]+')";
const "unordered_items","$hmi_element//*[regexp:test(@inkscape:label, $items_regex)]";
foreach "$unordered_items" {
@@ -35,27 +34,27 @@
const "elt","$unordered_items[@inkscape:label = $elt_label]";
const "pos","position()";
const "item_path", "$items_paths[$pos]";
- | [ /* item="«$elt_label»" path="«$item_path»" */
+ | [ /* item="«$elt_label»" path="«$item_path»" */
if "count($elt)=0" error > Missing item labeled «$elt_label» in ForEach widget «$hmi_element/@id»
foreach "func:refered_elements($elt)[@id = $hmi_elements/@id][not(@id = $elt/@id)]" {
if "not(func:is_descendant_path(func:widget(@id)/path/@value, $item_path))"
error > Widget id="«@id»" label="«@inkscape:label»" is having wrong path. Accroding to ForEach widget ancestor id="«$hmi_element/@id»", path should be descendant of «$item_path».
- | hmi_widgets["«@id»"]`if "position()!=last()" > ,`
+ | hmi_widgets["«@id»"]`if "position()!=last()" > ,`
}
- | ]`if "position()!=last()" > ,`
+ | ]`if "position()!=last()" > ,`
}
- | ],
+ | ]
+ | },
+ | item_offset: 0,
}
template "widget[@type='ForEach']", mode="widget_subscribe"{
// param "hmi_element";
| sub: function(off){
- | /*subscribe.call(this,off);*/
- /* TODO */
+ | subscribe_foreach.call(this,off);
| },
| unsub: function(){
- | /*unsubscribe.call(this);*/
- /* TODO */
+ | unsubscribe_foreach.call(this);
| },
}