summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/ui/JavaScript.java
blob: 53efb6296571c4dac1f322adeb38c889b7318a85 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* 
@VaadinApache2LicenseForJavaFiles@
 */

package com.vaadin.ui;

import java.util.HashMap;
import java.util.Map;

import com.vaadin.external.json.JSONArray;
import com.vaadin.external.json.JSONException;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc;
import com.vaadin.shared.extension.javascriptmanager.JavaScriptManagerState;
import com.vaadin.terminal.AbstractExtension;
import com.vaadin.terminal.Page;

/**
 * Provides access to JavaScript functionality in the web browser. To get an
 * instance of JavaScript, either use Page.getJavaScript() or
 * JavaScript.getCurrent() as a shorthand for getting the JavaScript object
 * corresponding to the current Page.
 * 
 * @author Vaadin Ltd
 * @version @VERSION@
 * @since 7.0.0
 */
public class JavaScript extends AbstractExtension {
    private Map<String, JavaScriptCallback> callbacks = new HashMap<String, JavaScriptCallback>();

    // Can not be defined in client package as this JSONArray is not available
    // in GWT
    public interface JavaScriptCallbackRpc extends ServerRpc {
        public void call(String name, JSONArray arguments);
    }

    /**
     * Creates a new JavaScript object. You should typically not this, but
     * instead use the JavaScript object already associated with your Page
     * object.
     */
    public JavaScript() {
        registerRpc(new JavaScriptCallbackRpc() {
            @Override
            public void call(String name, JSONArray arguments) {
                JavaScriptCallback callback = callbacks.get(name);
                // TODO handle situation if name is not registered
                try {
                    callback.call(arguments);
                } catch (JSONException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        });
    }

    @Override
    public JavaScriptManagerState getState() {
        return (JavaScriptManagerState) super.getState();
    }

    /**
     * Add a new function to the global JavaScript namespace (i.e. the window
     * object). The <code>call</code> method in the passed
     * {@link JavaScriptCallback} object will be invoked with the same
     * parameters whenever the JavaScript function is called in the browser.
     * 
     * A callback added with the name <code>"myCallback"</code> can thus be
     * invoked with the following JavaScript code:
     * <code>window.myCallback(argument1, argument2)</code>.
     * 
     * If the name parameter contains dots, simple objects are created on demand
     * to allow calling the function using the same name (e.g.
     * <code>window.myObject.myFunction</code>).
     * 
     * @param name
     *            the name that the callback function should get in the global
     *            JavaScript namespace.
     * @param callback
     *            the JavaScriptCallback that will be invoked if the JavaScript
     *            function is called.
     */
    public void addCallback(String name, JavaScriptCallback callback) {
        callbacks.put(name, callback);
        if (getState().getNames().add(name)) {
            requestRepaint();
        }
    }

    /**
     * Removes a JavaScripCallback from the browser's global JavaScript
     * namespace.
     * 
     * If the name contains dots and intermediate were created by
     * {@link #addCallback(String, JavaScriptCallback)}addCallback, these
     * objects will not be removed when the callback is removed.
     * 
     * @param name
     *            the name of the callback to remove
     */
    public void removeCallback(String name) {
        callbacks.remove(name);
        if (getState().getNames().remove(name)) {
            requestRepaint();
        }
    }

    /**
     * Executes the given JavaScript code in the browser.
     * 
     * @param script
     *            The JavaScript code to run.
     */
    public void execute(String script) {
        getRpcProxy(ExecuteJavaScriptRpc.class).executeJavaScript(script);
    }

    /**
     * Executes the given JavaScript code in the browser.
     * 
     * @param script
     *            The JavaScript code to run.
     */
    public static void eval(String script) {
        getCurrent().execute(script);
    }

    /**
     * Get the JavaScript object for the current Page, or null if there is no
     * current page.
     * 
     * @see Page#getCurrent()
     * 
     * @return the JavaScript object corresponding to the current Page, or
     *         <code>null</code> if there is no current page.
     */
    public static JavaScript getCurrent() {
        Page page = Page.getCurrent();
        if (page == null) {
            return null;
        }
        return page.getJavaScript();
    }

    /**
     * JavaScript is not designed to be removed.
     * 
     * @throws UnsupportedOperationException
     *             when invoked
     */
    @Override
    public void removeFromTarget() {
        throw new UnsupportedOperationException(
                "JavaScript is not designed to be removed.");
    }

}