diff options
Diffstat (limited to 'gwtquery-core')
14 files changed, 424 insertions, 307 deletions
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java index d7c97b2e..72beed5b 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java @@ -2495,7 +2495,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { * Since GQuery 1.4.0, this method binds handlers for both mouseenter and mouseleave events. */ public GQuery hover(Function fover, Function fout) { - return bind("mouseenter", null, fover).bind("mouseleave", null, fout); + return bind("mouseenter", fover).bind("mouseleave", fout); } /** @@ -2846,7 +2846,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { */ @Deprecated public GQuery load(Function f) { - return bind(Event.ONLOAD, null, f); + return bind(Event.ONLOAD, f); } /** diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index c9414232..c75dd238 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java @@ -221,7 +221,7 @@ public class Properties extends JavaScriptObject implements IsProperties { @SuppressWarnings("unchecked") public final <J extends IsProperties> J strip() { - return (J)this; + return (J) this; } public final <J extends IsProperties> J parse(String json) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index a33f676b..f0c46931 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java @@ -22,7 +22,6 @@ import com.google.gwt.query.client.Properties; import com.google.gwt.query.client.js.JsCache; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.js.JsUtils; -import com.google.gwt.user.client.Window; import java.util.Arrays; import java.util.List; @@ -60,7 +59,7 @@ public abstract class JsonBuilderBase<J extends JsonBuilderBase<?>> implements J p.<JsCache>cast().delete(jsonName); } } - return (J)this; + return (J) this; } @SuppressWarnings("unchecked") diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java index d7b83337..0a466a07 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java @@ -212,7 +212,7 @@ public class DocumentStyleImpl { } /** - * Return whether the element is visible + * Return whether the element is visible. */ public boolean isVisible(Element e) { return SelectorEngine.filters.get("visible").f(e, 0); 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 c3b0c5ce..13f6c4a3 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 @@ -236,7 +236,7 @@ public class JsCache extends JavaScriptObject { checkNull(this); } - private final native JsArrayString keysImpl() /*-{ + private native JsArrayString keysImpl() /*-{ 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) 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 84ce65dd..3983791a 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 @@ -21,8 +21,7 @@ import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.query.client.plugins.events.EventsListener; -import com.google.gwt.query.client.plugins.events.EventsListener.SpecialEvent; -import com.google.gwt.query.client.plugins.events.GqEvent; +import com.google.gwt.query.client.plugins.events.EventsListener.EventName; import com.google.gwt.user.client.Event; /** @@ -110,7 +109,7 @@ public class Events extends GQuery { public GQuery die(int eventbits, String nameSpace) { EventsListener.getInstance(Element.is(currentContext) ? (Element) currentContext : body).die( - eventbits, nameSpace, null, null, currentSelector); + eventbits, nameSpace, null, currentSelector); return this; } @@ -135,7 +134,7 @@ public class Events extends GQuery { public GQuery live(int eventbits, String nameSpace, final Object data, Function... funcs) { EventsListener.getInstance(Element.is(currentContext) ? (Element) currentContext : body).live( - eventbits, nameSpace, null, null, currentSelector, data, funcs); + eventbits, nameSpace, null, currentSelector, data, funcs); return this; } @@ -262,8 +261,20 @@ public class Events extends GQuery { * @param nativeEvent the browser native event. * @functions a set of function to run if the event is not canceled. */ - public Events trigger(NativeEvent nativeEvent, Function... functions) { - dispatchEvent(nativeEvent, null, functions); + public Events trigger(NativeEvent nativeEvent, Function... fcns) { + dispatchEvent(nativeEvent, null, fcns); + return this; + } + + /** + * Trigger a native event in all matched elements. + * + * @param nativeEvent the browser native event. + * @param datas a set of object passed as data when executed the handlers + * @param functions a set of function to run if the event is not canceled. + */ + public Events trigger(NativeEvent nativeEvent, Object[] datas, Function... functions) { + dispatchEvent(nativeEvent, datas, functions); return this; } @@ -271,7 +282,7 @@ public class Events extends GQuery { * Trigger a html event in all matched elements. * * @param htmlEvent A string representing the desired html event. - * @functions a set of function to run if the event is not canceled. + * @param functions a set of function to run. */ public Events triggerHtmlEvent(String htmlEvent, Function... functions) { return triggerHtmlEvent(htmlEvent, null, functions); @@ -281,35 +292,29 @@ public class Events extends GQuery { * Trigger a html event in all matched elements. * * @param htmlEvent An string representing the desired html event. - * @functions a set of function to run if the event is not canceled. + * @param datas a set of object passed as data when executed the handlers + * @param functions a set of function to run. */ public Events triggerHtmlEvent(String htmlEvent, Object[] datas, final Function... functions) { - SpecialEvent specialEvent = EventsListener.special.get(htmlEvent); - boolean isSpecialEvent = specialEvent != null; - - String originalEventName = htmlEvent; - String delegateEventName = isSpecialEvent ? specialEvent.getDelegateType() : htmlEvent; - - NativeEvent e = document.createHtmlEvent(delegateEventName, true, true); - - if (isSpecialEvent) { - GqEvent.setOriginalEventType(e, originalEventName); - } - - if ("submit".equals(htmlEvent)) { - Function submitFunction = new Function() { - public void f(Element e) { - // first submit the form then call the others functions - if (FormElement.is(e)) { - e.<FormElement> cast().submit(); + for (EventName part : EventName.split(htmlEvent)) { + NativeEvent e = document.createHtmlEvent(part.eventName, true, true); + JsUtils.prop(e, "namespace", part.nameSpace); + if ("submit".equals(part.eventName)) { + Function submitFunction = new Function() { + public void f(Element e) { + // first submit the form then call the others functions + if (FormElement.is(e)) { + e.<FormElement>cast().submit(); + } + callHandlers(e, getEvent(), functions); } - callHandlers(e, getEvent(), functions); - } - }; - dispatchEvent(e, datas, submitFunction); - } else { - dispatchEvent(e, datas, functions); + }; + dispatchEvent(e, datas, submitFunction); + } else { + dispatchEvent(e, datas, functions); + } } + return this; } @@ -344,7 +349,7 @@ public class Events extends GQuery { public Events unbind(int eventbits, String name, Function f) { for (Element e : elements()) { if (isEventCapable(e)) { - EventsListener.getInstance(e).unbind(eventbits, name, null, null, f); + EventsListener.getInstance(e).unbind(eventbits, name, null, f); } } return this; 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 fed2ffdf..cefedceb 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 @@ -268,7 +268,7 @@ public class Transitions extends GQuery { t.setFromString(prop, value); getStyleImpl().setStyleProperty(e, transform, t.toString()); } - } else if (!invalidTransitionNamesRegex.test(prop)){ + } else if (!invalidTransitionNamesRegex.test(prop)) { super.css(prop, value); } return this; @@ -297,7 +297,7 @@ public class Transitions extends GQuery { private Transform getTransform(Element e, String initial) { Transform t = data(e, TRANSFORM); - if (t == null || initial != null && !initial.isEmpty() ) { + if (t == null || initial != null && !initial.isEmpty()) { t = new Transform(initial); data(e, TRANSFORM, t); } @@ -334,12 +334,12 @@ public class Transitions extends GQuery { final double queuedAt = delay > 0 ? Duration.currentTimeMillis() : 0; // Use gQuery queue, so as we can chain transitions, animations etc. - queue(new Function(){ + 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)); + int d = Math.max(0, delay - (int) (Duration.currentTimeMillis() - queuedAt)); // Generate transition value String attribs = duration + "ms" + " " + ease + " " + d + "ms"; String newTransitionValue = ""; 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 6155540a..4636b12e 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 @@ -85,8 +85,8 @@ public class TransitionsAnimation extends PropertiesAnimation { int bit = currentAction == Action.HIDE ? 1 : 0; String originX = "left", originY = "top"; - int scaleXini = 0^bit, scaleYini = scaleXini; - int scaleXend = 1^bit, scaleYend = scaleXend; + int scaleXini = 0 ^ bit, scaleYini = scaleXini; + int scaleXend = 1 ^ bit, scaleYend = scaleXend; if (direction == Direction.VERTICAL) { scaleXini = scaleXend = 1; @@ -174,7 +174,7 @@ public class TransitionsAnimation extends PropertiesAnimation { trsStart = "" + st; double en = Double.parseDouble(trsEnd); - trsEnd = "" + (st + n*en); + trsEnd = "" + (st + n * en); } // Deal with non px units like "%" @@ -210,7 +210,7 @@ public class TransitionsAnimation extends PropertiesAnimation { private Properties getFxProperties(boolean isStart) { Properties p = $$(); for (int i = 0; i < effects.length(); i++) { - TransitFx fx = (TransitFx)effects.get(i); + TransitFx fx = (TransitFx) effects.get(i); String val = isStart ? fx.transitStart : fx.transitEnd; if (!val.isEmpty()) { p.set(fx.cssprop, val + fx.unit); @@ -240,8 +240,10 @@ public class TransitionsAnimation extends PropertiesAnimation { // Compute final properties p = getFxProperties(false); - g.transition(p, duration, easing, delay, new Function(){public void f() { - onComplete(); - }}); + g.transition(p, duration, easing, delay, new Function() { + public void f() { + onComplete(); + } + }); } } 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 bfb24d2c..7d88ac7c 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 @@ -26,12 +26,15 @@ import com.google.gwt.query.client.js.JsMap; import com.google.gwt.query.client.js.JsNamedArray; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.js.JsUtils; +import com.google.gwt.query.client.plugins.events.SpecialEvent.DefaultSpecialEvent; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * This class implements an event queue instance for one Element. The queue instance is configured @@ -45,91 +48,71 @@ import java.util.List; */ public class EventsListener implements EventListener { - public interface SpecialEvent { - String getDelegateType(); - - String getOriginalType(); - - Function createDelegateHandler(Function originalHandler); - } - /** - * Used for simulating mouseenter and mouseleave events + * Used for simulating mouseenter and mouseleave events. */ - public static class MouseSpecialEvent implements SpecialEvent { - - private String originalType; - private String delegateType; - - public MouseSpecialEvent(String originalType, String delegateType) { - this.originalType = originalType; - this.delegateType = delegateType; - } - - public String getDelegateType() { - return delegateType; - } - - public String getOriginalType() { - return originalType; - } - - public Function createDelegateHandler(Function originalHandler) { - return new SpecialMouseEventHandler(originalHandler); + private static class MouseSpecialEvent extends DefaultSpecialEvent { + public MouseSpecialEvent(final String type, String delegateType) { + super(type, delegateType); + handler = new Function() { + public boolean f(Event e, Object... arg) { + EventTarget eventTarget = e.getCurrentEventTarget(); + Element target = eventTarget != null ? eventTarget.<Element> cast() : null; + + EventTarget relatedEventTarget = e.getRelatedEventTarget(); + Element related = relatedEventTarget != null ? relatedEventTarget.<Element> cast() : null; + + if (related == null || (related != target && !GQuery.contains(target, related))) { + getInstance(target).dispatchEvent(e, type); + } + return true; + }; + }; } } - private interface HandlerWrapper { - Function getOriginalHandler(); - } - private static class SpecialMouseEventHandler extends Function implements HandlerWrapper { - - private Function delegateHandler; - - public SpecialMouseEventHandler(Function originalHandler) { - this.delegateHandler = originalHandler; - } - - @Override - public boolean f(Event e, Object... data) { - EventTarget eventTarget = e.getCurrentEventTarget(); - Element target = eventTarget != null ? eventTarget.<Element> cast() : null; - - EventTarget relatedEventTarget = e.getRelatedEventTarget(); - Element related = relatedEventTarget != null ? relatedEventTarget.<Element> cast() : null; - - // For mousenter/leave call the handler if related is outside the target. - if (related == null || (related != target && !GQuery.contains(target, related))) { - return delegateHandler != null ? delegateHandler.f(e, data) : false; + /** + * Utility class to split a list of events with or without namespaces. + */ + public static class EventName { + public final String nameSpace; + public final String eventName; + public EventName(String n, String e) { + nameSpace = n; + eventName = e; + } + + public static List<EventName> split(String events) { + List<EventName> ret = new ArrayList<EventName>(); + String[] parts = events.split("[\\s,]+"); + for (String event : parts) { + String[] tmp = event.split("\\.", 2); + String eventName = tmp[0]; + String nameSpace = tmp.length > 1 ? tmp[1] : null; + ret.add(new EventName(nameSpace, eventName)); } - - return false; - } - - public Function getOriginalHandler() { - return delegateHandler; + return ret; } } + /** + * The function used per each element event. + */ private static class BindFunction { - Object data; Function function; String nameSpace; - // for special event like mouseleave, mouseenter - String originalEventType; int times; int type; String eventName; - BindFunction(int type, String eventName, String nameSpace, String originalEventType, - Function function, Object data, int times) { + BindFunction(int type, String eventName, String nameSpace, Function function, Object data, + int times) { this.times = times; this.eventName = eventName; this.type = type; this.function = function; this.data = data; - this.originalEventType = originalEventType; this.nameSpace = nameSpace != null ? nameSpace : ""; } @@ -148,7 +131,10 @@ public class EventsListener implements EventListener { } else { arguments = eventData; } - return function.fe(event, arguments); + // FIXME(manolo): figure out when this is null, and fix or comment it. + if (function != null) { + return function.fe(event, arguments); + } } return true; } @@ -184,14 +170,7 @@ public class EventsListener implements EventListener { public boolean isEquals(Function f) { assert f != null : "function f cannot be null"; - Function functionToCompare = - function instanceof HandlerWrapper ? ((HandlerWrapper) function).getOriginalHandler() - : function; - return f.equals(functionToCompare); - } - - public Object getOriginalEventType() { - return originalEventType; + return f.equals(function); } } @@ -204,17 +183,17 @@ public class EventsListener implements EventListener { JsNamedArray<JsObjectArray<BindFunction>> bindFunctionBySelector; LiveBindFunction(String eventName, String namespace, Object data) { - super(BITLESS, eventName, namespace, null, null, data, -1); + super(BITLESS, eventName, namespace, null, data, -1); clean(); } LiveBindFunction(int type, String namespace, Object data) { - super(type, null, namespace, null, null, data, -1); + super(type, null, namespace, null, data, -1); clean(); } /** - * Add a {@link BindFunction} for a specific css selector + * Add a {@link BindFunction} for a specific css selector. */ public void addBindFunctionForSelector(String cssSelector, BindFunction f) { JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector); @@ -297,10 +276,10 @@ public class EventsListener implements EventListener { } /** - * Remove the BindFunction associated to this cssSelector + * Remove the BindFunction associated to this cssSelector. */ - public void removeBindFunctionForSelector(String cssSelector, String nameSpace, String originalEventName) { - if (nameSpace == null && originalEventName == null) { + public void removeBindFunctionForSelector(String cssSelector, String nameSpace) { + if (nameSpace == null) { bindFunctionBySelector.delete(cssSelector); } else { JsObjectArray<BindFunction> functions = bindFunctionBySelector.get(cssSelector); @@ -312,10 +291,7 @@ public class EventsListener implements EventListener { for (int i = 0; i < functions.length(); i++) { BindFunction f = functions.get(i); - boolean matchNamespace = nameSpace == null || nameSpace.equals(f.nameSpace); - boolean matchOriginalEventName = originalEventName == null || originalEventName.equals(f.originalEventType); - - if (!matchNamespace || !matchOriginalEventName) { + if (nameSpace != null && !nameSpace.equals(f.nameSpace)) { newFunctions.add(f); } } @@ -328,7 +304,7 @@ public class EventsListener implements EventListener { } /** - * Tell if no {@link BindFunction} are linked to this object + * Tell if no {@link BindFunction} are linked to this object. * * @return */ @@ -344,7 +320,7 @@ public class EventsListener implements EventListener { /** * Return the element whose the listener fired last. It represent the context element where the - * {@link LiveBindFunction} was binded + * {@link LiveBindFunction} was binded. * */ private Element getCurrentEventTarget(Event e) { @@ -358,7 +334,7 @@ public class EventsListener implements EventListener { } /** - * Return the element that was the actual target of the element + * Return the element that was the actual target of the element. */ private Element getEventTarget(Event e) { EventTarget eventTarget = e.getEventTarget(); @@ -377,10 +353,11 @@ public class EventsListener implements EventListener { public static String MOUSEENTER = "mouseenter"; public static String MOUSELEAVE = "mouseleave"; - public static JsMap<String, SpecialEvent> special; + public static Map<String, SpecialEvent> special; static { - special = JsMap.create(); + // Register some special events which already exist in jQuery + special = new HashMap<String, SpecialEvent>(); special.put(MOUSEENTER, new MouseSpecialEvent(MOUSEENTER, "mouseover")); special.put(MOUSELEAVE, new MouseSpecialEvent(MOUSELEAVE, "mouseout")); } @@ -478,94 +455,59 @@ public class EventsListener implements EventListener { } } - public void bind(int eventbits, String namespace, String originalEventType, Object data, - Function function, int times) { - bind(eventbits, namespace, null, originalEventType, data, function, times); + public void bind(int eventbits, String namespace, Object data, Function function, int times) { + bind(eventbits, namespace, null, data, function, times); } public void bind(String events, final Object data, Function... funcs) { - String[] parts = events.split("[\\s,]+"); - - for (String event : parts) { - - String nameSpace = null; - String eventName = event; - - // seperate possible namespace - // jDramaix: I removed old regex ^([^.]*)\.?(.*$) because it didn't work on IE8... - String[] subparts = event.split("\\.", 2); - - if (subparts.length == 2){ - nameSpace = subparts[1]; - eventName = subparts[0]; - } - - // handle special event like mouseenter or mouseleave - SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; + if (funcs.length == 0 || funcs[0] == null) { + unbind(events, null); + } - int b = Event.getTypeInt(eventName); + for (EventName ev : EventName.split(events)) { + SpecialEvent hook = special.get(ev.eventName); + boolean bind = hook == null || hook.setup(element) == false; for (Function function : funcs) { - Function handler = hook != null ? hook.createDelegateHandler(function) : function; - bind(b, nameSpace, eventName, originalEventName, data, handler, -1); + int b = Event.getTypeInt(ev.eventName); + if (bind) { + bind(b, ev.nameSpace, ev.eventName, data, function, -1); + } + if (hook != null) { + hook.add(element, ev.eventName, ev.nameSpace, data, function); + } } } } - private void bind(int eventbits, String namespace, String eventName, String originalEventType, - Object data, Function function, int times) { - if (function == null) { - unbind(eventbits, namespace, eventName, originalEventType, null); - return; - } - + public void bind(int eventbits, String namespace, String eventName, Object data, Function function, int times) { sink(eventbits, eventName); - - elementEvents.add(new BindFunction(eventbits, eventName, namespace, originalEventType, - function, data, times)); + elementEvents.add(new BindFunction(eventbits, eventName, namespace, function, data, times)); } - public void die(String eventNames, String cssSelector) { - String[] parts = eventNames.split("[\\s,]+"); - - for (String event : parts) { - String nameSpace = null; - String eventName = event; - - // seperate possible namespace - // jDramaix: I removed old regex ^([^.]*)\.?(.*$) because it didn't work on IE8... - String[] subparts = event.split("\\.", 2); - - if (subparts.length == 2) { - nameSpace = subparts[1]; - eventName = subparts[0]; + public void die(String events, String cssSelector) { + for (EventName ev : EventName.split(events)) { + SpecialEvent hook = special.get(ev.eventName); + boolean unbind = hook == null || hook.tearDown(element) == false; + if (unbind) { + die(Event.getTypeInt(ev.eventName), ev.nameSpace, ev.eventName, cssSelector); + } + if (hook != null) { + hook.remove(element, ev.eventName, ev.nameSpace, null); } - - // handle special event like mouseenter or mouseleave - SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; - - int b = Event.getTypeInt(eventName); - - die(b, nameSpace, eventName, originalEventName, cssSelector); } } - public void die(int eventbits, String nameSpace, String eventName, String originalEventName, - String cssSelector) { + public void die(int eventbits, String nameSpace, String eventName, String cssSelector) { if (eventbits <= 0) { if (eventName != null && eventName.length() > 0) { LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(eventName); - maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, BITLESS, eventName, nameSpace, - originalEventName); + maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, BITLESS, eventName, nameSpace); } else { // if eventbits == -1 and eventName is null, remove all event handlers for this selector for (String k : liveBindFunctionByEventType.keys()) { int bits = Integer.parseInt(k); LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(bits); - maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, bits, null, nameSpace, null); + maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, bits, null, nameSpace); } for (String k : liveBindFunctionByEventName.keys()) { @@ -573,23 +515,21 @@ public class EventsListener implements EventListener { LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(realKey); if (liveBindFunction != null) { String eName = liveBindFunction.eventName; - maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, BITLESS, eName, - nameSpace, originalEventName); + maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, BITLESS, eName, nameSpace); } } } } else { LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(eventbits); - maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, eventbits, null, nameSpace, - originalEventName); + maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, eventbits, null, nameSpace); } } private void maybeRemoveLiveBindFunction(LiveBindFunction liveBindFunction, String cssSelector, - int eventbits, String eventName, String nameSpace, String originalEventName) { + int eventbits, String eventName, String nameSpace) { if (liveBindFunction != null) { - liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace, originalEventName); - if (liveBindFunction.isEmpty()){ + liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace); + if (liveBindFunction.isEmpty()) { if (eventbits != BITLESS) { liveBindFunctionByEventType.remove(eventbits); } else { @@ -599,16 +539,26 @@ public class EventsListener implements EventListener { } } + /** + * Dispatch an event in this element. + */ public void dispatchEvent(Event event) { - String ename = event.getType(); - int etype = Event.getTypeInt(ename); - String originalEventType = GqEvent.getOriginalEventType(event); - Object[] handlerData = $(element).data(EVENT_DATA); + dispatchEvent(event, event.getType()); + } + /** + * Dispatch an event in this element but changing the type, + * it's useful for special events. + */ + public void dispatchEvent(Event event, String eventName) { + int etype = Event.getTypeInt(eventName); + Object[] handlerData = $(element).data(EVENT_DATA); for (int i = 0, l = elementEvents.length(); i < l; i++) { BindFunction listener = elementEvents.get(i); - if (listener != null && (listener.hasEventType(etype) || listener.isTypeOf(ename)) - && (originalEventType == null || originalEventType.equals(listener.getOriginalEventType()))) { + String namespace = JsUtils.prop(event, "namespace"); + boolean matchEV = listener != null && (listener.hasEventType(etype) || listener.isTypeOf(eventName)); + boolean matchNS = matchEV && (isNullOrEmpty(namespace) || listener.nameSpace.equals(namespace)); + if (matchEV && matchNS) { if (!listener.fire(event, handlerData)) { event.stopPropagation(); event.preventDefault(); @@ -626,45 +576,32 @@ public class EventsListener implements EventListener { } public void live(String events, String cssSelector, Object data, Function... funcs) { - - String[] parts = events.split("[\\s,]+"); - - for (String event : parts) { - - String nameSpace = null; - String eventName = event; - - String[] subparts = event.split("\\.", 2); - - if (subparts.length == 2) { - nameSpace = subparts[1]; - eventName = subparts[0]; - } - - // handle special event like mouseenter or mouseleave - SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; - - int b = Event.getTypeInt(eventName); + for (EventName ev : EventName.split(events)) { + SpecialEvent hook = special.get(ev.eventName); + boolean bind = hook == null || hook.setup(element) == false; for (Function function : funcs) { - Function handler = hook != null ? hook.createDelegateHandler(function) : function; - live(b, nameSpace, eventName, originalEventName, cssSelector, data, handler); + int b = Event.getTypeInt(ev.eventName); + if (bind) { + live(b, ev.nameSpace, ev.eventName, cssSelector, data, function); + } + if (hook != null) { + hook.add(element, ev.eventName, ev.nameSpace, data, function); + } } } } - public void live(int eventbits, String nameSpace, String eventName, String originalEventName, - String cssSelector, Object data, Function... funcs) { + public void live(int eventbits, String nameSpace, String eventName, String cssSelector, + Object data, Function... funcs) { if (eventbits != BITLESS) { - liveBitEvent(eventbits, nameSpace, originalEventName, cssSelector, data, funcs); + liveBitEvent(eventbits, nameSpace, cssSelector, data, funcs); } else { - liveBitlessEvent(eventName, nameSpace, originalEventName, cssSelector, data, funcs); + liveBitlessEvent(eventName, nameSpace, cssSelector, data, funcs); } } - private void liveBitlessEvent(String eventName, String nameSpace, String originalEventName, - String cssSelector, Object data, Function... funcs) { + private void liveBitlessEvent(String eventName, String nameSpace, String cssSelector, + Object data, Function... funcs) { LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(eventName); if (liveBindFunction == null) { @@ -676,12 +613,12 @@ public class EventsListener implements EventListener { for (Function f : funcs) { liveBindFunction.addBindFunctionForSelector(cssSelector, new BindFunction(BITLESS, eventName, - nameSpace, originalEventName, f, data, -1)); + nameSpace, f, data, -1)); } } - private void liveBitEvent(int eventbits, String nameSpace, String originalEventName, - String cssSelector, Object data, Function... funcs) { + private void liveBitEvent(int eventbits, String nameSpace, String cssSelector, Object data, + Function... funcs) { for (int i = 0; i < 28; i++) { int event = (int) Math.pow(2, i); if ((eventbits & event) == event) { @@ -697,7 +634,7 @@ public class EventsListener implements EventListener { for (Function f : funcs) { liveBindFunction.addBindFunctionForSelector(cssSelector, new BindFunction(event, - null, nameSpace, originalEventName, f, data, -1)); + null, nameSpace, f, data, -1)); } } } @@ -722,67 +659,58 @@ public class EventsListener implements EventListener { } public void unbind(int eventbits) { - unbind(eventbits, null, null, null, null); + unbind(eventbits, null, null, null); } - public void unbind(int eventbits, String namespace, String eventName, String originalEventType, - Function f) { - + public void unbind(int eventbits, String namespace, String eventName, Function f) { JsObjectArray<BindFunction> newList = JsObjectArray.createArray().cast(); for (int i = 0; i < elementEvents.length(); i++) { BindFunction listener = elementEvents.get(i); - boolean matchNS = isNullOrEmpty(namespace) || listener.nameSpace.equals(namespace); boolean matchEV = eventbits <= 0 || listener.hasEventType(eventbits); boolean matchEVN = matchEV || listener.isTypeOf(eventName); - boolean matchOEVT = (isNullOrEmpty(eventName) && !isNullOrEmpty(namespace) && matchNS) - || (originalEventType == null && listener.getOriginalEventType() == null) - || (originalEventType != null && originalEventType.equals(listener.getOriginalEventType())); boolean matchFC = f == null || listener.isEquals(f); - if (matchNS && matchEV && matchEVN && matchFC && matchOEVT) { + if (matchNS && matchEV && matchEVN && matchFC) { int currentEventbits = listener.unsink(eventbits); - if (currentEventbits == 0) { // the BindFunction doesn't listen anymore on any events continue; } } - newList.add(listener); } - elementEvents = newList; + elementEvents = newList; + } + + /** + * Return true if the element is listening for the + * given eventBit or eventName. + */ + public boolean hasHandlers(int eventBits, String eventName) { + for (int i = 0, j = elementEvents.length(); i < j; i++) { + BindFunction function = elementEvents.get(i); + if (function.hasEventType(eventBits) || function.isTypeOf(eventName)) { + return true; + } + } + return false; } - private boolean isNullOrEmpty(String s) { + private static boolean isNullOrEmpty(String s) { return s == null || s.isEmpty(); } public void unbind(String events, Function f) { - - String[] parts = events.split("[\\s,]+"); - - for (String event : parts) { - String nameSpace = null; - String eventName = event; - - // seperate possible namespace - // jDramaix: I removed old regex ^([^.]*)\.?(.*$) because it didn't work on IE8... - String[] subparts = event.split("\\.", 2); - - if (subparts.length == 2){ - nameSpace = subparts[1]; - eventName = subparts[0]; + for (EventName ev : EventName.split(events)) { + SpecialEvent hook = special.get(ev.eventName); + boolean unbind = hook == null || hook.tearDown(element) == false; + if (unbind) { + unbind(Event.getTypeInt(ev.eventName), ev.nameSpace, ev.eventName, f); + } + if (hook != null) { + hook.remove(element, ev.eventName, ev.nameSpace, f); } - - // handle special event - SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; - - int b = Event.getTypeInt(eventName); - - unbind(b, nameSpace, eventName, originalEventName, f); } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java index a93e5491..8493fd81 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java @@ -16,7 +16,6 @@ package com.google.gwt.query.client.plugins.events; import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.query.client.GQuery; import com.google.gwt.user.client.Event; @@ -35,14 +34,6 @@ import com.google.gwt.user.client.Event; */ public class GqEvent extends Event { - public static native void setOriginalEventType(NativeEvent evt, String originalEventName) /*-{ - evt["__gwtquery_originalEventName"] = originalEventName; - }-*/; - - public static native String getOriginalEventType(Event evt) /*-{ - return evt["__gwtquery_originalEventName"] || null; - }-*/; - // Gwt Events class has not this event defined, // so we have to select one power of 2 which is unused in Event class public static int ONSUBMIT = 0x10000000; @@ -97,9 +88,9 @@ public class GqEvent extends Event { * */ public final int pageX() { - if (getTouches() != null && getTouches().length() > 0){ + if (getTouches() != null && getTouches().length() > 0) { return getTouches().get(0).getPageX(); - }else{ + } else { return getClientX() + GQuery.document.getScrollLeft(); } } @@ -109,10 +100,14 @@ public class GqEvent extends Event { * */ public final int pageY() { - if (getTouches() != null && getTouches().length() > 0){ + if (getTouches() != null && getTouches().length() > 0) { return getTouches().get(0).getPageY(); - }else{ + } else { return getClientY() + GQuery.document.getScrollTop(); } } + + public static final GqEvent as(Event e) { + return e.cast(); + } } 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 new file mode 100644 index 00000000..8083b098 --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/SpecialEvent.java @@ -0,0 +1,115 @@ +/* + * 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.events; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.query.client.Function; +import com.google.gwt.user.client.Event; + +/** + * Interface used to register special events. + * + * Use EventsListeners.special.add( + */ +public interface SpecialEvent { + + /** + * Default implementation of SpecialEvents for simple cases like + * creating event aliases. Extend this for creating more complex + * cases. + */ + public static class DefaultSpecialEvent implements SpecialEvent { + protected final String delegateType; + protected final String type; + + protected Function handler = new Function() { + public boolean f(Event e, Object... arg) { + setEvent(e); + EventsListener.getInstance(getElement()).dispatchEvent(e, type); + return true; + }; + }; + + public DefaultSpecialEvent(String type, String delegateType) { + this.type = type; + this.delegateType = delegateType; + } + + protected EventsListener listener(Element e) { + return EventsListener.getInstance(e); + } + + @Override + public void add(Element e, String eventType, String nameSpace, Object data, Function f) { + // Nothing to do, let gQuery use default events mechanism + } + + @Override + public boolean hasHandlers(Element e) { + return listener(e).hasHandlers(Event.getTypeInt(type), type); + } + + @Override + public void remove(Element e, String eventType, String nameSpace, Function f) { + // Nothing to do, let gQuery use default events mechanism + } + + @Override + public boolean setup(Element e) { + if (!hasHandlers(e)) { + listener(e).bind(delegateType, null, handler); + } + return false; + } + + @Override + public boolean tearDown(Element e) { + if (!hasHandlers(e)) { + listener(e).unbind(delegateType, handler); + } + return false; + } + } + + /** + * For each bind call the add function is called. + */ + void add(Element e, String eventType, String nameSpace, Object data, Function f); + + /** + * Return true if there are handlers bound to this special event. + */ + boolean hasHandlers(Element e); + + /** + * For each unbind call the remove function is called. + */ + void remove(Element e, String eventType, String nameSpace, Function f); + + /** + * When the first event handler is bound for an EventsListener gQuery executes the setup function. + * + * If the method returns false means that gQuery has to run the default bind for the event before + * calling add. + */ + boolean setup(Element e); + + /** + * The last unbind call triggers the tearDown method. + * + * If the method returns false means that gQuery has to run the default unbind for the event + * before calling remove. + */ + boolean tearDown(Element e); +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java index 8d9b9a4c..adbdd233 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java @@ -1,3 +1,18 @@ +/* + * 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.vm; import com.google.gwt.query.client.Function; @@ -28,6 +43,9 @@ import elemental.json.JsonObject; import elemental.json.JsonString; import elemental.json.JsonValue; +/** + * Reflection handler for JsonBuilder implementation in JVM. + */ public class JsonBuilderHandler implements InvocationHandler { static JsonFactoryJre jsonFactory = new JsonFactoryJre(); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index 66a8f5bc..5a976f3f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -34,8 +34,6 @@ import elemental.json.impl.JreJsonNull; */ public class JsonFactoryJre implements JsonFactory { - - /** * Although functions cannot be serialized to json we use JsonBuilders * or IsProperties objects which can be used as settings in Ajax. diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java index 98700235..315999a1 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java @@ -383,7 +383,7 @@ public class GQueryEventsTestGwt extends GWTTestCase { $("p", e).click(); assertEquals("white", $("p", e).css("color", false)); - // hover (mouseover, mouseout) + // hover (mouseenter, mouseleave) $("p", e).hover(new Function() { public void f(Element elem) { $(elem).css(CSS.BACKGROUND_COLOR.with(RGBColor.YELLOW)); @@ -398,6 +398,11 @@ public class GQueryEventsTestGwt extends GWTTestCase { $("p", e).trigger(Event.ONMOUSEOUT); assertEquals("white", $("p", e).css("background-color", false)); + $("p", e).css(CSS.COLOR.with(RGBColor.WHITE)); + $("p", e).hover(null, null); + $("p", e).trigger(Event.ONMOUSEOVER); + assertEquals("white", $("p", e).css("background-color", false)); + // key events $(e).html("<input type='text'/>"); Function keyEventAction = new Function() { @@ -566,6 +571,46 @@ public class GQueryEventsTestGwt extends GWTTestCase { } + public void testLiveWithSpecial() { + $(e).html("<div id='div1'><div id='div2'>Content 1<span id='span1'> blop</span></div></div>"); + + $(".clickable", e).live("mouseenter", new Function() { + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.RED)); + } + }); + + $("#div1", e).addClass("clickable"); + $("#span1", e).mouseenter(); + assertEquals("red", $("#div1", e).css(CSS.COLOR, false)); + + $(".clickable", e).die("mouseenter"); + $("*", e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $("#span1", e).mouseenter(); + assertEquals("black", $("#div1", e).css(CSS.COLOR, false)); + } + + public void testOnOffWithSpecial() { + $(e).html("<div id='div1'><div id='div2'>Content 1<span id='span1'> blop</span></div></div>"); + + $(e).on("mouseenter", ".clickable", new Function() { + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.RED)); + } + }); + + $("#div1", e).addClass("clickable"); + $("#span1", e).mouseenter(); + assertEquals("red", $("#div1", e).css(CSS.COLOR, false)); + + $(e).off("mouseenter", ".clickable"); + $("*", e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $("#span1", e).mouseenter(); + assertEquals("black", $("#div1", e).css(CSS.COLOR, false)); + } + public void testLiveWithMultipleEvent() { $(e).html("<div id='div1'><div id='div2'>Content 1<span id='span1'> blop</span></div></div>"); @@ -1198,10 +1243,10 @@ public class GQueryEventsTestGwt extends GWTTestCase { $(".mainDiv", e).click(); assertEquals("red", $(".mainDiv", e).css("color", false)); - + // reset $(".mainDiv", e).css("color", "black"); - + $(".mainDiv", e).off("click"); $(".mainDiv", e).click(); @@ -1219,7 +1264,7 @@ public class GQueryEventsTestGwt extends GWTTestCase { $(".mainDiv", e).click(); assertEquals("red", $(".mainDiv", e).css("color", false)); - + // reset $(".mainDiv", e).css("color", "black"); @@ -1273,7 +1318,7 @@ public class GQueryEventsTestGwt extends GWTTestCase { assertEquals("white", $(".mainDiv", e).css("background-color", false)); } - + public void testOnOffWithSelector() { $(e).html("<div class='mainDiv'><div class='subDiv'>Content " + "0<span>blop</span></div></div><div class='mainDiv'><div class='subDiv'>" + @@ -1285,7 +1330,7 @@ public class GQueryEventsTestGwt extends GWTTestCase { $(e).css("color", "red"); } }); - + for (Element mainDiv : $(".mainDiv", e).elements()) { for (int i = 0; i < 3; i++) { @@ -1436,10 +1481,10 @@ public class GQueryEventsTestGwt extends GWTTestCase { $(b).trigger("custom"); assertEquals("200px", $("button").css("width", false)); } - + public void testIssue152() { $(e).html("<div class='mdiv'>"); - final GQuery div = $(".mdiv", e); + final GQuery div = $(".mdiv", e); final int[] count = { 0 }; div.one(Event.ONCLICK, null, new Function() { public void f() { @@ -1837,4 +1882,16 @@ public class GQueryEventsTestGwt extends GWTTestCase { assertEquals(2, mouseEnterFunction.invokationCounter); } + public void testBindAndTriggerWithNameSpace() { + $(e).html("<div id='mainDiv'>blop</div>"); + CounterFunction counter = new CounterFunction(); + $("#mainDiv", e).on("click.mynamespace;foo", counter); + $("#mainDiv").trigger("click"); + assertEquals(1, counter.invokationCounter); + $("#mainDiv").trigger("click.mynamespace;bar"); + assertEquals(1, counter.invokationCounter); + $("#mainDiv").trigger("click.mynamespace;foo"); + assertEquals(2, counter.invokationCounter); + } + } |