From: Joonas Lehtinen Date: Fri, 6 Nov 2009 09:41:07 +0000 (+0000) Subject: Merged implementation for #3589 X-Git-Tag: 6.7.0.beta1~2330 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=bf0c1c36b2f121a20df7245e8af6ad1688c9830f;p=vaadin-framework.git Merged implementation for #3589 svn changeset:9659/svn branch:6.2 --- diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java index 35b411ff1b..162d5fa5d7 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VView.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VView.java @@ -10,6 +10,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; +import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.DivElement; import com.google.gwt.dom.client.Document; import com.google.gwt.event.logical.shared.ResizeEvent; @@ -143,6 +144,40 @@ public class VView extends SimplePanel implements Container, ResizeHandler, $wnd.location.reload(); }-*/; + /** + * Evaluate given script in browser document. + * + * @param script + * Script to be executed with $1, $2, ... markers to be replaced + * with argument references. + * @param args + * JavaScript array of element references to be replaced in + * script + */ + private static native void eval(String script, JavaScriptObject args) + /*-{ + try { + if (script == null) return; + $wnd.evalargs = args; + if (args != null) + for (var i=1;i<= args.length;i++) + script = script.replace("$"+i, "$wnd.evalargs["+(i-1)+"]"); + eval(script); + $wnd.evalargs = null; + } catch (e) { + } + }-*/; + + /** Helper for creating empty javascript arrays */ + private native static JavaScriptObject createArray() /*-{ + return new Array(); + }-*/; + + /** Add an element to javascript array */ + private native static void pushArray(JavaScriptObject array, Element e) /*-{ + array.push(e); + }-*/; + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { rendering = true; @@ -263,6 +298,18 @@ public class VView extends SimplePanel implements Container, ResizeHandler, actionHandler = new ShortcutActionHandler(id, client); } actionHandler.updateActionMap(childUidl); + } else if (tag == "execJS") { + String script = childUidl.getStringAttribute("script"); + int argNum = childUidl.getChildCount(); + JavaScriptObject args = createArray(); + for (int i = 0; i < argNum; i++) { + String id = childUidl.getChildUIDL(i).getStringAttribute( + "ref"); + Paintable p = client.getPaintable(id); + pushArray(args, p == null ? null : ((Widget) p) + .getElement()); + } + eval(script, args); } else if (tag == "notifications") { for (final Iterator it = childUidl.getChildIterator(); it .hasNext();) { diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java index a91bd4026b..d8f4972104 100644 --- a/src/com/vaadin/ui/Window.java +++ b/src/com/vaadin/ui/Window.java @@ -8,6 +8,7 @@ import java.io.Serializable; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; +import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; @@ -19,6 +20,7 @@ import com.vaadin.Application; import com.vaadin.terminal.DownloadStream; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; +import com.vaadin.terminal.Paintable; import com.vaadin.terminal.ParameterHandler; import com.vaadin.terminal.Resource; import com.vaadin.terminal.Sizeable; @@ -119,6 +121,9 @@ public class Window extends Panel implements URIHandler, ParameterHandler { private Focusable pendingFocus; + private ArrayList jsExecQueue = null; + private ArrayList> jsExecParamsQueue = null; + /* ********************************************************************* */ /** @@ -520,6 +525,26 @@ public class Window extends Panel implements URIHandler, ParameterHandler { // Contents of the window panel is painted super.paintContent(target); + // Add executable javascripts if needed + if (jsExecQueue != null) { + while (jsExecQueue.size() > 0) { + String script = jsExecQueue.get(0); + ArrayList args = jsExecParamsQueue.get(0); + target.startTag("execJS"); + target.addAttribute("script", script); + for (Paintable p : args) { + target.startTag("arg"); + target.paintReference(p, "ref"); + target.endTag("arg"); + } + target.endTag("execJS"); + jsExecQueue.remove(0); + jsExecParamsQueue.remove(0); + } + jsExecQueue = null; + jsExecParamsQueue = null; + } + // Window position target.addVariable(this, "positionx", getPositionX()); target.addVariable(this, "positiony", getPositionY()); @@ -1632,4 +1657,67 @@ public class Window extends Panel implements URIHandler, ParameterHandler { } } + /** + * Executes JavaScript in this window. + * + *

+ * This method allows one to inject javascript from the server to client. + * Client implementation is not required to implenment this functionality, + * but currently all web-based clients do implement this. + *

+ * + *

+ * The script may contain markers indentified with "$x", where x is a one + * digit number. The number of markers must match to the number of optional + * Paintable reference parameters. The first marker is $1, second $2 and so + * on. If the markers are specified, the markers are replaced in the browser + * with references to outmost DOM elements connected to the given + * paintables. + *

+ * + *

+ * Use example 1: + mainWindow.executeJavaScript("alert(foo"); + * + *

+ * + *

+ * Use example 2: + Label label = new Label("Label"); + TextField textfield = new TextField("TestField"); + mainWindow.addComponent(label); + mainWindow.addComponent(textfield); + mainWindow.executeJavaScript("$1.style.backgroundColor='yellow';$2.style.borderColor='red';",label,textfield); + * + *

+ * + * @param script + * JavaScript snippet that will be executed and that might + * optionally contain $1, $2, ... markers. + * @param paintables + * References to number of visible paintables that correspond the + * to markers listed in script + */ + public void executeJavaScript(String script, Paintable... paintables) { + + if (getParent() != null) { + throw new UnsupportedOperationException( + "Only application level windows can execute javascript."); + } + + ArrayList ps = new ArrayList(); + for (Paintable p : paintables) { + ps.add(p); + } + + if (jsExecQueue == null) { + jsExecQueue = new ArrayList(); + jsExecParamsQueue = new ArrayList>(); + } + + jsExecQueue.add(script); + jsExecParamsQueue.add(ps); + + requestRepaint(); + } } diff --git a/tests/src/com/vaadin/tests/tickets/Ticket3589.java b/tests/src/com/vaadin/tests/tickets/Ticket3589.java new file mode 100644 index 0000000000..5b7182eb5e --- /dev/null +++ b/tests/src/com/vaadin/tests/tickets/Ticket3589.java @@ -0,0 +1,39 @@ +package com.vaadin.tests.tickets; + +import com.vaadin.Application; +import com.vaadin.ui.Button; +import com.vaadin.ui.Label; +import com.vaadin.ui.TextField; +import com.vaadin.ui.Window; +import com.vaadin.ui.Button.ClickEvent; + +public class Ticket3589 extends Application { + + @Override + public void init() { + final Window mainWindow = new Window("Test"); + setMainWindow(mainWindow); + + mainWindow.addComponent(new Button("alert('foo')", + new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + mainWindow.executeJavaScript("alert('foo');"); + } + })); + + final Label label = new Label("Label"); + final TextField textfield = new TextField("TestField"); + mainWindow.addComponent(label); + mainWindow.addComponent(textfield); + + final String script = "$1.style.backgroundColor='yellow';$2.style.borderColor='red';"; + mainWindow.addComponent(new Button(script, new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + mainWindow.executeJavaScript(script, label, textfield); + } + })); + + } +}