# HG changeset patch # User Edouard Tisserant # Date 1586246483 -7200 # Node ID 2670f5c53caf598e29a74c96bc71c8d56d263b82 # Parent 3ee337c8c7690e18d3802035be7a000dad05117f SVGHMI: HMI is not speculating on PLC variable update anymore when sending new variable value. HMI variable cache in JS was changed in advance for more responsive behaviour when updating a HMI tree variable. This was leading to display value different from hmi tree variable in case the expected update did not happen because PLC program did revert it. diff -r 3ee337c8c769 -r 2670f5c53caf svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Sat Apr 04 22:32:54 2020 +0200 +++ b/svghmi/gen_index_xhtml.xslt Tue Apr 07 10:01:23 2020 +0200 @@ -984,10 +984,6 @@ </xsl:text> <xsl:text> let new_val = change_hmi_value(this.indexes[0], opstr); </xsl:text> - <xsl:if test="$have_value"> - <xsl:text> this.value_elt.textContent = String(new_val); -</xsl:text> - </xsl:if> <xsl:text> }, </xsl:text> <xsl:text> on_edit_click: function(opstr) { @@ -1004,10 +1000,6 @@ </xsl:text> <xsl:text> apply_hmi_value(this.indexes[0], new_val); </xsl:text> - <xsl:if test="$have_value"> - <xsl:text> this.value_elt.textContent = String(new_val); -</xsl:text> - </xsl:if> <xsl:text> }, </xsl:text> </xsl:template> @@ -1567,6 +1559,7 @@ <xsl:comment> <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text> </xsl:comment> + <xsl:apply-templates mode="debug_as_comment" select="document('')/*/reflect:*"/> <html xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/1999/xhtml"> <head/> <body style="margin:0;overflow:hidden;"> @@ -2152,7 +2145,9 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text> cache[index] = value; + <xsl:text> // DON'T DO THAT unless read_iterator in svghmi.c modifies wbuf as well, not only rbuf +</xsl:text> + <xsl:text> // cache[index] = value; </xsl:text> <xsl:text>}; </xsl:text> @@ -2162,6 +2157,56 @@ </xsl:text> <xsl:text> let old_val = cache[index] </xsl:text> + <xsl:text> console.log("apply", index, new_val); +</xsl:text> + <xsl:text> if(new_val != undefined && old_val != new_val){ +</xsl:text> + <xsl:text> console.log("sending", new_val); +</xsl:text> + <xsl:text> send_hmi_value(index, new_val); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> return new_val; +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function change_hmi_value(index, opstr) { +</xsl:text> + <xsl:text> let op = opstr[0]; +</xsl:text> + <xsl:text> let given_val = opstr.slice(1); +</xsl:text> + <xsl:text> let old_val = cache[index] +</xsl:text> + <xsl:text> let new_val; +</xsl:text> + <xsl:text> switch(op){ +</xsl:text> + <xsl:text> case "=": +</xsl:text> + <xsl:text> eval("new_val"+opstr); +</xsl:text> + <xsl:text> break; +</xsl:text> + <xsl:text> case "+": +</xsl:text> + <xsl:text> case "-": +</xsl:text> + <xsl:text> case "*": +</xsl:text> + <xsl:text> case "/": +</xsl:text> + <xsl:text> if(old_val != undefined) +</xsl:text> + <xsl:text> new_val = eval("old_val"+opstr); +</xsl:text> + <xsl:text> break; +</xsl:text> + <xsl:text> } +</xsl:text> <xsl:text> if(new_val != undefined && old_val != new_val) </xsl:text> <xsl:text> send_hmi_value(index, new_val); @@ -2172,557 +2217,513 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text>function change_hmi_value(index, opstr) { -</xsl:text> - <xsl:text> let op = opstr[0]; -</xsl:text> - <xsl:text> let given_val = opstr.slice(1); -</xsl:text> - <xsl:text> let old_val = cache[index] -</xsl:text> - <xsl:text> let new_val; -</xsl:text> - <xsl:text> switch(op){ -</xsl:text> - <xsl:text> case "=": -</xsl:text> - <xsl:text> eval("new_val"+opstr); -</xsl:text> - <xsl:text> break; -</xsl:text> - <xsl:text> case "+": -</xsl:text> - <xsl:text> case "-": -</xsl:text> - <xsl:text> case "*": -</xsl:text> - <xsl:text> case "/": -</xsl:text> - <xsl:text> if(old_val != undefined) -</xsl:text> - <xsl:text> new_val = eval("old_val"+opstr); -</xsl:text> - <xsl:text> break; + <xsl:text>var current_visible_page; +</xsl:text> + <xsl:text>var current_subscribed_page; +</xsl:text> + <xsl:text>var current_page_index; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function prepare_svg() { +</xsl:text> + <xsl:text> for(let eltid in detachable_elements){ +</xsl:text> + <xsl:text> let [element,parent] = detachable_elements[eltid]; +</xsl:text> + <xsl:text> parent.removeChild(element); </xsl:text> <xsl:text> } </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> return new_val; + <xsl:text>}; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function switch_page(page_name, page_index) { +</xsl:text> + <xsl:text> if(current_subscribed_page != current_visible_page){ +</xsl:text> + <xsl:text> /* page switch already going */ +</xsl:text> + <xsl:text> /* TODO LOG ERROR */ +</xsl:text> + <xsl:text> return false; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(page_name == undefined) +</xsl:text> + <xsl:text> page_name = current_subscribed_page; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> let old_desc = page_desc[current_subscribed_page]; +</xsl:text> + <xsl:text> let new_desc = page_desc[page_name]; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(new_desc == undefined){ +</xsl:text> + <xsl:text> /* TODO LOG ERROR */ +</xsl:text> + <xsl:text> return false; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(page_index == undefined){ +</xsl:text> + <xsl:text> page_index = new_desc.page_index; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(old_desc){ +</xsl:text> + <xsl:text> old_desc.absolute_widgets.map(w=>w.unsub()); +</xsl:text> + <xsl:text> old_desc.relative_widgets.map(w=>w.unsub()); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> new_desc.absolute_widgets.map(w=>w.sub()); +</xsl:text> + <xsl:text> var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; +</xsl:text> + <xsl:text> new_desc.relative_widgets.map(w=>w.sub(new_offset)); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> update_subscriptions(); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> current_subscribed_page = page_name; +</xsl:text> + <xsl:text> current_page_index = page_index; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> jumps_need_update = true; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> requestHMIAnimation(); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> jump_history.push([page_name, page_index]); +</xsl:text> + <xsl:text> if(jump_history.length > 42) +</xsl:text> + <xsl:text> jump_history.shift(); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> return true; +</xsl:text> + <xsl:text>}; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function* chain(a,b){ +</xsl:text> + <xsl:text> yield* a; +</xsl:text> + <xsl:text> yield* b; +</xsl:text> + <xsl:text>}; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function unsubscribe(){ +</xsl:text> + <xsl:text> /* remove subsribers */ +</xsl:text> + <xsl:text> for(let index of this.indexes){ +</xsl:text> + <xsl:text> let idx = index + this.offset; +</xsl:text> + <xsl:text> subscribers[idx].delete(this); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> this.offset = 0; </xsl:text> <xsl:text>} </xsl:text> <xsl:text> </xsl:text> - <xsl:text>var current_visible_page; -</xsl:text> - <xsl:text>var current_subscribed_page; -</xsl:text> - <xsl:text>var current_page_index; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function prepare_svg() { -</xsl:text> - <xsl:text> for(let eltid in detachable_elements){ -</xsl:text> - <xsl:text> let [element,parent] = detachable_elements[eltid]; -</xsl:text> - <xsl:text> parent.removeChild(element); + <xsl:text>function subscribe(new_offset=0){ +</xsl:text> + <xsl:text> /* set the offset because relative */ +</xsl:text> + <xsl:text> this.offset = new_offset; +</xsl:text> + <xsl:text> /* add this's subsribers */ +</xsl:text> + <xsl:text> for(let index of this.indexes){ +</xsl:text> + <xsl:text> subscribers[index + new_offset].add(this); </xsl:text> <xsl:text> } </xsl:text> + <xsl:text> need_cache_apply.push(this); +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function foreach_unsubscribe(){ +</xsl:text> + <xsl:text> for(let item of this.items){ +</xsl:text> + <xsl:text> for(let widget of item) { +</xsl:text> + <xsl:text> unsubscribe.call(widget); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> this.offset = 0; +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function foreach_widgets_do(new_offset, todo){ +</xsl:text> + <xsl:text> this.offset = new_offset; +</xsl:text> + <xsl:text> for(let i = 0; i < this.items.length; i++) { +</xsl:text> + <xsl:text> let item = this.items[i]; +</xsl:text> + <xsl:text> let orig_item_index = this.index_pool[i]; +</xsl:text> + <xsl:text> let item_index = this.index_pool[i+this.item_offset]; +</xsl:text> + <xsl:text> let item_index_offset = item_index - orig_item_index; +</xsl:text> + <xsl:text> for(let widget of item) { +</xsl:text> + <xsl:text> todo.call(widget, new_offset + item_index_offset); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function foreach_subscribe(new_offset=0){ +</xsl:text> + <xsl:text> foreach_widgets_do.call(this, new_offset, subscribe); +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function widget_apply_cache() { +</xsl:text> + <xsl:text> for(let index of this.indexes){ +</xsl:text> + <xsl:text> /* dispatch current cache in newly opened page widgets */ +</xsl:text> + <xsl:text> let realindex = index+this.offset; +</xsl:text> + <xsl:text> let cached_val = cache[realindex]; +</xsl:text> + <xsl:text> if(cached_val != undefined) +</xsl:text> + <xsl:text> dispatch_value_to_widget(this, realindex, cached_val, cached_val); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function foreach_apply_cache() { +</xsl:text> + <xsl:text> foreach_widgets_do.call(this, this.offset, widget_apply_cache); +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function foreach_onclick(opstr, evt) { +</xsl:text> + <xsl:text> new_item_offset = eval(String(this.item_offset)+opstr) +</xsl:text> + <xsl:text> if(new_item_offset + this.items.length > this.index_pool.length) { +</xsl:text> + <xsl:text> if(this.item_offset + this.items.length == this.index_pool.length) +</xsl:text> + <xsl:text> new_item_offset = 0; +</xsl:text> + <xsl:text> else +</xsl:text> + <xsl:text> new_item_offset = this.index_pool.length - this.items.length; +</xsl:text> + <xsl:text> } else if(new_item_offset < 0) { +</xsl:text> + <xsl:text> if(this.item_offset == 0) +</xsl:text> + <xsl:text> new_item_offset = this.index_pool.length - this.items.length; +</xsl:text> + <xsl:text> else +</xsl:text> + <xsl:text> new_item_offset = 0; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> this.item_offset = new_item_offset; +</xsl:text> + <xsl:text> off = this.offset; +</xsl:text> + <xsl:text> foreach_unsubscribe.call(this); +</xsl:text> + <xsl:text> foreach_subscribe.call(this,off); +</xsl:text> + <xsl:text> update_subscriptions(); +</xsl:text> + <xsl:text> need_cache_apply.push(this); +</xsl:text> + <xsl:text> jumps_need_update = true; +</xsl:text> + <xsl:text> requestHMIAnimation(); +</xsl:text> + <xsl:text>} +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function switch_visible_page(page_name) { +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> let old_desc = page_desc[current_visible_page]; +</xsl:text> + <xsl:text> let new_desc = page_desc[page_name]; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(old_desc){ +</xsl:text> + <xsl:text> for(let eltid in old_desc.required_detachables){ +</xsl:text> + <xsl:text> if(!(eltid in new_desc.required_detachables)){ +</xsl:text> + <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; +</xsl:text> + <xsl:text> parent.removeChild(element); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> for(let eltid in new_desc.required_detachables){ +</xsl:text> + <xsl:text> if(!(eltid in old_desc.required_detachables)){ +</xsl:text> + <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; +</xsl:text> + <xsl:text> parent.appendChild(element); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> }else{ +</xsl:text> + <xsl:text> for(let eltid in new_desc.required_detachables){ +</xsl:text> + <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; +</xsl:text> + <xsl:text> parent.appendChild(element); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); +</xsl:text> + <xsl:text> current_visible_page = page_name; +</xsl:text> <xsl:text>}; </xsl:text> <xsl:text> </xsl:text> - <xsl:text>function switch_page(page_name, page_index) { -</xsl:text> - <xsl:text> if(current_subscribed_page != current_visible_page){ -</xsl:text> - <xsl:text> /* page switch already going */ -</xsl:text> - <xsl:text> /* TODO LOG ERROR */ -</xsl:text> - <xsl:text> return false; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> if(page_name == undefined) -</xsl:text> - <xsl:text> page_name = current_subscribed_page; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> let old_desc = page_desc[current_subscribed_page]; -</xsl:text> - <xsl:text> let new_desc = page_desc[page_name]; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> if(new_desc == undefined){ -</xsl:text> - <xsl:text> /* TODO LOG ERROR */ -</xsl:text> - <xsl:text> return false; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> if(page_index == undefined){ -</xsl:text> - <xsl:text> page_index = new_desc.page_index; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> if(old_desc){ -</xsl:text> - <xsl:text> old_desc.absolute_widgets.map(w=>w.unsub()); -</xsl:text> - <xsl:text> old_desc.relative_widgets.map(w=>w.unsub()); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> new_desc.absolute_widgets.map(w=>w.sub()); -</xsl:text> - <xsl:text> var new_offset = page_index == undefined ? 0 : page_index - new_desc.page_index; -</xsl:text> - <xsl:text> new_desc.relative_widgets.map(w=>w.sub(new_offset)); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> update_subscriptions(); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> current_subscribed_page = page_name; -</xsl:text> - <xsl:text> current_page_index = page_index; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> jumps_need_update = true; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> requestHMIAnimation(); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> jump_history.push([page_name, page_index]); -</xsl:text> - <xsl:text> if(jump_history.length > 42) -</xsl:text> - <xsl:text> jump_history.shift(); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> return true; + <xsl:text>function update_jumps() { +</xsl:text> + <xsl:text> page_desc[current_visible_page].jumps.map(w=>w.notify_page_change(current_visible_page,current_page_index)); +</xsl:text> + <xsl:text> jumps_need_update = false; </xsl:text> <xsl:text>}; </xsl:text> <xsl:text> </xsl:text> - <xsl:text>function* chain(a,b){ -</xsl:text> - <xsl:text> yield* a; -</xsl:text> - <xsl:text> yield* b; + <xsl:text> +</xsl:text> + <xsl:text>// Once connection established +</xsl:text> + <xsl:text>ws.onopen = function (evt) { +</xsl:text> + <xsl:text> init_widgets(); +</xsl:text> + <xsl:text> send_reset(); +</xsl:text> + <xsl:text> // show main page +</xsl:text> + <xsl:text> prepare_svg(); +</xsl:text> + <xsl:text> switch_page(default_page); </xsl:text> <xsl:text>}; </xsl:text> <xsl:text> </xsl:text> - <xsl:text>function unsubscribe(){ -</xsl:text> - <xsl:text> /* remove subsribers */ -</xsl:text> - <xsl:text> for(let index of this.indexes){ -</xsl:text> - <xsl:text> let idx = index + this.offset; -</xsl:text> - <xsl:text> subscribers[idx].delete(this); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> this.offset = 0; -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function subscribe(new_offset=0){ -</xsl:text> - <xsl:text> /* set the offset because relative */ -</xsl:text> - <xsl:text> this.offset = new_offset; -</xsl:text> - <xsl:text> /* add this's subsribers */ -</xsl:text> - <xsl:text> for(let index of this.indexes){ -</xsl:text> - <xsl:text> subscribers[index + new_offset].add(this); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> need_cache_apply.push(this); -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function foreach_unsubscribe(){ -</xsl:text> - <xsl:text> for(let item of this.items){ -</xsl:text> - <xsl:text> for(let widget of item) { -</xsl:text> - <xsl:text> unsubscribe.call(widget); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> this.offset = 0; -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function foreach_widgets_do(new_offset, todo){ -</xsl:text> - <xsl:text> this.offset = new_offset; -</xsl:text> - <xsl:text> for(let i = 0; i < this.items.length; i++) { -</xsl:text> - <xsl:text> let item = this.items[i]; -</xsl:text> - <xsl:text> let orig_item_index = this.index_pool[i]; -</xsl:text> - <xsl:text> let item_index = this.index_pool[i+this.item_offset]; -</xsl:text> - <xsl:text> let item_index_offset = item_index - orig_item_index; -</xsl:text> - <xsl:text> for(let widget of item) { -</xsl:text> - <xsl:text> todo.call(widget, new_offset + item_index_offset); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function foreach_subscribe(new_offset=0){ -</xsl:text> - <xsl:text> foreach_widgets_do.call(this, new_offset, subscribe); -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function widget_apply_cache() { -</xsl:text> - <xsl:text> for(let index of this.indexes){ -</xsl:text> - <xsl:text> /* dispatch current cache in newly opened page widgets */ -</xsl:text> - <xsl:text> let realindex = index+this.offset; -</xsl:text> - <xsl:text> let cached_val = cache[realindex]; -</xsl:text> - <xsl:text> if(cached_val != undefined) -</xsl:text> - <xsl:text> dispatch_value_to_widget(this, realindex, cached_val, cached_val); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function foreach_apply_cache() { -</xsl:text> - <xsl:text> foreach_widgets_do.call(this, this.offset, widget_apply_cache); -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function foreach_onclick(opstr, evt) { -</xsl:text> - <xsl:text> new_item_offset = eval(String(this.item_offset)+opstr) -</xsl:text> - <xsl:text> if(new_item_offset + this.items.length > this.index_pool.length) { -</xsl:text> - <xsl:text> if(this.item_offset + this.items.length == this.index_pool.length) -</xsl:text> - <xsl:text> new_item_offset = 0; -</xsl:text> - <xsl:text> else -</xsl:text> - <xsl:text> new_item_offset = this.index_pool.length - this.items.length; -</xsl:text> - <xsl:text> } else if(new_item_offset < 0) { -</xsl:text> - <xsl:text> if(this.item_offset == 0) -</xsl:text> - <xsl:text> new_item_offset = this.index_pool.length - this.items.length; -</xsl:text> - <xsl:text> else -</xsl:text> - <xsl:text> new_item_offset = 0; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> this.item_offset = new_item_offset; -</xsl:text> - <xsl:text> off = this.offset; -</xsl:text> - <xsl:text> foreach_unsubscribe.call(this); -</xsl:text> - <xsl:text> foreach_subscribe.call(this,off); -</xsl:text> - <xsl:text> update_subscriptions(); -</xsl:text> - <xsl:text> need_cache_apply.push(this); -</xsl:text> - <xsl:text> jumps_need_update = true; -</xsl:text> - <xsl:text> requestHMIAnimation(); -</xsl:text> - <xsl:text>} -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function switch_visible_page(page_name) { -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> let old_desc = page_desc[current_visible_page]; -</xsl:text> - <xsl:text> let new_desc = page_desc[page_name]; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> if(old_desc){ -</xsl:text> - <xsl:text> for(let eltid in old_desc.required_detachables){ -</xsl:text> - <xsl:text> if(!(eltid in new_desc.required_detachables)){ -</xsl:text> - <xsl:text> let [element, parent] = old_desc.required_detachables[eltid]; -</xsl:text> - <xsl:text> parent.removeChild(element); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> for(let eltid in new_desc.required_detachables){ -</xsl:text> - <xsl:text> if(!(eltid in old_desc.required_detachables)){ -</xsl:text> - <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; -</xsl:text> - <xsl:text> parent.appendChild(element); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> }else{ -</xsl:text> - <xsl:text> for(let eltid in new_desc.required_detachables){ -</xsl:text> - <xsl:text> let [element, parent] = new_desc.required_detachables[eltid]; -</xsl:text> - <xsl:text> parent.appendChild(element); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> svg_root.setAttribute('viewBox',new_desc.bbox.join(" ")); -</xsl:text> - <xsl:text> current_visible_page = page_name; + <xsl:text>ws.onclose = function (evt) { +</xsl:text> + <xsl:text> // TODO : add visible notification while waiting for reload +</xsl:text> + <xsl:text> console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s."); +</xsl:text> + <xsl:text> // TODO : re-enable auto reload when not in debug +</xsl:text> + <xsl:text> //window.setTimeout(() => location.reload(true), 10000); +</xsl:text> + <xsl:text> alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+"."); +</xsl:text> + <xsl:text> </xsl:text> <xsl:text>}; </xsl:text> <xsl:text> </xsl:text> - <xsl:text>function update_jumps() { -</xsl:text> - <xsl:text> page_desc[current_visible_page].jumps.map(w=>w.notify_page_change(current_visible_page,current_page_index)); -</xsl:text> - <xsl:text> jumps_need_update = false; + <xsl:text>var xmlns = "http://www.w3.org/2000/svg"; +</xsl:text> + <xsl:text>var edit_callback; +</xsl:text> + <xsl:text>function edit_value(path, valuetype, callback, initial) { +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> let [keypadid, xcoord, ycoord] = keypads[valuetype]; +</xsl:text> + <xsl:text> console.log('XXX TODO : Edit value', path, valuetype, callback, initial, keypadid); +</xsl:text> + <xsl:text> edit_callback = callback; +</xsl:text> + <xsl:text> let widget = hmi_widgets[keypadid]; +</xsl:text> + <xsl:text> widget.start_edit(path, valuetype, callback, initial); </xsl:text> <xsl:text>}; </xsl:text> <xsl:text> </xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>// Once connection established -</xsl:text> - <xsl:text>ws.onopen = function (evt) { -</xsl:text> - <xsl:text> init_widgets(); -</xsl:text> - <xsl:text> send_reset(); -</xsl:text> - <xsl:text> // show main page -</xsl:text> - <xsl:text> prepare_svg(); -</xsl:text> - <xsl:text> switch_page(default_page); + <xsl:text>var current_modal; /* TODO stack ?*/ +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>function show_modal() { +</xsl:text> + <xsl:text> let [element, parent] = detachable_elements[this.element.id]; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> tmpgrp = document.createElementNS(xmlns,"g"); +</xsl:text> + <xsl:text> tmpgrpattr = document.createAttribute("transform"); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> let [xcoord,ycoord] = this.coordinates; +</xsl:text> + <xsl:text> let [xdest,ydest] = page_desc[current_visible_page].bbox; +</xsl:text> + <xsl:text> tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")"; +</xsl:text> + <xsl:text> tmpgrp.setAttributeNode(tmpgrpattr); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> tmpgrp.appendChild(element); +</xsl:text> + <xsl:text> parent.appendChild(tmpgrp); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> current_modal = [this.element.id, tmpgrp]; </xsl:text> <xsl:text>}; </xsl:text> <xsl:text> </xsl:text> - <xsl:text>ws.onclose = function (evt) { -</xsl:text> - <xsl:text> // TODO : add visible notification while waiting for reload -</xsl:text> - <xsl:text> console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s."); -</xsl:text> - <xsl:text> // TODO : re-enable auto reload when not in debug -</xsl:text> - <xsl:text> //window.setTimeout(() => location.reload(true), 10000); -</xsl:text> - <xsl:text> alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+"."); -</xsl:text> - <xsl:text> + <xsl:text>function end_modal() { +</xsl:text> + <xsl:text> let [eltid, tmpgrp] = current_modal; +</xsl:text> + <xsl:text> let [element, parent] = detachable_elements[this.element.id]; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> parent.removeChild(tmpgrp); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> current_modal = undefined; </xsl:text> <xsl:text>}; </xsl:text> <xsl:text> </xsl:text> - <xsl:text>var xmlns = "http://www.w3.org/2000/svg"; -</xsl:text> - <xsl:text>var edit_callback; -</xsl:text> - <xsl:text>function edit_value(path, valuetype, callback, initial) { -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> let [keypadid, xcoord, ycoord] = keypads[valuetype]; -</xsl:text> - <xsl:text> console.log('XXX TODO : Edit value', path, valuetype, callback, initial, keypadid); -</xsl:text> - <xsl:text> edit_callback = callback; -</xsl:text> - <xsl:text> let widget = hmi_widgets[keypadid]; -</xsl:text> - <xsl:text> widget.start_edit(path, valuetype, callback, initial); + <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> console.log("active", eltsub); </xsl:text> <xsl:text>}; </xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>var current_modal; /* TODO stack ?*/ -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function show_modal() { -</xsl:text> - <xsl:text> let [element, parent] = detachable_elements[this.element.id]; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> tmpgrp = document.createElementNS(xmlns,"g"); -</xsl:text> - <xsl:text> tmpgrpattr = document.createAttribute("transform"); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> let [xcoord,ycoord] = this.coordinates; -</xsl:text> - <xsl:text> let [xdest,ydest] = page_desc[current_visible_page].bbox; -</xsl:text> - <xsl:text> tmpgrpattr.value = "translate("+String(xdest-xcoord)+","+String(ydest-ycoord)+")"; -</xsl:text> - <xsl:text> tmpgrp.setAttributeNode(tmpgrpattr); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> tmpgrp.appendChild(element); -</xsl:text> - <xsl:text> parent.appendChild(tmpgrp); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> current_modal = [this.element.id, tmpgrp]; + <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> console.log("inactive", eltsub); </xsl:text> <xsl:text>}; </xsl:text> - <xsl:text> -</xsl:text> - <xsl:text>function end_modal() { -</xsl:text> - <xsl:text> let [eltid, tmpgrp] = current_modal; -</xsl:text> - <xsl:text> let [element, parent] = detachable_elements[this.element.id]; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> parent.removeChild(tmpgrp); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> current_modal = undefined; -</xsl:text> - <xsl:text>}; -</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> console.log("active", eltsub); -</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> console.log("inactive", eltsub); -</xsl:text> - <xsl:text>}; -</xsl:text> </xsl:template> </xsl:stylesheet> diff -r 3ee337c8c769 -r 2670f5c53caf svghmi/svghmi.js --- a/svghmi/svghmi.js Sat Apr 04 22:32:54 2020 +0200 +++ b/svghmi/svghmi.js Tue Apr 07 10:01:23 2020 +0200 @@ -236,7 +236,8 @@ new Uint32Array([index]), tobinary(value)]); - cache[index] = value; + // DON'T DO THAT unless read_iterator in svghmi.c modifies wbuf as well, not only rbuf + // cache[index] = value; }; function apply_hmi_value(index, new_val) { diff -r 3ee337c8c769 -r 2670f5c53caf svghmi/widget_input.ysl2 --- a/svghmi/widget_input.ysl2 Sat Apr 04 22:32:54 2020 +0200 +++ b/svghmi/widget_input.ysl2 Tue Apr 07 10:01:23 2020 +0200 @@ -27,10 +27,10 @@ | }, | on_op_click: function(opstr) { | let new_val = change_hmi_value(this.indexes[0], opstr); - if "$have_value"{ - | this.value_elt.textContent = String(new_val); - /* TODO gray out value until refreshed */ - } + // if "$have_value"{ + // | this.value_elt.textContent = String(new_val); + // /* TODO gray out value until refreshed */ + // } | }, | on_edit_click: function(opstr) { | edit_value("«path/@value»", "«path/@type»", this, this.last_val); @@ -38,9 +38,9 @@ | edit_callback: function(new_val) { | apply_hmi_value(this.indexes[0], new_val); - if "$have_value"{ - | this.value_elt.textContent = String(new_val); - /* TODO gray out value until refreshed */ - } + // if "$have_value"{ + // | this.value_elt.textContent = String(new_val); + // /* TODO gray out value until refreshed */ + // } | }, }