SVGHMI: Fix browser side exception when some widget are not used, and are then discarded and not present in final SVG. In that case JS code was still making reference to discarded widget elements and was raising exception at init.
// hmi_tree.ysl2
// HMI Tree computed from VARIABLES.CSV in svghmi.py
const "hmitree", "ns:GetHMITree()";
const "_categories" {
noindex > HMI_PLC_STATUS
noindex > HMI_CURRENT_PAGE
}
const "categories", "exsl:node-set($_categories)";
// HMI Tree Index
const "_indexed_hmitree" apply "$hmitree", mode="index";
const "indexed_hmitree", "exsl:node-set($_indexed_hmitree)";
emit "preamble:hmi-tree" {
| var hmi_hash = [«$hmitree/@hash»];
|
| var heartbeat_index = «$indexed_hmitree/*[@hmipath = '/HEARTBEAT']/@index»;
|
| var hmitree_types = [
foreach "$indexed_hmitree/*"
| /* «@index» «@hmipath» */ "«substring(local-name(), 5)»"`if "position()!=last()" > ,`
| ];
|
}
template "*", mode="index" {
param "index", "0";
param "parentpath", "''";
const "content" {
const "path"
choose {
when "count(ancestor::*)=0" > /
when "count(ancestor::*)=1" > /«@name»
otherwise > «$parentpath»/«@name»
}
choose {
when "not(local-name() = $categories/noindex)" {
xsl:copy {
attrib "index" > «$index»
attrib "hmipath" > «$path»
foreach "@*" xsl:copy;
}
apply "*[1]", mode="index"{
with "index", "$index + 1";
with "parentpath" > «$path»
}
}
otherwise {
apply "*[1]", mode="index"{
with "index", "$index";
with "parentpath" > «$path»
}
}
}
}
copy "$content";
apply "following-sibling::*[1]", mode="index" {
with "index", "$index + count(exsl:node-set($content)/*)";
with "parentpath" > «$parentpath»
}
}
// Parses:
// "HMI:WidgetType:param1:param2@path1,path1min,path1max@path2"
//
// Into:
// widget type="WidgetType" id="blah456" {
// arg value="param1";
// arg value="param2";
// path value=".path1" index=".path1" min="path1min" max="path1max" type="PAGE_LOCAL";
// path value="/path1" index="348" type="HMI_INT";
// path value="path4" index="path4" type="HMI_LOCAL";
// }
//
template "*", mode="parselabel" {
const "label","@inkscape:label";
const "id","@id";
const "description", "substring-after($label,'HMI:')";
const "_args", "substring-before($description,'@')";
const "args" choose {
when "$_args" value "$_args";
otherwise value "$description";
}
const "_type", "substring-before($args,':')";
const "type" choose {
when "$_type" value "$_type";
otherwise value "$args";
}
if "$type" widget {
attrib "id" > «$id»
attrib "type" > «$type»
foreach "str:split(substring-after($args, ':'), ':')" {
arg {
attrib "value" > «.»
}
}
const "paths", "substring-after($description,'@')";
foreach "str:split($paths, '@')" {
if "string-length(.) > 0" path {
const "pathminmax", "str:split(.,',')";
const "path", "$pathminmax[1]";
const "pathminmaxcount", "count($pathminmax)";
attrib "value" > «$path»
choose {
when "$pathminmaxcount = 3" {
attrib "min" > «$pathminmax[2]»
attrib "max" > «$pathminmax[3]»
}
when "$pathminmaxcount = 2" {
error > Widget id:«$id» label:«$label» has wrong syntax of path section «$pathminmax»
}
}
choose {
when "regexp:test($path,'^\.[a-zA-Z0-9_]+')" {
attrib "type" > PAGE_LOCAL
}
when "regexp:test($path,'^[a-zA-Z0-9_]+')" {
attrib "type" > HMI_LOCAL
}
otherwise {
const "item", "$indexed_hmitree/*[@hmipath = $path]";
const "pathtype", "local-name($item)";
if "$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')" {
error > Widget id:«$id» label:«$label» path section «$pathminmax» use min and max on non mumeric value
}
if "count($item) = 1" {
attrib "index" > «$item/@index»
attrib "type" > «$pathtype»
}
}
}
}
}
}
}
const "_parsed_widgets" apply "$hmi_elements", mode="parselabel";
const "parsed_widgets","exsl:node-set($_parsed_widgets)";
def "func:widget" {
param "id";
result "$parsed_widgets/widget[@id = $id]";
}
def "func:is_descendant_path" {
param "descend";
param "ancest";
// TODO : use HMI tree to answer more accurately
result "string-length($ancest) > 0 and starts-with($descend,$ancest)";
}
def "func:same_class_paths" {
param "a";
param "b";
const "class_a", "$indexed_hmitree/*[@hmipath = $a]/@class";
const "class_b", "$indexed_hmitree/*[@hmipath = $b]/@class";
result "$class_a and $class_b and $class_a = $class_b";
}
// Debug data
template "*", mode="testtree"{
param "indent", "''";
> «$indent» «local-name()»
foreach "@*" > «local-name()»="«.»"
> \n
apply "*", mode="testtree" {
with "indent" value "concat($indent,'>')"
};
}
emit "debug:hmi-tree" {
| Raw HMI tree
apply "$hmitree", mode="testtree";
|
| Indexed HMI tree
apply "$indexed_hmitree", mode="testtree";
|
| Parsed Widgets
copy "_parsed_widgets";
apply "$parsed_widgets", mode="testtree";
}