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
+ * <pre>
+ * // 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);
+ * </pre>
+ *
+ * @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> 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.
* @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> T runJavascriptFunction(JavaScriptObject o, String meth, Object... args) {
return runJavascriptFunctionImpl(o, meth, JsObjectArray.create().add(args).<JsArrayMixed>cast());
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;
return Fx.off;
}
+ /**
+ * Maintain a cache table with vendor properties so as plugins can use it.
+ */
+ public static JsMap<String, String>vendorPropNames;
+
+ /**
+ * 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.
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);
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");
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";
*/
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;
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();
return null;
}
+
/**
* Return the Transform dictionary object of a element.
*/
*/
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);
}
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));
}
}
}
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)) {
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;
import com.google.gwt.regexp.shared.RegExp;
import java.util.ArrayList;
+import java.util.Arrays;
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> Transitions = GQuery.registerPlugin(
Transitions.class, new Plugin<Transitions>() {
public Transitions init(GQuery gq) {
@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 {
@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;
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();
+ }
}
}
public void onStart() {
- boolean hidden = !g.isVisible();
+ boolean hidden = !t.isVisible();
super.onStart();
if (action == null) {
originY = "bottom";
}
- g.show().css("transformOrigin", originX + " " + originY);
+ t.show().css("transformOrigin", originX + " " + originY);
effects.add(new TransitFx("scale", "", scaleXini + " " + scaleYini, scaleXend + " " + scaleYend, ""));
}
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";
}
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);
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) {
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;
@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) {
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;
@Override
public void onComplete() {
- g.css(Transitions.transition, oldTransitionValue);
+ t.css(Transitions.transition, oldTransitionValue);
super.onComplete();
}
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 = "";
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() {
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;
}
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
* 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;
}
}
@Override
public boolean hasHandlers(Element e) {
- return listener(e).hasHandlers(Event.getTypeInt(type), type);
+ return listener(e).hasHandlers(Event.getTypeInt(type), type, handler);
}
@Override
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;
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);
.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("<div>");
+ 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(
+ "<div id='parent' style='background-color: yellow; width: 100px; height: 200px; top:130px; position: absolute; left: 130px'>"
+ + "<p id='child' style='opacity: 0.7; background-color: pink; width: 100px; height: 100px; position: absolute; padding: 5px; margin: 0px'>Content 1</p></div>");
+ 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)");
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"));
timer.schedule(duration * 2);
}
- public void testComputeFxPropTransitions() {
- $(e).html("<div id='idtest' style='width: 200px; height 200px; border: solid 1px; position: absolute' ></div>");
- 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(