]> source.dussan.org Git - vaadin-framework.git/commitdiff
fixes #4605
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Thu, 29 Apr 2010 14:21:14 +0000 (14:21 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Thu, 29 Apr 2010 14:21:14 +0000 (14:21 +0000)
svn changeset:12930/svn branch:6.3

src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategy.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategyIE.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VUpload.java

diff --git a/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategy.java b/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategy.java
new file mode 100644 (file)
index 0000000..a79d1cd
--- /dev/null
@@ -0,0 +1,22 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+public class UploadIFrameOnloadStrategy {
+
+    native void hookEvents(com.google.gwt.dom.client.Element iframe,
+            VUpload upload)
+    /*-{
+        iframe.onload = function() {
+            upload.@com.vaadin.terminal.gwt.client.ui.VUpload::onSubmitComplete()();
+        };
+    }-*/;
+
+    /**
+     * @param iframe
+     *            the iframe whose onLoad event is to be cleaned
+     */
+    native void unHookEvents(com.google.gwt.dom.client.Element iframe)
+    /*-{
+        iframe.onload = null;
+    }-*/;
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategyIE.java b/src/com/vaadin/terminal/gwt/client/ui/UploadIFrameOnloadStrategyIE.java
new file mode 100644 (file)
index 0000000..698d630
--- /dev/null
@@ -0,0 +1,26 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.Element;
+
+/**
+ * IE does not have onload, detect onload via readystatechange
+ * 
+ */
+public class UploadIFrameOnloadStrategyIE extends UploadIFrameOnloadStrategy {
+    @Override
+    native void hookEvents(Element iframe, VUpload upload)
+    /*-{
+      iframe.onreadystatechange = function() {
+        if (iframe.readyState == 'complete') {
+          upload.@com.vaadin.terminal.gwt.client.ui.VUpload::onSubmitComplete()();
+        }
+      };
+    }-*/;
+
+    @Override
+    native void unHookEvents(Element iframe)
+    /*-{
+      iframe.onreadystatechange = null;
+    }-*/;
+
+}
index aded833138becbee6258427d2ac8566cf6d28f0b..d164de79db6813b5b7e78c22fe7220a6abdad729 100644 (file)
@@ -4,8 +4,14 @@
 
 package com.vaadin.terminal.gwt.client.ui;
 
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.FormElement;
 import com.google.gwt.event.dom.client.ClickEvent;
 import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Timer;
@@ -14,14 +20,18 @@ import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.FormPanel;
 import com.google.gwt.user.client.ui.Hidden;
 import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
-import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
+import com.google.gwt.user.client.ui.SimplePanel;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
 import com.vaadin.terminal.gwt.client.Paintable;
 import com.vaadin.terminal.gwt.client.UIDL;
 
-public class VUpload extends FormPanel implements Paintable,
-        SubmitCompleteHandler, SubmitHandler {
+/**
+ * 
+ * Note, we are not using GWT FormPanel as we want to listen submitcomplete
+ * events even though the upload component is already detached.
+ * 
+ */
+public class VUpload extends SimplePanel implements Paintable {
 
     private final class MyFileUpload extends FileUpload {
         @Override
@@ -53,6 +63,9 @@ public class VUpload extends FormPanel implements Paintable,
 
     Panel panel = new FlowPanel();
 
+    UploadIFrameOnloadStrategy onloadstrategy = GWT
+            .create(UploadIFrameOnloadStrategy.class);
+
     ApplicationConnection client;
 
     private String paintableId;
@@ -82,10 +95,16 @@ public class VUpload extends FormPanel implements Paintable,
 
     private Hidden maxfilesize = new Hidden();
 
+    private FormElement element;
+
+    private com.google.gwt.dom.client.Element synthesizedFrame;
+
     public VUpload() {
-        super();
-        setEncoding(FormPanel.ENCODING_MULTIPART);
-        setMethod(FormPanel.METHOD_POST);
+        super(com.google.gwt.dom.client.Document.get().createFormElement());
+
+        element = getElement().cast();
+        setEncoding(getElement(), FormPanel.ENCODING_MULTIPART);
+        element.setMethod(FormPanel.METHOD_POST);
 
         setWidget(panel);
         panel.add(maxfilesize);
@@ -103,12 +122,16 @@ public class VUpload extends FormPanel implements Paintable,
         });
         panel.add(submitButton);
 
-        addSubmitCompleteHandler(this);
-        addSubmitHandler(this);
-
         setStyleName(CLASSNAME);
     }
 
+    private static native void setEncoding(Element form, String encoding)
+    /*-{
+      form.enctype = encoding;
+      // For IE6
+      form.encoding = encoding;
+    }-*/;
+
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
         if (client.updateComponent(this, uidl, true)) {
             return;
@@ -116,7 +139,7 @@ public class VUpload extends FormPanel implements Paintable,
         setImmediate(uidl.getBooleanAttribute("immediate"));
         this.client = client;
         paintableId = uidl.getId();
-        setAction(client.getAppUri());
+        element.setAction(client.getAppUri());
         submitButton.setText(uidl.getStringAttribute("buttoncaption"));
         fu.setName(paintableId + "_file");
 
@@ -125,6 +148,7 @@ public class VUpload extends FormPanel implements Paintable,
         } else if (!uidl.getBooleanAttribute("state")) {
             // Enable the button only if an upload is not in progress
             enableUpload();
+            ensureTargetFrame();
         }
     }
 
@@ -182,24 +206,38 @@ public class VUpload extends FormPanel implements Paintable,
         }
     }
 
