aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Dramaix <julien.dramaix@gmail.com>2013-11-22 05:06:40 -0800
committerJulien Dramaix <julien.dramaix@gmail.com>2013-11-22 05:06:40 -0800
commitde46d0577920517ea8f3cb76bca585a62ff7d588 (patch)
treea6aae8d24fe68291e20f88706383397cde4f1caf
parent74edc0e4d202ec31bc591f19b63f54523f4ea776 (diff)
parent2da74cf135e92aec35a58cf9dc45d61fee172938 (diff)
downloadgwtquery-de46d0577920517ea8f3cb76bca585a62ff7d588.tar.gz
gwtquery-de46d0577920517ea8f3cb76bca585a62ff7d588.zip
Merge pull request #235 from gwtquery/jd_event
Refactor event to accept bitless events and custom events.
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java8
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java33
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java5
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java65
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java272
-rw-r--r--gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java4
-rw-r--r--gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java321
7 files changed, 534 insertions, 174 deletions
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 00b41def..e90ad93e 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
@@ -422,7 +422,7 @@ public abstract class Function {
* Override this method for bound event handlers if you wish to deal with
* per-handler user data.
*/
- public boolean f(Event e, Object arg) {
+ public boolean f(Event e, Object... arg) {
setArguments(arg);
setEvent(e);
return f(e);
@@ -527,16 +527,16 @@ public abstract class Function {
* catch the exception and send it to the GWT UncaughtExceptionHandler
* They are intentionally final to avoid override them
*/
- public final boolean fe(Event ev, Object arg) {
+ public final boolean fe(Event ev, Object... args) {
if (GWT.getUncaughtExceptionHandler() != null) {
try {
- return f(ev, arg);
+ return f(ev, args);
} catch (Exception e) {
GWT.getUncaughtExceptionHandler().onUncaughtException(e);
}
return true;
}
- return f(ev, arg);
+ return f(ev, args);
}
/**
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 270ad1cc..5950f6bf 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
@@ -1309,6 +1309,17 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
}
/**
+ * Bind Handlers or fire Events for each matched element.
+ */
+ private GQuery bindOrFire(String eventname, final Object data, final Function... funcs) {
+ if (funcs.length == 0) {
+ return as(Events).triggerHtmlEvent(eventname);
+ } else {
+ return bind(eventname, data, funcs);
+ }
+ }
+
+ /**
* Bind a set of functions to the blur event of each matched element. Or trigger the blur event if
* no functions are provided.
*/
@@ -1453,7 +1464,6 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
* DOM. This method allows retrieving the list of ancestors matching many selectors by traversing
* the DOM only one time.
*
- * @param selector
* @return
*/
public JsNamedArray<NodeList<Element>> closest(String[] selectors) {
@@ -1466,7 +1476,6 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
* DOM until reach the <code>context</code> node.. This method allows retrieving the list of
* ancestors matching many selectors by traversing the DOM only one time.
*
- * @param selector
* @return
*/
public JsNamedArray<NodeList<Element>> closest(String[] selectors, Node context) {
@@ -3032,7 +3041,6 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
* Get all following siblings of each element up to but not including the element matched by the
* DOM node, filtered by a selector.
*
- * @param selector
* @return
*/
public GQuery nextUntil(Element until, String filter) {
@@ -3043,7 +3051,6 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
* Get all following siblings of each element up to but not including the element matched by the
* GQuery object.
*
- * @param selector
* @return
*/
public GQuery nextUntil(GQuery until) {
@@ -3054,7 +3061,6 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
* Get all following siblings of each element up to but not including the element matched by the
* GQuery object, filtered by a selector
*
- * @param selector
* @return
*/
public GQuery nextUntil(GQuery until, String filter) {
@@ -3904,14 +3910,14 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
*
*/
public GQuery resize(Function... f) {
- return bindOrFire(EventsListener.ONRESIZE, null, f);
+ return bindOrFire("resize", null, f);
}
/**
* Bind an event handler to the "resize" JavaScript event, or trigger that event on an element.
*/
public GQuery resize(final Function f) {
- return bindOrFire(EventsListener.ONRESIZE, null, f);
+ return bindOrFire("resize", null, f);
}
/**
@@ -4257,7 +4263,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
* functions are provided.
*/
public GQuery submit(Function... funcs) {
- return bindOrFire(EventsListener.ONSUBMIT, null, funcs);
+ return bindOrFire("submit", null, funcs);
}
/**
@@ -4394,6 +4400,17 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
return as(Events).trigger(eventbits, keys);
}
+
+ /**
+ * Trigger a event in all matched elements.
+ *
+ * @param eventName An string representing the type of the event desired
+ * @param datas Additional parameters to pass along to the event handlers.
+ */
+ public GQuery trigger(String eventName, Object... datas) {
+ return as(Events).triggerHtmlEvent(eventName, datas);
+ }
+
/**
* Removes all events that match the eventbits.
*/
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java
index 472aed62..da0de164 100644
--- a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java
+++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java
@@ -485,7 +485,6 @@ public interface LazyGQuery<T> extends LazyBase<T>{
* DOM. This method allows retrieving the list of ancestors matching many selectors by traversing
* the DOM only one time.
*
- * @param selector
* @return
*/
JsNamedArray<NodeList<Element>> closest(String[] selectors);
@@ -496,7 +495,6 @@ public interface LazyGQuery<T> extends LazyBase<T>{
* DOM until reach the <code>context</code> node.. This method allows retrieving the list of
* ancestors matching many selectors by traversing the DOM only one time.
*
- * @param selector
* @return
*/
JsNamedArray<NodeList<Element>> closest(String[] selectors, Node context);
@@ -1522,7 +1520,6 @@ public interface LazyGQuery<T> extends LazyBase<T>{
* Get all following siblings of each element up to but not including the element matched by the
* DOM node, filtered by a selector.
*
- * @param selector
* @return
*/
LazyGQuery<T> nextUntil(Element until, String filter);
@@ -1531,7 +1528,6 @@ public interface LazyGQuery<T> extends LazyBase<T>{
* Get all following siblings of each element up to but not including the element matched by the
* GQuery object.
*
- * @param selector
* @return
*/
LazyGQuery<T> nextUntil(GQuery until);
@@ -1540,7 +1536,6 @@ public interface LazyGQuery<T> extends LazyBase<T>{
* Get all following siblings of each element up to but not including the element matched by the
* GQuery object, filtered by a selector
*
- * @param selector
* @return
*/
LazyGQuery<T> nextUntil(GQuery until, String filter);
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 f9ee5519..94d1ab8d 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
@@ -14,6 +14,7 @@
package com.google.gwt.query.client.plugins;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.FormElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Node;
import com.google.gwt.query.client.Function;
@@ -109,7 +110,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, currentSelector);
+ eventbits, nameSpace, null, null, currentSelector);
return this;
}
@@ -136,7 +137,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, currentSelector, data, funcs);
+ eventbits, nameSpace, null, null, currentSelector, data, funcs);
return this;
}
@@ -166,8 +167,6 @@ public class Events extends GQuery {
return bind("mouseenter", null, f);
}
- // TODO handle unbind !!
-
/**
* Bind an event handler to be fired when the mouse leaves an element, or trigger that handler on
* an element if no functions are provided.
@@ -258,26 +257,26 @@ public class Events extends GQuery {
if ((eventbits | Event.ONMOUSEWHEEL) == Event.ONMOUSEWHEEL)
dispatchEvent(document.createMouseEvent("mousewheel", true, true, 0, 0, 0, 0, 0, false,
false, false, false, NativeEvent.BUTTON_LEFT, null));
- if (eventbits == EventsListener.ONSUBMIT) {
- Event evt = document.createHtmlEvent("submit", true, true).cast();
- dispatchEvent(evt, new Function() {
- public native void f(Element e) /*-{
- e.submit();
- }-*/;
- });
- }
- if (eventbits == EventsListener.ONRESIZE)
- triggerHtmlEvent("resize");
return this;
}
/**
* Trigger a html event in all matched elements.
*
- * @param htmlEvent An string representing the html event desired
+ * @param htmlEvent A string representing the desired html event.
* @functions a set of function to run if the event is not canceled.
*/
public Events triggerHtmlEvent(String htmlEvent, Function... functions) {
+ return triggerHtmlEvent(htmlEvent, null, functions);
+ }
+
+ /**
+ * 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.
+ */
+ public Events triggerHtmlEvent(String htmlEvent, Object[] datas, final Function... functions) {
SpecialEvent specialEvent = EventsListener.special.get(htmlEvent);
boolean isSpecialEvent = specialEvent != null;
@@ -289,7 +288,21 @@ public class Events extends GQuery {
if (isSpecialEvent) {
GqEvent.setOriginalEventType(e, originalEventName);
}
- dispatchEvent(e, functions);
+
+ 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();
+ }
+ callHandlers(e, getEvent(), functions);
+ }
+ };
+ dispatchEvent(e, datas, submitFunction);
+ } else {
+ dispatchEvent(e, datas, functions);
+ }
return this;
}
@@ -315,7 +328,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, f);
+ EventsListener.getInstance(e).unbind(eventbits, name, null, null, f);
}
}
return this;
@@ -357,17 +370,27 @@ public class Events extends GQuery {
}
private void dispatchEvent(NativeEvent evt, Function... funcs) {
+ dispatchEvent(evt, null, funcs);
+ }
+
+ private void dispatchEvent(NativeEvent evt, Object[] datas, Function... funcs) {
for (Element e : elements()) {
if (isEventCapable(e)) {
+ $(e).data(EventsListener.EVENT_DATA, datas);
e.dispatchEvent(evt);
if (!JsUtils.isDefaultPrevented(evt)) {
- for (Function f : funcs) {
- f.setEvent(Event.as(evt));
- f.f(e);
- }
+ callHandlers(e, evt, funcs);
}
+ $(e).removeData(EventsListener.EVENT_DATA);
}
}
}
+ private void callHandlers(Element e, NativeEvent evt, Function... functions){
+ for (Function f : functions) {
+ f.setEvent(Event.as(evt));
+ f.f(e);
+ }
+ }
+
}
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 f348adaf..eacc9d18 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
@@ -31,6 +31,7 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -91,7 +92,7 @@ public class EventsListener implements EventListener {
}
@Override
- public boolean f(Event e, Object data) {
+ public boolean f(Event e, Object... data) {
EventTarget eventTarget = e.getCurrentEventTarget();
Element target = eventTarget != null ? eventTarget.<Element> cast() : null;
@@ -115,37 +116,50 @@ public class EventsListener implements EventListener {
Object data;
Function function;
- String nameSpace = "";
+ String nameSpace;
// for special event like mouseleave, mouseenter
String originalEventType;
- int times = -1;
+ int times;
int type;
+ String eventName;
- BindFunction(int t, String n, String originalEventType, Function f, Object d) {
- type = t;
- function = f;
- data = d;
- this.originalEventType = originalEventType;
- if (n != null) {
- nameSpace = n;
- }
- }
-
- BindFunction(int t, String n, String originalEventType, Function f, Object d, int times) {
- this(t, n, originalEventType, f, d);
+ BindFunction(int type, String eventName, String nameSpace, String originalEventType,
+ 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 : "";
}
- public boolean fire(Event event) {
+ public boolean fire(Event event, Object[] eventData) {
if (times != 0) {
times--;
- return function.fe(event, data);
+ Object[] arguments;
+ eventData = eventData != null ? eventData : new Object[0];
+ // The argument of the function will be first the data attached to the handler then the
+ // data attached to the event.
+ if (data != null) {
+ Object[] handlerData = data.getClass().isArray() ? (Object[]) data : new Object[]{data};
+ arguments = new Object[handlerData.length + eventData.length];
+ System.arraycopy(handlerData, 0, arguments, 0, handlerData.length);
+ System.arraycopy(eventData, 0, arguments, handlerData.length, eventData.length);
+ } else {
+ arguments = eventData;
+ }
+ return function.fe(event, arguments);
}
return true;
}
public boolean hasEventType(int etype) {
- return (type & etype) != 0;
+ return type != BITLESS && (type & etype) != 0;
+ }
+
+ public boolean isTypeOf(String eName) {
+ return eventName != null && eventName.equalsIgnoreCase(eName);
}
/**
@@ -190,8 +204,13 @@ public class EventsListener implements EventListener {
JsNamedArray<JsObjectArray<BindFunction>> bindFunctionBySelector;
- LiveBindFunction(int type, String namespace) {
- super(type, namespace, null, null, -1);
+ LiveBindFunction(String eventName, String namespace, Object data) {
+ super(BITLESS, eventName, namespace, null, null, data, -1);
+ clean();
+ }
+
+ LiveBindFunction(int type, String namespace, Object data) {
+ super(type, null, namespace, null, null, data, -1);
clean();
}
@@ -213,7 +232,7 @@ public class EventsListener implements EventListener {
}
@Override
- public boolean fire(Event event) {
+ public boolean fire(Event event, Object[] eventData) {
if (isEmpty()) {
return true;
}
@@ -233,7 +252,7 @@ public class EventsListener implements EventListener {
JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
for (int i = 0; bindFunctions != null && i < bindFunctions.length(); i++) {
BindFunction f = bindFunctions.get(i);
- if (f.hasEventType(event.getTypeInt())) {
+ if (f.hasEventType(event.getTypeInt()) || f.isTypeOf(event.getType())) {
validSelectors.add(cssSelector);
break;
}
@@ -254,7 +273,7 @@ public class EventsListener implements EventListener {
JsObjectArray<BindFunction> bindFunctions = bindFunctionBySelector.get(cssSelector);
for (int i = 0; bindFunctions != null && i < bindFunctions.length(); i++) {
BindFunction f = bindFunctions.get(i);
- if (f.hasEventType(event.getTypeInt())) {
+ if (f.hasEventType(event.getTypeInt()) || f.isTypeOf(event.getType())) {
NodeList<Element> n = realCurrentTargetBySelector.get(cssSelector);
for (int j = 0; n != null && j < n.getLength(); j++) {
Element element = n.getItem(j);
@@ -262,8 +281,9 @@ public class EventsListener implements EventListener {
// handlers for this element bound to this element
if (stopElement == null || element.equals(stopElement)) {
gqEvent.setCurrentElementTarget(element);
-
- if (!f.fire(gqEvent)) {
+ // data
+ eventData = $(element).data(EVENT_DATA);
+ if (!f.fire(gqEvent, eventData)) {
stopElement = element;
}
}
@@ -354,8 +374,9 @@ public class EventsListener implements EventListener {
}
- public static int ONSUBMIT = GqEvent.ONSUBMIT;
- public static int ONRESIZE = GqEvent.ONRESIZE;
+ public static final String EVENT_DATA = "___event_datas";
+ public static final int BITLESS = -1;
+
public static String MOUSEENTER = "mouseenter";
public static String MOUSELEAVE = "mouseleave";
@@ -382,7 +403,10 @@ public class EventsListener implements EventListener {
public static void rebind(Element e) {
EventsListener ret = getGQueryEventListener(e);
if (ret != null && ret.eventBits != 0) {
- ret.sink();
+ // rebind bit event
+ ret.sink(ret.eventBits, null);
+
+ // TODO manage bitless event
}
}
@@ -407,7 +431,7 @@ public class EventsListener implements EventListener {
}-*/;
// Gwt does't handle submit nor resize events in DOM.sinkEvents
- private static native void sinkEvent(Element elem, String name) /*-{
+ private static native void sinkBitlessEvent(Element elem, String name) /*-{
if (!elem.__gquery)
elem.__gquery = [];
if (elem.__gquery[name])
@@ -415,7 +439,7 @@ public class EventsListener implements EventListener {
elem.__gquery[name] = true;
var handle = function(event) {
- elem.__gqueryevent.@com.google.gwt.query.client.plugins.events.EventsListener::dispatchEvent(Lcom/google/gwt/user/client/Event;)(event);
+ elem.__gqueryevent.@com.google.gwt.query.client.plugins.events.EventsListener::onBrowserEvent(Lcom/google/gwt/user/client/Event;)(event);
};
if (elem.addEventListener)
@@ -426,14 +450,12 @@ public class EventsListener implements EventListener {
int eventBits = 0;
double lastEvnt = 0;
-
- int lastType = 0;
+ String lastType = "";
private Element element;
-
private JsObjectArray<BindFunction> elementEvents = JsObjectArray.createArray().cast();
-
private JsMap<Integer, LiveBindFunction> liveBindFunctionByEventType = JsMap.create();
+ private JsMap<String, LiveBindFunction> liveBindFunctionByEventName = JsMap.create();
private EventsListener(Element element) {
this.element = element;
@@ -454,16 +476,9 @@ public class EventsListener implements EventListener {
}
}
- public void bind(int eventbits, String namespace, String originalEventType, final Object data,
- final Function function, int times) {
- if (function == null) {
- unbind(eventbits, namespace, originalEventType, null);
- return;
- }
- eventBits |= eventbits;
- sink();
- elementEvents.add(new BindFunction(eventbits, namespace, originalEventType, function, data,
- times));
+ 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(String events, final Object data, Function... funcs) {
@@ -488,14 +503,27 @@ public class EventsListener implements EventListener {
eventName = hook != null ? hook.getDelegateType() : eventName;
String originalEventName = hook != null ? hook.getOriginalType() : null;
- int b = getTypeInt(eventName);
+ int b = Event.getTypeInt(eventName);
for (Function function : funcs) {
Function handler = hook != null ? hook.createDelegateHandler(function) : function;
- bind(b, nameSpace, originalEventName, data, handler, -1);
+ bind(b, nameSpace, eventName, originalEventName, data, handler, -1);
}
}
}
+ 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;
+ }
+
+ sink(eventbits, eventName);
+
+ elementEvents.add(new BindFunction(eventbits, eventName, namespace, originalEventType,
+ function, data, times));
+ }
+
public void die(String eventNames, String cssSelector) {
String[] parts = eventNames.split("[\\s,]+");
@@ -512,50 +540,66 @@ public class EventsListener implements EventListener {
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 = getTypeInt(eventName);
+ int b = Event.getTypeInt(eventName);
- die(b, nameSpace, originalEventName, cssSelector);
+ die(b, nameSpace, eventName, originalEventName, cssSelector);
}
}
- public void die(int eventbits, String nameSpace, String originalEventName,String cssSelector) {
+ public void die(int eventbits, String nameSpace, String eventName, String originalEventName,
+ String cssSelector) {
if (eventbits <= 0) {
+ if (eventName != null) {
+ LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(eventName);
+ maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, BITLESS, eventName, nameSpace,
+ originalEventName);
+ }
+
+ // if eventbits == -1 and eventName is null, remove all event handlers for this selector
for (String k : liveBindFunctionByEventType.keys()) {
- LiveBindFunction liveBindFunction = liveBindFunctionByEventType.<JsCache> cast().get(k);
- liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace, null);
- if (liveBindFunction.isEmpty()){
- liveBindFunctionByEventType.<JsCache>cast().delete(k);
- }
+ int bits = Integer.parseInt(k);
+ LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(bits);
+ maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, bits, null, nameSpace, null);
}
} else {
LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(eventbits);
- if (liveBindFunction != null) {
- liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace, originalEventName);
- }
+ maybeRemoveLiveBindFunction(liveBindFunction, cssSelector, eventbits, null, nameSpace,
+ originalEventName);
+ }
+ }
+
+ private void maybeRemoveLiveBindFunction(LiveBindFunction liveBindFunction, String cssSelector,
+ int eventbits, String eventName, String nameSpace, String originalEventName) {
+ if (liveBindFunction != null) {
+ liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace, originalEventName);
if (liveBindFunction.isEmpty()){
- liveBindFunctionByEventType.remove(eventbits);
+ if (eventbits != BITLESS) {
+ liveBindFunctionByEventType.remove(eventbits);
+ } else {
+ liveBindFunctionByEventName.remove(eventName);
+ }
}
}
}
public void dispatchEvent(Event event) {
- int etype = getTypeInt(event.getType());
+ String ename = event.getType();
+ int etype = Event.getTypeInt(ename);
String originalEventType = GqEvent.getOriginalEventType(event);
+ 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)
- && (originalEventType == null || originalEventType
- .equals(listener.getOriginalEventType()))) {
- if (!listener.fire(event)) {
+ if (listener != null && (listener.hasEventType(etype) || listener.isTypeOf(ename))
+ && (originalEventType == null || originalEventType.equals(listener.getOriginalEventType()))) {
+ if (!listener.fire(event, handlerData)) {
event.stopPropagation();
event.preventDefault();
}
@@ -593,15 +637,42 @@ public class EventsListener implements EventListener {
eventName = hook != null ? hook.getDelegateType() : eventName;
String originalEventName = hook != null ? hook.getOriginalType() : null;
- int b = getTypeInt(eventName);
+ int b = Event.getTypeInt(eventName);
for (Function function : funcs) {
Function handler = hook != null ? hook.createDelegateHandler(function) : function;
- live(b, nameSpace, originalEventName, cssSelector, data, handler);
+ live(b, nameSpace, eventName, originalEventName, cssSelector, data, handler);
}
}
}
- public void live(int eventbits, String nameSpace, String originalEventName, String cssSelector, Object data, Function... funcs) {
+ public void live(int eventbits, String nameSpace, String eventName, String originalEventName,
+ String cssSelector, Object data, Function... funcs) {
+ if (eventbits != BITLESS) {
+ liveBitEvent(eventbits, nameSpace, originalEventName, cssSelector, data, funcs);
+ } else {
+ liveBitlessEvent(eventName, nameSpace, originalEventName, cssSelector, data, funcs);
+ }
+ }
+
+ private void liveBitlessEvent(String eventName, String nameSpace, String originalEventName,
+ String cssSelector, Object data, Function... funcs) {
+ LiveBindFunction liveBindFunction = liveBindFunctionByEventName.get(eventName);
+
+ if (liveBindFunction == null) {
+ liveBindFunction = new LiveBindFunction(eventName, "live", data);
+ sink(BITLESS, eventName);
+ elementEvents.add(liveBindFunction);
+ liveBindFunctionByEventName.put(eventName, liveBindFunction);
+ }
+
+ for (Function f : funcs) {
+ liveBindFunction.addBindFunctionForSelector(cssSelector, new BindFunction(BITLESS, eventName,
+ nameSpace, originalEventName, f, data, -1));
+ }
+ }
+
+ private void liveBitEvent(int eventbits, String nameSpace, String originalEventName,
+ String cssSelector, Object data, Function... funcs) {
for (int i = 0; i < 28; i++) {
int event = (int) Math.pow(2, i);
if ((eventbits & event) == event) {
@@ -609,16 +680,15 @@ public class EventsListener implements EventListener {
// is a LiveBindFunction already attached for this kind of event
LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(event);
if (liveBindFunction == null) {
- liveBindFunction = new LiveBindFunction(event, "live");
- eventBits |= event;
- sink();
+ liveBindFunction = new LiveBindFunction(event, "live", data);
+ sink(eventbits, null);
elementEvents.add(liveBindFunction);
liveBindFunctionByEventType.put(event, liveBindFunction);
}
for (Function f : funcs) {
- liveBindFunction.addBindFunctionForSelector(cssSelector, new BindFunction(event, nameSpace,
- originalEventName, f, data));
+ liveBindFunction.addBindFunctionForSelector(cssSelector, new BindFunction(event,
+ null, nameSpace, originalEventName, f, data, -1));
}
}
}
@@ -627,15 +697,15 @@ public class EventsListener implements EventListener {
public void onBrowserEvent(Event event) {
double now = Duration.currentTimeMillis();
// Workaround for Issue_20
- if (lastType == event.getTypeInt() && now - lastEvnt < 10
+ if (lastType.equals(event.getType()) && now - lastEvnt < 10
&& "body".equalsIgnoreCase(element.getTagName())) {
return;
}
lastEvnt = now;
- lastType = event.getTypeInt();
+ lastType = event.getType();
// Execute the original Gwt listener
- if (getOriginalEventListener() != null) {
+ if (getOriginalEventListener() != null && getOriginalEventListener() != this) {
getOriginalEventListener().onBrowserEvent(event);
}
@@ -643,10 +713,11 @@ public class EventsListener implements EventListener {
}
public void unbind(int eventbits) {
- unbind(eventbits, null, null, null);
+ unbind(eventbits, null, null, null, null);
}
- public void unbind(int eventbits, String namespace, String originalEventType, Function f) {
+ public void unbind(int eventbits, String namespace, String eventName, String originalEventType,
+ Function f) {
JsObjectArray<BindFunction> newList = JsObjectArray.createArray().cast();
for (int i = 0; i < elementEvents.length(); i++) {
BindFunction listener = elementEvents.get(i);
@@ -654,13 +725,13 @@ public class EventsListener implements EventListener {
boolean matchNS =
namespace == null || namespace.isEmpty() || listener.nameSpace.equals(namespace);
boolean matchEV = eventbits <= 0 || listener.hasEventType(eventbits);
- boolean matchOEVT =
- (originalEventType == null && listener.getOriginalEventType() == null)
+ boolean matchEVN = matchEV || listener.isTypeOf(eventName);
+ boolean matchOEVT = (originalEventType == null && listener.getOriginalEventType() == null)
|| (originalEventType != null && originalEventType.equals(listener
- .getOriginalEventType()));
+ .getOriginalEventType()));
boolean matchFC = f == null || listener.isEquals(f);
- if (matchNS && matchEV && matchFC && matchOEVT) {
+ if (matchNS && matchEV && matchEVN && matchFC && matchOEVT) {
int currentEventbits = listener.unsink(eventbits);
if (currentEventbits == 0) {
@@ -697,9 +768,9 @@ public class EventsListener implements EventListener {
eventName = hook != null ? hook.getDelegateType() : eventName;
String originalEventName = hook != null ? hook.getOriginalType() : null;
- int b = getTypeInt(eventName);
+ int b = Event.getTypeInt(eventName);
- unbind(b, nameSpace, originalEventName, f);
+ unbind(b, nameSpace, eventName, originalEventName, f);
}
}
@@ -709,15 +780,14 @@ public class EventsListener implements EventListener {
liveBindFunctionByEventType = JsMap.create();
}
- private void sink() {
+ private void sink(int eventbits, String eventName) {
// ensure that the gwtQuery's event listener is set as event listener of the element
DOM.setEventListener((com.google.gwt.user.client.Element) element, this);
- if (eventBits == ONSUBMIT) {
- sinkEvent(element, "submit");
- } else if ((eventBits | ONRESIZE) == ONRESIZE) {
- sinkEvent(element, "resize");
- } else {
- if ((eventBits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS
+
+ if (eventbits != BITLESS) {
+ eventBits |= eventbits;
+
+ if ((eventBits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS
&& JsUtils.isElement(element)
&& element.getAttribute("tabIndex").length() == 0) {
element.setAttribute("tabIndex", "0");
@@ -725,29 +795,11 @@ public class EventsListener implements EventListener {
DOM.sinkEvents((com.google.gwt.user.client.Element) element, eventBits
| DOM.getEventsSunk((com.google.gwt.user.client.Element) element));
+ } else {
+ sinkBitlessEvent(element, eventName);
}
}
- private int getEventBits(String... events) {
- int ret = 0;
- for (String e : events) {
- String[] parts = e.split("[\\s,]+");
- for (String s : parts) {
- int event = getTypeInt(s);
- if (event > 0) {
- ret |= event;
- }
- }
- }
-
- return ret;
- }
-
- private int getTypeInt(String eventName) {
- return "submit".equals(eventName) ? ONSUBMIT : "resize".equals(eventName) ? ONRESIZE : Event
- .getTypeInt(eventName);
- }
-
public void cleanEventDelegation() {
for (String k : liveBindFunctionByEventType.keys()) {
LiveBindFunction function = liveBindFunctionByEventType.<JsCache> cast().get(k);
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 416d142e..c86b67e4 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
@@ -1859,8 +1859,8 @@ public class GQueryCoreTestGwt extends GWTTestCase {
assertEquals("E", g.text());
g.unbind(Event.ONCLICK).bind(Event.ONCLICK, "D", new Function(){
@Override
- public boolean f(Event e, Object o) {
- $(e).text("E" + o);
+ public boolean f(Event e, Object... o) {
+ $(e).text("E" + o[0]);
return false;
}
}).click();
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 768a376d..b13b3b4e 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
@@ -13,23 +13,6 @@
*/
package com.google.gwt.query.client;
-import static com.google.gwt.query.client.GQuery.$;
-import static com.google.gwt.query.client.GQuery.document;
-import static com.google.gwt.query.client.GQuery.lazy;
-import static com.google.gwt.user.client.Event.FOCUSEVENTS;
-import static com.google.gwt.user.client.Event.KEYEVENTS;
-import static com.google.gwt.user.client.Event.MOUSEEVENTS;
-import static com.google.gwt.user.client.Event.ONBLUR;
-import static com.google.gwt.user.client.Event.ONFOCUS;
-import static com.google.gwt.user.client.Event.ONKEYDOWN;
-import static com.google.gwt.user.client.Event.ONKEYPRESS;
-import static com.google.gwt.user.client.Event.ONKEYUP;
-import static com.google.gwt.user.client.Event.ONMOUSEDOWN;
-import static com.google.gwt.user.client.Event.ONMOUSEMOVE;
-import static com.google.gwt.user.client.Event.ONMOUSEOUT;
-import static com.google.gwt.user.client.Event.ONMOUSEOVER;
-import static com.google.gwt.user.client.Event.ONMOUSEUP;
-
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -43,16 +26,41 @@ import com.google.gwt.query.client.plugins.Events;
import com.google.gwt.query.client.plugins.events.EventsListener;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;
+import static com.google.gwt.query.client.GQuery.$;
+import static com.google.gwt.query.client.GQuery.document;
+import static com.google.gwt.query.client.GQuery.lazy;
+import static com.google.gwt.user.client.Event.FOCUSEVENTS;
+import static com.google.gwt.user.client.Event.KEYEVENTS;
+import static com.google.gwt.user.client.Event.MOUSEEVENTS;
+import static com.google.gwt.user.client.Event.ONBLUR;
+import static com.google.gwt.user.client.Event.ONFOCUS;
+import static com.google.gwt.user.client.Event.ONKEYDOWN;
+import static com.google.gwt.user.client.Event.ONKEYPRESS;
+import static com.google.gwt.user.client.Event.ONKEYUP;
+import static com.google.gwt.user.client.Event.ONMOUSEDOWN;
+import static com.google.gwt.user.client.Event.ONMOUSEMOVE;
+import static com.google.gwt.user.client.Event.ONMOUSEOUT;
+import static com.google.gwt.user.client.Event.ONMOUSEOVER;
+import static com.google.gwt.user.client.Event.ONMOUSEUP;
+
/**
* Test class for testing gwt events plugin api.
*/
public class GQueryEventsTestGwt extends GWTTestCase {
+ private static class CounterFunction extends Function {
+ private int invokationCounter;
+
+ @Override
+ public void f() {
+ invokationCounter++;
+ }
+ }
+
static Element e = null;
static HTML testPanel = null;
@@ -146,7 +154,6 @@ public class GQueryEventsTestGwt extends GWTTestCase {
assertEquals("", $("#test", e).val());
}
-
}
public void testBindUnbindSubmitEvent() {
@@ -156,7 +163,7 @@ public class GQueryEventsTestGwt extends GWTTestCase {
testSubmitEventCont = 0;
// Add an onsubmit function to the form returning false to cancel the action
- $("form").bind(EventsListener.ONSUBMIT, null, new Function() {
+ $("form").bind("submit", null, new Function() {
public boolean f(Event e) {
testSubmitEventCont++;
return false;
@@ -168,7 +175,7 @@ public class GQueryEventsTestGwt extends GWTTestCase {
assertEquals(1, testSubmitEventCont);
// Remove the binding
- $("form").unbind(EventsListener.ONSUBMIT);
+ $("form").unbind("submit");
// Check that on submit function is not called and the form has been
// submitted
@@ -1024,6 +1031,7 @@ public class GQueryEventsTestGwt extends GWTTestCase {
public void testResizeWindowEvent() {
GQuery w = $(GQuery.window);
+
delayTestFinish(100);
w.bind("resize", null, new Function() {
public void f(Element e) {
@@ -1031,7 +1039,8 @@ public class GQueryEventsTestGwt extends GWTTestCase {
}
});
- Window.resizeTo(w.width(), w.height() + 100);
+ w.trigger("resize");
+
}
/**
@@ -1047,7 +1056,7 @@ public class GQueryEventsTestGwt extends GWTTestCase {
testSubmitEventCont = 0;
// Add an onsubmit function to the form returning false to cancel the action
- $("form").bind(EventsListener.ONSUBMIT, null, new Function() {
+ $("form").bind("submit", null, new Function() {
public boolean f(Event e) {
testSubmitEventCont++;
return false;
@@ -1060,7 +1069,7 @@ public class GQueryEventsTestGwt extends GWTTestCase {
assertFalse($("#miframe").contents().find("body").text().contains("ERROR"));
// Remove the binding
- $("form").unbind(EventsListener.ONSUBMIT);
+ $("form").unbind("submit");
// Check that on submit function is not called and the form has been
// submitted
@@ -1314,4 +1323,268 @@ public class GQueryEventsTestGwt extends GWTTestCase {
div.click();
assertEquals(1, count[0]);
}
+
+ public void testCustomEvent() {
+ $(e).html("<div id='target'>");
+ GQuery target = $("#target", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding
+ target.bind("mycustomevent", handler);
+
+ target.trigger("mycustomevent");
+
+ assertEquals(1, handler.invokationCounter);
+
+ // test custom event unbinding
+ target.unbind("mycustomevent");
+
+ handler.invokationCounter = 0;
+
+ target.trigger("mycustomevent");
+
+ assertEquals(0, handler.invokationCounter);
+ }
+
+ public void testCustomEventWithEventData() {
+ $(e).html("<div id='target'>");
+ GQuery target = $("#target", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding with event data
+ target.bind("mycustomevent", "handlerdata0", handler);
+
+ target.trigger("mycustomevent");
+
+ assertEquals(1, handler.invokationCounter);
+ assertEquals("handlerdata0", handler.getArgument(0));
+
+ // unbind
+ target.unbind("mycustomevent");
+ handler.invokationCounter = 0;
+ target.trigger("mycustomevent");
+ assertEquals(0, handler.invokationCounter);
+
+ // test custom event binding with event data as array
+ target.bind("mycustomevent", new String[]{"handlerdata0", "handlerdata1"}, handler);
+
+ target.trigger("mycustomevent");
+
+ assertEquals(1, handler.invokationCounter);
+ assertEquals("handlerdata0", handler.getArgument(0));
+ assertEquals("handlerdata1", handler.getArgument(1));
+ }
+
+ public void testCustomEventWithHandlerData() {
+ $(e).html("<div id='target'>");
+ GQuery target = $("#target", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding
+ target.bind("mycustomevent", handler);
+
+ target.trigger("mycustomevent", "eventdata0", "eventdata1");
+
+ assertEquals(1, handler.invokationCounter);
+ assertEquals("eventdata0", handler.getArgument(0));
+ assertEquals("eventdata1", handler.getArgument(1));
+
+ // unbind
+ target.unbind("mycustomevent");
+ handler.invokationCounter = 0;
+ target.trigger("mycustomevent");
+ assertEquals(0, handler.invokationCounter);
+ }
+
+
+ public void testCustomEventWithEventDataAndHandlerData() {
+ $(e).html("<div id='target'>");
+ GQuery target = $("#target", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding with event data
+ target.bind("mycustomevent", "handlerdata0", handler);
+
+ target.trigger("mycustomevent", "eventdata0", "eventdata1");
+
+ assertEquals(1, handler.invokationCounter);
+ assertEquals("handlerdata0", handler.getArgument(0));
+ assertEquals("eventdata0", handler.getArgument(1));
+ assertEquals("eventdata1", handler.getArgument(2));
+
+ // unbind
+ target.unbind("mycustomevent");
+ handler.invokationCounter = 0;
+ target.trigger("mycustomevent");
+ assertEquals(0, handler.invokationCounter);
+
+ // test custom event binding with event data as array
+ target.bind("mycustomevent", new String[]{"handlerdata0", "handlerdata1"}, handler);
+
+ target.trigger("mycustomevent", "eventdata0", "eventdata1");
+
+ assertEquals(1, handler.invokationCounter);
+ assertEquals("handlerdata0", handler.getArgument(0));
+ assertEquals("handlerdata1", handler.getArgument(1));
+ assertEquals("eventdata0", handler.getArgument(2));
+ assertEquals("eventdata1", handler.getArgument(3));
+ }
+
+ public void testBitlessEventTriggersWithEventName() {
+ $(e).html("<div id='target'>");
+ GQuery target = $("#target", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ target.bind(Event.ONCLICK, handler);
+
+ target.trigger("click");
+
+ assertEquals(1, handler.invokationCounter);
+ }
+
+ public void testDelegationEventWithCustomEvent() {
+ $(e).html("<div id='container'></div>");
+ GQuery container = $("#container", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding
+ $(".custom", e).live("mycustomevent", handler);
+
+ container.html("<div class='custom'></div><div class='other'></div><div" +
+ " class='custom'>custom2</div>");
+
+ $(".custom").trigger("mycustomevent");
+
+ assertEquals(2, handler.invokationCounter);
+ handler.invokationCounter = 0;
+
+ $(".other").trigger("mycustomevent");
+ assertEquals(0, handler.invokationCounter);
+
+ // test custom event unbinding
+ $(".custom", e).die("mycustomevent");
+
+ handler.invokationCounter = 0;
+
+ $(".custom").trigger("mycustomevent");
+
+ assertEquals(0, handler.invokationCounter);
+ }
+
+
+ public void testDelegationEventWithCustomEventAndData() {
+ $(e).html("<div id='container'></div>");
+ GQuery container = $("#container", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding
+ $(".custom", e).live("mycustomevent", new String[]{"handlerdata0", "handlerdata1"}, handler);
+
+ container.html("<div class='custom'></div><div class='other'></div>");
+
+ $(".custom").trigger("mycustomevent", "eventdata0", "eventdata1");
+
+ assertEquals(1, handler.invokationCounter);
+ handler.invokationCounter = 0;
+ assertEquals("handlerdata0", handler.getArgument(0));
+ assertEquals("handlerdata1", handler.getArgument(1));
+ assertEquals("eventdata0", handler.getArgument(2));
+ assertEquals("eventdata1", handler.getArgument(3));
+
+ $(".other").trigger("mycustomevent");
+ assertEquals(0, handler.invokationCounter);
+
+ // test custom event unbinding
+ $(".custom", e).die("mycustomevent");
+
+ handler.invokationCounter = 0;
+
+ $(".custom").trigger("mycustomevent");
+
+ assertEquals(0, handler.invokationCounter);
+ }
+
+ public void testDelegationEventWithDelegateAndWithCustomEvent() {
+ $(e).html("<div id='container'></div>");
+ GQuery container = $("#container", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding
+ $(e).delegate(".custom", "mycustomevent", handler);
+
+ container.html("<div class='custom'></div><div class='other'></div>");
+
+ $(".custom").trigger("mycustomevent");
+
+ assertEquals(1, handler.invokationCounter);
+ handler.invokationCounter = 0;
+
+ $(".other").trigger("mycustomevent");
+ assertEquals(0, handler.invokationCounter);
+
+ // test custom event unbinding
+ $(e).undelegate(".custom", "mycustomevent");
+
+ handler.invokationCounter = 0;
+
+ $(".custom").trigger("mycustomevent");
+
+ assertEquals(0, handler.invokationCounter);
+ }
+
+
+ public void testDelegationEventWithDelegateAndWithCustomEventAndData() {
+ $(e).html("<div id='container'></div>");
+ GQuery container = $("#container", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding
+ $(e).delegate(".custom", "mycustomevent", new String[]{"handlerdata0", "handlerdata1"}, handler);
+
+ container.html("<div class='custom'></div><div class='other'></div><div class='custom'>custom2</div>");
+
+ $(".custom").trigger("mycustomevent", "eventdata0", "eventdata1");
+
+ assertEquals(2, handler.invokationCounter);
+ handler.invokationCounter = 0;
+ assertEquals("handlerdata0", handler.getArgument(0));
+ assertEquals("handlerdata1", handler.getArgument(1));
+ assertEquals("eventdata0", handler.getArgument(2));
+ assertEquals("eventdata1", handler.getArgument(3));
+
+ $(".other").trigger("mycustomevent");
+ assertEquals(0, handler.invokationCounter);
+
+ // test custom event unbinding
+ $(e).undelegate(".custom", "mycustomevent");
+
+ handler.invokationCounter = 0;
+
+ $(".custom").trigger("mycustomevent");
+
+ assertEquals(0, handler.invokationCounter);
+ }
+
+ public void testBitlessEvent() {
+ $(e).html("<div id='target'>");
+ GQuery target = $("#target", e);
+
+ CounterFunction handler = new CounterFunction();
+
+ // test custom event binding
+ target.bind("drag", handler);
+
+ target.trigger("drag");
+
+ assertEquals(1, handler.invokationCounter);
+ }
}