summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2012-06-20 14:36:21 +0300
committerLeif Åstrand <leif@vaadin.com>2012-06-20 14:36:29 +0300
commitf505d99754fa0139fbbe1b52236ad622c8c3246d (patch)
treeef1a33af9503b202045c60c6fdb1f8a738595aba /src/com/vaadin
parent29d592938cabec07c72e007008d019136fbe5f4f (diff)
downloadvaadin-framework-f505d99754fa0139fbbe1b52236ad622c8c3246d.tar.gz
vaadin-framework-f505d99754fa0139fbbe1b52236ad622c8c3246d.zip
Javadocs and minor tweaks for extensions, JavaScript and js wrappers
Diffstat (limited to 'src/com/vaadin')
-rw-r--r--src/com/vaadin/terminal/AbstractClientConnector.java31
-rw-r--r--src/com/vaadin/terminal/AbstractExtension.java42
-rw-r--r--src/com/vaadin/terminal/AbstractJavaScriptExtension.java130
-rw-r--r--src/com/vaadin/terminal/Extension.java18
-rw-r--r--src/com/vaadin/terminal/JavaScriptCallbackHelper.java14
-rw-r--r--src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java4
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java4
-rw-r--r--src/com/vaadin/terminal/gwt/server/ClientConnector.java56
-rw-r--r--src/com/vaadin/ui/AbstractJavaScriptComponent.java136
-rw-r--r--src/com/vaadin/ui/JavaScript.java74
-rw-r--r--src/com/vaadin/ui/JavaScriptCallback.java27
11 files changed, 488 insertions, 48 deletions
diff --git a/src/com/vaadin/terminal/AbstractClientConnector.java b/src/com/vaadin/terminal/AbstractClientConnector.java
index ee1a2ab981..6a87f58c71 100644
--- a/src/com/vaadin/terminal/AbstractClientConnector.java
+++ b/src/com/vaadin/terminal/AbstractClientConnector.java
@@ -31,7 +31,12 @@ import com.vaadin.ui.HasComponents;
import com.vaadin.ui.Root;
/**
- *
+ * An abstract base class for ClientConnector implementations. This class
+ * provides all the basic functionality required for connectors.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
*/
public abstract class AbstractClientConnector implements ClientConnector {
/**
@@ -115,6 +120,7 @@ public abstract class AbstractClientConnector implements ClientConnector {
throw new RuntimeException(
"Use registerRpc(T implementation, Class<T> rpcInterfaceType) if the Rpc implementation implements more than one interface");
}
+ @SuppressWarnings("unchecked")
Class<T> type = (Class<T>) interfaces[0];
registerRpc(implementation, type);
}
@@ -371,6 +377,14 @@ public abstract class AbstractClientConnector implements ClientConnector {
}
}
+ /**
+ * Get an Iterable for iterating over all child connectors, including both
+ * extensions and child components.
+ *
+ * @param connector
+ * the connector to get children for
+ * @return an Iterable giving all child connectors.
+ */
public static Iterable<ClientConnector> getAllChildrenIterable(
final ClientConnector connector) {
return new AllChildrenIterable(connector);
@@ -380,6 +394,13 @@ public abstract class AbstractClientConnector implements ClientConnector {
return Collections.unmodifiableCollection(extensions);
}
+ /**
+ * Add an extension to this connector. This method is protected to allow
+ * extensions to select which targets they can extend.
+ *
+ * @param extension
+ * the extension to add
+ */
protected void addExtension(Extension extension) {
ClientConnector previousParent = extension.getParent();
if (previousParent == this) {
@@ -439,6 +460,14 @@ public abstract class AbstractClientConnector implements ClientConnector {
}
}
+ /**
+ * {@inheritDoc}
+ *
+ * <p>
+ * The {@link #getApplication()} and {@link #getRoot()} methods might return
+ * <code>null</code> after this method is called.
+ * </p>
+ */
public void detach() {
for (ClientConnector connector : getAllChildrenIterable(this)) {
connector.detach();
diff --git a/src/com/vaadin/terminal/AbstractExtension.java b/src/com/vaadin/terminal/AbstractExtension.java
index 6753d6f929..33a60e39ef 100644
--- a/src/com/vaadin/terminal/AbstractExtension.java
+++ b/src/com/vaadin/terminal/AbstractExtension.java
@@ -6,19 +6,51 @@ package com.vaadin.terminal;
import com.vaadin.terminal.gwt.server.ClientConnector;
+/**
+ * An extension is an entity that is attached to a Component or another
+ * Extension and independently communicates between client and server.
+ * <p>
+ * Extensions can use shared state and RPC in the same way as components.
+ * <p>
+ * AbstractExtension adds a mechanism for adding the extension to any Connector
+ * (extend). To let the Extension determine what kind target it can be added to,
+ * the extend method is declared as protected.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
public abstract class AbstractExtension extends AbstractClientConnector
implements Extension {
private boolean previouslyAttached = false;
- protected Class<? extends ClientConnector> getAcceptedParentType() {
+ /**
+ * Gets a type that the parent must be an instance of. Override this if the
+ * extension only support certain targets, e.g. if only TextFields can be
+ * extended.
+ *
+ * @return a type that the parent must be an instance of
+ */
+ protected Class<? extends ClientConnector> getSupportedParentType() {
return ClientConnector.class;
}
+ /**
+ * Add this extension to the target connector. This method is protected to
+ * allow subclasses to require a more specific type of target.
+ *
+ * @param target
+ * the connector to attach this extension to
+ */
protected void extend(AbstractClientConnector target) {
target.addExtension(this);
}
- protected void removeFromTarget() {
+ /**
+ * Remove this extension from its target. After an extension has been
+ * removed, it can not be attached again.
+ */
+ public void removeFromTarget() {
getParent().removeExtension(this);
}
@@ -29,14 +61,14 @@ public abstract class AbstractExtension extends AbstractClientConnector
"An extension can not be set to extend a new target after getting detached from the previous.");
}
- Class<? extends ClientConnector> acceptedParentType = getAcceptedParentType();
- if (parent == null || acceptedParentType.isInstance(parent)) {
+ Class<? extends ClientConnector> supportedParentType = getSupportedParentType();
+ if (parent == null || supportedParentType.isInstance(parent)) {
super.setParent(parent);
previouslyAttached = true;
} else {
throw new IllegalArgumentException(getClass().getName()
+ " can only be attached to targets of type "
- + acceptedParentType.getName() + " but attach to "
+ + supportedParentType.getName() + " but attach to "
+ parent.getClass().getName() + " was attempted.");
}
}
diff --git a/src/com/vaadin/terminal/AbstractJavaScriptExtension.java b/src/com/vaadin/terminal/AbstractJavaScriptExtension.java
index a2f8019858..bdcd948c74 100644
--- a/src/com/vaadin/terminal/AbstractJavaScriptExtension.java
+++ b/src/com/vaadin/terminal/AbstractJavaScriptExtension.java
@@ -7,22 +7,146 @@ package com.vaadin.terminal;
import com.vaadin.terminal.gwt.client.JavaScriptExtensionState;
import com.vaadin.ui.JavaScriptCallback;
-public class AbstractJavaScriptExtension extends AbstractExtension {
+/**
+ * Base class for Extensions with all client-side logic implemented using
+ * JavaScript.
+ * <p>
+ * When a new JavaScript extension is initialized in the browser, the framework
+ * will look for a globally defined JavaScript function that will initialize the
+ * extension. The name of the initialization function is formed by replacing .
+ * with _ in the name of the server-side class. If no such function is defined,
+ * each super class is used in turn until a match is found. The framework will
+ * thus first attempt with <code>com_example_MyExtension</code> for the
+ * server-side
+ * <code>com.example.MyExtension extends AbstractJavaScriptExtension</code>
+ * class. If MyExtension instead extends <code>com.example.SuperExtension</code>
+ * , then <code>com_example_SuperExtension</code> will also be attempted if
+ * <code>com_example_MyExtension</code> has not been defined.
+ * <p>
+ *
+ * The initialization function will be called with <code>this</code> pointing to
+ * a connector wrapper object providing integration to Vaadin with the following
+ * functions:
+ * <ul>
+ * <li><code>getConnectorId()</code> - returns a string with the id of the
+ * connector.</li>
+ * <li><code>getParentId([connectorId])</code> - returns a string with the id of
+ * the connector's parent. If <code>connectorId</code> is provided, the id of
+ * the parent of the corresponding connector with the passed id is returned
+ * instead.</li>
+ * <li><code>getWidgetElement([connectorId])</code> - returns the DOM Element
+ * that is the root of a connector's widget. <code>null</code> is returned if
+ * the connector can not be found or if the connector doesn't have a widget. If
+ * <code>connectorId</code> is not provided, the connector id of the current
+ * connector will be used.</li>
+ * <li><code>getState()</code> - returns an object corresponding to the shared
+ * state defined on the server. The scheme for conversion between Java and
+ * JavaScript types is described bellow.</li>
+ * <li><code>registerRpc([name, ] rpcObject)</code> - registers the
+ * <code>rpcObject</code> as a RPC handler. <code>rpcObject</code> should be an
+ * object with field containing functions for all eligible RPC functions. If
+ * <code>name</code> is provided, the RPC handler will only used for RPC calls
+ * for the RPC interface with the same fully qualified Java name. If no
+ * <code>name</code> is provided, the RPC handler will be used for all incoming
+ * RPC invocations where the RPC method name is defined as a function field in
+ * the handler. The scheme for conversion between Java types in the RPC
+ * interface definition and the JavaScript values passed as arguments to the
+ * handler functions is described bellow.</li>
+ * <li><code>getRpcProxy([name])</code> - returns an RPC proxy object. If
+ * <code>name</code> is provided, the proxy object will contain functions for
+ * all methods in the RPC interface with the same fully qualified name, provided
+ * a RPC handler has been registered by the server-side code. If no
+ * <code>name</code> is provided, the returned RPC proxy object will contain
+ * functions for all methods in all RPC interfaces registered for the connector
+ * on the server. If the same method name is present in multiple registered RPC
+ * interfaces, the corresponding function in the RPC proxy object will throw an
+ * exception when called. The scheme for conversion between Java types in the
+ * RPC interface and the JavaScript values that should be passed to the
+ * functions is described bellow.</li>
+ * </ul>
+ * The connector wrapper also supports these special functions:
+ * <ul>
+ * <li><code>onStateChange</code> - If the JavaScript code assigns a function to
+ * the field, that function is called whenever the contents of the shared state
+ * is changed.</li>
+ * <li>Any field name corresponding to a call to
+ * {@link #registerCallback(String, JavaScriptCallback)} on the server will
+ * automatically be present as a function that triggers the registered callback
+ * on the server.</li>
+ * <li>Any field name referred to using
+ * {@link #invokeCallback(String, Object...)} on the server will be called if a
+ * function has been assigned to the field.</li>
+ * </ul>
+ * <p>
+ *
+ * Values in the Shared State and in RPC calls are converted between Java and
+ * JavaScript using the following conventions:
+ * <ul>
+ * <li>Primitive Java numbers (byte, char, int, long, float, double) and their
+ * boxed types (Byte, Character, Integer, Long, Float, Double) are represented
+ * by JavaScript numbers.</li>
+ * <li>The primitive Java boolean and the boxed Boolean are represented by
+ * JavaScript booleans.</li>
+ * <li>Java Strings are represented by JavaScript strings.</li>
+ * <li>List, Set and all arrays in Java are represented by JavaScript arrays.</li>
+ * <li>Map<String, ?> in Java is represented by JavaScript object with fields
+ * corresponding to the map keys.</li>
+ * <li>Any other Java Map is represented by a JavaScript array containing two
+ * arrays, the first contains the keys and the second contains the values in the
+ * same order.</li>
+ * <li>A Java Bean is represented by a JavaScript object with fields
+ * corresponding to the bean's properties.</li>
+ * <li>A Java Connector is represented by a JavaScript string containing the
+ * connector's id.</li>
+ * <li>A pluggable serialization mechanism is provided for types not described
+ * here. Please refer to the documentation for specific types for serialization
+ * information.</li>
+ * </ul>
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
+public abstract class AbstractJavaScriptExtension extends AbstractExtension {
private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper(
this);
@Override
- protected <T> void registerRpc(T implementation,
- java.lang.Class<T> rpcInterfaceType) {
+ protected <T> void registerRpc(T implementation, Class<T> rpcInterfaceType) {
super.registerRpc(implementation, rpcInterfaceType);
callbackHelper.registerRpc(rpcInterfaceType);
}
+ /**
+ * Register a {@link JavaScriptCallback} that can be called from the
+ * JavaScript using the provided name. A JavaScript function with the
+ * provided name will be added to the connector wrapper object (initially
+ * available as <code>this</code>). Calling that JavaScript function will
+ * cause the call method in the registered {@link JavaScriptCallback} to be
+ * invoked with the same arguments.
+ *
+ * @param functionName
+ * the name that should be used for client-side callback
+ * @param javaScriptCallback
+ * the callback object that will be invoked when the JavaScript
+ * function is called
+ */
protected void registerCallback(String functionName,
JavaScriptCallback javaScriptCallback) {
callbackHelper.registerCallback(functionName, javaScriptCallback);
}
+ /**
+ * Invoke a named function that the connector JavaScript has added to the
+ * JavaScript connector wrapper object. The arguments should only contain
+ * data types that can be represented in JavaScript, including primitive
+ * boxing types, arrays, String, List, Set, Map, Connector and JavaBeans.
+ *
+ * @param name
+ * the name of the function
+ * @param arguments
+ * function arguments
+ */
protected void invokeCallback(String name, Object... arguments) {
callbackHelper.invokeCallback(name, arguments);
}
diff --git a/src/com/vaadin/terminal/Extension.java b/src/com/vaadin/terminal/Extension.java
index 7769423f0d..ef5bb4cf8d 100644
--- a/src/com/vaadin/terminal/Extension.java
+++ b/src/com/vaadin/terminal/Extension.java
@@ -6,6 +6,22 @@ package com.vaadin.terminal;
import com.vaadin.terminal.gwt.server.ClientConnector;
+/**
+ * An extension is an entity that is attached to a Component or another
+ * Extension and independently communicates between client and server.
+ * <p>
+ * An extension can only be attached once. It is not supported to move an
+ * extension from one target to another.
+ * <p>
+ * Extensions can use shared state and RPC in the same way as components.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
public interface Extension extends ClientConnector {
-
+ /*
+ * Currently just an empty marker interface to distinguish between
+ * extensions and other connectors, e.g. components
+ */
}
diff --git a/src/com/vaadin/terminal/JavaScriptCallbackHelper.java b/src/com/vaadin/terminal/JavaScriptCallbackHelper.java
index 2da64d7b10..01db0267d9 100644
--- a/src/com/vaadin/terminal/JavaScriptCallbackHelper.java
+++ b/src/com/vaadin/terminal/JavaScriptCallbackHelper.java
@@ -14,11 +14,25 @@ import java.util.Set;
import com.vaadin.external.json.JSONArray;
import com.vaadin.external.json.JSONException;
+import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper;
import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper.JavaScriptConnectorState;
import com.vaadin.tools.ReflectTools;
+import com.vaadin.ui.AbstractJavaScriptComponent;
import com.vaadin.ui.JavaScript.JavaScriptCallbackRpc;
import com.vaadin.ui.JavaScriptCallback;
+/**
+ * Internal helper class used to implement functionality common to
+ * {@link AbstractJavaScriptComponent} and {@link AbstractJavaScriptExtension}.
+ * Corresponding support in client-side code is in
+ * {@link JavaScriptConnectorHelper}.
+ * <p>
+ * You should most likely no use this class directly.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
public class JavaScriptCallbackHelper implements Serializable {
private static final Method CALL_METHOD = ReflectTools.findMethod(
diff --git a/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java b/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java
index 61c50dbcb4..2a97e4a770 100644
--- a/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java
+++ b/src/com/vaadin/terminal/gwt/client/JavaScriptExtension.java
@@ -10,8 +10,8 @@ import com.vaadin.terminal.gwt.client.extensions.AbstractExtensionConnector;
import com.vaadin.terminal.gwt.client.ui.Connect;
@Connect(AbstractJavaScriptExtension.class)
-public class JavaScriptExtension extends AbstractExtensionConnector implements
- HasJavaScriptConnectorHelper {
+public final class JavaScriptExtension extends AbstractExtensionConnector
+ implements HasJavaScriptConnectorHelper {
private final JavaScriptConnectorHelper helper = new JavaScriptConnectorHelper(
this);
diff --git a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java
index ab5280fee9..bb062a6677 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/JavaScriptComponentConnector.java
@@ -8,8 +8,8 @@ import com.vaadin.terminal.gwt.client.communication.HasJavaScriptConnectorHelper
import com.vaadin.ui.AbstractJavaScriptComponent;
@Connect(AbstractJavaScriptComponent.class)
-public class JavaScriptComponentConnector extends AbstractComponentConnector
- implements HasJavaScriptConnectorHelper {
+public final class JavaScriptComponentConnector extends
+ AbstractComponentConnector implements HasJavaScriptConnectorHelper {
private final JavaScriptConnectorHelper helper = new JavaScriptConnectorHelper(
this) {
diff --git a/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/src/com/vaadin/terminal/gwt/server/ClientConnector.java
index 860627a352..dfdd58879d 100644
--- a/src/com/vaadin/terminal/gwt/server/ClientConnector.java
+++ b/src/com/vaadin/terminal/gwt/server/ClientConnector.java
@@ -12,7 +12,6 @@ import com.vaadin.terminal.gwt.client.Connector;
import com.vaadin.terminal.gwt.client.communication.SharedState;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
-import com.vaadin.ui.Root;
/**
* Interface implemented by all connectors that are capable of communicating
@@ -30,8 +29,6 @@ public interface ClientConnector extends Connector, RpcTarget {
*
* @return an unmodifiable ordered list of pending server to client method
* calls (not null)
- *
- * @since 7.0
*/
public List<ClientMethodInvocation> retrievePendingRpcCalls();
@@ -61,7 +58,7 @@ public interface ClientConnector extends Connector, RpcTarget {
* Causes a repaint of this connector, and all connectors below it.
*
* This should only be used in special cases, e.g when the state of a
- * descendant depends on the state of a ancestor.
+ * descendant depends on the state of an ancestor.
*/
public void requestRepaintAll();
@@ -69,18 +66,18 @@ public interface ClientConnector extends Connector, RpcTarget {
* Sets the parent connector of the connector.
*
* <p>
- * This method automatically calls {@link #attach()} if the parent becomes
- * attached to the application, regardless of whether it was attached
- * previously. Conversely, if the parent is {@code null} and the connector
- * is attached to the application, {@link #detach()} is called for the
- * connector.
+ * This method automatically calls {@link #attach()} if the connector
+ * becomes attached to the application, regardless of whether it was
+ * attached previously. Conversely, if the parent is {@code null} and the
+ * connector is attached to the application, {@link #detach()} is called for
+ * the connector.
* </p>
* <p>
* This method is rarely called directly. One of the
* {@link ComponentContainer#addComponent(Component)} or
- * {@link AbstractClientConnector#addFeature(Feature)} methods is normally
- * used for adding connectors to a container and it will call this method
- * implicitly.
+ * {@link AbstractClientConnector#addExtension(Extension)} methods are
+ * normally used for adding connectors to a parent and they will call this
+ * method implicitly.
* </p>
*
* <p>
@@ -103,15 +100,13 @@ public interface ClientConnector extends Connector, RpcTarget {
* The caller of this method is {@link #setParent(ClientConnector)} if the
* parent is itself already attached to the application. If not, the parent
* will call the {@link #attach()} for all its children when it is attached
- * to the application. This method is always called before the connector is
- * painted for the first time.
+ * to the application. This method is always called before the connector's
+ * data is sent to the client-side for the first time.
* </p>
*
* <p>
* The attachment logic is implemented in {@link AbstractClientConnector}.
* </p>
- *
- * @see #getApplication()
*/
public void attach();
@@ -119,25 +114,26 @@ public interface ClientConnector extends Connector, RpcTarget {
* Notifies the component that it is detached from the application.
*
* <p>
- * The {@link #getApplication()} and {@link #getRoot()} methods might return
- * <code>null</code> after this method is called.
- * </p>
- *
- * <p>
- * This method must call {@link Root#componentDetached(Component)} to let
- * the Root know that a new Component has been attached.
- * </p>
- * *
- * <p>
- * The caller of this method is {@link #setParent(Component)} if the parent
- * is in the application. When the parent is detached from the application
- * it is its response to call {@link #detach()} for all the children and to
- * detach itself from the terminal.
+ * The caller of this method is {@link #setParent(ClientConnector)} if the
+ * parent is in the application. When the parent is detached from the
+ * application it is its response to call {@link #detach()} for all the
+ * children and to detach itself from the terminal.
* </p>
*/
public void detach();
+ /**
+ * Get a read-only collection of all extensions attached to this connector.
+ *
+ * @return a collection of extensions
+ */
public Collection<Extension> getExtensions();
+ /**
+ * Remove an extension from this connector.
+ *
+ * @param extension
+ * the extension to remove.
+ */
public void removeExtension(Extension extension);
}
diff --git a/src/com/vaadin/ui/AbstractJavaScriptComponent.java b/src/com/vaadin/ui/AbstractJavaScriptComponent.java
index 343caf4abb..95c45f55f9 100644
--- a/src/com/vaadin/ui/AbstractJavaScriptComponent.java
+++ b/src/com/vaadin/ui/AbstractJavaScriptComponent.java
@@ -5,23 +5,151 @@ package com.vaadin.ui;
import com.vaadin.terminal.JavaScriptCallbackHelper;
import com.vaadin.terminal.gwt.client.ui.JavaScriptComponentState;
+import com.vaadin.terminal.gwt.client.ui.JavaScriptWidget;
+/**
+ * Base class for Components with all client-side logic implemented using
+ * JavaScript.
+ * <p>
+ * When a new JavaScript component is initialized in the browser, the framework
+ * will look for a globally defined JavaScript function that will initialize the
+ * component. The name of the initialization function is formed by replacing .
+ * with _ in the name of the server-side class. If no such function is defined,
+ * each super class is used in turn until a match is found. The framework will
+ * thus first attempt with <code>com_example_MyComponent</code> for the
+ * server-side
+ * <code>com.example.MyComponent extends AbstractJavaScriptComponent</code>
+ * class. If MyComponent instead extends <code>com.example.SuperComponent</code>
+ * , then <code>com_example_SuperComponent</code> will also be attempted if
+ * <code>com_example_MyComponent</code> has not been defined.
+ * <p>
+ * JavaScript components have a very simple GWT widget ({@link JavaScriptWidget}
+ * ) just consisting of a <code>div</code> element to which the JavaScript code
+ * should initialize its own user interface.
+ * <p>
+ * The initialization function will be called with <code>this</code> pointing to
+ * a connector wrapper object providing integration to Vaadin with the following
+ * functions:
+ * <ul>
+ * <li><code>getConnectorId()</code> - returns a string with the id of the
+ * connector.</li>
+ * <li><code>getParentId([connectorId])</code> - returns a string with the id of
+ * the connector's parent. If <code>connectorId</code> is provided, the id of
+ * the parent of the corresponding connector with the passed id is returned
+ * instead.</li>
+ * <li><code>getWidgetElement([connectorId])</code> - returns the DOM Element
+ * that is the root of a connector's widget. <code>null</code> is returned if
+ * the connector can not be found or if the connector doesn't have a widget. If
+ * <code>connectorId</code> is not provided, the connector id of the current
+ * connector will be used.</li>
+ * <li><code>getState()</code> - returns an object corresponding to the shared
+ * state defined on the server. The scheme for conversion between Java and
+ * JavaScript types is described bellow.</li>
+ * <li><code>registerRpc([name, ] rpcObject)</code> - registers the
+ * <code>rpcObject</code> as a RPC handler. <code>rpcObject</code> should be an
+ * object with field containing functions for all eligible RPC functions. If
+ * <code>name</code> is provided, the RPC handler will only used for RPC calls
+ * for the RPC interface with the same fully qualified Java name. If no
+ * <code>name</code> is provided, the RPC handler will be used for all incoming
+ * RPC invocations where the RPC method name is defined as a function field in
+ * the handler. The scheme for conversion between Java types in the RPC
+ * interface definition and the JavaScript values passed as arguments to the
+ * handler functions is described bellow.</li>
+ * <li><code>getRpcProxy([name])</code> - returns an RPC proxy object. If
+ * <code>name</code> is provided, the proxy object will contain functions for
+ * all methods in the RPC interface with the same fully qualified name, provided
+ * a RPC handler has been registered by the server-side code. If no
+ * <code>name</code> is provided, the returned RPC proxy object will contain
+ * functions for all methods in all RPC interfaces registered for the connector
+ * on the server. If the same method name is present in multiple registered RPC
+ * interfaces, the corresponding function in the RPC proxy object will throw an
+ * exception when called. The scheme for conversion between Java types in the
+ * RPC interface and the JavaScript values that should be passed to the
+ * functions is described bellow.</li>
+ * </ul>
+ * The connector wrapper also supports these special functions:
+ * <ul>
+ * <li><code>onStateChange</code> - If the JavaScript code assigns a function to
+ * the field, that function is called whenever the contents of the shared state
+ * is changed.</li>
+ * <li>Any field name corresponding to a call to
+ * {@link #registerCallback(String, JavaScriptCallback)} on the server will
+ * automatically be present as a function that triggers the registered callback
+ * on the server.</li>
+ * <li>Any field name referred to using
+ * {@link #invokeCallback(String, Object...)} on the server will be called if a
+ * function has been assigned to the field.</li>
+ * </ul>
+ * <p>
+ *
+ * Values in the Shared State and in RPC calls are converted between Java and
+ * JavaScript using the following conventions:
+ * <ul>
+ * <li>Primitive Java numbers (byte, char, int, long, float, double) and their
+ * boxed types (Byte, Character, Integer, Long, Float, Double) are represented
+ * by JavaScript numbers.</li>
+ * <li>The primitive Java boolean and the boxed Boolean are represented by
+ * JavaScript booleans.</li>
+ * <li>Java Strings are represented by JavaScript strings.</li>
+ * <li>List, Set and all arrays in Java are represented by JavaScript arrays.</li>
+ * <li>Map<String, ?> in Java is represented by JavaScript object with fields
+ * corresponding to the map keys.</li>
+ * <li>Any other Java Map is represented by a JavaScript array containing two
+ * arrays, the first contains the keys and the second contains the values in the
+ * same order.</li>
+ * <li>A Java Bean is represented by a JavaScript object with fields
+ * corresponding to the bean's properties.</li>
+ * <li>A Java Connector is represented by a JavaScript string containing the
+ * connector's id.</li>
+ * <li>A pluggable serialization mechanism is provided for types not described
+ * here. Please refer to the documentation for specific types for serialization
+ * information.</li>
+ * </ul>
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
public class AbstractJavaScriptComponent extends AbstractComponent {
private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper(
this);
@Override
- protected <T> void registerRpc(T implementation,
- java.lang.Class<T> rpcInterfaceType) {
+ protected <T> void registerRpc(T implementation, Class<T> rpcInterfaceType) {
super.registerRpc(implementation, rpcInterfaceType);
callbackHelper.registerRpc(rpcInterfaceType);
}
+ /**
+ * Register a {@link JavaScriptCallback} that can be called from the
+ * JavaScript using the provided name. A JavaScript function with the
+ * provided name will be added to the connector wrapper object (initially
+ * available as <code>this</code>). Calling that JavaScript function will
+ * cause the call method in the registered {@link JavaScriptCallback} to be
+ * invoked with the same arguments.
+ *
+ * @param functionName
+ * the name that should be used for client-side callback
+ * @param javaScriptCallback
+ * the callback object that will be invoked when the JavaScript
+ * function is called
+ */
protected void registerCallback(String functionName,
- JavaScriptCallback javascriptCallback) {
- callbackHelper.registerCallback(functionName, javascriptCallback);
+ JavaScriptCallback javaScriptCallback) {
+ callbackHelper.registerCallback(functionName, javaScriptCallback);
}
+ /**
+ * Invoke a named function that the connector JavaScript has added to the
+ * JavaScript connector wrapper object. The arguments should only contain
+ * data types that can be represented in JavaScript, including primitive
+ * boxing types, arrays, String, List, Set, Map, Connector and JavaBeans.
+ *
+ * @param name
+ * the name of the function
+ * @param arguments
+ * function arguments
+ */
protected void invokeCallback(String name, Object... arguments) {
callbackHelper.invokeCallback(name, arguments);
}
diff --git a/src/com/vaadin/ui/JavaScript.java b/src/com/vaadin/ui/JavaScript.java
index 241d477506..d256717711 100644
--- a/src/com/vaadin/ui/JavaScript.java
+++ b/src/com/vaadin/ui/JavaScript.java
@@ -15,6 +15,16 @@ import com.vaadin.terminal.gwt.client.communication.ServerRpc;
import com.vaadin.terminal.gwt.client.extensions.javascriptmanager.ExecuteJavaScriptRpc;
import com.vaadin.terminal.gwt.client.extensions.javascriptmanager.JavaScriptManagerState;
+/**
+ * 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>();
@@ -24,6 +34,11 @@ public class JavaScript extends AbstractExtension {
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() {
public void call(String name, JSONArray arguments) {
@@ -43,6 +58,27 @@ public class JavaScript extends AbstractExtension {
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)) {
@@ -50,6 +86,17 @@ public class JavaScript extends AbstractExtension {
}
}
+ /**
+ * 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)) {
@@ -57,10 +104,25 @@ public class JavaScript extends AbstractExtension {
}
}
+ /**
+ * 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);
}
+ /**
+ * 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) {
@@ -69,4 +131,16 @@ public class JavaScript extends AbstractExtension {
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.");
+ }
+
}
diff --git a/src/com/vaadin/ui/JavaScriptCallback.java b/src/com/vaadin/ui/JavaScriptCallback.java
index e6b16010e4..49f7695e89 100644
--- a/src/com/vaadin/ui/JavaScriptCallback.java
+++ b/src/com/vaadin/ui/JavaScriptCallback.java
@@ -8,7 +8,34 @@ import java.io.Serializable;
import com.vaadin.external.json.JSONArray;
import com.vaadin.external.json.JSONException;
+import com.vaadin.terminal.AbstractJavaScriptExtension;
+/**
+ * Defines a method that is called by a client-side JavaScript function. When
+ * the corresponding JavaScript function is called, the {@link #call(JSONArray)}
+ * method is invoked.
+ *
+ * @see JavaScript#addCallback(String, JavaScriptCallback)
+ * @see AbstractJavaScriptComponent#registerCallback(String, JavaScriptCallback)
+ * @see AbstractJavaScriptExtension#registerCallback(String, JavaScriptCallback)
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.0.0
+ */
public interface JavaScriptCallback extends Serializable {
+ /**
+ * Invoked whenever the corresponding JavaScript function is called in the
+ * browser.
+ * <p>
+ * Because of the asynchronous nature of the communication between client
+ * and server, no return value can be sent back to the browser.
+ *
+ * @param arguments
+ * an array with JSON representations of the arguments with which
+ * the JavaScript function was called.
+ * @throws JSONException
+ * if the arguments can not be interpreted
+ */
public void call(JSONArray arguments) throws JSONException;
}