From 85b16030e9636d01c98971b837818d182b3a657e Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Sat, 3 Jan 2015 20:03:49 +0100 Subject: Allow to use customized animations. And Fixes. In this patch there are many fixes found when playing with plugins. Also I have refactored Effects and Transitions plugins so as it is easier to extend and implement customized animations. Now we use properties instead of the Fx.css3 hack to disable modern animations. --- .../main/java/com/google/gwt/query/Query.gwt.xml | 22 +++ .../java/com/google/gwt/query/QueryMin.gwt.xml | 12 +- .../java/com/google/gwt/query/client/Function.java | 34 ++-- .../com/google/gwt/query/client/js/JsCache.java | 4 +- .../com/google/gwt/query/client/js/JsUtils.java | 92 ++++++--- .../google/gwt/query/client/plugins/Effects.java | 106 +++++----- .../client/plugins/effects/ClipAnimation.java | 27 +-- .../gwt/query/client/plugins/effects/Fx.java | 2 - .../plugins/effects/PropertiesAnimation.java | 34 +--- .../query/client/plugins/effects/Transform.java | 165 ++++++++++++++++ .../query/client/plugins/effects/Transitions.java | 215 ++++----------------- .../plugins/effects/TransitionsAnimation.java | 86 ++++++--- .../gwt/query/client/GQueryDeferredTestGwt.java | 2 - .../gwt/query/client/GQueryEffectsTestGwt.java | 52 ++++- 14 files changed, 463 insertions(+), 390 deletions(-) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml index 08a6ff11..9bbc7431 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml +++ b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml @@ -172,4 +172,26 @@ --> + + + + + + + + + + + + + + + + + + + + diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml index 28cfea6c..f21b6ba5 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml +++ b/gwtquery-core/src/main/java/com/google/gwt/query/QueryMin.gwt.xml @@ -22,10 +22,10 @@ - + - - + + @@ -39,11 +39,9 @@ - - - + - + diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java index 063aaf38..bd5e9be1 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java @@ -35,11 +35,11 @@ public abstract class Function { * Utility method to get a string representation with the content * of the arguments array. It recursively visits arrays and inspect * object to print an appropriate representation of them. - * + * * It is very useful to debug arguments passed in nested promises. - * + * * It is protected so as it can be used in Inner functions. - * + * * Output example: *
    * [0](com.google.gwt.query.client.plugins.QueuePlugin) 
a1
a2
@@ -124,7 +124,7 @@ public abstract class Function { /** * Return the first element of the arguments list. - * + * * @deprecated use getArgument(idx) instead. */ @Deprecated @@ -143,7 +143,7 @@ public abstract class Function { /** * Utility method for safety getting a JavaScriptObject present at a certain * position in the list of arguments composed by arrays. - * + * */ @SuppressWarnings("unchecked") public T getArgumentJSO(int argIdx, int pos) { @@ -161,10 +161,10 @@ public abstract class Function { /** * 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) { @@ -179,7 +179,7 @@ public abstract class Function { /** * Return the argument in the position idx or null if it doesn't exist. - * + * * Note: if the return type doesn't match the object, you * will get a casting exception. */ @@ -204,7 +204,7 @@ public abstract class Function { /** * Safety return the argument in the position idx. - * + * * If the element class is not of the requested type it returns null and * you don't get casting exeption. */ @@ -214,7 +214,7 @@ public abstract class Function { /** * Safety return the argument in the position idx. - * + * * If the element class is not of the requested type it returns null and * you don't get casting exeption. */ @@ -225,15 +225,15 @@ public abstract class Function { /** * Utility method for safety getting an object present at a certain * position in the list of arguments composed by arrays. - * + * * Useful for Deferred chains where result of each resolved * promise is set as an array in the arguments list. - * + * * When the object found in the array doesn't match the type required it returns a null. - * + * * Note: If type is null, we don't check the class of the object found andd you could * eventually get a casting exception. - * + * */ @SuppressWarnings("unchecked") public T getArgument(int argIdx, int pos, Class type) { @@ -302,7 +302,7 @@ public abstract class Function { /** * Return the index in a loop execution. - * + * * Used in GQuery.each() */ public int getIndex() { @@ -427,6 +427,8 @@ public abstract class Function { /** * Override this method for bound event handlers if you wish to deal with * per-handler user data. + * + * @return boolean false means stop propagation and prevent default */ public boolean f(Event e, Object... arg) { setArguments(arg); @@ -437,7 +439,7 @@ public abstract class Function { /** * Override this method for bound event handlers. * - * @return boolean: false means stop propagation and prevent default + * @return boolean false means stop propagation and prevent default */ public boolean f(Event e) { setEvent(e); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java index 13f6c4a3..2862ee0f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java @@ -135,7 +135,7 @@ public class JsCache extends JavaScriptObject { } public final native boolean isEmpty() /*-{ - for (k in this) return false; + for (k in this) if (this.hasOwnProperty(k)) return false; return true; }-*/; @@ -240,7 +240,7 @@ public class JsCache extends JavaScriptObject { var key, keys=[]; // Chrome in DevMode sets '__gwt_ObjectId' to JS objects // GWT sets '$H' when calling getHashCode (see com/google/gwt/core/client/impl/Impl.java) - for(key in this) if (key != '__gwt_ObjectId' && key != '$H') keys.push(String(key)); + for(key in this) if (this.hasOwnProperty(key) && key != '__gwt_ObjectId' && key != '$H') keys.push(String(key)); return keys; }-*/; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java index 13520fe4..ecd7c6a8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java @@ -15,10 +15,13 @@ */ package com.google.gwt.query.client.js; +import static com.google.gwt.query.client.GQuery.browser; + 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.JsonUtils; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Node; @@ -90,9 +93,9 @@ public class JsUtils { * Default JsUtils implementation. */ public static class JsUtilsImpl { - public native Properties parseJSON(String json) /*-{ - return $wnd.JSON.parse(json); - }-*/; + public Properties parseJSON(String json) { + return JsonUtils.safeEval(json); + } public native String JSON2String(JavaScriptObject o) /*-{ return $wnd.JSON.stringify(o); @@ -129,15 +132,9 @@ public class JsUtils { * IE JsUtils implemetation. */ public static class JsUtilsImplIE6 extends JsUtilsImpl { - public static final native Properties evalImpl(String properties) /*-{ - return eval(properties); - }-*/; - @Override public Properties parseJSON(String json) { - // No checks to the passed string so json should be - // a well-formed json string. - return evalImpl("(" + json + ")"); + return JsonUtils.unsafeEval(json); } @Override @@ -190,7 +187,7 @@ public class JsUtils { @Override public JsArray unique(JsArray a) { // in IE6 XML elements does not support adding hashId to the object - if (a.length() > 0 && isXML(a.get(0))) { + if (browser.ie6 && isXML(a.get(0))) { return a; } return super.unique(a); @@ -299,11 +296,23 @@ public class JsUtils { } /** - * Check if an object has already a property with name name - * defined. + * Check if an object has a property with name defined. + * It supports dots in the name meaning checking nested properties. + * + * Example: + *
+   *  // Check whether a browser supports touch events
+   *  hasProperty(window, "ontouchstart");
+   * 
*/ - public static native boolean hasProperty(JavaScriptObject o, String name) /*-{ + public static native boolean hasProperty(JavaScriptObject o, String name)/*-{ return o && name in o; + var p = name.split('.'); + for (var i in p) { + if (!(o && p[i] in o)) return false; + o = o[p[i]]; + } + return true; }-*/; /** @@ -348,7 +357,7 @@ public class JsUtils { /** * Return whether a node is detached to the DOM. - * + * * Be careful : This method works only on node that should be inserted within the body node. */ public static boolean isDetached(Node n) { @@ -480,6 +489,34 @@ public class JsUtils { return a }-*/; + /** + * Run any arbitrary function in javascript scope using the window as the base object. + * It checks the existence of the function and object hierarchy before executing it. + * It's very useful in order to avoid writing jsni blocks for very simple snippets. + * + * Note that GWT 3.0 jsinterop will come with a method similar, so we might deprecate + * this in the future. + * + * Example + *
+   *  // Create a svg node in our document.
+   *  Element svg = jsni("document.createElementNS", "http://www.w3.org/2000/svg", "svg");
+   *  // Append it to the dom
+   *  $(svg).appendTo(document);
+   *  // show the svg element in the debug console
+   *  jsni("console.log", svg);
+   * 
+ * + * @param meth the literal name of the function to call, dot separators are allowed. + * @param args an array with the arguments to pass to the function. + * @return the java ready boxed object returned by the jsni method or null, if the + * call return a number we will get a Double, if it returns a boolean we get a java + * Boolean, strings comes as java String, otherwise we get the javascript object. + */ + public static T jsni(String meth, Object... args) { + return runJavascriptFunction(null, meth, args); + } + /** * Call via jsni any arbitrary function present in a Javascript object. * @@ -494,20 +531,25 @@ public class JsUtils { * $(svg).appendTo(document); *
* - * @param o the javascript object where the function is. - * @param meth the literal name of the function to call. + * @param o the javascript object where the function is, it it is null we use window. + * @param meth the literal name of the function to call, dot separators are allowed. * @param args an array with the arguments to pass to the function. - * @return the javascript object returned by the jsni method or null. + * @return the java ready boxed object returned by the jsni method or null, if the + * call return a number we will get a Double, if it returns a boolean we get a java + * Boolean, strings comes as java String, otherwise we get the javascript object. */ public static T runJavascriptFunction(JavaScriptObject o, String meth, Object... args) { - return runJavascriptFunctionImpl(o, meth, JsObjectArray.create().add(args) - . cast()); + return runJavascriptFunctionImpl(o, meth, JsObjectArray.create().add(args).cast()); } - private static native T runJavascriptFunctionImpl(JavaScriptObject o, String meth, - JsArrayMixed args) /*-{ - return (f = o && o[meth]) - && @com.google.gwt.query.client.js.JsUtils::isFunction(*)(f) + private static native T runJavascriptFunctionImpl(JavaScriptObject o, String meth, JsArrayMixed args) /*-{ + var f = o || window, p = meth.split('.'); + for (var i in p) { + o = f; + f = f[p[i]]; + if (!f) return null; + } + return @com.google.gwt.query.client.js.JsUtils::isFunction(*)(f) && @com.google.gwt.query.client.js.JsCache::gwtBox(*)([f.apply(o, args)]); }-*/; @@ -542,7 +584,7 @@ public class JsUtils { /** * Returns a QueryString representation of a JavascriptObject. - * + * * TODO: jquery implementation accepts a second parameter (traditional) */ public static String param(JavaScriptObject js) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java index acb7fc17..762f4444 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java @@ -16,16 +16,14 @@ package com.google.gwt.query.client.plugins; import com.google.gwt.animation.client.Animation; +import com.google.gwt.core.client.GWT; 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.Properties; -import com.google.gwt.query.client.plugins.effects.ClipAnimation; -import com.google.gwt.query.client.plugins.effects.ClipAnimation.Direction; import com.google.gwt.query.client.plugins.effects.Fx; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; -import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation; /** * Effects plugin for Gwt Query. @@ -42,14 +40,34 @@ public class Effects extends QueuePlugin { // Each Animation is associated to one element protected Element e; protected Properties prps; + protected Easing easing; + protected Function[] funcs; + protected Effects g; - protected GQAnimation setElement(Element element) { + public GQAnimation setElement(Element element) { e = element; + g = $(e).as(Effects); return this; } - protected GQAnimation setProperties(Properties properties) { + public GQAnimation setProperties(Properties properties) { prps = properties == null ? Properties.create() : properties; + if (prps.defined("easing")) { + try { + easing = EasingCurve.valueOf(prps.getStr("easing")); + } catch (Exception ignore) { + } + } + return this; + } + + public GQAnimation setEasing(Easing ease) { + easing = ease != null ? ease : EasingCurve.swing; + return this; + } + + public GQAnimation setCallback(Function... f) { + funcs = f; return this; } @@ -92,12 +110,20 @@ public class Effects extends QueuePlugin { super(gq); } - private void queueAnimation(final Element e, final GQAnimation anim, final int duration) { + /** + * Queue an animation for an element. + * + * The goal of this method is to reuse animations. + * @param e + * @param anim + * @param duration + */ + public void queueAnimation(final GQAnimation anim, final int duration) { if (isOff()) { anim.onStart(); anim.onComplete(); } else { - queue(e, DEFAULT_NAME, new Function() { + queue(anim.e, DEFAULT_NAME, new Function() { public void cancel(Element e) { Animation anim = (Animation) data(e, GQAnimation.ACTUAL_ANIMATION, null); if (anim != null) { @@ -169,7 +195,6 @@ public class Effects extends QueuePlugin { * @param easing the easing function to use for the transition */ public Effects animate(Object stringOrProperties, int duration, Easing easing, Function... funcs) { - final Properties p = (stringOrProperties instanceof String) ? (Properties) $$((String) stringOrProperties) : (Properties) stringOrProperties; @@ -177,19 +202,25 @@ public class Effects extends QueuePlugin { if (p.getStr("duration") != null) { duration = p.getInt("duration"); } - duration = Math.abs(duration); for (Element e : elements()) { - if (Fx.css3) { - new TransitionsClipAnimation(easing, e, p, funcs).run(duration); - } else { - queueAnimation(e, new ClipAnimation(easing, e, p, funcs), duration); - } + GQAnimation a = createAnimation(); + a.setEasing(easing).setProperties(p).setElement(e).setCallback(funcs); + queueAnimation(a, duration); } return this; } + /** + * Override this to create plugins with customized animation implementation. + * + * By default it uses deferred binding. + */ + protected GQAnimation createAnimation() { + return GWT.create(GQAnimation.class); + } + /** * * The animate() method allows you to create animation effects on any numeric @@ -308,53 +339,6 @@ public class Effects extends QueuePlugin { return animate(stringOrProperties, duration, EasingCurve.linear, funcs); } - /** - * Animate the set of matched elements using the clip or scale property. It is possible to show or - * hide a set of elements, specify the direction of the animation and the start corner of the - * effect. Finally it executes the set of functions passed as arguments. - * - * @deprecated use animate() instead - */ - @Deprecated - public Effects clip(ClipAnimation.Action a, ClipAnimation.Corner c, - ClipAnimation.Direction d, Function... f) { - return clip(a, c, d, Speed.DEFAULT, f); - } - - /** - * Animate the set of matched elements using the clip or scale property. It is possible to show or - * hide a set of elements, specify the direction of the animation and the start corner of the - * effect. Finally it executes the set of functions passed as arguments. - * - * @deprecated use animate() instead - */ - @Deprecated - public Effects clip(final ClipAnimation.Action a, - final ClipAnimation.Corner c, final ClipAnimation.Direction d, - final int duration, final Function... f) { - for (Element e : elements()) { - if (Fx.css3) { - new TransitionsClipAnimation(e, a, c, d, null, null, f).run(duration); - } else { - queueAnimation(e, new ClipAnimation(e, a, c, d, f), duration); - } - } - return this; - } - - /** - * Animate the set of matched elements using the clip or scale property. It is possible to show or - * hide a set of elements, specify the direction of the animation and the start corner of the - * effect. Finally it executes the set of functions passed as arguments. - * - * @deprecated use animate() instead - */ - @Deprecated - public Effects clip(ClipAnimation.Action a, ClipAnimation.Corner c, - Function... f) { - return clip(a, c, Direction.BIDIRECTIONAL, Speed.DEFAULT, f); - } - /** * Reveal all matched elements by adjusting the clip or scale property firing an optional callback * after completion. The effect goes from the center to the perimeter. diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java index 627c0b47..6794d1c1 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java @@ -15,12 +15,11 @@ */ package com.google.gwt.query.client.plugins.effects; -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.Properties; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.Effects; +import com.google.gwt.query.client.plugins.Effects.GQAnimation; /** * Animation which uses the css clip property to show/hide an element. @@ -55,15 +54,10 @@ public class ClipAnimation extends PropertiesAnimation { private Corner corner; private Direction direction; private GQuery back = Effects.$(); - private Effects g; private Action currentAction; - public ClipAnimation(Element elem, Properties p, Function... funcs) { - this(null, elem, p, funcs); - } - - public ClipAnimation(Easing easing, Element elem, Properties p, Function... funcs) { - super(easing, elem, p, funcs); + @Override + public GQAnimation setProperties(Properties p) { corner = Corner.CENTER; try { corner = Corner.valueOf(getNormalizedValue("clip-origin", p)); @@ -78,26 +72,13 @@ public class ClipAnimation extends PropertiesAnimation { action = Action.valueOf(getNormalizedValue("clip-action", p)); } catch (Exception e) { } - g = GQuery.$(e).as(Effects.Effects); + return super.setProperties(p); } public static String getNormalizedValue(String value, Properties p) { return JsUtils.hyphenize(p.getStr(value)).replace("-", "_").toUpperCase(); } - public ClipAnimation(Element elem, Action a, Corner c, Direction d, Easing easing, - Properties p, final Function... funcs) { - super(easing, elem, p, funcs); - this.action = a; - this.corner = c; - this.direction = d; - g = GQuery.$(e).as(Effects.Effects); - } - - public ClipAnimation(Element elem, Action a, Corner c, Direction d, final Function... funcs) { - this(elem, a, c, d, null, Properties.create(), funcs); - } - @Override public void onComplete() { super.onComplete(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Fx.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Fx.java index b81a9de9..1e202e33 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Fx.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Fx.java @@ -33,8 +33,6 @@ public class Fx { */ public static boolean off = false; - public static boolean css3 = Transitions.transition != null; - /** * A pojo to store css3 transition values. */ diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java index e5a4c8f6..ceb6b556 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java @@ -15,12 +15,8 @@ */ package com.google.gwt.query.client.plugins.effects; -import static com.google.gwt.query.client.GQuery.$; - 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.Properties; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.plugins.Effects; import com.google.gwt.query.client.plugins.Effects.GQAnimation; @@ -159,7 +155,7 @@ public class PropertiesAnimation extends GQAnimation { .compile("^([+-]=)?([0-9+-.]+)(.*)?$"); protected static final RegExp REGEX_NON_PIXEL_ATTRS = - RegExp.compile("z-?index|font-?weight|opacity|zoom|line-?height|scale|rotation|^\\$", "i"); + RegExp.compile("z-?index|font-?weight|opacity|zoom|line-?height|scale|rotat|^\\$", "i"); private static final RegExp REGEX_COLOR_ATTR = RegExp.compile(".*color$", "i"); @@ -173,7 +169,6 @@ public class PropertiesAnimation extends GQAnimation { if (REGEX_COLOR_ATTR.test(key)) { return computeFxColorProp(e, key, val); } - return computeFxNumericProp(e, key, val, hidden); } @@ -288,32 +283,7 @@ public class PropertiesAnimation extends GQAnimation { return new Fx(key, val, start, end, unit, rkey); } - protected Easing easing; protected JsObjectArray effects; - private Function[] funcs; - private Effects g; - - public PropertiesAnimation(Element elem, Properties p, Function... funcs) { - this(null, elem, p, funcs); - } - - public PropertiesAnimation(Easing ease, Element elem, Properties p, Function... funcs) { - try { - easing = EasingCurve.valueOf(p.getStr("easing")); - } catch (Exception e) { - } - if (easing == null) { - easing = ease; - } - if (easing == null) { - easing = EasingCurve.swing; - } - this.funcs = funcs; - setProperties(p); - setElement(elem); - - g = $(e).as(Effects.Effects); - } @Override public void onCancel() { @@ -329,7 +299,7 @@ public class PropertiesAnimation extends GQAnimation { @Override public void onComplete() { super.onComplete(); - for (int i = 0; i < effects.length(); i++) { + for (int i = 0; effects != null && i < effects.length(); i++) { Fx fx = effects.get(i); if ("hide".equals(fx.value)) { g.hide(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java new file mode 100644 index 00000000..641a02cc --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java @@ -0,0 +1,165 @@ +/* + * Copyright 2014, The gwtquery team. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.query.client.plugins.effects; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.query.client.GQuery; +import com.google.gwt.regexp.shared.MatchResult; +import com.google.gwt.regexp.shared.RegExp; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map.Entry; + +/** + * A dictionary class with all the properties of an element transform + * which is able to return the correct syntax for setting the css transform + * property. + */ +public class Transform { + + private static final String TRANSFORM = "_t_"; + + protected static final RegExp transformRegex = RegExp.compile("^(scale([XYZ]|)|translate([XYZ]|3d)|rotate([XYZ]|3d)?|perspective|skew[XYZ]|x|y)$"); + private static final RegExp transform3dRegex = RegExp.compile("^(rotate([XYZ]|3d)|perspective)$"); + + private HashMap> map = new HashMap>(); + + /** + * Return the Transform dictionary object of a element. + */ + public static Transform getInstance(Element e) { + return getInstance(e, null); + } + + public static boolean isTransform(String propName) { + return transformRegex.test(propName); + } + + /** + * Return the Transform dictionary object of an element, but reseting + * historical values and setting them to the initial value passed. + */ + public static Transform getInstance(Element e, String initial) { + Transform t = GQuery.data(e, TRANSFORM); + if (t == null || initial != null && !initial.isEmpty()) { + t = new Transform(initial); + GQuery.data(e, TRANSFORM, t); + } + return t; + } + + public Transform(String s) { + parse(s); + } + + public String get(String prop) { + return listToStr(map.get(prop), ","); + } + + private String listToStr(List l, String sep) { + String v = ""; + if (l != null) { + for (String s : l) { + v += (v.isEmpty() ? "" : sep) + s; + } + } + return v; + } + + private void parse(String s) { + if (s != null) { + RegExp re = RegExp.compile("([a-zA-Z0-9]+)\\((.*?)\\)", "g"); + for (MatchResult r = re.exec(s); r != null; r = re.exec(s)) { + setFromString(r.getGroup(1), r.getGroup(2)); + } + } + } + + public void set(String prop, String ...val) { + setter(prop, val); + } + + public void setFromString(String prop, String ...val) { + if (val.length == 1) { + String[] vals = val[0].split("[\\s*,\\s*]"); + set(prop, vals); + } else { + set(prop, val); + } + } + + private void setter(String prop, String ...val) { + if (prop.matches("(rotate[XYZ]?|skew[XYZ])")) { + map.put(prop, unit(val[0], "deg")); + } else if ("scale".equals(prop)) { + String x = val.length < 1 ? "1" : val[0]; + String y = val.length < 2 ? x : val[1]; + map.put(prop, Arrays.asList(x, y)); + } else if ("perspective".equals(prop)) { + map.put(prop, unit(val[0], "px")); + } else if ("x".equals(prop)) { + setter("translate", val[0], null); + } else if ("y".equals(prop)) { + setter("translate", null, val[0]); + } else if (prop.matches("(translate[XYZ])")) { + map.put(prop, unit(val[0], "px")); + } else if ("translate".equals(prop)) { + if (map.get("translateX") == null) { + map.put("translateX", unit("0", "px")); + } + if (val[0] != null) { + map.put("translateX", unit(val[0], "px")); + } + if (map.get("translateY") == null) { + map.put("translateY", unit("0", "px")); + } + if (val.length > 1 && val[1] != null) { + map.put("translateY", unit(val[1], "px")); + } + if (map.get("translateZ") == null) { + map.put("translateZ", unit("0", "px")); + } + if (val.length > 2 && val[2] != null) { + map.put("translateZ", unit(val[0], "px")); + } + map.put("translate", Arrays.asList(map.get("translateX").get(0), map.get("translateY").get(0), map.get("translateY").get(0))); + } else { + map.put(prop, unit(val[0], "")); + } + } + + /** + * Converts the dictionary to a transition css string. + */ + public String toString() { + // purposely using string addition, since my last tests demonstrate + // that string addition performs better than string builders in gwt-prod. + String ret = ""; + for (Entry> e: map.entrySet()) { + if (Transitions.has3d || !transform3dRegex.test(e.getKey())) { + String v = listToStr(e.getValue(), ","); + ret += (ret.isEmpty() ? "" : " ") + e.getKey() + "(" + v + ")"; + } + } + return ret; + } + + private List unit(String val, String unit) { + return Arrays.asList(val + (val.endsWith(unit) ? "" : unit)); + } +} \ No newline at end of file diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java index cefedceb..b939a9b1 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java @@ -28,26 +28,22 @@ */ package com.google.gwt.query.client.plugins.effects; -import com.google.gwt.core.client.Duration; +import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.js.JsUtils; +import com.google.gwt.query.client.plugins.Effects; import com.google.gwt.query.client.plugins.Plugin; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; -import com.google.gwt.regexp.shared.MatchResult; +import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation; import com.google.gwt.regexp.shared.RegExp; -import com.google.gwt.user.client.DOM; -import com.google.gwt.user.client.Timer; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.Map.Entry; /** * Transitions and transformation plugin for gQuery. @@ -69,127 +65,24 @@ import java.util.Map.Entry; * */ -public class Transitions extends GQuery { - - /** - * A dictionary class with all the properties of an element transform - * which is able to return the correct syntax for setting css properties. - */ - public static class Transform { - - private static final RegExp transform3dRegex = RegExp.compile("^(rotate([XY]|3d)|perspective)$"); - - private HashMap> map = new HashMap>(); - - public Transform(String s) { - parse(s); - } - - public String get(String prop) { - return listToStr(map.get(prop), ","); - } - - private String listToStr(List l, String sep) { - String v = ""; - if (l != null) { - for (String s : l) { - v += (v.isEmpty() ? "" : sep) + s; - } - } - return v; - } - - private void parse(String s) { - if (s != null) { - RegExp re = RegExp.compile("([a-zA-Z0-9]+)\\((.*?)\\)", "g"); - for (MatchResult r = re.exec(s); r != null; r = re.exec(s)) { - setFromString(r.getGroup(1), r.getGroup(2)); - } - } - } - - public void set(String prop, String ...val) { - setter(prop, val); - } - - public void setFromString(String prop, String ...val) { - if (val.length == 1) { - String[] vals = val[0].split("[\\s*,\\s*]"); - set(prop, vals); - } else { - set(prop, val); - } - } - - private void setter(String prop, String ...val) { - if (prop.matches("(rotate[XY]?|skew[XY])")) { - map.put(prop, unit(val[0], "deg")); - } else if ("scale".equals(prop)) { - String x = val.length < 1 ? "1" : val[0]; - String y = val.length < 2 ? x : val[1]; - map.put(prop, Arrays.asList(x, y)); - } else if ("perspective".equals(prop)) { - map.put(prop, unit(val[0], "px")); - } else if ("x".equals(prop)) { - setter("translate", val[0], null); - } else if ("y".equals(prop)) { - setter("translate", null, val[0]); - } else if ("translate".equals(prop)) { - if (map.get("translateX") == null) { - map.put("translateX", unit("0", "px")); - } - if (val[0] != null) { - map.put("translateX", unit(val[0], "px")); - } - if (map.get("translateY") == null) { - map.put("translateY", unit("0", "px")); - } - if (val[1] != null) { - map.put("translateY", unit(val[1], "px")); - } - map.put("translate", Arrays.asList(map.get("translateX").get(0), map.get("translateY").get(0))); - } - } - - /** - * Converts the dictionary to a transition css string. - */ - public String toString() { - // purposely using string addition, since my last tests demonstrate - // that string addition performs better than string builders in gwt-prod. - String ret = ""; - for (Entry> e: map.entrySet()) { - if (has3d || !transform3dRegex.test(e.getKey())) { - String v = listToStr(e.getValue(), ","); - ret += (ret.isEmpty() ? "" : " ") + e.getKey() + "(" + v + ")"; - } - } - return ret; - } - - private List unit(String val, String unit) { - return Arrays.asList(val + (val.endsWith(unit) ? "" : unit)); - } - } +public class Transitions extends Effects { // Used to check supported properties in the browser - private static Style divStyle = DOM.createDiv().getStyle(); + protected static final Style divStyle = Document.get().createDivElement().getStyle(); - private static final String prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : ""; + public static final String prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : ""; private static final String transform = getVendorPropertyName("transform"); - private static final String TRANSFORM = "_t_"; private static final String transformOrigin = getVendorPropertyName("transformOrigin"); - protected static final RegExp transformRegex = RegExp.compile("^(scale|translate|rotate([XY]|3d)?|perspective|skew[XY]|x|y)$"); protected static final String transition = getVendorPropertyName("transition"); // passing an invalid transition property in chrome, makes disable all transitions in the element - private static final RegExp invalidTransitionNamesRegex = RegExp.compile("^(.*transform.*|duration|easing|delay|clip-.*)$"); + public static final RegExp invalidTransitionNamesRegex = RegExp.compile("^(.*transform.*|duration|function|easing|delay|clip-.*)$"); - private static final String transitionDelay = getVendorPropertyName("transitionDelay"); - private static final String transitionEnd = browser.mozilla || browser.msie ? "transitionend" : (prefix + "transitionEnd"); + protected static final String transitionDelay = getVendorPropertyName("transitionDelay"); + protected static final String transitionEnd = browser.mozilla || browser.msie ? "transitionend" : (prefix + "TransitionEnd"); - public static boolean has3d = supportsTransform3d(); + public static final boolean has3d = supportsTransform3d(); public static final Class Transitions = GQuery.registerPlugin( Transitions.class, new Plugin() { @@ -198,7 +91,8 @@ public class Transitions extends GQuery { } }); - private static String getVendorPropertyName(String prop) { + public static String getVendorPropertyName(String prop) { + assert divStyle != null; // we prefer vendor specific names by default String vendorProp = JsUtils.camelize("-" + prefix + "-" + prop); if (JsUtils.hasProperty(divStyle, vendorProp)) { @@ -215,7 +109,7 @@ public class Transitions extends GQuery { } private static String property(String prop) { - if (transformRegex.test(prop)) { + if (Transform.isTransform(prop)) { return transform; } return prop.replaceFirst("^(margin|padding).+$", "$1"); @@ -238,16 +132,15 @@ public class Transitions extends GQuery { @Override public String css(String prop, boolean force) { if ("transform".equals(prop)) { - return isEmpty() ? "" : getTransform(get(0), null).toString(); + return isEmpty() ? "" : Transform.getInstance(get(0), null).toString(); } else if ("transformOrigin".equals(prop)) { return super.css(transformOrigin, force); } else if ("transition".equals(prop)) { return super.css(transition, force); - } else if (transformRegex.test(prop)) { - return isEmpty() ? "" : getTransform(get(0), null).get(prop); + } else if (Transform.isTransform(prop)) { + return isEmpty() ? "" : Transform.getInstance(get(0), null).get(prop); } else { - String ret = super.css(prop, force); - return ret; + return super.css(prop, force); } } @@ -255,16 +148,16 @@ public class Transitions extends GQuery { public Transitions css(String prop, String value) { if ("transform".equals(prop)) { for (Element e : elements()) { - Transform t = getTransform(e, value); + Transform t = Transform.getInstance(e, value); getStyleImpl().setStyleProperty(e, transform, t.toString()); } } else if ("transformOrigin".equals(prop)) { super.css(transformOrigin, value); } else if ("transition".equals(prop)) { super.css(transition, value); - } else if (transformRegex.test(prop)) { + } else if (Transform.isTransform(prop)) { for (Element e : elements()) { - Transform t = getTransform(e, null); + Transform t = Transform.getInstance(e, null); t.setFromString(prop, value); getStyleImpl().setStyleProperty(e, transform, t.toString()); } @@ -274,7 +167,7 @@ public class Transitions extends GQuery { return this; } - private List filterTransitionPropertyNames(Properties p) { + public static List filterTransitionPropertyNames(Properties p) { List ret = new ArrayList(); for (String s : p.keys()) { if (invalidTransitionNamesRegex.test(s)) { @@ -295,15 +188,6 @@ public class Transitions extends GQuery { return ret; } - private Transform getTransform(Element e, String initial) { - Transform t = data(e, TRANSFORM); - if (t == null || initial != null && !initial.isEmpty()) { - t = new Transform(initial); - data(e, TRANSFORM, t); - } - return t; - } - /** * The transition() method allows you to create animation effects on any numeric HTML Attribute, * CSS property, or color using CSS3 transformations and transitions. @@ -320,49 +204,17 @@ public class Transitions extends GQuery { .transition("{x: +100, width: +40px}", 2000, EasingCurve.easeOut); * */ - public Transitions transition(Object stringOrProperties, final int duration, final Easing easing, final int delay, final Function... funcs) { - if (isEmpty()) { - return this; - } - - final Properties cssProps = (stringOrProperties instanceof String) - ? (Properties) $$((String) stringOrProperties) - : (Properties) stringOrProperties; - - final String ease = easing == null ? "ease" : easing.toString(); - final List transProps = filterTransitionPropertyNames(cssProps); - final double queuedAt = delay > 0 ? Duration.currentTimeMillis() : 0; - - // Use gQuery queue, so as we can chain transitions, animations etc. - queue(new Function() { - public void f() { - // This is called once per element - final String oldTransitionValue = $(this).css(transition); - // Recompute delay based on the time spent in the queue - int d = Math.max(0, delay - (int) (Duration.currentTimeMillis() - queuedAt)); - // Generate transition value - String attribs = duration + "ms" + " " + ease + " " + d + "ms"; - String newTransitionValue = ""; - for (String s : transProps) { - newTransitionValue += (newTransitionValue.isEmpty() ? "" : ", ") + s + " " + attribs; - } - - final Transitions thisTrans = $(this).as(Transitions); - // Configure animation using transition property - thisTrans.css(transition, newTransitionValue); - // Set all css properties for this transition using the css method in this class - thisTrans.css(cssProps); - - // TODO: Use transitionEnd events once GQuery supports non-bit events - // last time I tried, setting 'transitionEnd' made custom events fail (slideEnter) - new Timer() { - public void run() { - thisTrans.css(transition, oldTransitionValue).each(funcs).dequeue(); - } - }.schedule(d + duration); + public Transitions transition(Object stringOrProperties, final int duration, final Easing easing, + final int delay, final Function... funcs) { + if (!isEmpty()) { + Properties p = (stringOrProperties instanceof String) + ? $$((String) stringOrProperties) + : (Properties) stringOrProperties; + for (Element e : elements()) { + queueAnimation(new TransitionsClipAnimation().setEasing(easing).setProperties(p) + .setElement(e).setCallback(funcs), duration); } - }); - + } return this; } @@ -380,4 +232,9 @@ public class Transitions extends GQuery { public Transitions transition(Object stringOrProperties, int duration, String easing, int delay) { return transition(stringOrProperties, duration, EasingCurve.valueOf(easing), delay); } + + @Override + protected GQAnimation createAnimation() { + return new TransitionsAnimation(); + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java index 4636b12e..5a79e311 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java @@ -20,13 +20,16 @@ import static com.google.gwt.query.client.GQuery.$$; import static com.google.gwt.query.client.plugins.effects.ClipAnimation.getNormalizedValue; import com.google.gwt.dom.client.Element; -import com.google.gwt.query.client.Function; import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.plugins.Effects.GQAnimation; import com.google.gwt.query.client.plugins.effects.ClipAnimation.Action; import com.google.gwt.query.client.plugins.effects.ClipAnimation.Corner; import com.google.gwt.query.client.plugins.effects.ClipAnimation.Direction; import com.google.gwt.query.client.plugins.effects.Fx.TransitFx; import com.google.gwt.regexp.shared.MatchResult; +import com.google.gwt.user.client.Timer; + +import java.util.List; /** * Animation effects on any numeric CSS3 property or transformation @@ -44,12 +47,8 @@ public class TransitionsAnimation extends PropertiesAnimation { private Direction direction; private Action currentAction; - public TransitionsClipAnimation(Element elem, Properties p, Function... funcs) { - this(null, elem, p, funcs); - } - - public TransitionsClipAnimation(Easing easing, Element elem, Properties p, Function... funcs) { - super(easing, elem, p, funcs); + @Override + public GQAnimation setProperties(Properties p) { corner = Corner.CENTER; try { corner = Corner.valueOf(getNormalizedValue("clip-origin", p)); @@ -64,14 +63,7 @@ public class TransitionsAnimation extends PropertiesAnimation { action = Action.valueOf(getNormalizedValue("clip-action", p)); } catch (Exception e) { } - } - - public TransitionsClipAnimation(Element elem, Action a, Corner c, Direction d, Easing easing, - Properties p, final Function... funcs) { - super(easing, elem, p, funcs); - this.action = a; - this.corner = c; - this.direction = d; + return super.setProperties(p); } public void onStart() { @@ -119,7 +111,7 @@ public class TransitionsAnimation extends PropertiesAnimation { g.hide(); } g.css("transformOrigin", ""); - g.css("transform", "scale(1 1)"); + g.css("transform", ""); } } @@ -139,7 +131,7 @@ public class TransitionsAnimation extends PropertiesAnimation { } String cur = g.css(key, true); - String trsStart = cur, trsEnd = trsStart; + String trsStart = cur.matches("auto|initial") ? "" : cur, trsEnd = trsStart; if ("show".equals(val)) { g.saveCssAttrs(key); @@ -196,18 +188,26 @@ public class TransitionsAnimation extends PropertiesAnimation { protected Transitions g; protected int delay = 0; + private String oldTransitionValue; - public TransitionsAnimation(Element elem, Properties p, Function... funcs) { - this(null, elem, p, funcs); + @Override + public GQAnimation setProperties(Properties p) { + delay = p.getInt("delay"); + return super.setProperties(p); } - public TransitionsAnimation(Easing easing, Element elem, Properties p, Function... funcs) { - super(easing, elem, p, funcs); - delay = p.getInt("delay"); - g = $(e).as(Transitions.Transitions); + @Override + public GQAnimation setElement(Element elem) { + g = $(elem).as(Transitions.Transitions); + return super.setElement(elem); } - private Properties getFxProperties(boolean isStart) { + public TransitionsAnimation setDelay(int delay) { + this.delay = delay; + return this; + } + + public Properties getFxProperties(boolean isStart) { Properties p = $$(); for (int i = 0; i < effects.length(); i++) { TransitFx fx = (TransitFx) effects.get(i); @@ -221,7 +221,7 @@ public class TransitionsAnimation extends PropertiesAnimation { @Override protected Fx getFx(Element e, String key, String val, boolean hidden) { - return computeFxProp(e, key, val, hidden); + return Transitions.invalidTransitionNamesRegex.test(key) ? null : computeFxProp(e, key, val, hidden); } @Override @@ -229,21 +229,43 @@ public class TransitionsAnimation extends PropertiesAnimation { } @Override + public void onComplete() { + g.css(Transitions.transition, oldTransitionValue); + super.onComplete(); + } + public void run(int duration) { + // Calculate all Fx values for this animation onStart(); - // Compute initial properties Properties p = getFxProperties(true); - g.css(p) - // Some browsers need after setting initial properties re-flow (FF 24.4.0). - .offset(); + g.css(p); + // Some browsers need re-flow after setting initial properties (FF 24.4.0). + g.offset(); // Compute final properties p = getFxProperties(false); - g.transition(p, duration, easing, delay, new Function() { - public void f() { + + // Save old transition value + oldTransitionValue = g.css(Transitions.transition); + + // Set new transition value + String newTransitionValue = ""; + List transProps = Transitions.filterTransitionPropertyNames(p); + String attribs = duration + "ms" + " " + easing + " " + delay + "ms"; + for (String s : transProps) { + newTransitionValue += (newTransitionValue.isEmpty() ? "" : ", ") + s + " " + attribs; + } + g.css(Transitions.transition, newTransitionValue); + + // Set new css properties so as the element is animated + g.css(p); + + // Wait until transition has finished to run finish animation and dequeue + new Timer() { + public void run() { onComplete(); } - }); + }.schedule(delay + duration); } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java index a5a502ea..1ab2ca24 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryDeferredTestGwt.java @@ -263,7 +263,6 @@ public class GQueryDeferredTestGwt extends GWTTestCase { $("button", e) .click(new Function(){public void f() { - Fx.css3 = false; $("p", e).append(" Started... "); GQuery.when( effect ).done(new Function(){public void f() { $("p", e).append(" Finished! "); @@ -291,7 +290,6 @@ public class GQueryDeferredTestGwt extends GWTTestCase { $("button", e) .bind("click", new Function(){public void f() { - Fx.css3 = false; $("p", e).append(" Started... "); $("div",e).each(new Function(){public Object f(Element e, int i) { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java index da19afb1..9658e98b 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java @@ -15,7 +15,9 @@ */ 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.$$; +import static com.google.gwt.query.client.GQuery.Effects; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.RepeatingCommand; @@ -24,12 +26,13 @@ import com.google.gwt.junit.DoNotRunWith; import com.google.gwt.junit.Platform; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.query.client.GQuery.Offset; -import com.google.gwt.query.client.plugins.effects.Fx; +import com.google.gwt.query.client.plugins.Effects.GQAnimation; import com.google.gwt.query.client.plugins.effects.Fx.ColorFx; import com.google.gwt.query.client.plugins.effects.Fx.TransitFx; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; import com.google.gwt.query.client.plugins.effects.TransitionsAnimation; +import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Label; @@ -55,7 +58,6 @@ public class GQueryEffectsTestGwt extends GWTTestCase { } public void gwtSetUp() { - Fx.css3 = false; if (e == null) { testPanel = new HTML(); RootPanel.get().add(testPanel); @@ -259,9 +261,8 @@ public class GQueryEffectsTestGwt extends GWTTestCase { .toString()); prop1 = GQuery.$$("marginTop: '-110px', marginLeft: '-110px', top: '50%', left: '50%', width: '174px', height: '174px', padding: '20px'"); - PropertiesAnimation an = new PropertiesAnimation(EasingCurve.swing, g.get(0), prop1); - an.onStart(); - an.onComplete(); + GQAnimation an = new PropertiesAnimation().setEasing(EasingCurve.swing).setElement(g.get(0)).setProperties(prop1); + an.run(0); assertEquals("cssprop=marginTop value=0 start=-110 end=0 unit=px", PropertiesAnimation.computeFxProp(g.get(0), "marginTop", "0", false) @@ -285,9 +286,8 @@ public class GQueryEffectsTestGwt extends GWTTestCase { .toString()); prop1 = GQuery.$$("marginTop: '0', marginLeft: '0', top: '0%', left: '0%', width: '100px', height: '100px', padding: '5px'"); - an = new PropertiesAnimation(EasingCurve.swing, g.get(0), prop1); - an.onStart(); - an.onComplete(); + an = new PropertiesAnimation().setEasing(EasingCurve.swing).setElement(g.get(0)).setProperties(prop1); + an.run(0); assertEquals("cssprop=marginTop value=-110px start=0 end=-110 unit=px", PropertiesAnimation.computeFxProp(g.get(0), "marginTop", "-110px", @@ -312,6 +312,40 @@ public class GQueryEffectsTestGwt extends GWTTestCase { .toString()); } + public void testTransitionsAnimation() { + final GQuery m = $("
foo
").appendTo(e); + + TransitionsClipAnimation a = new TransitionsClipAnimation(); + a.setElement(m.get(0)); + a.setProperties($$("clip-action: show, clip-origin: top-right, scaleZ: 0.5, delay: 30, left: 100, top: +=50, rotateZ: 90, rotateY: 45deg, easing: custom, duration: 400")); + a.onStart(); + + Properties from = a.getFxProperties(true); + Properties to = a.getFxProperties(false); + + // HTMLUnit and chrome return different decimal part + assertEquals("0px", from.getStr("left").replace(".0", "")); + assertEquals("100px", to.getStr("left").replace(".0", "")); + assertEquals("10px", from.getStr("top").replace(".0", "")); + assertEquals("60px", to.getStr("top").replace(".0", "")); + assertEquals("0", from.getStr("rotateZ").replace(".0", "")); + assertEquals("90", to.getStr("rotateZ").replace(".0", "")); + assertEquals("0", from.getStr("rotateY").replace(".0", "")); + assertEquals("45", to.getStr("rotateY").replace(".0", "")); + assertEquals("0 0", from.getStr("scale").replace(".0", "")); + assertEquals("1 1", to.getStr("scale")); + assertNull(to.get("delay")); + assertNull(to.get("easing")); + + // HTMLUnit and chrome return different values + assertTrue(m.attr("style").contains("rigin: 100% 0%") || m.attr("style").contains("rigin: right top")); + assertTrue(m.attr("style").contains("top: 10px")); + + a.run(1); + assertTrue(m.attr("style").contains("rigin: 100% 0%") || m.attr("style").contains("rigin: right top")); + assertTrue(m.attr("style").contains("top: 60px")); + } + public void testColorEffectParsing(){ String html = "
Test
"; $(e).html(html); -- cgit v1.2.3 From 7551a677f9f96935a95b694a57299a0d347cfc03 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Sun, 4 Jan 2015 10:56:21 +0100 Subject: Adding Julien review suggestions. - Additionally, I have moved all remaining transform related stuff from transition plugin to transform class, and checked that regex are updated based on specification (it was a copy from original jQuery plugin). - Adding some tests. --- .../com/google/gwt/query/client/js/JsCache.java | 15 ++- .../com/google/gwt/query/client/js/JsUtils.java | 1 - .../query/client/plugins/effects/Transform.java | 103 ++++++++++++++++----- .../query/client/plugins/effects/Transitions.java | 59 +++--------- .../google/gwt/query/client/GQueryCoreTestGwt.java | 12 ++- .../gwt/query/client/GQueryEffectsTestGwt.java | 33 +++++++ 6 files changed, 149 insertions(+), 74 deletions(-) diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java index 2862ee0f..2f201626 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java @@ -135,7 +135,10 @@ public class JsCache extends JavaScriptObject { } public final native boolean isEmpty() /*-{ - for (k in this) if (this.hasOwnProperty(k)) return false; + for (k in this) { + if (this.hasOwnProperty(k)) + return false; + } return true; }-*/; @@ -185,7 +188,10 @@ public class JsCache extends JavaScriptObject { var key, ret = 0; // Chrome in DevMode injects a property to JS objects - for (key in this) if (key != "__gwt_ObjectId") ret ++; + for (key in this) { + if (key != "__gwt_ObjectId") + ret ++; + } return ret; }-*/; @@ -240,7 +246,10 @@ public class JsCache extends JavaScriptObject { var key, keys=[]; // Chrome in DevMode sets '__gwt_ObjectId' to JS objects // GWT sets '$H' when calling getHashCode (see com/google/gwt/core/client/impl/Impl.java) - for(key in this) if (this.hasOwnProperty(key) && key != '__gwt_ObjectId' && key != '$H') keys.push(String(key)); + for(key in this) { + if (this.hasOwnProperty(key) && key != '__gwt_ObjectId' && key != '$H') + keys.push(String(key)); + } return keys; }-*/; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java index ecd7c6a8..14908568 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java @@ -306,7 +306,6 @@ public class JsUtils { * */ public static native boolean hasProperty(JavaScriptObject o, String name)/*-{ - return o && name in o; var p = name.split('.'); for (var i in p) { if (!(o && p[i] in o)) return false; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java index 641a02cc..a165cf81 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java @@ -15,8 +15,13 @@ */ package com.google.gwt.query.client.plugins.effects; +import static com.google.gwt.query.client.GQuery.browser; + +import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Style; import com.google.gwt.query.client.GQuery; +import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.regexp.shared.MatchResult; import com.google.gwt.regexp.shared.RegExp; @@ -27,18 +32,60 @@ import java.util.Map.Entry; /** * A dictionary class with all the properties of an element transform - * which is able to return the correct syntax for setting the css transform + * which is able to return the correct syntax for setting the CSS transform * property. */ public class Transform { private static final String TRANSFORM = "_t_"; - protected static final RegExp transformRegex = RegExp.compile("^(scale([XYZ]|)|translate([XYZ]|3d)|rotate([XYZ]|3d)?|perspective|skew[XYZ]|x|y)$"); - private static final RegExp transform3dRegex = RegExp.compile("^(rotate([XYZ]|3d)|perspective)$"); + // Used to check supported properties in the browser + protected static final Style divStyle = Document.get().createDivElement().getStyle(); + + // Compute browser specific constants, public so as they are usable in plugins + public static final String prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : ""; + public static final String transform = getVendorPropertyName("transform"); + public static final String transformOrigin = getVendorPropertyName("transformOrigin"); + // Non final for testing purposes. + public static boolean has3d = supportsTransform3d(); + + // Regular expressions based on http://www.w3schools.com/cssref/css3_pr_transform.asp + protected static final RegExp transformRegex = RegExp.compile("^(matrix(3d)?|(translate|scale|rotate)([XYZ]|3d)?|skew([XY])?|perspective|x|y|z)$"); + private static final RegExp transform3dRegex = RegExp.compile("^(rotate[XY]|\\w+(Z|3d)|perspective)$"); + private static final RegExp transformParseRegex = RegExp.compile("(\\w+)\\((.*?)\\)", "g"); private HashMap> map = new HashMap>(); + // Some browsers like HTMLUnit only support 2d transformations + private static boolean supportsTransform3d() { + if (transform == null) { + return false; + } + String rotate = "rotateY(1deg)"; + divStyle.setProperty(transform, rotate); + rotate = divStyle.getProperty(transform); + return rotate != null && !rotate.isEmpty(); + } + + /** + * Compute the correct CSS property name for a specific browser vendor. + */ + public static String getVendorPropertyName(String prop) { + // we prefer vendor specific names by default + String vendorProp = JsUtils.camelize("-" + prefix + "-" + prop); + if (JsUtils.hasProperty(divStyle, vendorProp)) { + return vendorProp; + } + if (JsUtils.hasProperty(divStyle, prop)) { + return prop; + } + String camelProp = JsUtils.camelize(prop); + if (JsUtils.hasProperty(divStyle, camelProp)) { + return camelProp; + } + return null; + } + /** * Return the Transform dictionary object of a element. */ @@ -46,6 +93,9 @@ public class Transform { return getInstance(e, null); } + /** + * Return true if the propName is a valid value of the css3 transform property. + */ public static boolean isTransform(String propName) { return transformRegex.test(propName); } @@ -63,10 +113,17 @@ public class Transform { return t; } + /** + * Create a new Transform dictionary setting initial values based on the + * string passed. + */ public Transform(String s) { parse(s); } + /** + * Return the value of a transform property. + */ public String get(String prop) { return listToStr(map.get(prop), ","); } @@ -81,22 +138,31 @@ public class Transform { return v; } + /** + * Parse a transform value as string and fills the dictionary map. + */ private void parse(String s) { if (s != null) { - RegExp re = RegExp.compile("([a-zA-Z0-9]+)\\((.*?)\\)", "g"); - for (MatchResult r = re.exec(s); r != null; r = re.exec(s)) { + for (MatchResult r = transformParseRegex.exec(s); r != null; r = transformParseRegex.exec(s)) { setFromString(r.getGroup(1), r.getGroup(2)); } } } + /** + * Set a transform value or multi-value. + */ public void set(String prop, String ...val) { setter(prop, val); } + /** + * Set a transform multi-value giving either a set of strings or + * just an string of values separated by comma. + */ public void setFromString(String prop, String ...val) { if (val.length == 1) { - String[] vals = val[0].split("[\\s*,\\s*]"); + String[] vals = val[0].split("[\\s,]+"); set(prop, vals); } else { set(prop, val); @@ -104,7 +170,7 @@ public class Transform { } private void setter(String prop, String ...val) { - if (prop.matches("(rotate[XYZ]?|skew[XYZ])")) { + if (prop.matches("(rotate[XYZ]?|skew[XY])")) { map.put(prop, unit(val[0], "deg")); } else if ("scale".equals(prop)) { String x = val.length < 1 ? "1" : val[0]; @@ -116,42 +182,35 @@ public class Transform { setter("translate", val[0], null); } else if ("y".equals(prop)) { setter("translate", null, val[0]); + } else if ("z".equals(prop)) { + setter("translate", null, null, val[0]); } else if (prop.matches("(translate[XYZ])")) { map.put(prop, unit(val[0], "px")); } else if ("translate".equals(prop)) { - if (map.get("translateX") == null) { - map.put("translateX", unit("0", "px")); - } if (val[0] != null) { map.put("translateX", unit(val[0], "px")); } - if (map.get("translateY") == null) { - map.put("translateY", unit("0", "px")); - } if (val.length > 1 && val[1] != null) { map.put("translateY", unit(val[1], "px")); } - if (map.get("translateZ") == null) { - map.put("translateZ", unit("0", "px")); - } - if (val.length > 2 && val[2] != null) { - map.put("translateZ", unit(val[0], "px")); + if (has3d && val.length > 2 && val[2] != null) { + map.put("translateZ", unit(val[2], "px")); } - map.put("translate", Arrays.asList(map.get("translateX").get(0), map.get("translateY").get(0), map.get("translateY").get(0))); } else { - map.put(prop, unit(val[0], "")); + map.put(prop, Arrays.asList(val)); } } /** - * Converts the dictionary to a transition css string. + * Converts the dictionary to a transition css string value but + * excluding 3d properties if the browser only supports 2d. */ public String toString() { // purposely using string addition, since my last tests demonstrate // that string addition performs better than string builders in gwt-prod. String ret = ""; for (Entry> e: map.entrySet()) { - if (Transitions.has3d || !transform3dRegex.test(e.getKey())) { + if (has3d || !transform3dRegex.test(e.getKey())) { String v = listToStr(e.getValue(), ","); ret += (ret.isEmpty() ? "" : " ") + e.getKey() + "(" + v + ")"; } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java index b939a9b1..bff20334 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java @@ -28,9 +28,14 @@ */ package com.google.gwt.query.client.plugins.effects; -import com.google.gwt.dom.client.Document; +import static com.google.gwt.query.client.plugins.effects.Transform.getInstance; +import static com.google.gwt.query.client.plugins.effects.Transform.getVendorPropertyName; +import static com.google.gwt.query.client.plugins.effects.Transform.isTransform; +import static com.google.gwt.query.client.plugins.effects.Transform.prefix; +import static com.google.gwt.query.client.plugins.effects.Transform.transform; +import static com.google.gwt.query.client.plugins.effects.Transform.transformOrigin; + import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Style; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.Properties; @@ -67,13 +72,6 @@ import java.util.List; */ public class Transitions extends Effects { - // Used to check supported properties in the browser - protected static final Style divStyle = Document.get().createDivElement().getStyle(); - - public static final String prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : ""; - private static final String transform = getVendorPropertyName("transform"); - private static final String transformOrigin = getVendorPropertyName("transformOrigin"); - protected static final String transition = getVendorPropertyName("transition"); // passing an invalid transition property in chrome, makes disable all transitions in the element @@ -82,8 +80,6 @@ public class Transitions extends Effects { protected static final String transitionDelay = getVendorPropertyName("transitionDelay"); protected static final String transitionEnd = browser.mozilla || browser.msie ? "transitionend" : (prefix + "TransitionEnd"); - public static final boolean has3d = supportsTransform3d(); - public static final Class Transitions = GQuery.registerPlugin( Transitions.class, new Plugin() { public Transitions init(GQuery gq) { @@ -91,40 +87,13 @@ public class Transitions extends Effects { } }); - public static String getVendorPropertyName(String prop) { - assert divStyle != null; - // we prefer vendor specific names by default - String vendorProp = JsUtils.camelize("-" + prefix + "-" + prop); - if (JsUtils.hasProperty(divStyle, vendorProp)) { - return vendorProp; - } - if (JsUtils.hasProperty(divStyle, prop)) { - return prop; - } - String camelProp = JsUtils.camelize(prop); - if (JsUtils.hasProperty(divStyle, camelProp)) { - return camelProp; - } - return null; - } - private static String property(String prop) { - if (Transform.isTransform(prop)) { + if (isTransform(prop)) { return transform; } return prop.replaceFirst("^(margin|padding).+$", "$1"); } - private static boolean supportsTransform3d() { - if (transform == null) { - return false; - } - String rotate = "rotateY(1deg)"; - divStyle.setProperty(transform, rotate); - rotate = divStyle.getProperty(transform); - return rotate != null && !rotate.isEmpty(); - } - protected Transitions(GQuery gq) { super(gq); } @@ -132,13 +101,13 @@ public class Transitions extends Effects { @Override public String css(String prop, boolean force) { if ("transform".equals(prop)) { - return isEmpty() ? "" : Transform.getInstance(get(0), null).toString(); + return isEmpty() ? "" : getInstance(get(0), null).toString(); } else if ("transformOrigin".equals(prop)) { return super.css(transformOrigin, force); } else if ("transition".equals(prop)) { return super.css(transition, force); - } else if (Transform.isTransform(prop)) { - return isEmpty() ? "" : Transform.getInstance(get(0), null).get(prop); + } else if (isTransform(prop)) { + return isEmpty() ? "" : getInstance(get(0), null).get(prop); } else { return super.css(prop, force); } @@ -148,16 +117,16 @@ public class Transitions extends Effects { public Transitions css(String prop, String value) { if ("transform".equals(prop)) { for (Element e : elements()) { - Transform t = Transform.getInstance(e, value); + Transform t = getInstance(e, value); getStyleImpl().setStyleProperty(e, transform, t.toString()); } } else if ("transformOrigin".equals(prop)) { super.css(transformOrigin, value); } else if ("transition".equals(prop)) { super.css(transition, value); - } else if (Transform.isTransform(prop)) { + } else if (isTransform(prop)) { for (Element e : elements()) { - Transform t = Transform.getInstance(e, null); + Transform t = getInstance(e, null); t.setFromString(prop, value); getStyleImpl().setStyleProperty(e, transform, t.toString()); } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java index 36d38b70..4df6b85c 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java @@ -17,11 +17,9 @@ 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.console; import static com.google.gwt.query.client.GQuery.document; import static com.google.gwt.query.client.GQuery.window; -import com.google.gwt.core.client.js.JsType; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.InputElement; @@ -1032,11 +1030,19 @@ public class GQueryCoreTestGwt extends GWTTestCase { } public void testUtilsCallFunc() { + assertTrue(JsUtils.hasProperty(window, "document.body.style.background")); + assertTrue(JsUtils.hasProperty(window, "document.createElement")); + assertFalse(JsUtils.hasProperty(window, "document.body.style.foo")); + Element e = JsUtils.runJavascriptFunction(document, "createElement", "div"); assertNotNull(e); assertEquals(e.getTagName().toLowerCase(), "div"); - e = JsUtils.runJavascriptFunction(document, "foo", "bar", 2, true); + e = JsUtils.jsni("document.createElement", "span"); + assertNotNull(e); + assertEquals(e.getTagName().toLowerCase(), "span"); + + e = JsUtils.jsni("document.foo.bar"); assertNull(e); } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java index 9658e98b..0b210802 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java @@ -31,6 +31,7 @@ import com.google.gwt.query.client.plugins.effects.Fx.ColorFx; import com.google.gwt.query.client.plugins.effects.Fx.TransitFx; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; +import com.google.gwt.query.client.plugins.effects.Transform; import com.google.gwt.query.client.plugins.effects.TransitionsAnimation; import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation; import com.google.gwt.user.client.Timer; @@ -39,6 +40,9 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; +import java.util.Arrays; +import java.util.List; + /** * Test class for testing gwtquery effects plugin api. */ @@ -312,6 +316,35 @@ public class GQueryEffectsTestGwt extends GWTTestCase { .toString()); } + public void testTransformParser() { + Transform.has3d = true; + Transform t = new Transform("scaleZ(0.5) rotateZ(90deg) skewX(4) rotateY(45) scale(1, 1) x(10) y(12) z(14) matrix(1, 2,3 ,4)"); + List vals = Arrays.asList(t.toString().split(" ")); + // scale(1,1) matrix(1,2,3,4) rotateZ(90deg) translateZ(14px) rotateY(45deg) translateY(12px) skewX(4deg) translateX(10px) scaleZ(0.5) + assertEquals(9, vals.size()); + assertTrue(vals.contains("scaleZ(0.5)")); + assertTrue(vals.contains("rotateZ(90deg)")); + assertTrue(vals.contains("rotateY(45deg)")); + assertTrue(vals.contains("skewX(4deg)")); + assertTrue(vals.contains("rotateY(45deg)")); + assertTrue(vals.contains("scale(1,1)")); + assertTrue(vals.contains("translateX(10px)")); + assertTrue(vals.contains("translateY(12px)")); + assertTrue(vals.contains("translateZ(14px)")); + assertTrue(vals.contains("matrix(1,2,3,4)")); + + Transform.has3d = false; + t = new Transform("scaleZ(0.5) rotateZ(90deg) skewX(4) rotateY(45) scale(1, 1) x(10) y(12) z(14) matrix(1, 2,3 ,4)"); + vals = Arrays.asList(t.toString().split(" ")); + // scale(1,1) matrix(1,2,3,4) translateY(12px) skewX(4deg) translateX(10px) + assertEquals(5, vals.size()); + assertTrue(vals.contains("scale(1,1)")); + assertTrue(vals.contains("skewX(4deg)")); + assertTrue(vals.contains("translateX(10px)")); + assertTrue(vals.contains("translateY(12px)")); + assertTrue(vals.contains("matrix(1,2,3,4)")); + } + public void testTransitionsAnimation() { final GQuery m = $("
foo
").appendTo(e); -- cgit v1.2.3 From c9154098336089c1855b71fa9da5236059280e6c Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Wed, 7 Jan 2015 12:58:29 +0100 Subject: Adding more testing and fixes --- .../com/google/gwt/query/client/js/JsUtils.java | 31 ++++++++ .../google/gwt/query/client/plugins/Effects.java | 25 +++++++ .../google/gwt/query/client/plugins/Events.java | 2 +- .../plugins/effects/PropertiesAnimation.java | 17 ++--- .../query/client/plugins/effects/Transform.java | 35 +++++---- .../query/client/plugins/effects/Transitions.java | 40 ++++++----- .../plugins/effects/TransitionsAnimation.java | 76 ++++++++++++-------- .../client/plugins/events/EventsListener.java | 17 ++++- .../query/client/plugins/events/SpecialEvent.java | 2 +- .../gwt/query/client/GQueryEffectsTestGwt.java | 82 ++++++++++++++++++---- 10 files changed, 246 insertions(+), 81 deletions(-) diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java index 14908568..e1c0842b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java @@ -488,6 +488,35 @@ public class JsUtils { return a }-*/; + /** + * Call any arbitrary function present in a Javascript object. + * It checks the existence of the function and object hierarchy before executing it. + * It's very useful in order to avoid writing jsni blocks for very simple snippets. + * + * Note that GWT 3.0 jsinterop will come with a method similar, so we might deprecate + * this in the future. + * + * Example + *
+   *  // Create a svg node in our document.
+   *  Element svg = jsni(document, "createElementNS", "http://www.w3.org/2000/svg", "svg");
+   *  // Append it to the dom
+   *  $(svg).appendTo(document);
+   *  // show the svg element in the debug console
+   *  jsni("console.log", svg);
+   * 
+ * + * @param jso the object containing the method to execute + * @param meth the literal name of the function to call, dot separators are allowed. + * @param args an array with the arguments to pass to the function. + * @return the java ready boxed object returned by the jsni method or null, if the + * call return a number we will get a Double, if it returns a boolean we get a java + * Boolean, strings comes as java String, otherwise we get the javascript object. + */ + public static T jsni(JavaScriptObject jso, String meth, Object... args) { + return runJavascriptFunction(jso, meth, args); + } + /** * Run any arbitrary function in javascript scope using the window as the base object. * It checks the existence of the function and object hierarchy before executing it. @@ -536,6 +565,8 @@ public class JsUtils { * @return the java ready boxed object returned by the jsni method or null, if the * call return a number we will get a Double, if it returns a boolean we get a java * Boolean, strings comes as java String, otherwise we get the javascript object. + * + * @deprecated use jsni instead. */ public static T runJavascriptFunction(JavaScriptObject o, String meth, Object... args) { return runJavascriptFunctionImpl(o, meth, JsObjectArray.create().add(args).cast()); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java index 762f4444..36bee0df 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Effects.java @@ -21,6 +21,7 @@ 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.Properties; +import com.google.gwt.query.client.js.JsMap; import com.google.gwt.query.client.plugins.effects.Fx; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; @@ -142,6 +143,30 @@ public class Effects extends QueuePlugin { return Fx.off; } + /** + * Maintain a cache table with vendor properties so as plugins can use it. + */ + public static JsMapvendorPropNames; + + /** + * Browser prefix for vendor spedific properties. + */ + public static String prefix; + + static { + if (GWT.isClient()) { + vendorPropNames = JsMap.create(); + prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : ""; + } + } + + /** + * Get the cached vendor property name. + */ + public static String vendorProperty(String prop) { + return vendorPropNames.get(prop) != null ? vendorPropNames.get(prop) : prop; + } + /** * The animate() method allows you to create animation effects on any numeric * Attribute, CSS property, or color CSS property. diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java index 3983791a..56679a99 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java @@ -394,7 +394,7 @@ public class Events extends GQuery { dispatchEvent(evt, null, funcs); } - private void dispatchEvent(NativeEvent evt, Object[] datas, Function... funcs) { + public void dispatchEvent(NativeEvent evt, Object[] datas, Function... funcs) { for (Element e : elements()) { if (isEventCapable(e)) { $(e).data(EventsListener.EVENT_DATA, datas); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java index 883fdf20..9331124b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java @@ -149,13 +149,17 @@ public class PropertiesAnimation extends GQAnimation { protected static final String[] ATTRS_TO_SAVE = new String[] {"overflow"}; - private static final RegExp REGEX_NUMBER_UNIT = RegExp.compile("^([0-9+-.]+)(.*)?$"); + protected static final String NUMBER = "[\\d+-.]+"; + protected static final String UNIT = "[a-z%]+"; - protected static final RegExp REGEX_SYMBOL_NUMBER_UNIT = RegExp - .compile("^([+-]=)?([0-9+-.]+)(.*)?$"); + private static final RegExp REGEX_NUMBER_UNIT = RegExp.compile("^(" + NUMBER + ")(.*)?$"); - protected static final RegExp REGEX_NON_PIXEL_ATTRS = - RegExp.compile("z-?index|font-?weight|opacity|zoom|line-?height|scale|rotat|skew|perspect|^\\$", "i"); + protected static final RegExp REGEX_SYMBOL_NUMBER_UNIT = RegExp.compile("^([+-]=)?(" + NUMBER + ")(" + UNIT + ")?$"); + + protected static final RegExp REGEX_SCALE_ATTRS = RegExp.compile("scale|opacity"); + + protected static final RegExp REGEX_NON_PIXEL_ATTRS = RegExp.compile("scale|opacity" + + "|z-?index|font-?weight|zoom|line-?height|rotat|skew|perspect|^\\$", "i"); private static final RegExp REGEX_COLOR_ATTR = RegExp.compile(".*color$", "i"); @@ -246,9 +250,6 @@ public class PropertiesAnimation extends GQAnimation { start = 0; unit = REGEX_NON_PIXEL_ATTRS.test(key) ? "" : "px"; } else if ("hide".equals(val)) { - if (hidden) { - return null; - } g.saveCssAttrs(key); end = 0; unit = REGEX_NON_PIXEL_ATTRS.test(key) ? "" : "px"; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java index 00016147..da0bb509 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transform.java @@ -15,7 +15,9 @@ */ package com.google.gwt.query.client.plugins.effects; -import static com.google.gwt.query.client.GQuery.browser; +import static com.google.gwt.query.client.plugins.Effects.prefix; +import static com.google.gwt.query.client.plugins.Effects.vendorPropNames; +import static com.google.gwt.query.client.plugins.Effects.vendorProperty; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; @@ -43,9 +45,20 @@ public class Transform { protected static final Style divStyle = Document.get().createDivElement().getStyle(); // Compute browser specific constants, public so as they are usable in plugins - public static final String prefix = browser.msie ? "ms" : browser.opera ? "o" : browser.mozilla ? "moz" : browser.webkit ? "webkit" : ""; - public static final String transform = getVendorPropertyName("transform"); - public static final String transformOrigin = getVendorPropertyName("transformOrigin"); + + static { + for (String s: new String[]{"transition", "transitionDelay", "transform", "transformOrigin"}) { + vendorPropNames.put(s, getVendorPropertyName(s)); + } + // x,y,z are aliases + for (String s: new String[]{"x", "y", "z"}) { + vendorPropNames.put(s, "translate" + s.toUpperCase()); + } + } + + public static final String transform = vendorProperty("transform"); + public static final String transformOrigin = vendorProperty("transformOrigin"); + // Non final for testing purposes. public static boolean has3d = supportsTransform3d(); @@ -88,6 +101,7 @@ public class Transform { return null; } + /** * Return the Transform dictionary object of a element. */ @@ -108,7 +122,10 @@ public class Transform { */ public static Transform getInstance(Element e, String initial) { Transform t = GQuery.data(e, TRANSFORM); - if (t == null || initial != null && !initial.isEmpty()) { + if (t == null || initial != null) { + if (initial == null) { + initial = GQuery.getSelectorEngine().getDocumentStyleImpl().curCSS(e, transform, false); + } t = new Transform(initial); GQuery.data(e, TRANSFORM, t); } @@ -146,7 +163,7 @@ public class Transform { private void parse(String s) { if (s != null) { for (MatchResult r = transformParseRegex.exec(s); r != null; r = transformParseRegex.exec(s)) { - setFromString(r.getGroup(1), r.getGroup(2)); + setFromString(vendorProperty(r.getGroup(1)), r.getGroup(2)); } } } @@ -180,12 +197,6 @@ public class Transform { map.put(prop, Arrays.asList(x, y)); } else if ("perspective".equals(prop)) { map.put(prop, unit(val[0], "px")); - } else if ("x".equals(prop)) { - setter("translate", val[0], null); - } else if ("y".equals(prop)) { - setter("translate", null, val[0]); - } else if ("z".equals(prop)) { - setter("translate", null, null, val[0]); } else if (translatePropRegex.test(prop)) { map.put(prop, unit(val[0], "px")); } else if ("translate".equals(prop)) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java index bff20334..1bf8ad7d 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java @@ -29,11 +29,8 @@ package com.google.gwt.query.client.plugins.effects; import static com.google.gwt.query.client.plugins.effects.Transform.getInstance; -import static com.google.gwt.query.client.plugins.effects.Transform.getVendorPropertyName; import static com.google.gwt.query.client.plugins.effects.Transform.isTransform; -import static com.google.gwt.query.client.plugins.effects.Transform.prefix; import static com.google.gwt.query.client.plugins.effects.Transform.transform; -import static com.google.gwt.query.client.plugins.effects.Transform.transformOrigin; import com.google.gwt.dom.client.Element; import com.google.gwt.query.client.Function; @@ -48,6 +45,7 @@ import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.Transiti import com.google.gwt.regexp.shared.RegExp; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -72,14 +70,13 @@ import java.util.List; */ public class Transitions extends Effects { - protected static final String transition = getVendorPropertyName("transition"); - // passing an invalid transition property in chrome, makes disable all transitions in the element public static final RegExp invalidTransitionNamesRegex = RegExp.compile("^(.*transform.*|duration|function|easing|delay|clip-.*)$"); - protected static final String transitionDelay = getVendorPropertyName("transitionDelay"); protected static final String transitionEnd = browser.mozilla || browser.msie ? "transitionend" : (prefix + "TransitionEnd"); + protected static final String transition = vendorProperty("transition"); + public static final Class Transitions = GQuery.registerPlugin( Transitions.class, new Plugin() { public Transitions init(GQuery gq) { @@ -100,12 +97,9 @@ public class Transitions extends Effects { @Override public String css(String prop, boolean force) { - if ("transform".equals(prop)) { + prop = vendorProperty(prop); + if (transform.equals(prop)) { return isEmpty() ? "" : getInstance(get(0), null).toString(); - } else if ("transformOrigin".equals(prop)) { - return super.css(transformOrigin, force); - } else if ("transition".equals(prop)) { - return super.css(transition, force); } else if (isTransform(prop)) { return isEmpty() ? "" : getInstance(get(0), null).get(prop); } else { @@ -115,22 +109,19 @@ public class Transitions extends Effects { @Override public Transitions css(String prop, String value) { - if ("transform".equals(prop)) { + prop = vendorProperty(prop); + if (transform.equals(prop)) { for (Element e : elements()) { - Transform t = getInstance(e, value); + Transform t = getInstance(e, value != null ? value : ""); getStyleImpl().setStyleProperty(e, transform, t.toString()); } - } else if ("transformOrigin".equals(prop)) { - super.css(transformOrigin, value); - } else if ("transition".equals(prop)) { - super.css(transition, value); } else if (isTransform(prop)) { for (Element e : elements()) { Transform t = getInstance(e, null); t.setFromString(prop, value); getStyleImpl().setStyleProperty(e, transform, t.toString()); } - } else if (!invalidTransitionNamesRegex.test(prop)) { + } else { super.css(prop, value); } return this; @@ -206,4 +197,17 @@ public class Transitions extends Effects { protected GQAnimation createAnimation() { return new TransitionsAnimation(); } + + @Override + public boolean isVisible() { + for (String s : Arrays.asList("opacity", "scale", "scaleX", "scaleY", "scale3d", "width", "height")) { + String[] parts = css(s).split("\\s*,\\s*"); + for (String p : parts) { + if (p.matches("^0[a-z%]*")) { + return false; + } + } + } + return super.isVisible(); + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java index 5a79e311..5dcc56df 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java @@ -67,7 +67,7 @@ public class TransitionsAnimation extends PropertiesAnimation { } public void onStart() { - boolean hidden = !g.isVisible(); + boolean hidden = !t.isVisible(); super.onStart(); if (action == null) { @@ -96,7 +96,7 @@ public class TransitionsAnimation extends PropertiesAnimation { originY = "bottom"; } - g.show().css("transformOrigin", originX + " " + originY); + t.show().css("transformOrigin", originX + " " + originY); effects.add(new TransitFx("scale", "", scaleXini + " " + scaleYini, scaleXend + " " + scaleYend, "")); } @@ -108,16 +108,16 @@ public class TransitionsAnimation extends PropertiesAnimation { return; } if (currentAction == Action.HIDE) { - g.hide(); + t.hide(); } - g.css("transformOrigin", ""); - g.css("transform", ""); + t.css("transformOrigin", ""); + t.css("transform", ""); } } - public static Fx computeFxProp(Element e, String key, String val, boolean hidden) { + public static TransitFx computeFxProp(Element e, String key, String val, boolean hidden) { Transitions g = $(e).as(Transitions.Transitions); - String unit = ""; + String unit = REGEX_NON_PIXEL_ATTRS.test(key) ? "" : "px"; if ("toggle".equals(val)) { val = hidden ? "show" : "hide"; } @@ -135,9 +135,17 @@ public class TransitionsAnimation extends PropertiesAnimation { if ("show".equals(val)) { g.saveCssAttrs(key); - trsStart = "0"; + if (trsStart.isEmpty()) { + trsStart = "0"; + } + if (REGEX_SCALE_ATTRS.test(key)) { + trsEnd = "1"; + } } else if ("hide".equals(val)) { g.saveCssAttrs(key); + if (trsStart.isEmpty() && REGEX_SCALE_ATTRS.test(key)) { + trsStart = "1"; + } trsEnd = "0"; } else { MatchResult parts = REGEX_SYMBOL_NUMBER_UNIT.exec(val); @@ -148,15 +156,16 @@ public class TransitionsAnimation extends PropertiesAnimation { String part3 = parts.getGroup(3); trsEnd = "" + Double.parseDouble(part2); - unit = REGEX_NON_PIXEL_ATTRS.test(key) ? "" : part3 == null || part3.isEmpty() ? "px" : part3; + if (part3 != null && !part3.isEmpty()) { + unit = part3; + } if (trsStart.isEmpty()) { - trsStart = key.matches("scale") ? "1" : "0"; + trsStart = REGEX_SCALE_ATTRS.test(key) ? "1" : "0"; } if (part1 != null && !part1.isEmpty()) { double n = "-=".equals(part1) ? -1 : 1; - double st = 0; MatchResult sparts = REGEX_SYMBOL_NUMBER_UNIT.exec(trsStart); if (sparts != null) { @@ -164,29 +173,39 @@ public class TransitionsAnimation extends PropertiesAnimation { unit = sparts.getGroup(3) == null || sparts.getGroup(3).isEmpty() ? unit : sparts.getGroup(3); } trsStart = "" + st; - double en = Double.parseDouble(trsEnd); trsEnd = "" + (st + n * en); } // Deal with non px units like "%" - if (!unit.isEmpty() && !"px".equals(unit) && trsStart.matches("[-+]?[\\d.]+")) { + if (!unit.isEmpty() && !"px".equals(unit) && trsStart.matches(NUMBER)) { double start = Double.parseDouble(trsStart); - double to = Double.parseDouble(trsEnd); - g.css(key, to + unit); - start = to * start / g.cur(key, true); - trsStart = "" + start; - g.css(key, start + unit); + if (start != 0) { + double to = Double.parseDouble(trsEnd); + g.css(key, to + unit); + start = to * start / g.cur(key, true); + trsStart = "" + start; + g.css(key, start + unit); + } } } else { trsStart = ""; trsEnd = val; + if (trsStart.isEmpty()) { + trsStart = REGEX_SCALE_ATTRS.test(key) ? "1" : "0"; + } } } + if (trsStart.matches(NUMBER)) { + trsStart += unit; + } + if (trsEnd.matches(NUMBER)) { + trsEnd += unit; + } return new TransitFx(key, val, trsStart, trsEnd, unit); } - protected Transitions g; + protected Transitions t; protected int delay = 0; private String oldTransitionValue; @@ -198,8 +217,9 @@ public class TransitionsAnimation extends PropertiesAnimation { @Override public GQAnimation setElement(Element elem) { - g = $(elem).as(Transitions.Transitions); - return super.setElement(elem); + e = elem; + g = t = $(elem).as(Transitions.Transitions); + return this; } public TransitionsAnimation setDelay(int delay) { @@ -213,7 +233,7 @@ public class TransitionsAnimation extends PropertiesAnimation { TransitFx fx = (TransitFx) effects.get(i); String val = isStart ? fx.transitStart : fx.transitEnd; if (!val.isEmpty()) { - p.set(fx.cssprop, val + fx.unit); + p.set(fx.cssprop, val); } } return p; @@ -230,7 +250,7 @@ public class TransitionsAnimation extends PropertiesAnimation { @Override public void onComplete() { - g.css(Transitions.transition, oldTransitionValue); + t.css(Transitions.transition, oldTransitionValue); super.onComplete(); } @@ -239,15 +259,15 @@ public class TransitionsAnimation extends PropertiesAnimation { onStart(); // Compute initial properties Properties p = getFxProperties(true); - g.css(p); + t.css(p); // Some browsers need re-flow after setting initial properties (FF 24.4.0). - g.offset(); + t.offset(); // Compute final properties p = getFxProperties(false); // Save old transition value - oldTransitionValue = g.css(Transitions.transition); + oldTransitionValue = t.css(Transitions.transition); // Set new transition value String newTransitionValue = ""; @@ -256,10 +276,10 @@ public class TransitionsAnimation extends PropertiesAnimation { for (String s : transProps) { newTransitionValue += (newTransitionValue.isEmpty() ? "" : ", ") + s + " " + attribs; } - g.css(Transitions.transition, newTransitionValue); + t.css(Transitions.transition, newTransitionValue); // Set new css properties so as the element is animated - g.css(p); + t.css(p); // Wait until transition has finished to run finish animation and dequeue new Timer() { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java index 7d88ac7c..94dcc501 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java @@ -14,6 +14,7 @@ package com.google.gwt.query.client.plugins.events; import static com.google.gwt.query.client.GQuery.$; +import static com.google.gwt.query.client.GQuery.console; import com.google.gwt.core.client.Duration; import com.google.gwt.dom.client.Element; @@ -641,6 +642,11 @@ public class EventsListener implements EventListener { } public void onBrowserEvent(Event event) { +// console.log("onBrowser", event.getType(), event, element); + if (JsUtils.isDefaultPrevented(event)) { + console.log("RETTT"); + return; + } double now = Duration.currentTimeMillis(); // Workaround for Issue_20 if (lastType.equals(event.getType()) && now - lastEvnt < 10 @@ -688,9 +694,18 @@ public class EventsListener implements EventListener { * given eventBit or eventName. */ public boolean hasHandlers(int eventBits, String eventName) { + return hasHandlers(eventBits, eventName, null); + } + + /** + * Return true if the element is listening for the + * given eventBit or eventName and the handler matches. + */ + public boolean hasHandlers(int eventBits, String eventName, Function handler) { for (int i = 0, j = elementEvents.length(); i < j; i++) { BindFunction function = elementEvents.get(i); - if (function.hasEventType(eventBits) || function.isTypeOf(eventName)) { + if ((function.hasEventType(eventBits) || function.isTypeOf(eventName)) + && (handler == null || function.isEquals(handler))) { return true; } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/SpecialEvent.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/SpecialEvent.java index 8083b098..f45b32a9 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/SpecialEvent.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/SpecialEvent.java @@ -57,7 +57,7 @@ public interface SpecialEvent { @Override public boolean hasHandlers(Element e) { - return listener(e).hasHandlers(Event.getTypeInt(type), type); + return listener(e).hasHandlers(Event.getTypeInt(type), type, handler); } @Override diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java index 0b210802..eba3fe6d 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEffectsTestGwt.java @@ -32,6 +32,7 @@ import com.google.gwt.query.client.plugins.effects.Fx.TransitFx; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation; import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.EasingCurve; import com.google.gwt.query.client.plugins.effects.Transform; +import com.google.gwt.query.client.plugins.effects.Transitions; import com.google.gwt.query.client.plugins.effects.TransitionsAnimation; import com.google.gwt.query.client.plugins.effects.TransitionsAnimation.TransitionsClipAnimation; import com.google.gwt.user.client.Timer; @@ -263,6 +264,12 @@ public class GQueryEffectsTestGwt extends GWTTestCase { assertEquals("cssprop=padding value=20px start=5 end=20 unit=px", PropertiesAnimation.computeFxProp(g.get(0), "padding", "20px", false) .toString()); + assertEquals("cssprop=opacity value=show start=0 end=1 unit=", + PropertiesAnimation.computeFxProp(g.get(0), "opacity", "toggle", true) + .toString()); + assertEquals("cssprop=opacity value=hide start=1 end=0 unit=", + PropertiesAnimation.computeFxProp(g.get(0), "opacity", "toggle", false) + .toString()); prop1 = GQuery.$$("marginTop: '-110px', marginLeft: '-110px', top: '50%', left: '50%', width: '174px', height: '174px', padding: '20px'"); GQAnimation an = new PropertiesAnimation().setEasing(EasingCurve.swing).setElement(g.get(0)).setProperties(prop1); @@ -316,6 +323,67 @@ public class GQueryEffectsTestGwt extends GWTTestCase { .toString()); } + private void assertTransitFx(TransitFx fx, String prop, String val, String unit, String start, String end) { + assertEquals(prop, fx.cssprop); + assertEquals(val, fx.value); + assertEquals(unit, fx.unit); + if (!start.contains(".")) { + // discard decimals + assertEquals(start, fx.transitStart.replaceAll("\\.\\d+([a-z%]*)$", "$1")); + } else { + assertEquals(start, fx.transitStart); + } + if (!end.contains(".")) { + // discard decimals + assertEquals(end, fx.transitEnd.replaceAll("\\.\\d+([a-z%]*)$", "$1")); + } else { + assertEquals(end, fx.transitEnd); + } + } + + public void testTransitionsCss() { + $(e).html("
"); + Transitions t = $("div", e).as(Transitions.Transitions); + + t.css("transform", "scale(1,2) rotateX(5deg) x(7) y(8)"); + assertEquals("1,2", t.css("scale")); + assertEquals("7px", t.css("x")); + assertEquals("7px", t.css("translateX")); + t.css("y", "8"); + assertEquals("8px", t.css("y")); + assertEquals("8px", t.css("translateY")); + } + + public void testTransitionsAnimationComputeEffects() { + $(e) + .html( + "
" + + "

Content 1

"); + GQuery g = $("#child"); + TransitFx f; + + f = TransitionsAnimation.computeFxProp(g.get(0), "rotateY", "90deg", false); + assertTransitFx(f, "rotateY", "90deg", "deg", "0deg", "90deg"); + + f = TransitionsAnimation.computeFxProp(g.get(0), "marginTop", "-110px", false); + assertTransitFx(f, "marginTop", "-110px", "px", "0px", "-110px"); + + f = TransitionsAnimation.computeFxProp(g.get(0), "opacity", "toggle", false); + assertTransitFx(f, "opacity", "hide", "", "0.7", "0"); + + f = TransitionsAnimation.computeFxProp(g.get(0), "scaleX", "show", true); + assertTransitFx(f, "scaleX", "show", "", "0", "1"); + + f = TransitionsAnimation.computeFxProp(g.get(0), "width", "toggle", false); + assertTransitFx(f, "width", "hide", "px", "100px", "0px"); + + f = TransitionsAnimation.computeFxProp(g.get(0), "width", "+=45", false); + assertTransitFx(f, "width", "+=45", "px", "100px", "145px"); + + f = TransitionsAnimation.computeFxProp(g.get(0), "width", "100%", false); + assertTransitFx(f, "width", "100%", "%", "100px", "100%"); + } + public void testTransformParser() { Transform.has3d = true; Transform t = new Transform("scaleZ(0.5) rotateZ(90deg) skewX(4) rotateY(45) scale(1, 1) x(10) y(12) z(14) matrix(1, 2,3 ,4)"); @@ -363,8 +431,8 @@ public class GQueryEffectsTestGwt extends GWTTestCase { assertEquals("60px", to.getStr("top").replace(".0", "")); assertEquals("0", from.getStr("rotateZ").replace(".0", "")); assertEquals("90", to.getStr("rotateZ").replace(".0", "")); - assertEquals("0", from.getStr("rotateY").replace(".0", "")); - assertEquals("45", to.getStr("rotateY").replace(".0", "")); + assertEquals("0deg", from.getStr("rotateY").replace(".0", "")); + assertEquals("45deg", to.getStr("rotateY").replace(".0", "")); assertEquals("0 0", from.getStr("scale").replace(".0", "")); assertEquals("1 1", to.getStr("scale")); assertNull(to.get("delay")); @@ -452,16 +520,6 @@ public class GQueryEffectsTestGwt extends GWTTestCase { timer.schedule(duration * 2); } - public void testComputeFxPropTransitions() { - $(e).html("
"); - final GQuery g = $("#idtest", e); - - TransitFx fx = (TransitFx)TransitionsAnimation.computeFxProp(g.get(0), "width", "+=100", false); - assertEquals("200", fx.transitStart.replace(".0","")); - assertEquals("300", fx.transitEnd.replace(".0","")); - assertEquals("px", fx.unit); - } - public void testStop() { $(e) .html( -- cgit v1.2.3