From: Julien Dramaix Date: Fri, 8 Apr 2011 18:35:54 +0000 (+0000) Subject: implement live() and die methods X-Git-Tag: release-1.3.2~428 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f9d6e292acc225f85dd6fc281805cf47395a1694;p=gwtquery.git implement live() and die methods --- 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 e6958722..c8c95539 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 @@ -352,7 +352,7 @@ public class GQuery implements Lazy { n = n.getLastChild(); } // TODO: add fixes for IE TBODY issue - return $((NodeList) n.getChildNodes().cast()).as(Events).addLiveEvents(); + return $((NodeList) n.getChildNodes().cast()); } protected static Object data(Element item, String name, S value) { @@ -972,7 +972,7 @@ public class GQuery implements Lazy { GQuery ret = new GQuery(result); ret.currentContext = currentContext; ret.currentSelector = currentSelector; - return ret.as(Events).addLiveEvents(); + return ret; } /** @@ -987,67 +987,80 @@ public class GQuery implements Lazy { } /** - * Returns a {@link Map} object as key a selector and as value the first ancestor elements matching this selectors, beginning at the - * first matched element and progressing up through the DOM. This method allows retrieving the list of closest ancestors matching - * many selectors and by reducing the number of DOM traversing. + * Returns a {@link Map} object as key a selector and as value the list of + * ancestor elements matching this selectors, beginning at the first matched + * element and progressing up through the DOM. This method allows retrieving + * the list of ancestors matching many selectors by traversing the DOM only + * one time. * * @param selector * @return */ - public Map closest(String[] selectors){ + public Map> closest(String[] selectors) { return closest(selectors, null); } - + /** - * Returns a GQuery object containing the first ancestor elements matching each selectors, beginning at the - * first matched element and progressing up through the DOM tree until reach the context node.. - * This method allows retrieving the list of closest ancestors matching many selectors and by reducing the number of DOM traversing. + * Returns a {@link Map} object as key a selector and as value the list of + * ancestor elements matching this selectors, beginning at the first matched + * element and progressing up through the DOM until reach the + * context node.. This method allows retrieving the list of + * ancestors matching many selectors by traversing the DOM only one time. * * @param selector * @return */ - public Map closest(String[] selectors, Node context){ - Map results = new HashMap(); - - if (context == null){ + public Map> closest(String[] selectors, Node context) { + Map> results = new HashMap>(); + + if (context == null) { context = currentContext; } - + Element first = get(0); - - if (first != null && selectors != null && selectors.length > 0){ - + + if (first != null && selectors != null && selectors.length > 0) { + Map matches = new HashMap(); - - for (String selector : selectors){ - if (!matches.containsKey(selector)){ - matches.put(selector, selector.matches(POS_REGEX) ? $(selector, context) : null); + + for (String selector : selectors) { + if (!matches.containsKey(selector)) { + matches.put(selector, selector.matches(POS_REGEX) ? $(selector, + context) : null); } } - + Element current = first; - - while (current != null && current.getOwnerDocument() != null && current != context){ - //for each selector, check if the current element match it. - for (String selector : matches.keySet()){ - if (results.containsKey(selector)){ - //first ancestors already found for this selector - continue; - } + + while (current != null && current.getOwnerDocument() != null + && current != context) { + // for each selector, check if the current element match it. + for (String selector : matches.keySet()) { + GQuery pos = matches.get(selector); - boolean match = pos != null ? pos.index(current) > -1 : $(current).is(selector); - if (match){ - results.put(selector, current); + + boolean match = pos != null ? pos.index(current) > -1 + : $(current).is(selector); + + if (match) { + + List elementsMatchingSelector = results.get(selector); + + if (elementsMatchingSelector == null) { + elementsMatchingSelector = new ArrayList(); + results.put(selector, elementsMatchingSelector); + } + + elementsMatchingSelector.add(current); } } - - current = current.getParentElement(); + + current = current.getParentElement(); } - - + } - - return results; + + return results; } /** @@ -1406,16 +1419,27 @@ public class GQuery implements Lazy { public GQuery detach(String filter) { return remove(filter, false); } - + /** - * Remove all event handlers previously attached using live() - * The selector used with it must match exactly the selector initially - * used with live(). + * Remove all event handlers previously attached using + * {@link #live(String, Function)}. In order for this method to function + * correctly, the selector used with it must match exactly the selector + * initially used with {@link #live(String, Function)} */ - public GQuery die(int eventbits) { - return as(Events).die(eventbits); + public GQuery die() { + return as(Events).die(null); } - + + /** + * Remove an event handlers previously attached using + * {@link #live(String, Function)} In order for this method to function + * correctly, the selector used with it must match exactly the selector + * initially used with {@link #live(String, Function)} + */ + public GQuery die(String eventName) { + return as(Events).die(eventName); + } + /** * Run one or more Functions over each element of the GQuery. You have to * override one of these funcions: public void f(Element e) public String @@ -1763,7 +1787,7 @@ public class GQuery implements Lazy { } e.setInnerHTML(html); } - return as(Events).addLiveEvents(); + return this; } /** @@ -1932,13 +1956,117 @@ public class GQuery implements Lazy { public int length() { return size(); } + + /** + *

+ * Attach a handler for this event to all elements which match the current + * selector, now and in the future. + *

+ *

+ * Ex : + * + *

