aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/main/java/com/vaadin/ui/JavaScript.java
blob: 91ee1ccc20d6f0b98857996eb8f9fb45a2bd389e (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
158
159
160
161
162
163
164
165
/*
 * Copyright 2000-2014 Vaadin Ltd.
 *
 * Licensed 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.
 */

package com.vaadin.ui;

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

import com.vaadin.server.AbstractExtension;
import com.vaadin.server.Page;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc;
import com.vaadin.shared.extension.javascriptmanager.JavaScriptManagerState;

import elemental.json.JsonArray;
import elemental.json.JsonException;

/**
 * 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
 * @since 7.0.0
 */
public class JavaScript extends AbstractExtension {
    private Map<String, JavaScriptFunction> functions = new HashMap<String, JavaScriptFunction>();

    // 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) {
                JavaScriptFunction function = functions.get(name);
                // TODO handle situation if name is not registered
                try {
                    function.call(arguments);
                } catch (JsonException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        });
    }

    @Override
    protected 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 JavaScriptFunction} object will be invoked with the same
     * parameters whenever the JavaScript function is called in the browser.
     *
     * A function added with the name <code>"myFunction"</code> can thus be
     * invoked with the following JavaScript code:
     * <code>window.myFunction(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 function should get in the global JavaScript
     *            namespace.
     * @param function
     *            the JavaScriptFunction that will be invoked if the JavaScript
     *            function is called.
     */
    public void addFunction(String name, JavaScriptFunction function) {
        functions.put(name, function);
        getState().names.add(name);
    }

    /**
     * Removes a JavaScripFunction from the browser's global JavaScript
     * namespace.
     *
     * If the name contains dots and intermediate objects were created by
     * {@link #addFunction(String, JavaScriptFunction)}, these objects will not
     * be removed by this method.
     *
     * @param name
     *            the name of the callback to remove
     */
    public void removeFunction(String name) {
        functions.remove(name);
        getState().names.remove(name);
    }

    /**
     * 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 remove() {
        throw new UnsupportedOperationException(
                "JavaScript is not designed to be removed.");
    }

}