Scripts in ZUML"

From Documentation
m (remove empty version history (via JWB))
 
(69 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{ZKDevelopersReferencePageHeader}}
 
{{ZKDevelopersReferencePageHeader}}
  
= Write Java code in ZUML =
+
=Embed Server-side Script Code=
For fast prototyping, you can embed codes in ZUML page. By default, it's java. Keep in mind, it's simply java but interpreted by Beanshell. Therefore you can define variables, methods, event class inside <tt>zscript</tt>. Please refer to [[Getting_started#Write_java_code_in_you_ZUML | Write Java code in your ZUML]] for a simple example. Please also refer to [[Zscript%2C_java%2C_EL | Zscript, java, EL]] for some useful examples about zscript.
+
To make it easier to create a dynamic web page, the ZUML document allows you to embed the script code. Notice that there are two types of script code: server-side and client-side. How the client-side code can be embedded is discussed in the [[ZK Developer's Reference/UI Composing/Client-side UI Composing|Client-side UI Composing]] and [[ZK Developer's Reference/Event Handling/Client-side Event Listening|Client-side Event Listening]] sections. Here we will discuss how to embed the server-side script code in a ZUML document.
 +
 
 +
 
 +
== Fast Prototyping ==
 +
Embedding Java code in a ZUML page is a powerful way for fast prototyping. For example, you can quickly build a prototype UI page to discuss with business analysts and UI designers. Then, modify it directly and get feedback immediately without going through drawings and even recompiling.
 +
 
 +
== Performance Notice ==
 +
Notice that the performance of BeanShell is not good and, like any interpreter, typos can be found only when it is evaluated. For more information, please refer to [[ZK Developer's Reference/Performance Tips/Use Compiled Java Codes|the Performance Tips section]]
 +
 
 +
 
 +
= 2 Places to Embed =
 +
Depending on the requirement, there are two ways to embed the server-side script code in a ZUML document: the <code>zscript</code> element and the event handler. The <code>zscript</code> element is used to embed the code that will execute when the page is loaded, while the event handler will execute when the event is received.
 +
 
 +
==zscript==
 +
First, you could embed the code inside the [[ZUML Reference/ZUML/Elements/zscript|zscript element]], such that they will be evaluated when the page is rendered<ref>The zscript element has an attribute called [[ZUML Reference/ZUML/Elements/zscript#deferred|deferred]] that could make the evaluation as late as possible</ref>. For example,
  
There are two ways to write <tt>zscript</tt>. First, inside <zscript></zscript>:
 
 
<source lang="xml" >
 
<source lang="xml" >
 
<zscript>
 
<zscript>
 
//inside is zscript
 
//inside is zscript
 
//you can declare variable, function, and even Java class here.
 
//you can declare variable, function, and even Java class here.
 +
void foo(String msg) {
 +
    //...
 +
}
 +
comp.addEventListener("onClick",
 +
    new EventListener() {
 +
        public void onEvent(Event event) {
 +
            //...
 +
        }
 +
    });
 
</zscript>
 
</zscript>
 
</source>
 
</source>
  
Second, inside event handler.
+
Notice that, by default, the code inside the <code>zscript</code> element is Java but you could also use other languages, such as Groovy. Keep in mind that it is ''interpreted'' at run time (by [https://github.com/beanshell/beanshell Beanshell]), so typo or syntax error will be found only when it is interpreted. In addition, it runs on the server, so it could access any Java libraries. You could even define variables, methods, and classes with it, and they are visible to EL expressions on the same page.
 +
 
 +
===CDATA===
 +
 
 +
The code embedded in the zscript element must be a valid XML text. In other words, you must encode the special characters well, such as  < must be replaced with &amp;lt;, & with &amp;amp; and so on. In addition to encoding individual characters, you can also enclose the whole code with XML CDATA as follows.
 +
 
 +
<source lang="xml">
 +
<zscript><![CDATA[
 +
if (some < another && another < last) //OK since CDATA is used
 +
  doSomething();
 +
]]></zscript>
 +
</source>
 +
 
 +
As depicted CDATA is represented with <code><![CDATA[</code> and <code>]]></code>.
 +
 
 +
<blockquote>
 +
----
 +
<references/>
 +
</blockquote>
 +
 
 +
===Class Declaration===
 +
 
 +
You could define a class declared in a ZUML document, and the class is accessible only in the page it was defined. For example,
 +
 
 +
<source lang="xml">
 +
<?xml version="1.0" encoding="UTF-8"?>
 +
<zk>
 +
<zscript><![CDATA[
 +
public class FooModel extends AbstractTreeModel {
 +
    public FooModel() {
 +
        super("Root");
 +
    }
 +
    public boolean isLeaf(Object node) {
 +
        return getLevel((String)node) >= 4; //at most 4 levels
 +
    }
 +
    public Object getChild(Object parent, int index) {
 +
        return parent + "." + index;
 +
    }
 +
    public int getChildCount(Object parent) {
 +
        return 5; //each node has 5 children
 +
    }
 +
    public int getIndexOfChild(Object parent, Object child) {
 +
        String data = (String)child;
 +
        int i = data.lastIndexOf('.');
 +
        return Integer.parseInt(data.substring(i + 1));
 +
    }
 +
    private int getLevel(String data) {
 +
        for (int i = -1, level = 0;; ++level)
 +
            if ((i = data.indexOf('.', i + 1)) < 0)
 +
                return level;
 +
    }
 +
};
 +
FooModel model = new FooModel();
 +
]]></zscript>
 +
<tree model="${model}">
 +
    <treecols>
 +
        <treecol label="Names"/>
 +
    </treecols>
 +
</tree>
 +
</zk>
 +
</source>
 +
 
 +
==Event Handlers==
 +
Second, you could put the code inside an event handler, such that it will execute when the event is received, as depicted below.
 
<source lang="xml" >
 
<source lang="xml" >
 
<button onClick='alert("event handler for onXXX inside ZUML is also zscript")'/>
 
<button onClick='alert("event handler for onXXX inside ZUML is also zscript")'/>
 
</source>
 
</source>
  
=Hints to read <tt>zscript</tt>=
+
Notice that the name of the event must start with <code>on</code>, and the third letter must be an '''upper''' case. Otherwise, it will be considered as a property.
When beginner first meet <tt>zscript</tt>, he usually get confused with "where is the declaration of such variable?". ZK use [http://www.beanshell.org/ Beanshell] as java interpreter. As [http://www.beanshell.org/docs.html Beanshell's manual] says: Beanshell supports "loose" or dynamically typed variable. That is, you can refer to variables without declaring them first and without specifying any type. Also, <tt>zscript</tt> can access component's field and implicit object, they may look like strange undeclared variables to java programmer.
 
  
Some packages are imported implicitly by Beanshell, but some package have to be imported by developer.
+
Again, the code is Java interpreted at run time and running on the server. For client-side listening, please refer to the [[ZK Developer's Reference/Event Handling/Client-side Event Listening|Client-side Event Listening]] section.
  
Typical usage of <tt>zscript</tt> includes initialization and declaring global variables and methods.
+
For the sake of discussion, we call it zscript no matter the code is embedded in the <code>zscript</code> element or in an event handler.
  
=Distinguish <tt>zscript</tt> from EL=
+
===Attribute===
Keep in mind, EL is enclosed by ${}.
 
  
<tt>${self.label}</tt> is EL.
+
If the code is too complicated, you could specify the event handle in the [[ZUML Reference/ZUML/Elements/attribute|attribute element]]. For example,
 +
 
 +
<source lang="xml">
 +
<button label="hi">
 +
    <attribute name="onClick"><![DATA[
 +
    if (anything > best)
 +
        best = anything;
 +
    ]]></attribute>
 +
</button>
 +
</source>
 +
 
 +
=Distinguish <code>zscript</code> from EL=
 +
Keep in mind, [[ZK Developer's Reference/UI Composing/ZUML/EL Expressions|an EL expression]] is enclosed by ${ }.
 +
 
 +
For example, <code>${self.label}</code> and <code>${ok.label}</code> are both EL expressions in the following example:
 
<source lang="xml" >
 
<source lang="xml" >
 
<window>
 
<window>
Line 35: Line 132:
 
</source>
 
</source>
  
<tt>alert(self.label)</tt> is not EL, it's a piece of <tt>zscript</tt>
+
On the other hand, in the following example, <code>alert(self.label)</code> is not an EL expression. Rather, it's the zscript code:
 
<source lang="xml" >
 
<source lang="xml" >
 
<window>
 
<window>
Line 42: Line 139:
 
</source>
 
</source>
  
Although they both look alike, but EL and zscript have different life cycle, EL is not available at certain phase. Therefore in some cases, you can't use EL but <tt>zscript</tt>.
+
You cannot mix the use of EL expressions with zscript:
 
 
 
<source lang="xml" >
 
<source lang="xml" >
 
<window>
 
<window>
Line 51: Line 147:
 
</source>
 
</source>
  
= Java Interpreter (BeanShell) =
+
Also notice that the evaluation of EL expressions is very fast, so EL can be used in a production system. On the other hand, [[ZK Developer's Reference/Performance Tips/Use Compiled Java Codes|zscript is suggested to use only in prototyping or quick-fix]].
== Scope for Each ID space ==
+
 
Java interpreter (BeanShell) is a typical multi-scope interpreter. It creates an interpreter-dependent scope for each ID space. And it's '''hierarchical'''. If a variable can't be found in current id space, it will go further to parent's id space try to resolve the variable. For example, two logical scopes are created for window<ref>Built in id space owner includes <tt>window</tt>, <tt>page</tt> and <tt>regular macro</tt>.</ref> <tt>A</tt> and <tt>B</tt>, respectively in the following example. Therefore, <tt>var2</tt> is visible only to window <tt>B</tt>, while <tt>var1</tt> is visible to both window <tt>A</tt> and <tt>B </tt>in the following example.
+
==Variables Defined in zscript Visible to EL==
 +
 
 +
A variable defined in zscript is visible to EL expression, unless it is a local variable, which will be discussed later.
 +
 
 +
<source lang="xml">
 +
<zscript>
 +
Date now = new Date();
 +
</zscript>
 +
${now}
 +
</source>
 +
 
 +
= Java Interpreter =
 +
The default interpreter is based on [http://www.beanshell.org BeanShell]. It is a Java Interpreter.
 +
 
 +
== Scope for Each ID Space ==
 +
The Java interpreter is a ''multi-scope'' interpreter. It creates a scope for each [[ZK Developer's Reference/UI Composing/Component-based UI#ID_Space|ID space]]. Since ID space is hierarchical, so are the scopes. If a variable cannot be found in the current ID space, it will go further to parent's ID space to try to resolve the variable.
 +
 
 +
For example, in the following example, two logical scopes are created for window<ref>Built in id space owner includes <javadoc>org.zkoss.zul.Window</javadoc>, <javadoc type="interface">org.zkoss.zk.ui.Page</javadoc> and [[ZK Developer's Reference/UI Composing/Macro Component|macro components]].</ref> <code>A</code> and <code>B</code> respectively. Therefore, <code>var2</code> is visible only to window <code>B</code>, while <code>var1</code> is visible to both window <code>A</code> and <code>B</code>.
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 64: Line 177:
 
</source>
 
</source>
  
'''Notes'''
+
<blockquote>
 +
----
 
<references/>
 
<references/>
 +
</blockquote>
  
== Declare local variable ==
+
== Declare a Local Variable ==
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. Furthermore, you can make a local variable invisible to EL expressions by enclosing it with <tt>{}</tt> as follows.
+
If a variable is declared inside a pair of curly braces, it is visible only to the scope defined by the curly braces. It is called a local variable. For example,
  
You can see how <tt>{}</tt> and class name as <tt>Date</tt> affect scope and EL in the following example.
+
<source lang="xml">
 +
<zscript>
 +
void echo() {
 +
  String a_local_variable;
 +
}
 +
</script>
 +
</sourcE>
 +
 
 +
Here is another example,
  
 
<source lang="xml" >
 
<source lang="xml" >
Line 76: Line 199:
 
<zscript>
 
<zscript>
 
{
 
{
    Date now = new Date();
+
    Date now = new Date(); //local variable
    abc ="def";
+
    abc ="def"; //global variable since not defined before and not Class specified
 
}
 
}
 +
String first = "first"; //global variable
 
</zscript>
 
</zscript>
 +
0: ${first}
 
1:${abc}
 
1:${abc}
 
2:${now}
 
2:${now}
Line 85: Line 210:
 
</source>
 
</source>
  
The result shows: <tt>1:def 2: </tt> . <tt>abc</tt> is visible, and <tt>now</tt> is invisible.
+
The result shows: <code>0:first 1:def 2:</code> . It is because <code>now</code> is a local variable and it is invisible to EL expressions. On the other hand, <code>first</code> and <code>abc</code> are both global variables that are visible to EL expressions. Notice that <code>abc</code> is not declared but assigned directly, and it causes a global variable to be created.
 +
 
 +
Please refer to the [http://beanshell.org/docs.html Beanshell Documentation] and search "scoping" and "local" for more information.
 +
 
 +
= Use Other Languages =
 +
Currently, zscript supports Java, Groovy, Ruby, JavaScript and Python. For example,
 +
 
 +
<source lang="xml">
 +
<?page zscriptLanguage="Groovy"?>
 +
<window border="normal">
 +
<vbox id="vb">
 +
<label id="l" value="Hi"/>
 +
<button label="change label" onClick="l.value='Hi, Groovy';"/>
 +
<button label="add label" onClick="new Label('New').setParent(vb);"/>
 +
</vbox>
 +
<button label="alert" onClick="alert('Hi, Groovy')"/>
 +
</window>
 +
</source>
  
Please refer to [http://www.beanshell.org/manual/bshmanual.pdf Beanshell's manual] and search "scoping"、"local" for more information.
+
In addition, you could add your own interpreter by implementing <javadoc type="interface">org.zkoss.zk.scripting.Interpreter</javadoc>. For more information, please refer to [[ZUML Reference/Extensions/zscript|ZUML Reference]].
  
= zscript other than Java =
 
Currently, zscript already support java, javascript, ruby, groovy. You can add other language to support zscript as you like. Please refer to section [[Zscript_other_than_java | Zscript other than java]] for more information.
 
  
=Version History=
 
{{LastUpdated}}
 
{| border='1px' | width="100%"
 
! Version !! Date !! Content
 
|-
 
| &nbsp;
 
| &nbsp;
 
| &nbsp;
 
|}
 
  
 
{{ZKDevelopersReferencePageFooter}}
 
{{ZKDevelopersReferencePageFooter}}

Latest revision as of 05:54, 6 February 2024

Embed Server-side Script Code

To make it easier to create a dynamic web page, the ZUML document allows you to embed the script code. Notice that there are two types of script code: server-side and client-side. How the client-side code can be embedded is discussed in the Client-side UI Composing and Client-side Event Listening sections. Here we will discuss how to embed the server-side script code in a ZUML document.


Fast Prototyping

Embedding Java code in a ZUML page is a powerful way for fast prototyping. For example, you can quickly build a prototype UI page to discuss with business analysts and UI designers. Then, modify it directly and get feedback immediately without going through drawings and even recompiling.

Performance Notice

Notice that the performance of BeanShell is not good and, like any interpreter, typos can be found only when it is evaluated. For more information, please refer to the Performance Tips section


2 Places to Embed

Depending on the requirement, there are two ways to embed the server-side script code in a ZUML document: the zscript element and the event handler. The zscript element is used to embed the code that will execute when the page is loaded, while the event handler will execute when the event is received.

zscript

First, you could embed the code inside the zscript element, such that they will be evaluated when the page is rendered[1]. For example,

<zscript>
//inside is zscript
//you can declare variable, function, and even Java class here.
void foo(String msg) {
    //...
}
comp.addEventListener("onClick",
    new EventListener() {
        public void onEvent(Event event) {
            //...
        }
    });
</zscript>

Notice that, by default, the code inside the zscript element is Java but you could also use other languages, such as Groovy. Keep in mind that it is interpreted at run time (by Beanshell), so typo or syntax error will be found only when it is interpreted. In addition, it runs on the server, so it could access any Java libraries. You could even define variables, methods, and classes with it, and they are visible to EL expressions on the same page.

CDATA

The code embedded in the zscript element must be a valid XML text. In other words, you must encode the special characters well, such as < must be replaced with &lt;, & with &amp; and so on. In addition to encoding individual characters, you can also enclose the whole code with XML CDATA as follows.

<zscript><![CDATA[
if (some < another && another < last) //OK since CDATA is used
   doSomething();
]]></zscript>

As depicted CDATA is represented with <![CDATA[ and ]]>.


  1. The zscript element has an attribute called deferred that could make the evaluation as late as possible

Class Declaration

You could define a class declared in a ZUML document, and the class is accessible only in the page it was defined. For example,

<?xml version="1.0" encoding="UTF-8"?>
<zk>
<zscript><![CDATA[
public class FooModel extends AbstractTreeModel {
    public FooModel() {
        super("Root");
    }
    public boolean isLeaf(Object node) {
        return getLevel((String)node) >= 4; //at most 4 levels
    }
    public Object getChild(Object parent, int index) {
        return parent + "." + index;
    }
    public int getChildCount(Object parent) {
        return 5; //each node has 5 children
    }
    public int getIndexOfChild(Object parent, Object child) {
        String data = (String)child;
        int i = data.lastIndexOf('.');
        return Integer.parseInt(data.substring(i + 1));
    }
    private int getLevel(String data) {
        for (int i = -1, level = 0;; ++level)
            if ((i = data.indexOf('.', i + 1)) < 0)
                return level;
    }
};
FooModel model = new FooModel();
]]></zscript>
<tree model="${model}">
    <treecols>
        <treecol label="Names"/>
    </treecols>
</tree>
</zk>

Event Handlers

Second, you could put the code inside an event handler, such that it will execute when the event is received, as depicted below.

<button onClick='alert("event handler for onXXX inside ZUML is also zscript")'/>

Notice that the name of the event must start with on, and the third letter must be an upper case. Otherwise, it will be considered as a property.

Again, the code is Java interpreted at run time and running on the server. For client-side listening, please refer to the Client-side Event Listening section.

For the sake of discussion, we call it zscript no matter the code is embedded in the zscript element or in an event handler.

Attribute

If the code is too complicated, you could specify the event handle in the attribute element. For example,

<button label="hi">
    <attribute name="onClick"><![DATA[
    if (anything > best)
        best = anything;
    ]]></attribute>
</button>

Distinguish zscript from EL

Keep in mind, an EL expression is enclosed by ${ }.

For example, ${self.label} and ${ok.label} are both EL expressions in the following example:

<window>	
	<button label="ok" id="${self.label}"/>
	${ok.label}		
</window>

On the other hand, in the following example, alert(self.label) is not an EL expression. Rather, it's the zscript code:

<window>	
	<button label="ok" onClick='alert(self.label)'/>		
</window>

You cannot mix the use of EL expressions with zscript:

<window>	
	<!-- It's wrong, for java don't accept syntax as ${}-->
	<button label="ok" onClick='alert(${self.label})'/>		
</window>

Also notice that the evaluation of EL expressions is very fast, so EL can be used in a production system. On the other hand, zscript is suggested to use only in prototyping or quick-fix.

Variables Defined in zscript Visible to EL

A variable defined in zscript is visible to EL expression, unless it is a local variable, which will be discussed later.

<zscript>
Date now = new Date();
</zscript>
${now}

Java Interpreter

The default interpreter is based on BeanShell. It is a Java Interpreter.

Scope for Each ID Space

The Java interpreter is a multi-scope interpreter. It creates a scope for each ID space. Since ID space is hierarchical, so are the scopes. If a variable cannot be found in the current ID space, it will go further to parent's ID space to try to resolve the variable.

For example, in the following example, two logical scopes are created for window[1] A and B respectively. Therefore, var2 is visible only to window B, while var1 is visible to both window A and B.

<window id="A">
    <zscript>var1 = "abc";</zscript>
    <window id="B">
        <zscript>var2 = "def";</zscript>
    </window>
</window>

  1. Built in id space owner includes Window, Page and macro components.

Declare a Local Variable

If a variable is declared inside a pair of curly braces, it is visible only to the scope defined by the curly braces. It is called a local variable. For example,

<zscript>
void echo() {
   String a_local_variable;
}
</script>

Here is another example,

<window>
	<zscript>
	{
	    Date now = new Date(); //local variable
	    abc ="def"; //global variable since not defined before and not Class specified
	}
	String first = "first"; //global variable
	</zscript>
	0: ${first}
	1:${abc}
	2:${now}
</window>

The result shows: 0:first 1:def 2: . It is because now is a local variable and it is invisible to EL expressions. On the other hand, first and abc are both global variables that are visible to EL expressions. Notice that abc is not declared but assigned directly, and it causes a global variable to be created.

Please refer to the Beanshell Documentation and search "scoping" and "local" for more information.

Use Other Languages

Currently, zscript supports Java, Groovy, Ruby, JavaScript and Python. For example,

<?page zscriptLanguage="Groovy"?>
<window border="normal">
	<vbox id="vb">
		<label id="l" value="Hi"/>
		<button label="change label" onClick="l.value='Hi, Groovy';"/>
		<button label="add label" onClick="new Label('New').setParent(vb);"/>
	</vbox>
	<button label="alert" onClick="alert('Hi, Groovy')"/>
</window>

In addition, you could add your own interpreter by implementing Interpreter. For more information, please refer to ZUML Reference.




Last Update : 2024/02/06

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.