From ff6aee1545e86f8fa6e44589c2116d6d8cdb09cf Mon Sep 17 00:00:00 2001 From: Ray Cromwell Date: Wed, 6 May 2009 20:57:23 +0000 Subject: Completion of Effects framework --- .../java/com/google/gwt/query/client/Effects.java | 499 ++++++++++++++------- .../java/com/google/gwt/query/client/GQuery.java | 98 ++-- .../com/google/gwt/query/client/Properties.java | 5 +- 3 files changed, 402 insertions(+), 200 deletions(-) (limited to 'gwtquery-core/src') diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java index a15948c7..e7bd1718 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Effects.java @@ -15,7 +15,6 @@ */ package com.google.gwt.query.client; -import com.google.gwt.animation.client.Animation; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NodeList; import com.google.gwt.core.client.Duration; @@ -27,52 +26,66 @@ import com.google.gwt.user.client.Timer; public class Effects extends GQuery { /** - * Used to register the plugin. + * Built in easing functions. */ - private static class EffectsPlugin implements Plugin { - - public Effects init(GQuery gq) { - return new Effects(gq.get()); - } - } - - public static final Class Effects = Effects.class; - - static { - GQuery.registerPlugin(Effects.class, new EffectsPlugin()); - } - public enum Easing { + /** + * Linear easing function. + */ LINEAR { public double ease(double p, double n, double firstNum, double diff) { return firstNum + diff * p; } - }, SWING { + }, + /** + * Sinusoidal easing function. + */ + SWING { public double ease(double p, double n, double firstNum, double diff) { return ((-Math.cos(p * Math.PI) / 2) + 0.5) * diff + firstNum; } }; + /** + * Override to implement custom easing functions. + */ public abstract double ease(double p, double n, double firstNum, double diff); } + /** + * Build in speed constants. + */ public enum Speed { - SLOW(600), FAST(200), DEFAULT(400); - - public int getDuration() { - return duration; - } + /** + * 600 millisecond animation. + */ + SLOW(600), + /** + * 200 millisecond animation. + */ + FAST(200), + /** + * 400 millisecond animation. + */ + DEFAULT(400); private final int duration; Speed(int dur) { this.duration = dur; } + + public int getDuration() { + return duration; + } } + /** + * Utility class. + */ protected class PropFx { public SpeedOpts opt; @@ -100,9 +113,31 @@ public class Effects extends GQuery { || elem.getStyle().getProperty(prop) == null)) { return elem.getPropertyDouble(prop); } - double r = Double.parseDouble(GQuery.curCSS(elem, prop, force)); + double r = parseDouble(GQuery.curCSS(elem, prop, force)); return !Double.isNaN(r) && r > -10000 ? r - : Double.parseDouble(GQuery.curCSS(elem, prop, false)); + : parseDouble(GQuery.curCSS(elem, prop, false)); + } + + public void hide() { + opt.cache.put(prop, elem.getStyle().getProperty(prop)); + opt.hide = true; + custom(cur(false), 0); + } + + public Effects hide(Speed speed) { + return hide(speed, null); + } + + public Effects hide(Speed speed, Function callback) { + return animate(genFx("hide", 3), speed, Easing.LINEAR, callback); + } + + public Effects show(Speed speed) { + return show(speed, null); + } + + public Effects show(Speed speed, Function callback) { + return animate(genFx("show", 3), speed, Easing.LINEAR, callback); } public void show() { @@ -112,6 +147,52 @@ public class Effects extends GQuery { cur(false)); } + public Effects toggle(Speed speed) { + return hide(speed, null); + } + + public Effects toggle(Speed speed, Function callback) { + return animate(genFx("toggle", 3), speed, Easing.LINEAR, callback); + } + + public void update() { + if ("opacity".equals(prop)) { + GQuery.setStyleProperty(prop, "" + now, elem); + } else { + if (elem.getStyle() != null + && elem.getStyle().getProperty(prop) != null) { + elem.getStyle().setProperty(prop, now + unit); + } else { + elem.setPropertyString(prop, "" + now); + } + } + if (("height".equals(prop) || "width".equals(prop)) + && elem.getStyle() != null) { + elem.getStyle().setProperty("display", "block"); + } + } + + private void custom(double from, double to) { + custom(from, to, "px"); + } + + private void custom(double from, double to, String unit) { + startTime = Duration.currentTimeMillis(); + start = from; + end = to; + now = start; + this.unit = unit; + Timer t = new Timer() { + @Override + public void run() { + if (!step(false)) { + cancel(); + } + } + }; + t.scheduleRepeating(13); + } + private boolean step(boolean gotoEnd) { double t = Duration.currentTimeMillis(); @@ -149,45 +230,35 @@ public class Effects extends GQuery { double n = t - startTime; state = n / opt.duration; pos = opt.easing.ease(this.state, n, 0, 1); + now = start + ((this.end - this.start) * this.pos); + update(); return true; } } + } - public void update() { - (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this ); + /** + * Used to register the plugin. + */ + private static class EffectsPlugin implements Plugin { - // Set display property to block for height/width animations - if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style ) - this.elem.style.display = "block"; + public Effects init(GQuery gq) { + return new Effects(gq.get()); } + } - public void hide() { - opt.cache.put(prop, elem.getStyle().getProperty(prop)); - opt.hide = true; - custom(cur(false), 0); - } + private class SpeedOpts { - private void custom(double from, double to) { - custom(from, to, "px"); - } + public String display; - private void custom(double from, double to, String unit) { - startTime = Duration.currentTimeMillis(); - start = from; - end = to; - now = start; + public String overflow; - Timer t = new Timer() { - @Override - public void run() { - step(false); - } - }; - } - } + public Properties curAnim; - private class SpeedOpts { + public boolean hide; + + public boolean show; private Properties properties; @@ -199,80 +270,98 @@ public class Effects extends GQuery { private boolean queue = true; - public String display; - - public String overflow; + private GQuery.DataCache cache = DataCache.createObject().cast(); - public Properties curAnim; + protected SpeedOpts(int speed, Easing easing, Function complete) { + this.complete = complete; + this.easing = easing; + this.duration = speed; + } - public boolean hide; + protected SpeedOpts(Speed speed, Easing easing, Function complete) { + this.complete = complete; + this.easing = easing; + this.duration = speed.getDuration(); + } - private GQuery.DataCache cache = DataCache.createObject().cast(); + public void complete(Element elem) { + if (queue) { + $(elem).dequeue(); + } + if (complete != null) { + complete.f(elem); + } + } - public boolean show; + public Function getComplete() { + return complete; + } - public boolean isQueue() { - return queue; + public int getDuration() { + return duration; } - public void setQueue(boolean queue) { - this.queue = queue; + public Easing getEasing() { + return easing; } - protected SpeedOpts(int speed, Easing easing, Function complete) { - this.complete = complete; - this.easing = easing; - this.duration = speed; + public Properties getProperties() { + return properties; } - public Function getComplete() { - return complete; + public boolean isQueue() { + return queue; } public void setComplete(Function complete) { this.complete = complete; } - public int getDuration() { - return duration; - } - public void setDuration(int duration) { this.duration = duration; } - public Easing getEasing() { - return easing; - } - public void setEasing(Easing easing) { this.easing = easing; } - public Properties getProperties() { - return properties; - } - public void setProperties(Properties properties) { this.properties = properties; } - protected SpeedOpts(Speed speed, Easing easing, Function complete) { - this.complete = complete; - this.easing = easing; - this.duration = speed.getDuration(); + public void setQueue(boolean queue) { + this.queue = queue; } + } - public void complete(Element elem) { - if (queue) { - $(elem).dequeue(); - } - if (complete != null) { - complete.f(elem); + public static final Class Effects = Effects.class; + + private static String[][] fxAttrs = { + {"height", "marginTop", "marginBottom", "paddingTop", "paddingBottom"}, + {"width", "marginLeft", "marginRight", "paddingLeft", "paddingRight"}, + {"opacity"}}; + + static { + GQuery.registerPlugin(Effects.class, new EffectsPlugin()); + } + + private static Properties genFx(String type, int num) { + Properties prop = Properties.createObject().cast(); + for (int i = 0; i < num; i++) { + for (int j = 0; j < fxAttrs[i].length; j++) { + prop.set(fxAttrs[i][j], type); } } + return prop; } + // don't valid double after parsing + private static native double parseDouble(String dstr) /*-{ + return parseFloat(dstr); + }-*/; + + private DataCache elemDisplay = DataCache.createObject().cast(); + public Effects(Element element) { super(element); } @@ -287,7 +376,7 @@ public class Effects extends GQuery { public Effects animate(final Properties properties, final Speed speed, final Easing easing, final Function complete) { - if (properties.get("queue") != null) { + if (!"false".equals(properties.get("queue"))) { queue(new Function() { final SpeedOpts optall = new SpeedOpts(speed, easing, complete); @@ -333,7 +422,7 @@ public class Effects extends GQuery { double start = fx.cur(true); if (parts != null) { - double end = Double.parseDouble(parts.getStr(2)); + double end = parseDouble(parts.getStr(2)); String unit = parts.getStr(3); if (unit == null) { unit = "px"; @@ -348,7 +437,7 @@ public class Effects extends GQuery { } fx.custom(start, end, unit); } else { - fx.custom(start, Double.parseDouble(val), ""); + fx.custom(start, parseDouble(val), ""); } } } @@ -358,106 +447,103 @@ public class Effects extends GQuery { return this; } -// jQuery.each( prop, function(name, val){ -// var e = new jQuery.fx( self, opt, name ); -// -// if ( /toggle|show|hide/.test(val) ) -// e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); -// else { -// var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/), -// start = e.cur(true) || 0; -// -// if ( parts ) { -// var end = parseFloat(parts[2]), -// unit = parts[3] || "px"; -// -// // We need to compute starting value -// if ( unit != "px" ) { -// self.style[ name ] = (end || 1) + unit; -// start = ((end || 1) / e.cur(true)) * start; -// self.style[ name ] = start + unit; -// } -// -// // If a +=/-= token was provided, we're doing a relative animation -// if ( parts[1] ) -// end = ((parts[1] == "-=" ? -1 : 1) * end) + start; -// -// e.custom( start, end, unit ); -// } else -// e.custom( start, val, "" ); -// } -// }); -// -// // For JS strict compliance -// return true; -// }); -// }, -// } - + /** + * Fade in all matched elements by adjusting their opacity. Only the opacity + * is adjusted for this animation, meaning that all of the matched elements + * should already have some form of height and width associated with them. + */ public Effects fadeIn() { - Animation a = new Animation() { - - public void onCancel() { - } - - public void onComplete() { - } + return fadeIn(Speed.DEFAULT); + } - public void onStart() { - } + /** + * Fade in all matched elements by adjusting their opacity. Only the opacity + * is adjusted for this animation, meaning that all of the matched elements + * should already have some form of height and width associated with them. + */ + public Effects fadeIn(Speed speed) { + return fadeIn(speed, null); + } - public void onUpdate(double progress) { - for (int i = 0; i < elements.getLength(); i++) { - elements.getItem(i).getStyle() - .setProperty("opacity", String.valueOf(progress)); - } - } - }; - a.run(1000); - return this; + /** + * Fade in all matched elements by adjusting their opacity and firing an + * optional callback after completion. Only the opacity is adjusted for this + * animation, meaning that all of the matched elements should already have + * some form of height and width associated with them. + */ + public Effects fadeIn(Speed speed, Function callback) { + return animate($$("opacity: \"hide\""), speed, Easing.LINEAR, callback); } + /** + * Fade out all matched elements by adjusting their opacity to 0, then setting + * display to "none". Only the opacity is adjusted for this animation, meaning + * that all of the matched elements should already have some form of height + * and width associated with them. + */ public Effects fadeOut() { - Animation a = new Animation() { + return fadeOut(Speed.DEFAULT); + } - public void onCancel() { - } + /** + * Fade out all matched elements by adjusting their opacity to 0, then setting + * display to "none". Only the opacity is adjusted for this animation, meaning + * that all of the matched elements should already have some form of height + * and width associated with them. + */ + public Effects fadeOut(Speed speed) { + return fadeOut(speed, null); + } - public void onComplete() { - for (int i = 0; i < elements.getLength(); i++) { - elements.getItem(i).getStyle().setProperty("opacity", "0"); - elements.getItem(i).getStyle().setProperty("display", "none"); - } - } + /** + * Fade out all matched elements by adjusting their opacity to 0, then setting + * display to "none" and firing an optional callback after completion. Only + * the opacity is adjusted for this animation, meaning that all of the matched + * elements should already have some form of height and width associated with + * them. + */ + public Effects fadeOut(Speed speed, Function callback) { + return animate($$("opacity: \"hide\""), speed, Easing.LINEAR, callback); + } - public void onStart() { - } + /** + * Fade the opacity of all matched elements to a specified opacity. Only the + * opacity is adjusted for this animation, meaning that all of the matched + * elements should already have some form of height and width associated with + * them. + */ + public Effects fadeTo(Speed speed, double opacity) { + return fadeTo(speed, opacity, null); + } - public void onUpdate(double progress) { - for (int i = 0; i < elements.getLength(); i++) { - elements.getItem(i).getStyle() - .setProperty("opacity", String.valueOf(1.0 - progress)); - } - } - }; - a.run(1000); - return this; + /** + * Fade the opacity of all matched elements to a specified opacity and firing + * an optional callback after completion. Only the opacity is adjusted for + * this animation, meaning that all of the matched elements should already + * have some form of height and width associated with them. + */ + public Effects fadeTo(Speed speed, double opacity, Function callback) { + return animate($$("opacity: " + opacity), speed, Easing.LINEAR, callback); } + /** + * Hides each of the set of matched elements if they are shown. + */ public Effects hide() { for (Element e : elements()) { GQuery q = $(e); String old = (String) q.data("olddisplay"); if (old != null && !"none".equals(old)) { q.data("olddisplay", GQuery.curCSS(e, "display", false)); - e.getStyle().setProperty("display", "none"); } + e.getStyle().setProperty("display", "none"); } return this; } - private DataCache elemDisplay = DataCache.createObject().cast(); - + /** + * Displays each of the set of matched elements if they are hidden. + */ public Effects show() { for (Element e : elements()) { GQuery q = $(e); @@ -482,6 +568,81 @@ public class Effects extends GQuery { return this; } + /** + * Reveal all matched elements by adjusting their height . + */ + public Effects slideDown() { + return slideDown(Speed.DEFAULT, null); + } + + /** + * Reveal all matched elements by adjusting their height . + */ + public Effects slideDown(Speed speed) { + return slideDown(speed, null); + } + + /** + * Reveal all matched elements by adjusting their height and firing an + * optional callback after completion. + */ + public Effects slideDown(Speed speed, Function callback) { + return animate(genFx("show", 1), speed, Easing.LINEAR, callback); + } + + /** + * Toggle the visibility of all matched elements by adjusting their height. + * Only the height is adjusted for this animation, causing all matched + * elements to be hidden or shown in a "sliding" manner + */ + public Effects slideToggle() { + return slideToggle(Speed.DEFAULT, null); + } + + /** + * Toggle the visibility of all matched elements by adjusting their height. + * Only the height is adjusted for this animation, causing all matched + * elements to be hidden or shown in a "sliding" manner + */ + public Effects slideToggle(Speed speed) { + return slideToggle(speed, null); + } + + /** + * Toggle the visibility of all matched elements by adjusting their height and + * firing an optional callback after completion. Only the height is adjusted + * for this animation, causing all matched elements to be hidden or shown in a + * "sliding" manner + */ + public Effects slideToggle(Speed speed, Function callback) { + return animate(genFx("toggle", 1), speed, Easing.LINEAR, callback); + } + + /** + * Hide all matched elements by adjusting their height . + */ + public Effects slideUp() { + return slideUp(Speed.DEFAULT, null); + } + + /** + * Hide all matched elements by adjusting their height. + */ + public Effects slideUp(Speed speed) { + return slideUp(speed, null); + } + + /** + * Hide all matched elements by adjusting their height and firing an optional + * callback after completion. + */ + public Effects slideUp(Speed speed, Function callback) { + return animate(genFx("hide", 1), speed, Easing.LINEAR, callback); + } + + /** + * Toggle displaying each of the set of matched elements. + */ public Effects toggle() { for (Element e : elements()) { Effects ef = new Effects(e); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java index 2c9c354e..37e2c196 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java @@ -122,11 +122,11 @@ public class GQuery implements Lazy { }-*/; public native void put(String id, Object obj) /*-{ - return this[id]=obj; + this[id]=obj; }-*/; public native void put(int id, Object obj) /*-{ - return this[id]=obj; + this[id]=obj; }-*/; } @@ -307,9 +307,24 @@ public class GQuery implements Lazy { } public static native String camelize(String s)/*-{ - return s.toLowerCase().replace(/-([a-z])/ig, function(a, c){return c.toUpperCase()} ); + return s.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); }-*/; + public static String curCSS(Element elem, String name, boolean force) { + Style s = elem.getStyle(); + ensureStyleImpl(); + if (!force) { + name = styleImpl.getPropertyName(name); + + if (SelectorEngine.truth(s.getProperty(name))) { + return s.getProperty(name); + } + } + return styleImpl.getCurrentStyle(elem, name); + } + public static void registerPlugin(Class plugin, Plugin pluginFactory) { if (plugins == null) { @@ -374,21 +389,18 @@ public class GQuery implements Lazy { } } - private static String curCSS(Element elem, String name) { - return curCSS(elem, name, false); + protected static void setStyleProperty(String prop, String val, Element e) { + String property = camelize(prop); + e.getStyle().setProperty(property, val); + if ("opacity".equals(property)) { + e.getStyle().setProperty("zoom", "1"); + e.getStyle().setProperty("filter", + "alpha(opacity=" + (int) (Double.valueOf(val) * 100) + ")"); + } } - public static String curCSS(Element elem, String name, boolean force) { - Style s = elem.getStyle(); - ensureStyleImpl(); - if (!force) { - name = styleImpl.getPropertyName(name); - - if (SelectorEngine.truth(s.getProperty(name))) { - return s.getProperty(name); - } - } - return styleImpl.getCurrentStyle(elem, name); + private static String curCSS(Element elem, String name) { + return curCSS(elem, name, false); } private static void ensureStyleImpl() { @@ -794,13 +806,7 @@ public class GQuery implements Lazy { */ public GQuery css(String prop, String val) { for (Element e : elements()) { - String property = camelize(prop); - e.getStyle().setProperty(property, val); - if ("opacity".equals(property)) { - e.getStyle().setProperty("zoom", "1"); - e.getStyle().setProperty("filter", - "alpha(opacity=" + (int) (Double.valueOf(val) * 100) + ")"); - } + setStyleProperty(prop, val, e); } return this; } @@ -900,10 +906,6 @@ public class GQuery implements Lazy { return this; } - public LazyGQuery lazy() { - return GWT.create(GQuery.class); - } - /** * Revert the most recent 'destructive' operation, changing the set of matched * elements to its previous state (right before the destructive operation). @@ -1287,6 +1289,10 @@ public class GQuery implements Lazy { return bind(Event.ONKEYUP, null, f); } + public LazyGQuery lazy() { + return GWT.create(GQuery.class); + } + /** * Returns the number of elements currently matched. The size function will * return the same value. @@ -1428,8 +1434,34 @@ public class GQuery implements Lazy { return ret; } + /** + * Get the current offset of the first matched element, in pixels, relative to + * the document. The returned object contains two Float properties, top and + * left. Browsers usually round these values to the nearest integer pixel for + * actual positioning. The method works only with visible elements. + */ public Offset offset() { - return new Offset(get(0).getOffsetLeft(), get(0).getOffsetTop()); + if (length() == 0) { + return new Offset(0, 0); + } + int boxtop = getClientBoundingRectTop(get(0)); + int boxleft = getClientBoundingRectLeft(get(0)); + Element docElem = Document.get().getDocumentElement(); + Element body = Document.get().getBody(); + int clientTop = docElem.getPropertyInt("clientTop"); + if (clientTop == 0) { + clientTop = body.getPropertyInt("clientTop"); + } + int clientLeft = docElem.getPropertyInt("clientLeft"); + if (clientLeft == 0) { + clientLeft = body.getPropertyInt("clientLeft"); + } + int wleft = Window.getScrollLeft(); + int wtop = Window.getScrollTop(); + int top = boxtop + (wtop == 0 ? body.getScrollTop() : wtop) - clientTop; + int left = boxleft + (wleft == 0 ? body.getScrollLeft() : wleft) + - clientLeft; + return new Offset(top, left); } /** @@ -2434,6 +2466,14 @@ public class GQuery implements Lazy { return key; } + private native int getClientBoundingRectLeft(Element element) /*-{ + return element.getClientBoundingRect().left; + }-*/; + + private native int getClientBoundingRectTop(Element element) /*-{ + return element.getClientBoundingRect().top; + }-*/; + private native Document getContentDocument(Node n) /*-{ return n.contentDocument || n.contentWindow.document; }-*/; @@ -2483,7 +2523,7 @@ public class GQuery implements Lazy { if (data != null) { qq.enqueue(data); } - if (SelectorEngine.eq(type, "__FX") && qq.length() == 1) { + if (SelectorEngine.eq(type, "__FXqueue") && qq.length() == 1) { data.f(elem); } return qq; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index 56e24a7b..9d6c1bfb 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -64,14 +64,15 @@ public class Properties extends JavaScriptObject { return keys; }-*/; - public native Properties cloneProps() /*-{ + public final native Properties cloneProps() /*-{ var props = {}; for(p in this) { props[p] = this[p]; } + return props; }-*/; - public native void set(String key, String val) /*-{ + public final native void set(String key, String val) /*-{ this[key]=val; }-*/; } -- cgit v1.2.3