<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you under the Apache License,
Version 2.0 (the "License"); you may not use this file except in
compliance with the License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

<document id="scripting">
    <properties>
        <title>Scripting</title>
    </properties>

    <body>
        <p>
            Pivot applications can take
            advantage of the JVM scripting support provided by the <tt>javax.script</tt> package
            included with JDK versions 1.6 and later. While these APIs can be used on their own to
            script Pivot applications, Pivot includes platform support for easily embedding script
            code in BXML files.
        </p>

        <p>
            Script blocks can be defined in BXML files in three different ways:
        </p>

        <ul>
            <li>
                Inline in a <tt>&lt;bxml:script&gt;</tt> tag
            </li>
            <li>
                As an external file included by a <tt>&lt;bxml:script&gt;</tt> with a <tt>src</tt>
                attribute
            </li>
            <li>
                In an event listener attribute
            </li>
            <li>
                In a <tt>&lt;bxml:script&gt;</tt> tag defined in an event listener element
            </li>
        </ul>

        <p>
            Though the first and last methods may seem similar, they are actually handled slightly
            differently. All four methods are discussed in more detail below.
        </p>

        <p>
            The following application demonstrate's Pivot's scripting support:
        </p>

        <application class="org.apache.pivot.tutorials.scripting.Scripting"
            width="480" height="360">
            <libraries>
                <library>core</library>
                <library>wtk</library>
                <library>wtk-terra</library>
                <library>tutorials</library>
            </libraries>
        </application>

        <p>
            This application is completely contrived - it doesn't present any practical example,
            but instead serves only to demonstrate the various means of using scripting in a BXML
            file. The Java source code for the application is shown below:
        </p>

        <source type="java" location="org/apache/pivot/tutorials/scripting/Scripting.java">
            <![CDATA[
            package org.apache.pivot.tutorials.scripting;

            import org.apache.pivot.beans.BXMLSerializer;
            import org.apache.pivot.collections.List;
            import org.apache.pivot.collections.Map;
            import org.apache.pivot.wtk.Application;
            import org.apache.pivot.wtk.Button;
            import org.apache.pivot.wtk.ButtonPressListener;
            import org.apache.pivot.wtk.DesktopApplicationContext;
            import org.apache.pivot.wtk.Display;
            import org.apache.pivot.wtk.Window;

            public class Scripting implements Application {
                public static class MyButtonPressListener implements ButtonPressListener {
                    @Override
                    public void buttonPressed(Button button) {
                        System.out.println("[Java] A button was clicked.");
                    }
                }

                private Window window = null;

                private String foo;
                private List<?> listData;

                @Override
                public void startup(Display display, Map<String, String> properties)
                    throws Exception {
                    BXMLSerializer bxmlSerializer = new BXMLSerializer();
                    bxmlSerializer.getNamespace().put("bar", "12345");

                    window = (Window)bxmlSerializer.readObject(Scripting.class, "scripting.bxml");
                    foo = (String)bxmlSerializer.getNamespace().get("foo");
                    listData = (List<?>)bxmlSerializer.getNamespace().get("listData");

                    System.out.println("foo = " + foo);
                    System.out.println("listData.getLength() = " + listData.getLength());

                    window.open(display);
                }

                @Override
                public boolean shutdown(boolean optional) {
                    if (window != null) {
                        window.close();
                    }

                    return false;
                }

                @Override
                public void suspend() {
                }

                @Override
                public void resume() {
                }

                public static void main(String[] args) {
                    DesktopApplicationContext.main(Scripting.class, args);
                }
            }
            ]]>
        </source>

        <p>
            Notice how the <tt>startup()</tt> method calls <tt>put()</tt> on the
            <tt>BXMLSerializer</tt> instance. <tt>BXMLSerializer</tt>'s dictionary methods allow a
            caller to manipulate the script namespace before the BXML is loaded and retrieve values
            from it afterwards. In this example, the "bar" variable is pre-populated with the value
            "12345", which is later written to the console by script defined in "scripting.bxml".
            Similarly, the values of "foo" and "listData" are obtained from the serializer and
            written to the console after the BXML file has been read.
        </p>

        <p>
            The BXML source is shown below:
        </p>

        <source type="xml" location="org/apache/pivot/tutorials/scripting/Scripting.java">
            <![CDATA[
            <Window title="Scripting Demo" maximized="true"
                WindowStateListener.windowOpened="java.lang.System.out.println('Window opened: ' + x)"
                WindowStateListener.windowClosed="java.lang.System.out.println('Window closed: ' + y)"
                xmlns:bxml="http://pivot.apache.org/bxml"
                xmlns:scripting="org.apache.pivot.demos.scripting"
                xmlns="org.apache.pivot.wtk">
                <bxml:script>
                importClass(java.lang.System);
                importPackage(org.apache.pivot.wtk);
                System.out.println("bar = " + bar);

                var x = 10;
                var y = 20;

                function buttonClicked(button) {
                    Prompt.prompt("y = " + y, button.window);
                }
                </bxml:script>

                <bxml:script src="example.js"/>

                <Border styles="{padding:2}">
                    <BoxPane orientation="vertical" styles="{padding:6}">
                        <PushButton buttonData="Click Me!">
                            <buttonPressListeners>
                                importPackage(org.apache.pivot.wtk);
                                function buttonPressed(button) {
                                    Prompt.prompt("x = " + x, button.getWindow());
                                }
                            </buttonPressListeners>
                        </PushButton>

                        <PushButton buttonData="No, Click Me!"
                            ButtonPressListener.buttonPressed="buttonClicked(arguments[0])"/>

                        <Border styles="{color:10}">
                            <ListView listData="$listData" selectedIndex="0"/>
                        </Border>
                    </BoxPane>
                </Border>
            </Window>
            ]]>
        </source>

        <p>
            This code demonstrates the various means by which script code can be used in BXML:
        </p>

        <ul>
            <li>
                <p>
                    <i>Inline in a <tt>&lt;bxml:script&gt;</tt> tag.</i> The first
                    <tt>&lt;bxml:script&gt;</tt> tag defines its content inline. This code is
                    executed as it is processed by the BXML serializer. This example first outputs
                    the "bar" value set by the application, then declares two variables
                    (<tt>x</tt> and <tt>y</tt>) and a function (<tt>buttonClicked()</tt>. These
                    values are visible to all other script code declared within the page.
                </p>
            </li>
            <li>
                <p>
                    <i>As an external file included by a <tt>&lt;bxml:script&gt;</tt> with a
                    <tt>src</tt> attribute.</i> The second <tt>&lt;bxml:script&gt;</tt> tag
                    includes an externally defined script into the page. The contents of the script
                    are defined in "example.js", which is shown below. Any previously defined
                    values will be visible to the script, and any variables declared by the script
                    will be visible to other script blocks declared by the page.
                </p>
            </li>
            <li>
                <p>
                    <i>In an event listener attribute.</i> Event listeners can be declared in
                    attributes, using a syntax similar to that used for static property setters.
                    The attribute name for an event listener consists of the name of the interface
                    that defines the event plus the name of the event, separated by a period. The
                    BXML source contains several examples of attribute-based listeners:
                </p>
                <ul>
                    <li>
                        <tt>WindowStateListener.windowOpened</tt>
                    </li>
                    <li>
                        <tt>WindowStateListener.windowClosed</tt>
                    </li>
                    <li>
                        <tt>ButtonPressListener.buttonPressed</tt>
                    </li>
                </ul>
            </li>
            <li>
                <p>
                    <i>In a <tt>&lt;bxml:script&gt;</tt> tag defined in an event listener
                    element.</i> Attribute-based event handlers are convenient for simple one-line
                    listeners, but are not particuarly well suited to anything much more complex.
                    Pivot also provides the ability to define event listeners within a listener
                    list element. For example, the <tt>buttonPressListeners</tt> sub-element of
                    the "Click Me!" push button defines a <tt>buttonPressed()</tt> function that
                    is invoked when the corresponding button press event is fired by the button.
                    Because the script for element-based listeners doesn't need to fit within a
                    single XML attribute, more sophisticated handler code can be defined, while
                    still maintaining proximity to the element to which the handler applies.
                </p>
                <p>
                    Though it isn't obvious from this simple example, script-based event handlers
                    are not required to provide implementations for every method defined by the
                    listener interface. Any omitted methods are simply processed by a default no-op
                    handler.
                </p>
            </li>
        </ul>

        <p>
            Note that a special scope is created for event listener scripts that is local to the
            listener; although all page-level variables remain visible to the listener code, any
            variables defined within the listener (including functions) are only visible within
            that block. This prevents listener script from "polluting" the global page namespace.
            While this is generally not an issue for attribute-based listeners (which tend to be
            focused and short), can easily become an issue for element-based listeners, which may
            declare multiple functions with the same name (for example, when multiple button press
            handlers are defined within the same page).
        </p>

        <p>
            The "example.js" file is defined as follows:
        </p>

        <source type="jscript" location="org/apache/pivot/tutorials/scripting/example.js">
            <![CDATA[
            importClass(java.lang.System);
            importPackage(org.apache.pivot.collections);

            System.out.println("Executing external script block; x = " + x);

            var foo = "ABCDE";

            var listData = new ArrayList();
            listData.add("One");
            listData.add("Two");
            listData.add("Three");
            ]]>
        </source>

        <p>
            This script declares the "foo" value that is later output by the Java application code,
            and also defines the list data that is used by the example <tt>ListView</tt> defined by
            the BXML file.
        </p>
    </body>
</document>
