]> source.dussan.org Git - gwtquery.git/commitdiff
Implementation of Deferred.when. Some changes and deprecations in Function (need...
authorManuel Carrasco Moñino <manuel.carrasco.m@gmail.com>
Mon, 4 Mar 2013 13:16:50 +0000 (14:16 +0100)
committerManuel Carrasco Moñino <manuel.carrasco.m@gmail.com>
Mon, 4 Mar 2013 13:16:50 +0000 (14:16 +0100)
gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java
gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java
gwtquery-core/src/main/java/com/google/gwt/query/client/Promise.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Deferred.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/callbacks/Callbacks.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java

index 5bb4f5f63b3c95bdb64c5030fba9fefca3b761af..76a0bc3cbbe42156f1b51cb2d117ced60b85d342 100644 (file)
@@ -52,6 +52,9 @@ public abstract class Function {
     index = i;
   }
   
+  /**
+   * @deprecated use getArguments instead.
+   */
   @Deprecated
   public Object[] getData() {
     return getArguments();
@@ -61,6 +64,9 @@ public abstract class Function {
     return arguments;
   }
   
+  /**
+   * @deprecated use use setArguments instead
+   */
   @Deprecated
   public void setData(Object...arguments) {
     setArguments(arguments);
@@ -75,7 +81,9 @@ public abstract class Function {
 
   /**
    * Return the first element of the arguments list
+   * @deprecated use getArgument(idx) instead.
    */
+  @Deprecated
   public Object getDataObject() {
     return getArgument(0);
   }
@@ -89,10 +97,50 @@ public abstract class Function {
   }
 
   /**
-   * return the argument in position idx; 
+   * Utility method for safety getting a JavaScriptObject present at a certain
+   * position in the list of arguments composed by arrays.
+   * 
+   */
+  public <T extends JavaScriptObject> T getArgumentJSO(int argIdx, int pos) {
+    Object[] objs = getArgumentArray(argIdx);
+    if (objs.length > pos && objs[pos] instanceof JavaScriptObject) {
+      return ((JavaScriptObject)objs[pos]).cast();
+    }
+    return null;
+  }
+  
+  /**
+   * Utility method for safety getting a JavaScriptObject present at a certain
+   * position in the list of arguments.
+   */
+  public <T extends JavaScriptObject> T getArgumentJSO(int idx) {
+    return getArgumentJSO(-1, idx);
+  }
+  
+  /**
+   * Utility method for safety getting an array present at a certain
+   * position in the list of arguments.
+   * 
+   * Useful for Deferred chains where result of each resolved 
+   * promise is set as an array in the arguments list.
+   * 
+   * Always returns an array.
+   */
+  public Object[] getArgumentArray(int idx) {
+    Object o = idx < 0 ? arguments: getArgument(idx);
+    if (o != null && o.getClass().isArray()) {
+      return (Object[])o;
+    } else if (idx == 0) {
+      return arguments;
+    }
+    return new Object[0];
+  }
+
+  /**
+   * return the argument in the position idx; 
    */
   public Object getArgument(int idx) {
-    return arguments != null && arguments.length > idx ? arguments[idx] : null;
+    return arguments.length > idx ? arguments[idx] : null;
   }
 
   public Properties getDataProperties() {
@@ -100,11 +148,7 @@ public abstract class Function {
   }
 
   public Properties getDataProperties(int idx) {
-    Object o = getArgument(idx);
-    if (o != null && o instanceof JavaScriptObject) {
-      return (Properties)o;
-    }
-    return null;
+    return getArgumentJSO(idx);
   }
 
   public void setData(boolean b) {
@@ -115,8 +159,8 @@ public abstract class Function {
     setData(Double.valueOf(b));
   }
 
-  public void setDataObject(Object data) {
-    setArguments(data);
+  public void setDataObject(Object arg) {
+    setArguments(arg);
   }
 
   public int getIndex() {
@@ -204,8 +248,8 @@ public abstract class Function {
   /**
    * Override this method for bound callbacks
    */
-  public Object f(Object... data) {
-    setArguments(data);
+  public Object f(Object... args) {
+    setArguments(args);
     f();
     return true;
   }
@@ -213,22 +257,22 @@ public abstract class Function {
   /**
    * Override this method for bound callbacks
    */
-  public void f(int i, Object data) {
-    f(i, new Object[]{data});
+  public void f(int i, Object arg) {
+    f(i, new Object[]{arg});
   }
 
   /**
    * Override this method for bound callbacks
    */
-  public void f(int i, Object... data) {
+  public void f(int i, Object... args) {
     setIndex(i);
-    setArguments(data);
-    if (data.length == 1 && data[0] instanceof JavaScriptObject) {
-      if (JsUtils.isElement((JavaScriptObject)data[0])) {
-        setElement((com.google.gwt.dom.client.Element)data[0]);
+    setArguments(args);
+    if (args.length == 1 && args[0] instanceof JavaScriptObject) {
+      if (JsUtils.isElement((JavaScriptObject)args[0])) {
+        setElement((com.google.gwt.dom.client.Element)args[0]);
         f(getElement(), i);
-      } else if (JsUtils.isEvent((JavaScriptObject)data[0])) {
-        setEvent((Event)data[0]);
+      } else if (JsUtils.isEvent((JavaScriptObject)args[0])) {
+        setEvent((Event)args[0]);
         f(getEvent());
       } else {
         f();
@@ -240,8 +284,8 @@ public abstract class Function {
    * Override this method for bound event handlers if you wish to deal with
    * per-handler user data.
    */
-  public boolean f(Event e, Object data) {
-    setArguments(data);
+  public boolean f(Event e, Object arg) {
+    setArguments(arg);
     setEvent(e);
     return f(e);
   }
@@ -319,8 +363,8 @@ public abstract class Function {
    * catch the exception and send it to the GWT UncaughtExceptionHandler
    * They are intentionally final to avoid override them
    */
-  public final void fe(Object data) {
-    fe(new Object[]{data});
+  public final void fe(Object arg) {
+    fe(new Object[]{arg});
   }
 
   /**
@@ -328,16 +372,16 @@ public abstract class Function {
    * catch the exception and send it to the GWT UncaughtExceptionHandler
    * They are intentionally final to avoid override them
    */
-  public final Object fe(Object... data) {
+  public final Object fe(Object... args) {
     if (GWT.getUncaughtExceptionHandler() != null) {
       try {
-        return f(data);
+        return f(args);
       } catch (Exception e) {
         GWT.getUncaughtExceptionHandler().onUncaughtException(e);
       }
       return true;
     }
-    return f(data);
+    return f(args);
   }
 
   /**
@@ -345,16 +389,16 @@ public abstract class Function {
    * catch the exception and send it to the GWT UncaughtExceptionHandler
    * They are intentionally final to avoid override them
    */
-  public final boolean fe(Event ev, Object  data) {
+  public final boolean fe(Event ev, Object arg) {
     if (GWT.getUncaughtExceptionHandler() != null) {
       try {
-        return f(ev, data);
+        return f(ev, arg);
       } catch (Exception e) {
         GWT.getUncaughtExceptionHandler().onUncaughtException(e);
       }
       return true;
     }
-    return f(ev, data);
+    return f(ev, arg);
   }
 
   /**
index 1a2afc78dfe80f4c9b743d78686a30f03f99cfe3..e233218157dc40a74e1f1563a2e079e588544cc9 100644 (file)
@@ -51,6 +51,7 @@ import com.google.gwt.query.client.js.JsNodeArray;
 import com.google.gwt.query.client.js.JsObjectArray;
 import com.google.gwt.query.client.js.JsRegexp;
 import com.google.gwt.query.client.js.JsUtils;
+import com.google.gwt.query.client.plugins.Deferred;
 import com.google.gwt.query.client.plugins.Effects;
 import com.google.gwt.query.client.plugins.Events;
 import com.google.gwt.query.client.plugins.Plugin;
@@ -540,8 +541,8 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   /**
    * Perform an ajax request to the server using GET.
    */
-  public static void get(String url, Properties data, final Function onSuccess) {
-    Ajax.get(url, data, onSuccess);
+  public static Promise get(String url, Properties data, final Function onSuccess) {
+    return Ajax.get(url, data, onSuccess);
   }
 
   /**
@@ -584,8 +585,8 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   /**
    * Perform an ajax request to the server using POST and parsing the json response.
    */
-  public static void getJSON(String url, Properties data, final Function onSuccess) {
-    Ajax.getJSON(url, data, onSuccess);
+  public static Promise getJSON(String url, Properties data, final Function onSuccess) {
+    return Ajax.getJSON(url, data, onSuccess);
   }
 
   /**
@@ -610,8 +611,8 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    </pre>
    *
    */
-  public static void getJSONP(String url, Properties data, final Function onSuccess) {
-    Ajax.getJSONP(url, data, onSuccess);
+  public static Promise getJSONP(String url, Properties data, final Function onSuccess) {
+    return Ajax.getJSONP(url, data, onSuccess);
   }
 
   protected static DocumentStyleImpl getStyleImpl() {
@@ -694,8 +695,8 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   /**
    * Perform an ajax request to the server using POST.
    */
-  public static void post(String url, Properties data, final Function onSuccess) {
-    Ajax.post(url, data, onSuccess);
+  public static Promise post(String url, Properties data, final Function onSuccess) {
+    return Ajax.post(url, data, onSuccess);
   }
 
   public static <T extends GQuery> Class<T> registerPlugin(Class<T> plugin, Plugin<T> pluginFactory) {
@@ -706,6 +707,19 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
     plugins.put(plugin, pluginFactory);
     return plugin;
   }
+  
+  /**
+   * Provides a way to execute callback Functions based on one or more Promise objects
+   * that represent asynchronous events.
+   * 
+   * Returns a new promise which will be finalized when all of its subordinates finish.
+   * In the case of all subordinates are resolved correctly the promise will be resolved
+   * otherwise it will be rejected.
+   * 
+   */
+  public static Promise when(Promise... subordinates) {
+    return Deferred.when(subordinates);
+  }
 
   private static native void scrollIntoViewImpl(Node n) /*-{
                if (n)
@@ -744,9 +758,12 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   }
 
   protected GQuery(GQuery gq) {
-    this(gq == null ? null : gq.get());
-    currentSelector = gq.getSelector();
-    currentContext = gq.getContext();
+    if (gq != null) {
+      elements = gq.elements;
+      nodeList = gq.nodeList;
+      currentSelector = gq.currentSelector;
+      currentContext = gq.currentContext;
+    }
   }
 
   private GQuery(JsNodeArray nodes) {
@@ -4546,7 +4563,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   public boolean visible() {
     return isVisible();
   }
-
+  
   /**
    * Return the first non null attached widget from the matched elements or null if there isn't any.
    */
index c31e0c99ab4cf6da9f914442acb73dee479f6521..bb7b24ccae0adb6fbf6ac0d54b76329b70907ad0 100644 (file)
@@ -24,18 +24,50 @@ public interface Promise {
   public static final String REJECTED = "rejected";
   public static final String RESOLVED = "resolved";
 
+  /**
+   * Add handlers to be called when the Deferred object is either resolved or rejected.
+   */
   Promise always(Function... o);
 
+  /**
+   * Add handlers to be called when the Deferred object is resolved.
+   */
   Promise done(Function... o);
 
+  /**
+   * Add handlers to be called when the Deferred object is rejected.
+   */
   Promise fail(Function... o);
 
+  /**
+   * Utility method to filter and/or chain Deferreds.
+   * 
+   * @deprecated use 'then' instead. 
+   *   it was deprecated in jquery, and we maintain it here for compatibility.
+   */
+  @Deprecated
   Promise pipe(Function... f);
 
+  /**
+   * Utility method to filter and/or chain Deferreds.
+   */
   Promise progress(Function... o);
 
+  /**
+   * Return the status of the deferred object.
+   * 
+   * Valid values are: Promise.PENDING, Promise.REJECTED, Promise.RESOLVED
+   * 
+   */
   String state();
 
+  /**
+   * Add handlers to be called when the Deferred object is resolved, rejected, or still in progress.
+   * 
+   * @param f a list of 1, 2, or 3 functions, which will be used in this way:
+   *   1st function will be called when the deferred is resolved.
+   *   2nd function that is called when the deferred is rejected.
+   *   3rd one will be called when progress notifications are sent.  
+   */
   Promise then(Function... f);
-
 }
\ No newline at end of file
index 6b89b8849442cf829b63b0a48e1a2534a6363aac..24d977c6cd5220d1fe854a9e35b51caf7b8fe87e 100644 (file)
  */
 package com.google.gwt.query.client.plugins;
 
+import static com.google.gwt.query.client.Promise.PENDING;
+import static com.google.gwt.query.client.Promise.REJECTED;
+import static com.google.gwt.query.client.Promise.RESOLVED;
+
 import com.google.gwt.query.client.Function;
 import com.google.gwt.query.client.GQuery;
 import com.google.gwt.query.client.Promise;
@@ -23,6 +27,9 @@ import com.google.gwt.query.client.plugins.callbacks.Callbacks;
  */
 public class Deferred extends GQuery {
   
+  /**
+   * Implementation of the Promise interface which is used internally by Deferred.
+   */
   private class DeferredPromise extends GQuery implements Promise {
     private Deferred dfd;
 
@@ -37,17 +44,17 @@ public class Deferred extends GQuery {
       }
     }
     
-    public Promise always(Function... o) {
-      return done(o).fail(o);
+    public Promise always(Function... f) {
+      return done(f).fail(f);
     }
 
-    public Promise done(Function... o) {
-      dfd.resolve.add(o);
+    public Promise done(Function... f) {
+      dfd.resolve.add(f);
       return this;
     }
     
-    public Promise fail(Function... o) {
-      dfd.reject.add(o);
+    public Promise fail(Function... f) {
+      dfd.reject.add(f);
       return this;
     }
 
@@ -55,8 +62,8 @@ public class Deferred extends GQuery {
       return then(f);
     }
     
-    public Promise progress(Function... o) {
-      dfd.notify.add(o);
+    public Promise progress(Function... f) {
+      dfd.notify.add(f);
       return this;
     }
     
@@ -65,23 +72,87 @@ public class Deferred extends GQuery {
     }
     
     public Promise then(Function... f) {
+      assert f.length < 4 : "Promise.then: Too much arguments";
       switch (f.length) {
-        case 3: progress(f[0]);
-        case 2: fail(f[0]);
+        case 3: progress(f[2]);
+        case 2: fail(f[1]);
         case 1: done(f[0]);
       }
       return this;
     }
   }
+  
+  /**
+   * Internal Deferred class used to combine a set of subordinate promises. 
+   */
+  private static class WhenDeferred extends Deferred {
+    /**
+     * Internal function used to track whether all deferred 
+     * subordinates are resolved. 
+     */
+    private class DoneFnc extends Function {
+      final int idx;
+      public DoneFnc(int i, Deferred d) {
+        idx = i; 
+      }
+      public Object f(Object... args) {
+        values[idx] = args;
+        if (--remaining == 0) {
+          WhenDeferred.this.resolve(values);
+        }
+        return true;
+      }
+    }
+    
+    private Function failFnc = new Function() {
+      public Object f(Object... o) {
+        WhenDeferred.this.reject(o);
+        return true;
+      }
+    };
+    
+    private Function progressFnc = new Function() {
+      public Object f(Object... o) {
+        WhenDeferred.this.notify(o);
+        return true;
+      }
+    };
+    
+    // Remaining counter
+    private int remaining;
+    
+    // An indexed array with the fired values of all subordinated
+    private final Object[] values;
+    
+    public WhenDeferred(Promise[] sub) {
+      int l = remaining = sub.length;
+      values = new Object[l];
+      for (int i = 0; i < l; i++) {
+        sub[i].done(new DoneFnc(i, this)).progress(progressFnc).fail(failFnc);
+      }
+    }
+  }
+  
+  // Register Deferred as a GQuery plugin
   public static final Class<Deferred> Deferred = GQuery.registerPlugin(
       Deferred.class, new Plugin<Deferred>() {
         public Deferred init(GQuery gq) {
           return new Deferred(gq);
         }
       });
-  public static Promise when(Deferred d) {
-    return d.promise();
+  
+  public static Promise when(Promise... d) {
+    final int n = d.length;
+    switch (n) {
+      case 1:
+        return d[0];
+      case 0:
+        return new Deferred().resolve().promise();
+      default:
+        return new WhenDeferred(d).promise();
+    }
   }
+  
   private Callbacks notify = new Callbacks("memory");
   
   private Promise promise = null;
@@ -90,13 +161,17 @@ public class Deferred extends GQuery {
   
   private Callbacks resolve = new Callbacks("once memory");
   
-  private String state = Promise.PENDING;
+  private String state = PENDING;
+  
+  public Deferred() {
+    this(null);
+  }
   
   protected Deferred(GQuery gq) {
     super(gq);
     resolve.add(new Function() {
       public void f() {
-        state = Promise.RESOLVED;
+        state = RESOLVED;
         resolve.disable();
         notify.lock();
       }
@@ -104,35 +179,25 @@ public class Deferred extends GQuery {
 
     reject.add(new Function() {
       public void f() {
-        state = Promise.REJECTED;
+        state = REJECTED;
         reject.disable();
         notify.lock();
       }
     });
   }
-  // private, used from jsni
-  @SuppressWarnings("unused")
-  private void err(Object o) {
-    reject(o);
-  }
+  
   public Deferred notify(Object... o) {
+    notify(o);
     notify.fire(o);
     return this;
   }
-  
-  // private, used from jsni
-  @SuppressWarnings("unused")
-  private void ok(Object o) {
-    resolve(o);
-  }
-  
+
   public Promise promise() {
     if (promise == null) {
       promise = new DeferredPromise(this);
     }
     return promise;
   }
-
   
   public Deferred reject(Object... o) {
     reject.fire(o);
@@ -143,4 +208,16 @@ public class Deferred extends GQuery {
     resolve.fire(o);
     return this;
   }
+
+  // private, used from jsni because it does not handles variable arguments
+  @SuppressWarnings("unused")
+  private void err(Object o) {
+    reject(o);
+  }
+  
+  // private, used from jsni because it does not handles variable arguments
+  @SuppressWarnings("unused")
+  private void ok(Object o) {
+    resolve(o);
+  }
 }
index 0c60de9c59a39420e1410e099caf03fad0148428..08f7a1a337e9abcf7992bb1dcb749f0808ad27d3 100644 (file)
@@ -36,7 +36,7 @@ import com.google.gwt.xhr.client.XMLHttpRequest;
  *
  */
 public class Ajax extends GQuery {
-
+  
   /**
    * Ajax Settings object
    */
@@ -108,16 +108,19 @@ public class Ajax extends GQuery {
    * @param onError the function to execute on error
    * @param settings a Properties object with the configuration of the Ajax request.
    */
-  public static void ajaxOld(Settings settings) {
+  public static Promise ajax(Settings settings) {
+    final Deferred dfd = $().as(Deferred.Deferred);
 
     final Function onSuccess = settings.getSuccess();
     if (onSuccess != null) {
       onSuccess.setElement(settings.getContext());
+      dfd.promise().done(onSuccess);
     }
 
     final Function onError = settings.getError();
     if (onError != null) {
       onError.setElement(settings.getContext());
+      dfd.promise().fail(onError);
     }
 
     Method httpMethod = resolveHttpMethod(settings);
@@ -127,20 +130,15 @@ public class Ajax extends GQuery {
 
     if ("jsonp".equalsIgnoreCase(dataType)) {
       int timeout = settings.getTimeout();
-      getJSONP(url, onSuccess, onError, timeout);
-      return;
+      return getJSONP(url, onSuccess, onError, timeout);
     }
 
     final RequestBuilder requestBuilder = createRequestBuilder(settings, httpMethod, url, data);
     requestBuilder.setCallback(new RequestCallback() {
       public void onError(Request request, Throwable exception) {
-        if (onError != null) {
-          onError.f(null, exception.getMessage(), request, null, exception);
-        }
+        dfd.reject(null, exception.getMessage(), request, null, exception);
       }
       
-      
-
       public void onResponseReceived(Request request, Response response) {
         int statusCode = response.getStatusCode();
         if (statusCode <= 0 || statusCode >= 400) {
@@ -148,9 +146,7 @@ public class Ajax extends GQuery {
             // Just warn the developer about the status code
             GWT.log("GQuery.ajax error, the response.statusCode is 0, this usually happens when you try to access an external server without CORS enabled. url=" + url);
           }
-          if (onError != null) {
-            onError.fe(response.getText(), "error", request, response);
-          }
+          dfd.reject(response.getText(), "error", request, response);
         } else if (onSuccess != null) {
           Object retData = null;
           try {
@@ -166,7 +162,7 @@ public class Ajax extends GQuery {
               GWT.getUncaughtExceptionHandler().onUncaughtException(e);
             }
           }
-          onSuccess.fe(retData, "success", request, response);
+          dfd.resolve(retData, "success", request, response);
         }
       }
     });
@@ -174,14 +170,14 @@ public class Ajax extends GQuery {
     try {
       requestBuilder.send();
     } catch (RequestException e) {
-      if (onError != null) {
-        onError.f(null, -1, null, null, e);
-      }
+      dfd.reject(null, e.getMessage(), null, null, e);
     }
+
+    return dfd.promise();
   }
   
   
-  public static Promise ajax(Settings settings) {
+  public static Promise ajaxNew(Settings settings) {
 
     final Deferred dfd = $().as(Deferred.Deferred);
 
@@ -210,7 +206,7 @@ public class Ajax extends GQuery {
     RequestCallback mdb = new RequestCallback() {
       public void onError(Request request, Throwable exception) {
         if (onError != null) {
-          onError.f(null, exception.getMessage(), request, null, exception);
+          dfd.reject(null, exception.getMessage(), request, null, exception);
         }
       }
 
@@ -247,22 +243,22 @@ public class Ajax extends GQuery {
     try {
       xmlHttpRequest.send(data);
     } catch (JavaScriptException e) {
-      dfd.reject(e.getMessage(), "error", null, null, e);
+      dfd.reject(null, e.getMessage(), null, null, e);
     }
     
     return dfd.promise();
   }
   
-  
+  // Accessing protected constructor at XMLHttpRequest
   private static native Request createRequest(XMLHttpRequest r, int t, RequestCallback c) /*-{
    return @com.google.gwt.http.client.Request::new(Lcom/google/gwt/xhr/client/XMLHttpRequest;ILcom/google/gwt/http/client/RequestCallback;)(r, t, c);
   }-*/;
   
+  // Accessing protected method at XMLHttpRequest
   private static native void fireOnResponseReceived(Request q, RequestCallback c) /*-{
     q.@com.google.gwt.http.client.Request::fireOnResponseReceived(*)(c);
   }-*/;
   
-  
   private static XMLHttpRequest createXHR (Settings settings, String httpMethod, String url, String data, final RequestCallback cb) {
     XMLHttpRequest xmlHttpRequest = XMLHttpRequest.create();
 
@@ -413,34 +409,38 @@ public class Ajax extends GQuery {
     return s;
   }
 
-  public static void get(String url, Properties data, final Function onSuccess) {
+  public static Promise get(String url, Properties data, Function onSuccess) {
     Settings s = createSettings();
     s.setUrl(url);
     s.setDataType("txt");
     s.setType("get");
     s.setData(data);
     s.setSuccess(onSuccess);
-    ajax(s);
+    return ajax(s);
   }
 
-  public static void getJSON(String url, Properties data, final Function onSuccess) {
+  public static Promise getJSON(String url, Properties data, Function onSuccess) {
     Settings s = createSettings();
     s.setUrl(url);
     s.setDataType("json");
     s.setType("post");
     s.setData(data);
     s.setSuccess(onSuccess);
-    ajax(s);
+    return ajax(s);
   }
-
-  public static void getJSONP(String url, Properties data, Function onSuccess) {
+  
+  public static Promise getJSONP(String url) {
+    return getJSONP(url, null, null, 0);
+  }
+  
+  public static Promise getJSONP(String url, Properties data, Function onSuccess) {
     Settings s = createSettings();
     s.setUrl(url);
     s.setDataType("jsonp");
     s.setType("get");
     s.setData(data);
     s.setSuccess(onSuccess);
-    ajax(s);
+    return ajax(s);
   }
 
   public static Promise getJSONP(String url, Function success, Function error, int timeout) {
@@ -458,14 +458,14 @@ public class Ajax extends GQuery {
     return dfd.promise();
   }
 
-  public static void post(String url, Properties data, final Function onSuccess) {
+  public static Promise post(String url, Properties data, final Function onSuccess) {
     Settings s = createSettings();
     s.setUrl(url);
     s.setDataType("txt");
     s.setType("post");
     s.setData(data);
     s.setSuccess(onSuccess);
-    ajax(s);
+    return ajax(s);
   }
 
   protected Ajax(GQuery gq) {
@@ -512,7 +512,7 @@ public class Ajax extends GQuery {
 
   private static int callBackCounter = 0;
 
-  public static native void getJsonpImpl(Element elem, String url, String charset, Deferred dfd, int timeout) /*-{
+  private static native void getJsonpImpl(Element elem, String url, String charset, Deferred dfd, int timeout) /*-{
     var fName = "__GQ_cb_" + @com.google.gwt.query.client.plugins.ajax.Ajax::callBackCounter ++;
     var done = false;
     $wnd[fName] = function(data) {
index 7ffd510aa738a6b5e14fc57a47313844b78a54ba..14d3d59d02250d271883191e8e760590ddbe532d 100644 (file)
@@ -162,15 +162,13 @@ public class Callbacks {
   }
   
   private void addAll(Object...o) {
-    if (stack != null) {
-      for (Object c : o) {
-        if (!opts.getUnique() || !stack.contains(c)) {
-          stack.add(c);
-        }
-        // In jQuery add always is run when memory is true even when unique is set
-        if (opts.getMemory() && memory != null) {
-          run(c, memory.elements());
-        }
+    for (Object c : o) {
+      if (!done && (!opts.getUnique() || !stack.contains(c))) {
+        stack.add(c);
+      }
+      // In jQuery add always is run when memory is true even when unique is set
+      if (opts.getMemory() && memory != null) {
+        run(c, memory.elements());
       }
     }
   }  
index c7ceb12885e5b64cd9a51da62be1d2fce6409ef8..2cffb6d0eff9475cddaa7a8599fb002dca82ba34 100644 (file)
 package com.google.gwt.query.client;
 
 
+import static com.google.gwt.query.client.GQuery.when;
+
 import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.query.client.plugins.ajax.Ajax;
 import com.google.gwt.query.client.plugins.callbacks.Callbacks;
 import com.google.gwt.query.client.plugins.callbacks.Callbacks.Callback;
 
@@ -141,5 +144,41 @@ public class GQueryDeferredTestGwt extends GWTTestCase {
     callbacks.add( fn1 );
     assertEquals(" f1: bar f2: bar f2: bar f1: bar", result);
   }
+  
+  public void testDeferredAjaxWhenDone() {
+    String url = "https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY";
+    
+    delayTestFinish(5000);
+
+    when(Ajax.getJSONP(url, null, null, 1000))
+      .done(new Function() {
+        public void f() {
+          Properties p = getArgumentJSO(0, 0);
+          assertEquals(400, p.getJavaScriptObject("error").<Properties>cast().getInt("code"));
+          finishTest();
+        }
+      });
+  }
+
+  public void testDeferredAjaxWhenFail() {
+    String url1 = "https://www.googleapis.com/blogger/v2/blogs/user_id/posts/post_id?callback=?&key=NO-KEY";
+    String url2 = "https://localhost:4569/foo";
+    
+    delayTestFinish(5000);
+
+    when(
+        Ajax.getJSONP(url1), 
+        Ajax.getJSONP(url2, null, null, 1000))
+      .done(new Function() {
+        public void f() {
+          fail();
+        }
+      })
+      .fail(new Function(){
+        public void f() {
+          finishTest();
+        }
+      });
+  }
 
 }