index = i;
}
+ /**
+ * @deprecated use getArguments instead.
+ */
@Deprecated
public Object[] getData() {
return getArguments();
return arguments;
}
+ /**
+ * @deprecated use use setArguments instead
+ */
@Deprecated
public void setData(Object...arguments) {
setArguments(arguments);
/**
* Return the first element of the arguments list
+ * @deprecated use getArgument(idx) instead.
*/
+ @Deprecated
public Object getDataObject() {
return getArgument(0);
}
}
/**
- * 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() {
}
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) {
setData(Double.valueOf(b));
}
- public void setDataObject(Object data) {
- setArguments(data);
+ public void setDataObject(Object arg) {
+ setArguments(arg);
}
public int getIndex() {
/**
* Override this method for bound callbacks
*/
- public Object f(Object... data) {
- setArguments(data);
+ public Object f(Object... args) {
+ setArguments(args);
f();
return true;
}
/**
* 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();
* 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);
}
* 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});
}
/**
* 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);
}
/**
* 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);
}
/**
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;
/**
* 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);
}
/**
/**
* 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);
}
/**
</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() {
/**
* 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) {
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)
}
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) {
public boolean visible() {
return isVisible();
}
-
+
/**
* Return the first non null attached widget from the matched elements or null if there isn't any.
*/
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
*/
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;
*/
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;
}
}
- 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;
}
return then(f);
}
- public Promise progress(Function... o) {
- dfd.notify.add(o);
+ public Promise progress(Function... f) {
+ dfd.notify.add(f);
return this;
}
}
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;
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();
}
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);
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);
+ }
}
*
*/
public class Ajax extends GQuery {
-
+
/**
* Ajax Settings object
*/
* @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);
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) {
// 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 {
GWT.getUncaughtExceptionHandler().onUncaughtException(e);
}
}
- onSuccess.fe(retData, "success", request, response);
+ dfd.resolve(retData, "success", request, response);
}
}
});
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);
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);
}
}
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();
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) {
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) {
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) {
}
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());
}
}
}
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;
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();
+ }
+ });
+ }
}