-    public void onSubmitComplete(SubmitCompleteEvent event) {
-        if (client != null) {
-            if (t != null) {
-                t.cancel();
-            }
-            ApplicationConnection.getConsole().log("Submit complete");
-            client.sendPendingVariableChanges();
-        }
+    /**
+     * Called by JSNI (hooked via {@link #onloadstrategy})
+     */
+    @SuppressWarnings("unused")
+    private void onSubmitComplete() {
+        /* Needs to be run dereferred to avoid various browser issues. */
+        DeferredCommand.addCommand(new Command() {
+            public void execute() {
+                if (client != null) {
+                    if (t != null) {
+                        t.cancel();
+                    }
+                    ApplicationConnection.getConsole().log("Submit complete");
+                    client.sendPendingVariableChanges();
+                }
 
-        rebuildPanel();
+                rebuildPanel();
 
-        submitted = false;
-        enableUpload();
+                submitted = false;
+                enableUpload();
+                if (!isAttached()) {
+                    /*
+                     * Upload is complete when upload is already abandoned.
+                     */
+                    cleanTargetFrame();
+                }
+            }
+        });
     }
 
-    public void onSubmit(SubmitEvent event) {
+    private void submit() {
         if (fu.getFilename().length() == 0 || submitted || !enabled) {
-            event.cancel();
             ApplicationConnection
                     .getConsole()
                     .log(
@@ -210,6 +248,7 @@ public class VUpload extends FormPanel implements Paintable,
         // before upload
         client.sendPendingVariableChanges();
 
+        element.submit();
         submitted = true;
         ApplicationConnection.getConsole().log("Submitted form");
 
@@ -222,10 +261,62 @@ public class VUpload extends FormPanel implements Paintable,
         t = new Timer() {
             @Override
             public void run() {
+                ApplicationConnection
+                        .getConsole()
+                        .log(
+                                "Visiting server to see if upload started event changed UI.");
                 client.sendPendingVariableChanges();
             }
         };
         t.schedule(800);
     }
 
+    @Override
+    protected void onAttach() {
+        super.onAttach();
+        if (client != null) {
+            ensureTargetFrame();
+        }
+    }
+
+    private void ensureTargetFrame() {
+        if (synthesizedFrame == null) {
+            // Attach a hidden IFrame to the form. This is the target iframe to
+            // which
+            // the form will be submitted. We have to create the iframe using
+            // innerHTML,
+            // because setting an iframe's 'name' property dynamically doesn't
+            // work on
+            // most browsers.
+            DivElement dummy = Document.get().createDivElement();
+            dummy.setInnerHTML("<iframe src=\"javascript:''\" name='"
+                    + getFrameName()
+                    + "' style='position:absolute;width:0;height:0;border:0'>");
+            synthesizedFrame = dummy.getFirstChildElement();
+            Document.get().getBody().appendChild(synthesizedFrame);
+            element.setTarget(getFrameName());
+            onloadstrategy.hookEvents(synthesizedFrame, this);
+        }
+    }
+
+    private String getFrameName() {
+        return paintableId + "_TGT_FRAME";
+    }
+
+    @Override
+    protected void onDetach() {
+        super.onDetach();
+        if (!submitted) {
+            cleanTargetFrame();
+        }
+    }
+
+    private void cleanTargetFrame() {
+        if (synthesizedFrame != null) {
+            Document.get().getBody().removeChild(synthesizedFrame);
+            onloadstrategy.unHookEvents(synthesizedFrame);
+            synthesizedFrame = null;
+        }
+    }
+
 }