]> source.dussan.org Git - gwtquery.git/commitdiff
Add support for Forms and progress in ajax. Fixes issue #253
authorManolo Carrasco <manolo@apache.org>
Wed, 18 Dec 2013 18:43:09 +0000 (19:43 +0100)
committerManolo Carrasco <manolo@apache.org>
Wed, 18 Dec 2013 18:43:09 +0000 (19:43 +0100)
gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/deferred/PromiseReqBuilder.java

index 693ff708dd6126b3a0e438897538b55acf3e7595..be06f79b5387273dace28adf974c3706b2fa3d04 100644 (file)
@@ -316,6 +316,13 @@ public class JsUtils {
     return Object.prototype.toString.call(o) == '[object Array]'
         || typeof o.length == 'number';
   }-*/;
+  
+  /**
+   * Check is a javascript object is a FormData
+   */
+  public static native boolean isFormData(JavaScriptObject o) /*-{
+    return Object.prototype.toString.call(o) == '[object FormData]';
+  }-*/;
 
   /**
    * Return whether the event was prevented
index 3c8343305c30f96677d7a9fd842f27b4eb8a28f8..3170c3cbe932c33d86a81789ddf1c04e1eb375e3 100644 (file)
@@ -5,8 +5,6 @@ import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.ScriptInjector;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.http.client.Request;
-import com.google.gwt.http.client.RequestBuilder;
-import com.google.gwt.http.client.RequestBuilder.Method;
 import com.google.gwt.http.client.Response;
 import com.google.gwt.query.client.Function;
 import com.google.gwt.query.client.GQuery;
@@ -18,7 +16,6 @@ import com.google.gwt.query.client.plugins.Plugin;
 import com.google.gwt.query.client.plugins.deferred.PromiseFunction;
 import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilder;
 import com.google.gwt.query.client.plugins.deferred.PromiseReqBuilderJSONP;
-import com.google.gwt.user.client.ui.FormPanel;
 
 /**
  * Ajax class for GQuery.
@@ -119,8 +116,8 @@ public class Ajax extends GQuery {
       onError.setElement(settings.getContext());
     }
 
-    Method httpMethod = resolveHttpMethod(settings);
-    String data = resolveData(settings, httpMethod);
+    String httpMethod = settings.getType() == null ? "POST" : settings.getType().toUpperCase();
+    Object data = resolveData(settings, httpMethod);
     final String url = resolveUrl(settings, httpMethod, data);
     final String dataType = settings.getDataType();
 
@@ -131,7 +128,7 @@ public class Ajax extends GQuery {
     } else if ("loadscript".equalsIgnoreCase(dataType)){
       ret = createPromiseScriptInjector(url);
     } else {
-      ret = createPromiseRequestBuilder(settings, httpMethod, url, data)
+      ret = new PromiseReqBuilder(settings, httpMethod, url, data)
         .then(new Function() {
           public Object f(Object...args) {
             Response response = (Response)args[0];
@@ -172,45 +169,6 @@ public class Ajax extends GQuery {
     return ret;
   }
   
-  private static Promise createPromiseRequestBuilder(Settings settings, Method httpMethod, String url, String data) {
-
-    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, url);
-
-    if (data != null && httpMethod != RequestBuilder.GET) {
-      String ctype = settings.getContentType();
-      if (ctype == null) {
-        String type = settings.getDataType();
-        if (type != null && type.toLowerCase().startsWith("json")) {
-          ctype = "application/json; charset=utf-8";
-        } else {
-          ctype = FormPanel.ENCODING_URLENCODED;
-        }
-      }
-      requestBuilder.setHeader("Content-Type", ctype);
-      requestBuilder.setRequestData(data);
-    }
-
-    requestBuilder.setTimeoutMillis(settings.getTimeout());
-
-    String user = settings.getUsername();
-    if (user != null) {
-      requestBuilder.setUser(user);
-    }
-
-    String password = settings.getPassword();
-    if (password != null) {
-      requestBuilder.setPassword(password);
-    }
-
-    Properties headers = settings.getHeaders();
-    if (headers != null) {
-      for (String headerKey : headers.keys()) {
-        requestBuilder.setHeader(headerKey, headers.getStr(headerKey));
-      }
-    }
-
-    return new PromiseReqBuilder(requestBuilder);
-  }
 
   private static Promise createPromiseScriptInjector(final String url) {
     return new PromiseFunction() {
@@ -228,48 +186,33 @@ public class Ajax extends GQuery {
     };
   }
 
-  private static String resolveUrl(Settings settings, Method httpMethod, String data) {
+  private static String resolveUrl(Settings settings, String httpMethod, Object data) {
     String url = settings.getUrl();
     assert url != null : "no url found in settings";
-    if (httpMethod == RequestBuilder.GET && data != null) {
+    if ("GET".equals(httpMethod) && data instanceof String) {
       url += (url.contains("?") ? "&" : "?") + data;
     }
     return url;
   }
 
-  private static String resolveData(Settings settings, Method httpMethod) {
-    String data = settings.getDataString();
-    if (data == null && settings.getData() != null) {
+  private static Object resolveData(Settings settings, String httpMethod) {
+    Object data = settings.getDataString();
+    Properties sdata = settings.getData();
+    if (data == null && sdata != null) {
       String type = settings.getDataType();
       if (type != null
-          && (httpMethod == RequestBuilder.POST || httpMethod == RequestBuilder.PUT)
+          && (httpMethod.matches("(POST|PUT)"))
           && type.equalsIgnoreCase("json")) {
-        data = settings.getData().toJsonString();
+        data = sdata.toJsonString();
+      } else if (JsUtils.isFormData(sdata)) {
+        data = sdata;
       } else {
-        data = settings.getData().toQueryString();
+        data = sdata.toQueryString();
       }
     }
     return data;
   }
 
-  private static Method resolveHttpMethod(Settings settings) {
-    String method = settings.getType();
-    if ("get".equalsIgnoreCase(method)) {
-      return RequestBuilder.GET;
-    } else if ("post".equalsIgnoreCase(method)) {
-      return RequestBuilder.POST;
-    } else if ("put".equalsIgnoreCase(method)) {
-      return RequestBuilder.PUT;
-    } else if ("delete".equalsIgnoreCase(method)) {
-      return RequestBuilder.DELETE;
-    } else if ("head".equalsIgnoreCase(method)) {
-      return RequestBuilder.HEAD;
-    }
-
-    GWT.log("GQuery.Ajax: no method type provided, using POST as default method");
-    return RequestBuilder.POST;
-  }
-
   public static Promise ajax(String url, Function onSuccess, Function onError) {
     return ajax(url, onSuccess, onError, (Settings) null);
   }
@@ -384,6 +327,10 @@ public class Ajax extends GQuery {
     );
   }
 
+  public static Promise post(String url, Properties data) {
+    return post(url, data, null);
+  }
+  
   public static Promise post(String url, Properties data, final Function onSuccess) {
     Settings s = createSettings();
     s.setUrl(url);
@@ -398,6 +345,10 @@ public class Ajax extends GQuery {
     super(gq);
   }
 
+  public Ajax load(String url, Properties data) {
+    return load(url, data);
+  }
+  
   public Ajax load(String url, Properties data, final Function onSuccess) {
     Settings s = createSettings();
     final String filter = url.contains(" ") ? url.replaceFirst("^[^\\s]+\\s+", "") : "";
index 9486b64d153948540cac03c7f363f0a5c8d6636c..05224653f9c5fd0e09ff5f580c236f219c579d0c 100644 (file)
@@ -13,12 +13,23 @@ package com.google.gwt.query.client.plugins.deferred;
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
+import com.google.gwt.core.client.JavaScriptException;
+import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.http.client.Request;
 import com.google.gwt.http.client.RequestBuilder;
 import com.google.gwt.http.client.RequestCallback;
 import com.google.gwt.http.client.RequestException;
+import com.google.gwt.http.client.RequestPermissionException;
 import com.google.gwt.http.client.Response;
+import com.google.gwt.query.client.Function;
+import com.google.gwt.query.client.Properties;
+import com.google.gwt.query.client.js.JsCache;
+import com.google.gwt.query.client.js.JsUtils;
+import com.google.gwt.query.client.plugins.ajax.Ajax.Settings;
 import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl;
+import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.xhr.client.ReadyStateChangeHandler;
+import com.google.gwt.xhr.client.XMLHttpRequest;
 
 /**
  * Utility class used to create promises for RequestBuilder.
@@ -38,6 +49,7 @@ import com.google.gwt.query.client.plugins.deferred.Deferred.DeferredPromiseImpl
  * </pre>
  */
 public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCallback {
+  
   public PromiseReqBuilder(RequestBuilder builder) {
     builder.setCallback(this);
     try {
@@ -46,6 +58,94 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal
       onError(null, e);
     }
   }
+  
+  /**
+   * Using this constructor we access to some things in the xmlHttpRequest
+   * which are not available in GWT, like adding progress handles or sending
+   * javascript data (like forms in modern html5 file api)
+   */
+  public PromiseReqBuilder(Settings settings, String httpMethod, String url, Object data) {
+    XMLHttpRequest xmlHttpRequest = XMLHttpRequest.create();
+System.out.println("AQUI");
+    try {
+      if (settings.getUsername() != null && settings.getPassword() != null) {
+        xmlHttpRequest.open(httpMethod, url, settings.getUsername(), settings.getPassword());
+      } else if (settings.getUsername() != null) {
+        xmlHttpRequest.open(httpMethod, url, settings.getUsername());
+      } else {
+        xmlHttpRequest.open(httpMethod, url);
+      }
+    } catch (JavaScriptException e) {
+      RequestPermissionException requestPermissionException = new RequestPermissionException(url);
+      requestPermissionException.initCause(new RequestException(e.getMessage()));
+      onError(null, e);
+      return;
+    }
+    
+    JsUtils.prop(xmlHttpRequest, "onprogress", JsUtils.wrapFunction(new Function() {
+      public void f() {
+        JsCache p = arguments(0);
+        double total = p.getDouble("total");
+        double loaded = p.getDouble("loaded");
+        double percent = 100 * loaded / total;
+        dfd.notify(total, loaded, percent, "download");
+      }
+    }));
+    
+    JavaScriptObject upload = JsUtils.prop(xmlHttpRequest, "upload");
+    JsUtils.prop(upload, "onprogress", JsUtils.wrapFunction(new Function() {
+      public void f() {
+        JsCache p = arguments(0);
+        double total = p.getDouble("total");
+        double loaded = p.getDouble("loaded");
+        double percent = 100 * loaded / total;
+        dfd.notify(total, loaded, percent, "upload");
+      }
+    }));
+    
+    Properties headers = settings.getHeaders();
+    if (headers != null) {
+      for (String headerKey : headers.keys()) {
+        xmlHttpRequest.setRequestHeader(headerKey, headers.getStr(headerKey));
+      }
+    }
+    
+    if (data != null && !"GET".equalsIgnoreCase(httpMethod)) {
+      String ctype = settings.getContentType();
+      if (data instanceof JavaScriptObject && JsUtils.isFormData((JavaScriptObject)data)) {
+        ctype = FormPanel.ENCODING_MULTIPART;;
+      } else if (ctype == null) {
+        String type = settings.getDataType();
+        if (type != null && type.toLowerCase().startsWith("json")) {
+          ctype = "application/json; charset=utf-8";
+        } else {
+          ctype = FormPanel.ENCODING_URLENCODED;
+        }
+      }
+      System.out.println(ctype);
+      xmlHttpRequest.setRequestHeader("Content-Type", ctype);
+    }
+
+    xmlHttpRequest.setWithCredentials(true);
+    
+    final Request request = createRequestVltr(xmlHttpRequest, settings.getTimeout(), this);
+    
+    xmlHttpRequest.setOnReadyStateChange(new ReadyStateChangeHandler() {
+      public void onReadyStateChange(XMLHttpRequest xhr) {
+        if (xhr.getReadyState() == XMLHttpRequest.DONE) {
+          xhr.clearOnReadyStateChange();
+          fireOnResponseReceivedVltr(request, PromiseReqBuilder.this);
+        }
+      }
+    });
+
+    try {
+      System.out.println("DATA " + data.getClass().getName());
+      JsUtils.runJavascriptFunction(xmlHttpRequest, "send", data);
+    } catch (JavaScriptException e) {
+      onError(null, e);
+    }
+  }
 
   public void onError(Request request, Throwable exception) {
     dfd.reject(exception, request);
@@ -60,4 +160,18 @@ public class PromiseReqBuilder extends DeferredPromiseImpl implements RequestCal
       dfd.resolve(response, request);
     }
   }
+  
+  /**
+   * Using violator pattern to execute private method
+   */
+  private native void fireOnResponseReceivedVltr(Request rq, RequestCallback cb) /*-{
+    rq.@com.google.gwt.http.client.Request::fireOnResponseReceived(Lcom/google/gwt/http/client/RequestCallback;)(cb);
+  }-*/;
+  
+  /**
+   * Using violator pattern to use protected constructor
+   */
+  private native Request createRequestVltr(XMLHttpRequest rq, int ms, RequestCallback cb) /*-{
+    return @com.google.gwt.http.client.Request::new(Lcom/google/gwt/xhr/client/XMLHttpRequest;ILcom/google/gwt/http/client/RequestCallback;)(rq, 
+  }-*/;
 }