In addition to executing codes, you could define variables and functions in the zscript element directly as depicted below.
<window id="A> <zscript> Object myvar = new LinkedList(); void myfunc() { ... } </zscript> ... <button label="add" onClick="myvar.add(some)"/> <button label="some" onClick="myfunc()"/> </window>
The variables and methods defined in zscript are stored in the interpreter of the corresponding scripting language.
Like namespaces[25], variable defined in zscript are all visible to EL expressions.
<window> <zscript> String var = "abc"; self.setVariable("var2", "xyz", true); </zscript> ${var} ${var2} </window>
is equivalent to
<window> abc xyz </window>
Notice that variables defined in zscript has the higher priority than those defined in the namespace.
<window> <zscript> String var = "abc"; self.setVariable("var", "xyz", true); </zscript> ${var} </window>
is equivalent to
<window> abc </window>
It is sometimes confusing, if you declare a component later as shown in the following example.
<window> <zscript> String var = "abc"; </zscript> <label id="var" value="A label"/> ${var.value} <!-- Wrong! var is "abc", not the label --> </window>
Therefore, it is suggested to use some naming pattern to avoid the confusion. For example, you can prefix all interpreter variables with zs_.
In additions, you shall use local variables if possible. A local variable is declared with the class name, and it is visible only to a particular scope of zscript codes.
<zscript> Date now = new Date(); </zscript>
Furthermore, you can make a local variable invisible to EL expressions by enclosing it with curly braces as follows.
<zscript> { //create a new logic scope String var = "abc"; //visible only inside of the enclosing curly brace } </zscript>
Depending on the implementation, an interpreter might have exactly one logical scope, or one logic scope per ID space to store these variables and methods. For sake of description, we call them the single-scope and multi-scope interpreters, respectively.
Java interpreter (BeanShell) is a typical multi-scope interpreter[26]. It creates an interpreter-dependent scope for each ID space. For example, two logical scopes are created for window A and B, respectively in the following example. Therefore, var2 is visible only to window B, while var1 is visible to both window A and B in the following example.
<window id="A"> <zscript>var1 = "abc";</zscript> <window id="B"> <zscript>var2 = "def";</zscript> </window> </window>
With Java Interpreter (BeanShell), you can declare an interpreter variable local to the logical scope of the nearest ID space (i.e., a window) by specifying the class name as below,
<window id="A"> <window id="B"> <zscript> String b = "local to window B"; </zscript> </window> </window>
The following is a more sophisticated example which will generate abc def.
<window id="A"> <zscript> var1 = var2 = "abc"; </zscript> <window id="B"> <zscript> Object var1 = "123"; var2 = "def"; var3 = "xyz"; </zscript> </window> ${var1} ${var2} ${var3} </window>
where Object var1 = "123" actually creates a variable local to window B since the class name, Object, is specified. On the other hand, var2 = "def" causes the interpreter to look up any variable called var2 defined in the current scope or any scope in the upper layers. Since var2 was defined in window A, the variable is overridden. In the case of var3 = "xyz", a variable local to window B is created, since window A doesn't define any variable called var3.
Ruby, Groovy and JavaScript interpreters don't support multi-scope yet[27]. It means all variables defined in, say, Ruby are stored in one logical scope (per interpreter). Thus, the interpreter variables defined in one window override those defined in another window if they are in the same page. To avoid confusion, you could prefix the variable names with special prefix denoting the window.
Tip: Each page has its own interpreter to evaluate zscript codes. If a desktop has multiple pages, then it might have multiple instances of the interpreters (per scripting language).
Each scripting language is associated with one interpreter. Thus, variables and methods defined in one language are not visible to another language. For example, var1 and var2 belong to two different interpreters in the following example.
<zscript language="Java"> var1 = 123; </zscript> <zscript language="JavaScript"> var2 = 234; </zscript>
Variables defined in the namespace can be retrieved by use of the getVariable method.
On the other hand, variables defined in zscript is part of the interpret that interprets it. They are not a part of any namespace. In other words, you can not retrieve them by use of the getVariable method.
<zscript> var1 = 123; //var1 belongs to the interpreter, not any namespace page.getVariable("var1"); //returns null </zscript>
Instead, you have to use getZScriptVariable to retrieve variables defined in zscript. Similarly, you can use getZScriptClass to retrieve classes and getZScriptMethod to retrieve methods defined in zscript. These methods will iterate through all loaded interpreters until the specified one is found.
If you want to search a particular interpreter, you can use the getInterpreter method to retrieve the interpreter first, as follows.
page.getInterpreter("JavaScript").getVariable("some"); //interpreter for JavaScript page.getInterpreter(null).getVariable("some"); //interpreter for default language