+   * $(".clickable").live("click", new Function(){
+   *  public void f(Element e){
+   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
+   *  }
+   * });
+   *  
+ * + * With this code, all elements with class "clickable" present in the DOM or + * added to the DOM in the future will be clickable. The text color will be + * changed to red when they will be clicked. So if after in the code, you add + * another element : + * + *
+   * $("body").append("
Click me and I will be red
"); + *
+ * + * The click on this new element will also trigger the handler. + *

+ *

+ * In the same way, if you add "clickable" class on some existing element, + * these elements will be clickable also. + *

+ *

+ *

important remarks

+ *
    + *
  • + * The live method should be always called after a selector
  • + *
  • + * Live events are bound to the context of the {@link GQuery} object : + * + *
    +   * $(".clickable", myElement).live("click", new Function(){
    +   *  public void f(Element e){
    +   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
    +   *  }
    +   * });
    +   * 
    + * The {@link Function} will be called only on elements having the class + * "clickable" and being descendant of myElement.
  • + *
+ *

+ */ + public GQuery live(String eventName, Function func) { + return as(Events).live(eventName, null, func); + } + /** - * Add events to all elements which match the current selector, - * now and in the future. + *

+ * Attach a handler for this event to all elements which match the current + * selector, now and in the future. + * The data parameter allows us to pass data to the handler. + *

+ *

+ * Ex : + * + *

+   * $(".clickable").live("click", new Function(){
+   *  public void f(Element e){
+   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
+   *  }
+   * });
+   *  
+ * + * With this code, all elements with class "clickable" present in the DOM or + * added to the DOM in the future will be clickable. The text color will be + * changed to red when they will be clicked. So if after in the code, you add + * another element : + * + *
+   * $("body").append("
Click me and I will be red
"); + *
+ * + * The click on this new element will also trigger the handler. + *

+ *

+ * In the same way, if you add "clickable" class on some existing element, + * these elements will be clickable also. + *

+ *

+ *

important remarks

+ *
    + *
  • + * The live method should be always called after a selector
  • + *
  • + * Live events are bound to the context of the {@link GQuery} object : + * + *
    +   * $(".clickable", myElement).live("click", new Function(){
    +   *  public void f(Element e){
    +   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
    +   *  }
    +   * });
    +   * 
    + * The {@link Function} will be called only on elements having the class + * "clickable" and being descendant of myElement.
  • + *
+ *

*/ - public GQuery live(int eventBits, Function... funcs) { - return as(Events).live(eventBits, funcs); + public GQuery live(String eventName, Object data, Function func) { + return as(Events).live(eventName, data, func); } /** 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 402d782f..2a5b32ce 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 @@ -57,6 +57,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Map; import com.google.gwt.query.client.LazyBase; public interface LazyGQuery extends LazyBase{ @@ -399,6 +400,48 @@ public interface LazyGQuery extends LazyBase{ */ LazyGQuery clone(); + /** + * Get the first ancestor element that matches the selector (for each matched element), beginning at the + * current element and progressing up through the DOM tree. + * + * @param selector + * @return + */ + LazyGQuery closest(String selector); + + /** + * Returns a {@link Map} object as key a selector and as value the list of + * ancestor elements matching this selectors, beginning at the first matched + * element and progressing up through the DOM. This method allows retrieving + * the list of ancestors matching many selectors by traversing the DOM only + * one time. + * + * @param selector + * @return + */ + Map> closest(String[] selectors); + + /** + * Returns a {@link Map} object as key a selector and as value the list of + * ancestor elements matching this selectors, beginning at the first matched + * element and progressing up through the DOM until reach the + * context node.. This method allows retrieving the list of + * ancestors matching many selectors by traversing the DOM only one time. + * + * @param selector + * @return + */ + Map> closest(String[] selectors, Node context); + + /** + * Get the first ancestor element that matches the selector (for each matched element), beginning at the + * current element and progressing up through the DOM tree until reach the context node. + * + * If no context is passed in then the context of the gQuery object will be used instead. + * + */ + LazyGQuery closest(String selector, Node context); + /** * Filter the set of elements to those that contain the specified text. */ @@ -622,11 +665,20 @@ public interface LazyGQuery extends LazyBase{ LazyGQuery detach(String filter); /** - * Remove all event handlers previously attached using live() - * The selector used with it must match exactly the selector initially - * used with live(). + * Remove all event handlers previously attached using + * {@link #live(String, Function)}. In order for this method to function + * correctly, the selector used with it must match exactly the selector + * initially used with {@link #live(String, Function)} + */ + LazyGQuery die(); + + /** + * Remove an event handlers previously attached using + * {@link #live(String, Function)} In order for this method to function + * correctly, the selector used with it must match exactly the selector + * initially used with {@link #live(String, Function)} */ - LazyGQuery die(int eventbits); + LazyGQuery die(String eventName); /** * Run one or more Functions over each element of the GQuery. You have to @@ -760,6 +812,8 @@ public interface LazyGQuery extends LazyBase{ */ Element get(int i); + Node getContext(); + /** * Return the previous set of matched elements prior to the last destructive * operation (e.g. query) @@ -946,10 +1000,111 @@ public interface LazyGQuery extends LazyBase{ int length(); /** - * Add events to all elements which match the current selector, - * now and in the future. + *

+ * Attach a handler for this event to all elements which match the current + * selector, now and in the future. + *

+ *

+ * Ex : + * + *

+   * $(".clickable").live("click", new Function(){
+   *  public void f(Element e){
+   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
+   *  }
+   * });
+   *  
+ * + * With this code, all elements with class "clickable" present in the DOM or + * added to the DOM in the future will be clickable. The text color will be + * changed to red when they will be clicked. So if after in the code, you add + * another element : + * + *
+   * $("body").append("
Click me and I will be red
"); + *
+ * + * The click on this new element will also trigger the handler. + *

+ *

+ * In the same way, if you add "clickable" class on some existing element, + * these elements will be clickable also. + *

+ *

+ *

important remarks

+ *
    + *
  • + * The live method should be always called after a selector
  • + *
  • + * Live events are bound to the context of the {@link GQuery} object : + * + *
    +   * $(".clickable", myElement).live("click", new Function(){
    +   *  public void f(Element e){
    +   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
    +   *  }
    +   * });
    +   * 
    + * The {@link Function} will be called only on elements having the class + * "clickable" and being descendant of myElement.
  • + *
+ *

+ */ + LazyGQuery live(String eventName, Function func); + + /** + *

+ * Attach a handler for this event to all elements which match the current + * selector, now and in the future. + * The data parameter allows us to pass data to the handler. + *

+ *

+ * Ex : + * + *

+   * $(".clickable").live("click", new Function(){
+   *  public void f(Element e){
+   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
+   *  }
+   * });
+   *  
+ * + * With this code, all elements with class "clickable" present in the DOM or + * added to the DOM in the future will be clickable. The text color will be + * changed to red when they will be clicked. So if after in the code, you add + * another element : + * + *
+   * $("body").append("
Click me and I will be red
"); + *
+ * + * The click on this new element will also trigger the handler. + *

+ *

+ * In the same way, if you add "clickable" class on some existing element, + * these elements will be clickable also. + *

+ *

+ *

important remarks

+ *
    + *
  • + * The live method should be always called after a selector
  • + *
  • + * Live events are bound to the context of the {@link GQuery} object : + * + *
    +   * $(".clickable", myElement).live("click", new Function(){
    +   *  public void f(Element e){
    +   *    $(e).css(CSS.COLOR.with(RGBColor.RED));
    +   *  }
    +   * });
    +   * 
    + * The {@link Function} will be called only on elements having the class + * "clickable" and being descendant of myElement.
  • + *
+ *

*/ - LazyGQuery live(int eventBits, Function... funcs); + LazyGQuery live(String eventName, Object data, Function func); /** * Bind a function to the load event of each matched element. 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 d8e5d52b..fc58ce0f 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 @@ -19,8 +19,6 @@ import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQuery; -import com.google.gwt.query.client.js.JsCache; -import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.query.client.plugins.events.EventsListener; import com.google.gwt.user.client.Event; @@ -30,8 +28,6 @@ import com.google.gwt.user.client.Event; public class Events extends GQuery { public static final Class Events = Events.class; - - protected static final String LIVE_ID_DATA = "_lid_"; static { GQuery.registerPlugin(Events.class, new Plugin() { @@ -44,6 +40,7 @@ public class Events extends GQuery { public Events(GQuery gq) { super(gq); } + /** * Binds a set of handlers to a particular Event for each matched element. * @@ -55,7 +52,7 @@ public class Events extends GQuery { * parameter * */ - public Events bind(int eventbits, Object data, Function...funcs) { + public Events bind(int eventbits, Object data, Function... funcs) { for (Element e : elements()) { EventsListener.getInstance(e).bind(eventbits, data, funcs); } @@ -65,8 +62,8 @@ public class Events extends GQuery { /** * Binds a set of handlers to a particular Event for each matched element. * - * The namespace is a way to group events of the same type, making easier unbind - * specific handlers. + * The namespace is a way to group events of the same type, making easier + * unbind specific handlers. * * The event handlers are passed as Functions that you can use to prevent * default behavior. To stop both default action and event bubbling, the @@ -74,8 +71,9 @@ public class Events extends GQuery { * * You can pass an additional Object data to your Function * - */ - public Events bind(int eventbits, String namespace, Object data, Function...funcs) { + */ + public Events bind(int eventbits, String namespace, Object data, + Function... funcs) { for (Element e : elements()) { EventsListener.getInstance(e).bind(eventbits, namespace, data, funcs); } @@ -85,8 +83,8 @@ public class Events extends GQuery { /** * Binds a set of handlers to a particular Event for each matched element. * - * The name could contain a namespace which is a way to group events of the same type, - * making easier unbind specific handlers. + * The name could contain a namespace which is a way to group events of the + * same type, making easier unbind specific handlers. * * The event handlers are passed as Functions that you can use to prevent * default behavior. To stop both default action and event bubbling, the @@ -94,89 +92,68 @@ public class Events extends GQuery { * * You can pass an additional Object data to your Function * - */ - public Events bind(String event, Object data, Function...funcs) { + */ + public Events bind(String event, Object data, Function... funcs) { for (Element e : elements()) { EventsListener.getInstance(e).bind(event, data, funcs); } return this; } - + /** - * Remove all event handlers previously attached using live() - * The selector used with it must match exactly the selector initially - * used with live(). + * Remove an event handlers previously attached using live() The selector used + * with it must match exactly the selector initially used with live(). if + * eventName is null, all event handlers corresponding of the + * GQuery selector will be removed */ - public GQuery die(int eventbits) { - JsCache d = dataCache.get(LIVE_ID_DATA); - if (d != null) { - JsCache cache = d.get(currentSelector); - if (cache != null) { - cache.delete(eventbits); - } - } - unbind(eventbits); + public GQuery die(String eventName) { + EventsListener.getInstance( + Element.is(currentContext) ? (Element) currentContext : body).die( + eventName, currentSelector); return this; } - - /** - * Add events to all elements which match the current selector, - * now and in the future. - */ - public GQuery live(int eventBits, Function... funcs) { - if (currentSelector == null || currentSelector.isEmpty()) { - return this; - } - JsCache d = dataCache.get(LIVE_ID_DATA); - if (d == null) { - d = JsCache.create(); - dataCache.put(LIVE_ID_DATA, d); - } - JsCache cache = d.get(currentSelector); - if (cache == null) { - cache = JsCache.create(); - d.put(currentSelector, cache); - } - - JsObjectArray functions = cache.get(eventBits); - if (functions == null) { - functions = JsObjectArray.create().cast(); - cache.put(eventBits, functions); - } - functions.add(funcs); - bind(eventBits, null, funcs); + public GQuery live(String eventName, final Object data, Function func) { + + // bind live delegating event to the current context + EventsListener.getInstance( + Element.is(currentContext) ? (Element) currentContext : body).live( + eventName, currentSelector, data, func); + return this; + } - + /** * Binds a handler to a particular Event (like Event.ONCLICK) for each matched * element. The handler is executed only once for each element. - * + * * The event handler is passed as a Function that you can use to prevent * default behavior. To stop both default action and event bubbling, the * function event handler has to return false. - * + * * You can pass an additional Object data to your Function as the second * parameter - */ + */ public Events one(int eventbits, final Object data, final Function f) { for (Element e : elements()) { EventsListener.getInstance(e).bind(eventbits, data, f, 1); } return this; } - + /** - * Execute all handlers and behaviors attached to the matched elements for the given event types. + * Execute all handlers and behaviors attached to the matched elements for the + * given event types. * - * Different event types can be passed joining these using the or bit wise operator. + * Different event types can be passed joining these using the or bit wise + * operator. * - * For keyboard events you can pass a second parameter which represents - * the key-code of the pushed key. + * For keyboard events you can pass a second parameter which represents the + * key-code of the pushed key. * - * Example: fire(Event.ONCLICK | Event.ONFOCUS) - * Example: fire(Event.ONKEYDOWN. 'a'); + * Example: fire(Event.ONCLICK | Event.ONFOCUS) Example: fire(Event.ONKEYDOWN. + * 'a'); */ @SuppressWarnings("deprecation") public Events trigger(int eventbits, int... keys) { @@ -185,35 +162,46 @@ public class Events extends GQuery { if ((eventbits | Event.ONCHANGE) == Event.ONCHANGE) dispatchEvent(document.createChangeEvent()); if ((eventbits | Event.ONCLICK) == Event.ONCLICK) - dispatchEvent(document.createClickEvent(0, 0, 0, 0, 0, false, false, false, false)); + dispatchEvent(document.createClickEvent(0, 0, 0, 0, 0, false, false, + false, false)); if ((eventbits | Event.ONDBLCLICK) == Event.ONDBLCLICK) - dispatchEvent(document.createDblClickEvent(0, 0, 0, 0, 0, false, false, false, false)); + dispatchEvent(document.createDblClickEvent(0, 0, 0, 0, 0, false, false, + false, false)); if ((eventbits | Event.ONFOCUS) == Event.ONFOCUS) dispatchEvent(document.createFocusEvent()); if ((eventbits | Event.ONKEYDOWN) == Event.ONKEYDOWN) - dispatchEvent(document.createKeyDownEvent(false, false, false, false, keys[0], 0)); + dispatchEvent(document.createKeyDownEvent(false, false, false, false, + keys[0], 0)); if ((eventbits | Event.ONKEYPRESS) == Event.ONKEYPRESS) - dispatchEvent(document.createKeyPressEvent(false, false, false, false, keys[0], 0)); + dispatchEvent(document.createKeyPressEvent(false, false, false, false, + keys[0], 0)); if ((eventbits | Event.ONKEYUP) == Event.ONKEYUP) - dispatchEvent(document.createKeyUpEvent(false, false, false, false, keys[0], 0)); + dispatchEvent(document.createKeyUpEvent(false, false, false, false, + keys[0], 0)); if ((eventbits | Event.ONLOSECAPTURE) == Event.ONLOSECAPTURE) triggerHtmlEvent("losecapture"); if ((eventbits | Event.ONMOUSEDOWN) == Event.ONMOUSEDOWN) - dispatchEvent(document.createMouseDownEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT)); + dispatchEvent(document.createMouseDownEvent(0, 0, 0, 0, 0, false, false, + false, false, NativeEvent.BUTTON_LEFT)); if ((eventbits | Event.ONMOUSEMOVE) == Event.ONMOUSEMOVE) - dispatchEvent(document.createMouseMoveEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT)); + dispatchEvent(document.createMouseMoveEvent(0, 0, 0, 0, 0, false, false, + false, false, NativeEvent.BUTTON_LEFT)); if ((eventbits | Event.ONMOUSEOUT) == Event.ONMOUSEOUT) - dispatchEvent(document.createMouseOutEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT, null)); + dispatchEvent(document.createMouseOutEvent(0, 0, 0, 0, 0, false, false, + false, false, NativeEvent.BUTTON_LEFT, null)); if ((eventbits | Event.ONMOUSEOVER) == Event.ONMOUSEOVER) - dispatchEvent(document.createMouseOverEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT, null)); + dispatchEvent(document.createMouseOverEvent(0, 0, 0, 0, 0, false, false, + false, false, NativeEvent.BUTTON_LEFT, null)); if ((eventbits | Event.ONMOUSEUP) == Event.ONMOUSEUP) - dispatchEvent(document.createMouseUpEvent(0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT)); + dispatchEvent(document.createMouseUpEvent(0, 0, 0, 0, 0, false, false, + false, false, NativeEvent.BUTTON_LEFT)); if ((eventbits | Event.ONSCROLL) == Event.ONSCROLL) dispatchEvent(document.createScrollEvent()); if ((eventbits | Event.ONERROR) == Event.ONERROR) dispatchEvent(document.createErrorEvent()); 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)); + dispatchEvent(document.createMouseEvent("mousewheel", true, true, 0, 0, + 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT, null)); if (eventbits == EventsListener.ONSUBMIT) triggerHtmlEvent("submit"); return this; @@ -222,14 +210,13 @@ public class Events extends GQuery { /** * Trigger a html event in all matched elements. * - * @param htmlEvent - * An string representing the html event desired + * @param htmlEvent An string representing the html event desired */ public Events triggerHtmlEvent(String htmlEvent) { dispatchEvent(document.createHtmlEvent(htmlEvent, true, true)); return this; } - + /** * Removes all handlers, that matches the events bits passed, from each * element. @@ -242,7 +229,7 @@ public class Events extends GQuery { } return this; } - + /** * Removes all handlers, that matches the events bits and the namespace * passed, from each element. @@ -255,10 +242,10 @@ public class Events extends GQuery { } return this; } - + /** - * Removes all handlers, that matches event name passed. This name - * could contain a namespace. + * Removes all handlers, that matches event name passed. This name could + * contain a namespace. * * Example: unbind("click.my.namespace") */ @@ -268,29 +255,11 @@ public class Events extends GQuery { } return this; } - + private void dispatchEvent(NativeEvent evt) { for (Element e : elements()) { e.dispatchEvent(evt); } } - - public GQuery addLiveEvents() { - if (dataCache.exists(LIVE_ID_DATA)) { - JsCache d = dataCache.get(LIVE_ID_DATA); - for (String selector : d.keys()) { - GQuery g = find(selector).add(filter(selector)); - if (g.size() > 0) { - JsCache cache = d.get(selector); - for (int eventBits : cache.indexes()) { - JsObjectArray functions = cache.get(eventBits); - for (int j = 0; j extends LazyBase{ * parameter * */ - LazyEvents bind(int eventbits, Object data, Function...funcs); + LazyEvents bind(int eventbits, Object data, Function... funcs); /** * Binds a set of handlers to a particular Event for each matched element. * - * The namespace is a way to group events of the same type, making easier unbind - * specific handlers. + * The namespace is a way to group events of the same type, making easier + * unbind specific handlers. * * The event handlers are passed as Functions that you can use to prevent * default behavior. To stop both default action and event bubbling, the @@ -51,14 +49,14 @@ public interface LazyEvents extends LazyBase{ * * You can pass an additional Object data to your Function * - */ - LazyEvents bind(int eventbits, String namespace, Object data, Function...funcs); + */ + LazyEvents bind(int eventbits, String namespace, Object data, Function... funcs); /** * Binds a set of handlers to a particular Event for each matched element. * - * The name could contain a namespace which is a way to group events of the same type, - * making easier unbind specific handlers. + * The name could contain a namespace which is a way to group events of the + * same type, making easier unbind specific handlers. * * The event handlers are passed as Functions that you can use to prevent * default behavior. To stop both default action and event bubbling, the @@ -66,53 +64,51 @@ public interface LazyEvents extends LazyBase{ * * You can pass an additional Object data to your Function * - */ - LazyEvents bind(String event, Object data, Function...funcs); - - /** - * Remove all event handlers previously attached using live() - * The selector used with it must match exactly the selector initially - * used with live(). */ - GQuery die(int eventbits); + LazyEvents bind(String event, Object data, Function... funcs); /** - * Add events to all elements which match the current selector, - * now and in the future. + * Remove an event handlers previously attached using live() The selector used + * with it must match exactly the selector initially used with live(). if + * eventName is null, all event handlers corresponding of the + * GQuery selector will be removed */ - GQuery live(int eventBits, Function... funcs); + GQuery die(String eventName); + + GQuery live(String eventName, Object data, Function func); /** * Binds a handler to a particular Event (like Event.ONCLICK) for each matched * element. The handler is executed only once for each element. - * + * * The event handler is passed as a Function that you can use to prevent * default behavior. To stop both default action and event bubbling, the * function event handler has to return false. - * + * * You can pass an additional Object data to your Function as the second * parameter - */ + */ LazyEvents one(int eventbits, Object data, Function f); /** - * Execute all handlers and behaviors attached to the matched elements for the given event types. + * Execute all handlers and behaviors attached to the matched elements for the + * given event types. * - * Different event types can be passed joining these using the or bit wise operator. + * Different event types can be passed joining these using the or bit wise + * operator. * - * For keyboard events you can pass a second parameter which represents - * the key-code of the pushed key. + * For keyboard events you can pass a second parameter which represents the + * key-code of the pushed key. * - * Example: fire(Event.ONCLICK | Event.ONFOCUS) - * Example: fire(Event.ONKEYDOWN. 'a'); + * Example: fire(Event.ONCLICK | Event.ONFOCUS) Example: fire(Event.ONKEYDOWN. + * 'a'); */ LazyEvents trigger(int eventbits, int... keys); /** * Trigger a html event in all matched elements. * - * @param htmlEvent - * An string representing the html event desired + * @param htmlEvent An string representing the html event desired */ LazyEvents triggerHtmlEvent(String htmlEvent); @@ -133,8 +129,8 @@ public interface LazyEvents extends LazyBase{ LazyEvents unbind(int eventbits, String name); /** - * Removes all handlers, that matches event name passed. This name - * could contain a namespace. + * Removes all handlers, that matches event name passed. This name could + * contain a namespace. * * Example: unbind("click.my.namespace") */ diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/MousePlugin.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/MousePlugin.java index 5dee20d5..ccac4b19 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/MousePlugin.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/MousePlugin.java @@ -62,14 +62,14 @@ public abstract class MousePlugin extends UiPlugin { (Object) null, new Function() { @Override public boolean f(com.google.gwt.user.client.Event event) { - return mouseDown(e, Event.create(event)); + return mouseDown(e, (Event)Event.create(event)); } }).bind(Event.ONCLICK, getPluginName(), (Object) null, new Function() { @Override public boolean f(com.google.gwt.user.client.Event event) { - preventClickEvent |= !mouseClick(e, Event.create(event)); + preventClickEvent |= !mouseClick(e, (Event)Event.create(event)); if (preventClickEvent) { @@ -212,14 +212,14 @@ public abstract class MousePlugin extends UiPlugin { (Object) null, new Function() { @Override public boolean f(com.google.gwt.user.client.Event e) { - mouseMove(element, Event.create(e)); + mouseMove(element, (Event) Event.create(e)); return false; } }).bind(Event.ONMOUSEUP, getPluginName(), (Object) null, new Function() { @Override public boolean f(com.google.gwt.user.client.Event e) { - mouseUp(element, Event.create(e)); + mouseUp(element, (Event) Event.create(e)); return false; } }); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/UiPlugin.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/UiPlugin.java index 78dc3b10..92c75395 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/UiPlugin.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/UiPlugin.java @@ -64,72 +64,14 @@ public class UiPlugin extends GQuery { } /** - * This object allows you to have a full copy of the original Event and - * implements some useful method of the jQuery event model. This is also - * useful in Internet Explorer because it use the same javascript object to - * fire MouseDownEvent, MouseMoveEvent or MouseStopEvent on the same element. - * So, we cannot keep a copy of the MouseDownEvent during a dragginf for - * example. Now we can ! * - * TOBEFIXED : the method preventDefault() must be called directly on the - * original event * - * + * @deprecated use {@link com.google.gwt.query.client.plugins.events.Event} instead */ - public static class Event extends com.google.gwt.user.client.Event { - - /** - * Create a new {@link Event} by copying the originalEvent. - */ - public static Event create(com.google.gwt.user.client.Event originalEvent) { - Event gQueryEvent = createObject().cast(); - copy(originalEvent, gQueryEvent); - return gQueryEvent; - } - - private static native void copy( - com.google.gwt.user.client.Event originalEvent, Event gQueryEvent) /*-{ - for ( var field in originalEvent ) { - gQueryEvent[field] = originalEvent[field]; - } - gQueryEvent.originalEvent = originalEvent; - }-*/; - - protected Event() { - } - - /** - * Return the original event (the one created by the browser) - */ - public final native com.google.gwt.user.client.Event getOriginalEvent()/*-{ - return this.originalEvent; - }-*/; - - /** - * Tell whether ctrl or cmd key is pressed - * - */ - public final boolean isMetaKeyPressed() { - return getMetaKey() || getCtrlKey(); - } - - /** - * The mouse position relative to the left edge of the document - * - */ - public final int pageX() { - return getClientX() + document.getScrollLeft(); - } - - /** - * The mouse position relative to the top edge of the document. - * - */ - public final int pageY() { - return getClientY() + document.getScrollTop(); - } + public static class Event extends com.google.gwt.query.client.plugins.events.Event { } + private static class GQueryUiImpl { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/Event.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/Event.java new file mode 100644 index 00000000..0b5ae1bd --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/Event.java @@ -0,0 +1,88 @@ +package com.google.gwt.query.client.plugins.events; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.query.client.GQuery; + +/** + * This object allows you to have a full copy of the original Event and + * implements some useful method of the jQuery event model. + * + * This is also useful in Internet Explorer because it use the same javascript + * object to fire MouseDownEvent, MouseMoveEvent or MouseStopEvent on the same + * element. So, we cannot keep a copy of the MouseDownEvent during a dragging + * for example. + * + * + * + * TOBEFIXED : the method preventDefault() must be called directly on the + * original event + * + * + */ +public class Event extends com.google.gwt.user.client.Event { + + + /** + * Create a new {@link Event} by copying the originalEvent. + */ + public static Event create(com.google.gwt.user.client.Event originalEvent) { + Event gQueryEvent = createObject().cast(); + copy(originalEvent, gQueryEvent); + return gQueryEvent; + } + + private static native void copy( + com.google.gwt.user.client.Event originalEvent, Event gQueryEvent) /*-{ + for ( var field in originalEvent) { + gQueryEvent[field] = originalEvent[field]; + } + gQueryEvent.originalEvent = originalEvent; + }-*/; + + protected Event() { + } + + /** + * Return the original event (the one created by the browser) + */ + public final native com.google.gwt.user.client.Event getOriginalEvent()/*-{ + return this.originalEvent; + }-*/; + + public final native void setCurrentElementTarget(Element e)/*-{ + + this.currentTarget = e; + + //ie don't have a currentEventTarget field on event + try{ + @com.google.gwt.dom.client.DOMImplTrident::currentEventTarget = e; + }catch(e){} + }-*/; + + /** + * Tell whether ctrl or cmd key is pressed + * + */ + public final boolean isMetaKeyPressed() { + return getMetaKey() || getCtrlKey(); + } + + /** + * The mouse position relative to the left edge of the document + * + */ + public final int pageX() { + return getClientX() + GQuery.document.getScrollLeft(); + } + + /** + * The mouse position relative to the top edge of the document. + * + */ + public final int pageY() { + return getClientY() + GQuery.document.getScrollTop(); + } + + + +} 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 dbb7e70a..e77540ff 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 @@ -15,14 +15,21 @@ */ package com.google.gwt.query.client.plugins.events; +import static com.google.gwt.query.client.GQuery.$; + import com.google.gwt.core.client.Duration; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.EventTarget; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.js.JsObjectArray; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; +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 as the default event listener in GWT. @@ -48,7 +55,7 @@ public class EventsListener implements EventListener { type = t; function = f; data = d; - if (n!=null) { + if (n != null) { nameSpace = n; } } @@ -69,17 +76,148 @@ public class EventsListener implements EventListener { public boolean hasEventType(int etype) { return (type & etype) == type; } + + @Override + public String toString() { + return "bind function for event type " + type; + } + } + + /** + * {@link BindFunction} used for live() method. + * + */ + private static class LiveBindFunction extends BindFunction { + + // TODO can be a list of BindFunction + Map bindFunctionBySelector; + + LiveBindFunction(int type, String namespace) { + + super(type, namespace, null, null, -1); + bindFunctionBySelector = new HashMap(); + } + + /** + * Add a {@link BindFunction} for a specific css selector + */ + public void addBindFunctionForSelector(String cssSelector, BindFunction f) { + bindFunctionBySelector.put(cssSelector, f); + } + + @Override + public boolean fire(Event event) { + + if (isEmpty()) { + return true; + } + + String[] selectors = bindFunctionBySelector.keySet().toArray( + new String[0]); + + // first element where the event was fired + Element eventTarget = getEventTarget(event); + // last element where the event was dispatched on + Element liveContextElement = getCurrentEventTarget(event); + + if (eventTarget == null || liveContextElement == null) { + return true; + } + + Map> realCurrentTargetBySelector = $(eventTarget).closest( + selectors, liveContextElement); + + // nothing match the selectors + if (realCurrentTargetBySelector.isEmpty()) { + return true; + } + + boolean result = true; + + com.google.gwt.query.client.plugins.events.Event gqEvent = com.google.gwt.query.client.plugins.events.Event.create(event); + + for (String cssSelector : realCurrentTargetBySelector.keySet()) { + BindFunction f = bindFunctionBySelector.get(cssSelector); + for (Element element : realCurrentTargetBySelector.get(cssSelector)) { + gqEvent.setCurrentElementTarget(element); + boolean subResult = f.fire(gqEvent); + result &= subResult; + if (!subResult) { + // Event should not continue to be bubbled, break the second for + break; + } + } + } + + // trick to reset the right currentTarget on the original event on ie + gqEvent.setCurrentElementTarget(liveContextElement); + + return result; + + } + + /** + * Remove the BindFunction associated to this cssSelector + */ + public BindFunction removeBindFunctionForSelector(String cssSelector) { + return bindFunctionBySelector.remove(cssSelector); + } + + /** + * Tell if no {@link BindFunction} are linked to this object + * + * @return + */ + public boolean isEmpty() { + return bindFunctionBySelector.isEmpty(); + } + + @Override + public String toString() { + return "live bind function for selector " + + bindFunctionBySelector.keySet(); + } + + /** + * Return the element whose the listener fired last. It represent the + * context element where the {@link LiveBindFunction} was binded + * + */ + private Element getCurrentEventTarget(Event e) { + EventTarget currentEventTarget = e.getCurrentEventTarget(); + + if (!Element.is(currentEventTarget)) { + return null; + } + + return Element.as(currentEventTarget); + } + + /** + * Return the element that was the actual target of the element + */ + private Element getEventTarget(Event e) { + EventTarget eventTarget = e.getEventTarget(); + + if (!Element.is(eventTarget)) { + return null; + } + + return Element.as(eventTarget); + } + } + // Gwt Events class has not this event defined public static int ONSUBMIT = 0x08000; public static void clean(Element e) { EventsListener ret = getGQueryEventListener(e); - if (ret != null){ + if (ret != null) { ret.clean(); - } + } } - + public static EventsListener getInstance(Element e) { EventsListener ret = getGQueryEventListener(e); return ret != null ? ret : new EventsListener(e); @@ -87,9 +225,9 @@ public class EventsListener implements EventListener { public static void rebind(Element e) { EventsListener ret = getGQueryEventListener(e); - if (ret != null && ret.eventBits != 0){ + if (ret != null && ret.eventBits != 0) { ret.sink(); - } + } } private static native void cleanGQListeners(Element elem) /*-{ @@ -100,39 +238,41 @@ public class EventsListener implements EventListener { elem.__gqueryevent = null }-*/; - + private static native EventsListener getGQueryEventListener(Element elem) /*-{ - return elem.__gqueryevent; + return elem.__gqueryevent; }-*/; - + private static native EventListener getGwtEventListener(Element elem) /*-{ - return elem.__gwtlistener; + return elem.__gwtlistener; }-*/; private static native void setGQueryEventListener(Element elem, EventsListener gqevent) /*-{ - if (elem.__gqueryevent) { - elem.__listener = elem.__gqueryevent; - } else { - elem.__gwtlistener = elem.__listener; - elem.__gqueryevent = gqevent; - } + if (elem.__gqueryevent) { + elem.__listener = elem.__gqueryevent; + } else { + elem.__gwtlistener = elem.__listener; + elem.__gqueryevent = gqevent; + } }-*/; // Gwt does't handle submit events in DOM.sinkEvents private static native void sinkSubmitEvent(Element elem) /*-{ - if (elem.__gquerysubmit) return; - elem.__gquerysubmit = true; - - var handle = function(event) { - elem.__gqueryevent.@com.google.gwt.query.client.plugins.events.EventsListener::dispatchEvent(Lcom/google/gwt/user/client/Event;)(event); - }; - - if (elem.addEventListener) - elem.addEventListener("submit", handle, true); - else - elem.attachEvent("onsubmit", handle); + if (elem.__gquerysubmit) + return; + elem.__gquerysubmit = true; + + var handle = function(event) { + elem.__gqueryevent.@com.google.gwt.query.client.plugins.events.EventsListener::dispatchEvent(Lcom/google/gwt/user/client/Event;)(event); + }; + + if (elem.addEventListener) + elem.addEventListener("submit", handle, true); + else + elem.attachEvent("onsubmit", handle); }-*/; + int eventBits = 0; double lastEvnt = 0; @@ -140,14 +280,14 @@ public class EventsListener implements EventListener { private Element element; - private JsObjectArray elementEvents = JsObjectArray - .createArray().cast(); - + private JsObjectArray elementEvents = JsObjectArray.createArray().cast(); + private Map liveBindFunctionByEventType = new HashMap(); + private EventsListener(Element element) { this.element = element; } - - public void bind(int eventbits, final Object data, Function...funcs) { + + public void bind(int eventbits, final Object data, Function... funcs) { bind(eventbits, null, data, funcs); } @@ -155,25 +295,27 @@ public class EventsListener implements EventListener { int times) { bind(eventbits, null, data, function, times); } - - public void bind(int eventbits, String name, final Object data, Function...funcs) { - for (Function function: funcs) { + + public void bind(int eventbits, String name, final Object data, + Function... funcs) { + for (Function function : funcs) { bind(eventbits, name, data, function, -1); } } - - public void bind(int eventbits, String namespace, final Object data, final Function function, - int times) { + + public void bind(int eventbits, String namespace, final Object data, + final Function function, int times) { if (function == null) { unbind(eventbits, namespace); return; } eventBits |= eventbits; sink(); - elementEvents.add(new BindFunction(eventbits, namespace, function, data, times)); + elementEvents.add(new BindFunction(eventbits, namespace, function, data, + times)); } - - public void bind(String event, final Object data, Function...funcs) { + + public void bind(String event, final Object data, Function... funcs) { String nameSpace = event.replaceFirst("^[^\\.]+\\.*(.*)$", "$1"); String eventName = event.replaceFirst("^([^\\.]+).*$", "$1"); int b = 0; @@ -182,12 +324,25 @@ public class EventsListener implements EventListener { } else { b = Event.getTypeInt(eventName); } - for (Function function: funcs) { + for (Function function : funcs) { bind(b, nameSpace, data, function, -1); } } - + + public void die(String eventName, String cssSelector) { + if (eventName == null) { + for (LiveBindFunction liveBindFunction : liveBindFunctionByEventType.values()) { + liveBindFunction.removeBindFunctionForSelector(cssSelector); + } + } else { + LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(eventName); + liveBindFunction.removeBindFunctionForSelector(cssSelector); + } + + } + public void dispatchEvent(Event event) { + int etype = "submit".equalsIgnoreCase(event.getType()) ? ONSUBMIT : DOM.eventGetType(event); for (int i = 0; i < elementEvents.length(); i++) { @@ -200,16 +355,38 @@ public class EventsListener implements EventListener { } } } - + /** - * Return the original gwt EventListener associated with - * this element, before gquery replaced it to introduce its - * own event handler. + * Return the original gwt EventListener associated with this element, before + * gquery replaced it to introduce its own event handler. */ public EventListener getOriginalEventListener() { return getGwtEventListener(element); } - + + public void live(String eventName, String cssSelector, Object data, Function f) { + int eventType = 0; + if ("submit".equals(eventName)) { + eventType = ONSUBMIT; + } else { + eventType = Event.getTypeInt(eventName); + } + + // is a LiveBindFunction already attached for this kind of event + LiveBindFunction liveBindFunction = liveBindFunctionByEventType.get(eventName); + if (liveBindFunction == null) { + liveBindFunction = new LiveBindFunction(eventType, "live"); + eventBits |= eventType; + sink(); + elementEvents.add(liveBindFunction); + liveBindFunctionByEventType.put(eventName, liveBindFunction); + } + + liveBindFunction.addBindFunctionForSelector(cssSelector, new BindFunction( + eventType, "live", f, data)); + + } + public void onBrowserEvent(Event event) { // Workaround for Issue_20 if (lastType == event.getTypeInt() @@ -224,20 +401,20 @@ public class EventsListener implements EventListener { if (getOriginalEventListener() != null) { getOriginalEventListener().onBrowserEvent(event); } - + dispatchEvent(event); } - + public void unbind(int eventbits) { unbind(eventbits, null); } - + public void unbind(int eventbits, String namespace) { - JsObjectArray newList = JsObjectArray - .createArray().cast(); + JsObjectArray newList = JsObjectArray.createArray().cast(); for (int i = 0; i < elementEvents.length(); i++) { BindFunction listener = elementEvents.get(i); - boolean matchNS = namespace == null || namespace.isEmpty() || listener.nameSpace.equals(namespace); + boolean matchNS = namespace == null || namespace.isEmpty() + || listener.nameSpace.equals(namespace); boolean matchEV = eventbits <= 0 || listener.hasEventType(eventbits); if (matchNS && matchEV) { continue; @@ -246,7 +423,7 @@ public class EventsListener implements EventListener { } elementEvents = newList; } - + public void unbind(String event) { String nameSpace = event.replaceFirst("^[^\\.]+\\.*(.*)$", "$1"); String eventName = event.replaceFirst("^([^\\.]+).*$", "$1"); @@ -258,24 +435,26 @@ public class EventsListener implements EventListener { } unbind(b, nameSpace); } - - private void clean(){ + + private void clean() { cleanGQListeners(element); - elementEvents = JsObjectArray.createArray().cast(); + elementEvents = JsObjectArray.createArray().cast(); + liveBindFunctionByEventType = new HashMap(); } - + private void sink() { setGQueryEventListener(element, this); - DOM.setEventListener((com.google.gwt.user.client.Element)element, this); + DOM.setEventListener((com.google.gwt.user.client.Element) element, this); if (eventBits == ONSUBMIT) { sinkSubmitEvent(element); } else { - if ((eventBits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS && element.getAttribute("tabIndex").length() == 0) { + if ((eventBits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS + && element.getAttribute("tabIndex").length() == 0) { element.setAttribute("tabIndex", "0"); } DOM.sinkEvents((com.google.gwt.user.client.Element) element, eventBits | DOM.getEventsSunk((com.google.gwt.user.client.Element) element)); - + } } } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTest.java index 5d1d7ddf..ed8d3b80 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTest.java @@ -1201,18 +1201,28 @@ public class GQueryCoreTest extends GWTTestCase { public void testClosestMethodWithArrayOfString(){ - String html = "

"; + String html = "

"; $(e).html(html); - Map close = $("input", e).closest(new String[]{"p","div", ".test", "#unknown"}); + Map> close = $("input", e).closest(new String[]{"p","div", ".test", "#unknown"}); assertEquals(3, close.size()); + assertNotNull(close.get("p")); - assertEquals("firstP", close.get("p").getId()); + assertEquals(1,close.get("p").size()); + assertEquals("mainP", close.get("p").get(0).getId()); + assertNotNull(close.get("div")); - assertEquals("firstDiv", close.get("div").getId()); + assertEquals(3,close.get("div").size()); + assertEquals("subSubDiv", close.get("div").get(0).getId()); + assertEquals("subDiv", close.get("div").get(1).getId()); + assertEquals("mainDiv", close.get("div").get(2).getId()); + assertNotNull(close.get(".test")); - assertEquals("mainDiv", close.get(".test").getId()); + assertEquals(2,close.get(".test").size()); + assertEquals("testSpan", close.get(".test").get(0).getId()); + assertEquals("subDiv", close.get(".test").get(1).getId()); + assertNull(close.get("#unknown")); } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTest.java index eb4a9e80..99515ec3 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTest.java @@ -58,10 +58,90 @@ public class GQueryEventsTest extends GWTTestCase { e = testPanel.getElement(); e.setId("evnt-tst"); } else { + EventsListener.clean(e); e.setInnerHTML(""); } } + + + public void testDie() { + $(e).html("
content
"); + $(".clickMe", e).live("click", new Function(){ + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.RED)); + } + }); + + $(".clickMe", e).live("dblclick", new Function(){ + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.BLUE)); + } + }); + + $("#div1",e).addClass("clickMe"); + + $("#div1",e).click(); + assertEquals(RGBColor.RED.getCssName(), $("#div1", e).css(CSS.COLOR)); + + $("#div1",e).dblclick(); + assertEquals(RGBColor.BLUE.getCssName(), $("#div1", e).css(CSS.COLOR)); + + //reset + $("#div1",e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $(".clickMe", e).die("click"); + $("#div1",e).click(); + assertEquals(RGBColor.BLACK.getCssName(), $("#div1", e).css(CSS.COLOR)); + + $("#div1",e).dblclick(); + assertEquals(RGBColor.BLUE.getCssName(), $("#div1", e).css(CSS.COLOR)); + + //reset + $("#div1",e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $(".clickMe", e).die("dblclick"); + + $("#div1",e).dblclick(); + assertEquals(RGBColor.BLACK.getCssName(), $("#div1", e).css(CSS.COLOR)); + + } + + public void testDie2() { + $(e).html("
content
"); + $(".clickMe", e).live("click", new Function(){ + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.RED)); + } + }); + + $(".clickMe", e).live("dblclick", new Function(){ + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.BLUE)); + } + }); + + $("#div1",e).addClass("clickMe"); + + $("#div1",e).click(); + assertEquals(RGBColor.RED.getCssName(), $("#div1", e).css(CSS.COLOR)); + + $("#div1",e).dblclick(); + assertEquals(RGBColor.BLUE.getCssName(), $("#div1", e).css(CSS.COLOR)); + + //reset + $("#div1",e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $(".clickMe", e).die(); + + $("#div1",e).click(); + assertEquals(RGBColor.BLACK.getCssName(), $("#div1", e).css(CSS.COLOR)); + + $("#div1",e).dblclick(); + assertEquals(RGBColor.BLACK.getCssName(), $("#div1", e).css(CSS.COLOR)); + + } + /** * TODO: DblClick doesn't work with HtmlUnit, investigate and report. */ @@ -77,7 +157,7 @@ public class GQueryEventsTest extends GWTTestCase { $("p", e).dblclick(); assertEquals("yellow", $("p", e).css("color")); } - + public void testEventsPlugin() { $(e).html("

Content

"); @@ -184,30 +264,6 @@ public class GQueryEventsTest extends GWTTestCase { $("input", e).keyup('c'); assertEquals("abc", $("input", e).val()); } - - public void testLive() { - $(e).html("
Content 1
"); - $(".clickMe").live(Event.ONCLICK, new Function(){ - public void f(Element e) { - $(e).css("color", "red"); - } - }); - $(e).append("

Content 2

"); - assertEquals("", $("#d1").css("color")); - - $(".clickMe", e).click(); - assertEquals("red", $("div", e).css("color")); - assertEquals("red", $("p", e).css("color")); - - $(".clickMe", e).css("color", "yellow"); - $(".clickMe").die(Event.ONCLICK); - $(e).append("Content 3"); - - $(".clickMe", e).click(); - assertEquals("yellow", $("div", e).css("color")); - assertEquals("yellow", $("p", e).css("color")); - assertEquals("", $("span", e).css("color")); - } public void testLazyMethods() { $(e).css(CSS.COLOR.with(RGBColor.WHITE)); @@ -222,6 +278,92 @@ public class GQueryEventsTest extends GWTTestCase { assertEquals("black", $(e).css("color")); } + public void testLive() { + $(e).html("
Content 1 blop
"); + $(".clickMe", e).live("click", new Function(){ + public void f(Element el) { + $(el).css("color", "red"); + } + }); + + $(e).append("
Content 2
blop
"); + + $(".clickMe", e).click(); + assertEquals("red", $("#div1", e).css("color")); + assertEquals("red", $("#div3", e).css("color")); + + //reset + $("*", e).css(CSS.COLOR.with(RGBColor.BLACK)); + assertEquals("black", $("div", e).css("color")); + assertEquals("black", $("span", e).css("color")); + + $("#span1", e).click(); + assertEquals("red", $("#div1", e).css("color")); + assertEquals("black", $("#div3", e).css("color")); + + //reset + $("*", e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $("#span2", e).click(); + assertEquals("black", $("#div1", e).css("color")); + assertEquals("red", $("#div3", e).css("color")); + + //reset + $("*", e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $("#div2, #div4", e).addClass("clickMe"); + + $("#span1", e).click(); + assertEquals("red", $("#div1", e).css("color")); + assertEquals("red", $("#div2", e).css("color")); + assertEquals("black", $("#div3", e).css("color")); + assertEquals("black", $("#div4", e).css("color")); + + //reset + $("*", e).css(CSS.COLOR.with(RGBColor.BLACK)); + + $("#span2", e).click(); + assertEquals("black", $("#div1", e).css("color")); + assertEquals("black", $("#div2", e).css("color")); + assertEquals("red", $("#div3", e).css("color")); + assertEquals("red", $("#div4", e).css("color")); + + } + + public void testLive2() { + + $(e).html("
Content 1 blop
"); + + $(".clickable", e).live("click", new Function(){ + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.RED)); + } + }); + + $(".clickable2", e).live("click", new Function(){ + public void f(Element e) { + $(e).css(CSS.COLOR.with(RGBColor.BLUE)); + } + }); + + $(".hover", e).live("mouseover", new Function(){ + public void f(Element e) { + $(e).css(CSS.BACKGROUND_COLOR.with(RGBColor.YELLOW)); + } + }); + + $("#div1", e).addClass("clickable"); + $("#div2", e).addClass("clickable2", "hover"); + + $("#span1", e).click(); + + assertEquals("red", $("#div1", e).css(CSS.COLOR)); + assertEquals("blue", $("#div2", e).css(CSS.COLOR)); + assertNotSame("yellow", $("#div2", e).css(CSS.BACKGROUND_COLOR)); + + + } + public void testNamedBinding() { $(e).html("

Content

"); @@ -269,6 +411,18 @@ public class GQueryEventsTest extends GWTTestCase { assertEquals(12.0d, $("p", e).cur("fontSize", true)); } + public void testRebind() { + final GQuery b = $("

content

"); + b.click(new Function() { + public void f(Element e){ + b.css(CSS.COLOR.with(RGBColor.RED)); + } + }); + $(e).append(b); + b.click(); + assertEquals("red", $(b).css("color")); + } + public void testSubmitEvent() { // Add a form and an iframe to the dom. The form target is the iframe $(e).html("