*/
Promise then(Function... f);
+ /**
+ * Add filters to be called just in case the Deferred object is rejected returning
+ * a new valid promise so as we can continue the flow control of the chain.
+ *
+ * It works in the same way than adding a second parameter to {@link then} method but
+ * continuing the flow and making more readable the code.
+ *
+ * NOTE: this method is in gQuery but not in jQuery.
+ *
+ * Example:
+ * <pre>
+ GQuery.when(gettingConfigurationFromCache())
+ .or(gettingConfigurationFromServer())
+ .done(drawUI());
+ * </pre>
+ *
+ * NOTE: this is a convenience method in gQuery not present in jQuery.
+ */
+ Promise or(Function f);
+
+ /**
+ * Add filters to be called just in case the Deferred object is resolved.
+ *
+ * It works in the same way than {@link then} does but making more readable
+ * the code flow.
+ *
+ * NOTE: this method is in gQuery but not in jQuery.
+ *
+ * Example:
+ * <pre>
+ GQuery.when(login())
+ .and(getConfiguration())
+ .done(drawUI());
+ * </pre>
+ *
+ * NOTE: this is a convenience method in gQuery not present in jQuery.
+ */
+ Promise and(Function f);
+
/**
* Determine whether a Deferred object has been resolved.
*/
*/
package com.google.gwt.query.client.plugins.deferred;
-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 static com.google.gwt.query.client.Promise.*;
import com.google.gwt.query.client.Function;
import com.google.gwt.query.client.GQuery;
// Private class used to handle `Promise.then()`
private static class ThenFunction extends Function {
- // Used internally in ThenFunction, to resolve deferred object
- private class DoFunction extends Function {
- int type;
- public DoFunction(int type) {
- this.type = type;
- }
- public void f() {
- if (type == DONE) dfd.resolve(getArguments());
- if (type == FAIL) dfd.reject(getArguments());
- if (type == PROGRESS) dfd.notify(getArguments());
- }
- }
// Original filter function
private final Function filter;
private final int type;
// Original deferred object
private final Deferred dfd;
+ // Whether break the flow if old deferred fails
+ boolean cont = false;
- public ThenFunction(Deferred newDfd, Function[] subordinates, int funcType) {
+ public ThenFunction(Deferred newDfd, Function[] subordinates, int funcType, boolean continueFlow) {
type = funcType;
filter = subordinates.length > type ? subordinates[type] : null;
dfd = newDfd;
+ cont = continueFlow;
}
public void f() {
- final Object[] args = getArguments();
- Function doIt = new DoFunction(type).setArguments(args);
+ final Object[] oldArgs = getArguments();
if (filter != null) {
// We filter resolved arguments with the filter function
- Object newArgs = filter.setArguments(args).f(args);
- // If filter function returns a promise we pipeline it and don't resolve this
+ Object newArgs = filter.setArguments(oldArgs).f(oldArgs);
+
if (newArgs instanceof Promise) {
- Promise p = (Promise) newArgs;
- p.done(new DoFunction(DONE));
- p.fail(new DoFunction(FAIL));
- p.progress(new DoFunction(PROGRESS));
- return;
- // Otherwise we change the arguments with the new args
- } else if (newArgs != null && newArgs.getClass().isArray()) {
- doIt.setArguments((Object[])newArgs);
+ // If filter function returns a promise we pipeline it.
+ final Promise p = (Promise) newArgs;
+ if (type == PROGRESS) {
+ p.progress(new Function(){public void f() {
+ settle(PROGRESS, getArguments());
+ }});
+ } else {
+ p.always(new Function(){public void f() {
+ if (p.isRejected() && !cont) {
+ settle(FAIL, getArguments());
+ } else {
+ settle(DONE, getArguments());
+ }
+ }});
+ }
+
} else {
- doIt.setArguments(newArgs);
+ // Otherwise we change the arguments by the new ones
+ newArgs = Boolean.TRUE.equals(newArgs) ? oldArgs :
+ newArgs != null && newArgs.getClass().isArray() ? (Object[])newArgs : newArgs;
+ settle(type, newArgs);
}
+ } else {
+ // just continue the flow when filter is null
+ settle(type, oldArgs);
}
- // run the function with the new args to resolve this deferred
- doIt.f();
+ }
+
+ private void settle(int action, Object... args) {
+ if (action == DONE) dfd.resolve(args);
+ if (action == FAIL) dfd.reject(args);
+ if (action == PROGRESS) dfd.notify(args);
}
}
public Promise always(Function... f) {
return done(f).fail(f);
}
-
+
+ public Promise and(Function f) {
+ return then(f);
+ }
+
public Promise done(Function... f) {
dfd.resolve.add(f);
return this;
dfd.reject.add(f);
return this;
}
-
+
+ public Promise or(final Function f) {
+ return then(false, null, f);
+ }
+
public Promise pipe(Function... f) {
return then(f);
}
return dfd.state;
}
- public Promise then(final Function... f) {
+ private Promise then(boolean continueFlow, final Function... f) {
final Deferred newDfd = new com.google.gwt.query.client.plugins.deferred.Deferred();
- done(new ThenFunction(newDfd, f, DONE));
- fail(new ThenFunction(newDfd, f, FAIL));
- progress(new ThenFunction(newDfd, f, PROGRESS));
+ done(new ThenFunction(newDfd, f, DONE, continueFlow));
+ fail(new ThenFunction(newDfd, f, FAIL, continueFlow));
+ progress(new ThenFunction(newDfd, f, PROGRESS, continueFlow));
return newDfd.promise();
}
+
+ public Promise then(final Function... f) {
+ return then(false, f);
+ }
public boolean isResolved() {
return Promise.RESOLVED.equals(state());
dfd.resolve("message");
}
})
- .then(new FunctionDeferred() {
+ .and(new FunctionDeferred() {
public void f(Deferred dfd) {
dfd.resolve("then1 " + arguments[0]);
}
dfd.resolve("message");
}
})
+ .and(new Function(){
+ public Object f(Object... data) {
+ return (arguments[0] + " then1");
+ }
+ })
+ .then(new Function(){
+ public void f() {
+ // should return the previous value
+ }
+ })
.then(new FunctionDeferred() {
public void f(Deferred dfd) {
- dfd.resolve("then1 " + arguments[0]);
+ dfd.reject("then2 " + arguments[0]);
}
})
.then(new FunctionDeferred() {
public void f(Deferred dfd) {
- dfd.reject("then2 " + arguments[0]);
+ dfd.resolve("then3 " + arguments[0]);
}
})
.done(new Function() {
})
.fail(new Function() {
public void f() {
- assertEquals("then2 then1 message", arguments(0));
+ assertEquals("then2 message then1", arguments(0));
finishTest();
done = true;
}
assertTrue(done);
}
}
+
+ public void testDeferredOr() {
+ done = false;
+ delayTestFinish(5000);
+
+ GQuery
+ .when(new PromiseFunction() {
+ public void f(Deferred dfd) {
+ dfd.reject("reject-when");
+ }
+ })
+ .or(new FunctionDeferred() {
+ public void f(Deferred dfd) {
+ dfd.reject(arguments[0] + " reject-or1");
+ }
+ })
+ .or(new FunctionDeferred() {
+ public void f(Deferred dfd) {
+ dfd.reject(arguments[0] + " reject-or2");
+ }
+ })
+ .then(null, new FunctionDeferred() {
+ public void f(Deferred dfd) {
+ dfd.resolve(arguments[0] + " resolve-or3");
+ }
+ })
+ .or(new FunctionDeferred() {
+ public void f(Deferred dfd) {
+ dfd.resolve(arguments[0] + " or4");
+ }
+ })
+ .or(new FunctionDeferred() {
+ public void f(Deferred dfd) {
+ dfd.reject(arguments[0] + " or5");
+ }
+ })
+ .done(new Function() {
+ public void f() {
+ assertEquals("reject-when reject-or1 reject-or2 resolve-or3", arguments(0));
+ finishTest();
+ done = true;
+ }
+ })
+ .fail(new Function() {
+ public void f() {
+ finishTest();
+ fail();
+ }
+ });
+
+ if (!GWT.isClient()) {
+ assertTrue(done);
+ }
+ }
public void testProtected() {