* Override this for GQuery methods which take a callback and do not expect a
* return value.
*
- * @param e takes a com.google.gwt.user.client.Element
+ * @param elem takes a com.google.gwt.user.client.Element
*/
private boolean loop = false;
public void f(com.google.gwt.user.client.Element e) {
}
/**
- * Provides a way to execute callback Functions based on one or more Promise objects
+ * Provides a way to execute callback Functions based on one or more objects
* that represent asynchronous events.
*
- * Returns a new promise which will be finalized when all of its subordinates finish.
+ * Arguments can be of any Object, but normally you would pass Promises.
+ * In the case you provide a GQuery object it will call the promise() method to return
+ * a Promise which will be executed when the queue is resolved.
+ * In the case you provide a normal Object, it will return a promise which will be immediately
+ * resolved with the object as argument.
+ * In the case you provide a Function it will executed and if the f(Object...) method returns
+ * a new promise it will be used, otherwise we will use the returned object like in the last case.
+ *
+ * It 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) {
+ public static Promise when(Object... subordinates) {
return Deferred.when(subordinates);
}
}
return pushStack(unique(result), "prevUntil", getSelector());
}
-
+
+ /**
+ * Returns a dynamically generated Promise that is resolved once all actions
+ * in the queue have ended.
+ */
+ public Promise promise() {
+ return as(Queue).promise();
+ }
+
+ /**
+ * Returns a dynamically generated Promise that is resolved once all actions
+ * in the named queue have ended.
+ */
+ public Promise promise(String name) {
+ return as(Queue).promise(name);
+ }
+
/**
* Get the value of a property for the first element in the set of matched elements.
*
* the License.
*/
package com.google.gwt.query.client;
-import static com.google.gwt.query.client.plugins.QueuePlugin.Queue;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JavaScriptObject;
-import com.google.gwt.core.client.JsArray;
-import com.google.gwt.core.client.JsArrayMixed;
-import com.google.gwt.core.client.JsArrayString;
-import com.google.gwt.dom.client.BodyElement;
-import com.google.gwt.dom.client.ButtonElement;
-import com.google.gwt.dom.client.Document;
+
import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.OptionElement;
-import com.google.gwt.dom.client.SelectElement;
-import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.HasCssName;
-import com.google.gwt.dom.client.TextAreaElement;
+import com.google.gwt.query.client.GQuery.Offset;
import com.google.gwt.query.client.css.CSS;
import com.google.gwt.query.client.css.HasCssValue;
import com.google.gwt.query.client.css.TakesCssValue;
import com.google.gwt.query.client.css.TakesCssValue.CssSetter;
-import com.google.gwt.query.client.impl.AttributeImpl;
-import com.google.gwt.query.client.impl.DocumentStyleImpl;
-import com.google.gwt.query.client.impl.SelectorEngine;
-import com.google.gwt.query.client.js.JsCache;
-import com.google.gwt.query.client.js.JsMap;
import com.google.gwt.query.client.js.JsNamedArray;
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.Effects;
-import com.google.gwt.query.client.plugins.Events;
-import com.google.gwt.query.client.plugins.Plugin;
-import com.google.gwt.query.client.plugins.Widgets;
-import com.google.gwt.query.client.plugins.ajax.Ajax;
-import com.google.gwt.query.client.plugins.ajax.Ajax.Settings;
-import com.google.gwt.query.client.plugins.deferred.Deferred;
import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing;
-import com.google.gwt.query.client.plugins.events.EventsListener;
-import com.google.gwt.query.client.plugins.widgets.WidgetsUtils;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.EventListener;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.query.client.GQuery.Offset;
-import com.google.gwt.query.client.LazyBase;
public interface LazyGQuery<T> extends LazyBase<T>{
*/
LazyGQuery<T> prevUntil(GQuery until, String filter);
+ /**
+ * Returns a dynamically generated Promise that is resolved once all actions
+ * in the queue have ended.
+ */
+ Promise promise();
+
+ /**
+ * Returns a dynamically generated Promise that is resolved once all actions
+ * in the named queue have ended.
+ */
+ Promise promise(String name);
+
/**
* Get the value of a property for the first element in the set of matched elements.
*
*/
package com.google.gwt.query.client.plugins;
+import java.util.LinkedList;
+import java.util.Queue;
+
import com.google.gwt.dom.client.Element;
import com.google.gwt.query.client.Function;
import com.google.gwt.query.client.GQuery;
+import com.google.gwt.query.client.Promise;
+import com.google.gwt.query.client.plugins.deferred.Callbacks;
import com.google.gwt.user.client.Timer;
-import java.util.LinkedList;
-import java.util.Queue;
-
/**
* Class used in plugins which need a queue system.
*/
}
});
+ /**
+ * Function used to delay the execution of a set of functions in
+ * a queue.
+ */
protected class DelayFunction extends Function {
private class SimpleTimer extends Timer {
public void run() {
- g.each(funcs);
- for (Element e: g.elements()) {
- dequeueIfNotDoneYet(e, name, DelayFunction.this);
+ for (Function f : funcs) {
+ f.fe(elem);
}
+ dequeueIfNotDoneYet(elem, name, DelayFunction.this);
}
}
private int delay;
Function[] funcs;
- GQuery g;
+ Element elem;
String name;
- public DelayFunction(GQuery gquery, String name, int delayInMilliseconds, Function... f) {
- this.g = gquery;
- this.delay = delayInMilliseconds;
+ public DelayFunction(Element elem, String name, int delay, Function... f) {
+ this.elem = elem;
+ this.delay = delay;
this.funcs = f;
this.name = name;
}
public static final String JUMP_TO_END = QueuePlugin.class.getName() + ".StopData";
protected static final String QUEUE_DATA_PREFIX = QueuePlugin.class.getName() + ".Queue-";
protected static String DEFAULT_NAME = QUEUE_DATA_PREFIX + "fx";
+ private static final String EMPTY_HOOKS = ".Empty";
protected QueuePlugin(GQuery gq) {
super(gq);
*/
@SuppressWarnings("unchecked")
public T delay(int milliseconds, String name, Function... funcs) {
- queue(name, new DelayFunction(this, name, milliseconds, funcs));
- return (T) this;
+ for (Element e : elements()) {
+ queue(e, name, new DelayFunction(e, name, milliseconds, funcs));
+ }
+ return (T)this;
}
/**
return (T) this;
}
+ /**
+ * Returns a dynamically generated Promise that is resolved once all actions
+ * in the queue have ended.
+ */
+ public Promise promise() {
+ return promise(DEFAULT_NAME);
+ }
+
+ /**
+ * Returns a dynamically generated Promise that is resolved once all actions
+ * in the named queue have ended.
+ */
+ public Promise promise(String name) {
+ final Promise.Deferred dfd = Deferred();
+
+ Function resolve = new Function() {
+ int l = QueuePlugin.this.length();
+ public Object f(Object... args) {
+ if (--l == 0) {
+ dfd.resolve();
+ }
+ return null;
+ }
+ };
+
+ for (Element elem: elements()) {
+ emptyHooks(elem, name).add(resolve);
+ }
+
+ return dfd.promise();
+ }
+
/**
* Show the number of functions to be executed on the first matched element
* in the effects queue.
* in the named queue.
*/
public int queue(String name) {
- Queue<Object> q = isEmpty() ? null : queue(get(0), name, null);
+ Queue<?> q = isEmpty() ? null : queue(get(0), name, null);
return q == null? 0 : q.size();
}
}
private void dequeueCurrentAndRunNext(Element elem, String name) {
- Queue<?> q = queue(elem, name, null);
+ Queue<? extends Function> q = queue(elem, name, null);
if (q != null) {
// Remove current function
q.poll();
// Run the next in the queue
- Object f = q.peek();
- if (f != null) {
- if (f instanceof Function) {
- ((Function) f).fe(elem);
- }
- } else {
- // if it is the last function remove the queue to avoid leaks (issue 132)
- removeData(elem, name);
- }
+ runNext(elem, name, q);
+ }
+ }
+
+ private void runNext(Element elem, String name, Queue<? extends Function> q) {
+ assert q != null;
+ Function f = q.peek();
+ if (f != null) {
+ f.fe(elem);
+ } else {
+ // Run final hooks when emptying the queue, used in promises
+ emptyHooks(elem, name).fire(elem, name, f);
+ // It is the last function, remove the queue to avoid leaks (issue 132)
+ removeData(elem, name);
}
}
@SuppressWarnings("unchecked")
- protected <S> Queue<S> queue(Element elem, String name, S func) {
+ protected <S extends Function> Queue<S> queue(Element elem, String name, S func) {
if (elem != null) {
Queue<S> q = (Queue<S>) data(elem, name, null);
if (func != null) {
}
q.add(func);
if (q.size() == 1) {
- if (func instanceof Function) {
- ((Function) func).fe(elem);
- }
+ runNext(elem, name, q);
}
}
return q;
public void dequeueIfNotDoneYet(Element elem, String name, Object object) {
Queue<?> queue = queue(elem, name, null);
if (queue != null && object.equals(queue.peek())) {
- dequeue(name);
+ dequeueCurrentAndRunNext(elem, name);
}
}
data(elem, name, queue);
}
}
+
+ private Callbacks emptyHooks(Element elem, String name) {
+ String key = name + EMPTY_HOOKS;
+ Callbacks c = (Callbacks)data(elem, key, null);
+ if (c == null) {
+ c = (Callbacks)data(elem, key, new Callbacks("once memory"));
+ }
+ return c;
+ }
private void stop(Element elem, String name, boolean clear, boolean jumpToEnd) {
Queue<?> q = queue(elem, name, null);
return new Deferred(gq);
}
});
-
+
+ public static Promise when(Object... d) {
+ int l = d.length;
+ Promise[] p = new Promise[l];
+ for (int i = 0; i < l; i++) {
+ p[i] = makePromise(d[i]);
+ }
+ return when(p);
+ }
+
+ private static Promise makePromise(final Object o) {
+ if (o instanceof Promise) {
+ return (Promise)o;
+ } else if (o instanceof Function) {
+ return makePromise(((Function)o).f(new Object[0]));
+ } else if (o instanceof GQuery) {
+ return ((GQuery)o).promise();
+ } else {
+ return new PromiseFunction() {
+ public void f(Deferred dfd) {
+ dfd.resolve(o);
+ }
+ };
+ }
+ }
+
public static Promise when(Promise... d) {
final int n = d.length;
switch (n) {
package com.google.gwt.query.client;
+import static com.google.gwt.query.client.GQuery.$;
+import static com.google.gwt.query.client.GQuery.$$;
+import static com.google.gwt.query.client.GQuery.document;
+
+import com.google.gwt.core.client.Duration;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.query.client.plugins.ajax.Ajax;
import com.google.gwt.query.client.plugins.deferred.Callbacks;
import com.google.gwt.query.client.plugins.deferred.Callbacks.Callback;
import com.google.gwt.query.client.plugins.deferred.PromiseFunction;
+import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.RootPanel;
/**
* Test class for testing deferred and callbacks stuff.
*/
public class GQueryDeferredTestGwt extends GWTTestCase {
+
+ static Element e = null;
+
+ static HTML testPanel = null;
public String getModuleName() {
return "com.google.gwt.query.Query";
}
- private String result = "";
+ public void gwtTearDown() {
+ $(e).remove();
+ e = null;
+ }
+ public void gwtSetUp() {
+ if (e == null) {
+ testPanel = new HTML();
+ RootPanel.get().add(testPanel);
+ e = testPanel.getElement();
+ e.setId("core-tst");
+ } else {
+ e.setInnerHTML("");
+ }
+ }
+
+ private String result = "";
public void testCallbacks() {
Function fn1 = new Function() {
public Object f(Object...arguments) {
}
});
}
+
+ public void testDeferredQueueDelay() {
+ final int delay = 300;
+ final double init = Duration.currentTimeMillis();
+
+ delayTestFinish(delay * 2);
+
+ Function doneFc = new Function() {
+ public void f() {
+ finishTest();
+ double ellapsed = Duration.currentTimeMillis() - init;
+ assertTrue(ellapsed >= delay);
+ }
+ };
+
+ $(document).delay(delay).promise().done(doneFc);
+ }
+
+ int deferredRun = 0;
+ public void testDeferredQueueMultipleDelay() {
+ final int delay = 300;
+ final double init = Duration.currentTimeMillis();
+ deferredRun = 0;
+
+ delayTestFinish(delay * 3);
+
+ $("<div>a1</div><div>a2</div>")
+ .delay(delay, new Function() {
+ public void f() {
+ double ellapsed = Duration.currentTimeMillis() - init;
+ assertTrue(ellapsed >= delay);
+ deferredRun ++;
+ }
+ })
+ .delay(delay, new Function() {
+ public void f() {
+ double ellapsed = Duration.currentTimeMillis() - init;
+ assertTrue(ellapsed >= (delay * 2));
+ deferredRun ++;
+ }
+ })
+ .promise().done(new Function() {
+ public void f() {
+ finishTest();
+ // Functions are run 4 times (2 functions * 2 elements)
+ assertEquals(4, deferredRun);
+ }
+ });
+ }
+
+ /**
+ * Example taken from the gquery.promise() documentation
+ */
+ public void testDeferredEffect() {
+ $(e).html("<button>click</button><p>Ready...</p><br/><div></div>");
+ $("div", e).css($$("height: 50px; width: 50px;float: left; margin-right: 10px;display: none; background-color: #090;"));
+
+ final Function effect = new Function() {public Object f(Object... args) {
+ return $("div", e).fadeIn(800).delay(1200).fadeOut();
+ }};
+
+ final double init = Duration.currentTimeMillis();
+
+ delayTestFinish(10000);
+
+ $("button", e)
+ .click(new Function(){public void f() {
+ $("p", e).append(" Started... ");
+ GQuery.when( effect ).done(new Function(){public void f() {
+ $("p", e).append(" Finished! ");
+ assertEquals("Ready... Started... Finished! ", $("p", e).text());
+
+ double ellapsed = Duration.currentTimeMillis() - init;
+ assertTrue(ellapsed >= (800 + 1200 + 400));
+
+ finishTest();
+ }});
+ }})
+ .click();
+ }
+
+ /**
+ * Example taken from the gquery.promise() documentation
+ */
+ public void testDeferredEffectEach() {
+ $(e).html("<button>click</button><p>Ready...</p><br/><div></div><div></div><div></div><div></div>");
+ $("div", e).css($$("height: 50px; width: 50px;float: left; margin-right: 10px;display: none; background-color: #090;"));
+
+ final double init = Duration.currentTimeMillis();
+
+ delayTestFinish(10000);
+
+ $("button", e)
+ .bind("click", new Function(){public void f() {
+ $("p", e).append(" Started... ");
+
+ $("div",e).each(new Function(){public Object f(Element e, int i) {
+ return $( this ).fadeIn().fadeOut( 1000 * (i+1) );
+ }});
+
+ $("div", e).promise().done(new Function(){ public void f() {
+ $("p", e).append( " Finished! " );
+
+ assertEquals("Ready... Started... Finished! ", $("p", e).text());
+ double ellapsed = Duration.currentTimeMillis() - init;
+ assertTrue(ellapsed >= (1000 * 4));
+
+ finishTest();
+ }});
+ }})
+ .click();
+ }
}