]> source.dussan.org Git - gwtquery.git/commitdiff
Implement live and die methods, fixes issue#69. Little changes in .js package
authorManolo Carrasco <manolo@apache.org>
Mon, 4 Apr 2011 12:20:03 +0000 (12:20 +0000)
committerManolo Carrasco <manolo@apache.org>
Mon, 4 Apr 2011 12:20:03 +0000 (12:20 +0000)
gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java
gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java
gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java
gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java
gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsMap.java
gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsObjectArray.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTest.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTest.java

index f26e70e396b78546cfc78253e58fc239288c76e3..cfbc6be0804b050ea0a575f18ec8e29f521686ba 100644 (file)
@@ -107,7 +107,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    */\r
   public static final Element window = window();\r
 \r
-  private static JsCache dataCache = null;\r
+  protected static JsCache dataCache = null;\r
 \r
   private static SelectorEngine engine;\r
 \r
@@ -115,7 +115,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       FUNC_BEFORE = 3;\r
 \r
   private static final String OLD_DATA_PREFIX = "old-";\r
-\r
+  \r
   private static JsMap<Class<? extends GQuery>, Plugin<? extends GQuery>> plugins;\r
 \r
   private static DocumentStyleImpl styleImpl = GWT.create(DocumentStyleImpl.class);\r
@@ -216,7 +216,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
           : ctx.getOwnerDocument();\r
       return $(cleanHtmlString(selectorOrHtml, doc));\r
     }\r
-    return new GQuery(select(selectorOrHtml, ctx));\r
+    return new GQuery(select(selectorOrHtml, ctx)).setSelector(selectorOrHtml);\r
   }\r
 \r
   /**\r
@@ -231,7 +231,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
     try {\r
       if (plugins != null) {\r
         T gquery = (T) plugins.get(plugin).init(\r
-            new GQuery(select(selector, context)));\r
+            new GQuery(select(selector, context))).setSelector(selector);\r
         return gquery;\r
       }\r
       throw new RuntimeException("No plugin for class " + plugin);\r
@@ -348,7 +348,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       n = n.getLastChild();\r
     }\r
     // TODO: add fixes for IE TBODY issue\r
-    return $((NodeList<Element>) n.getChildNodes().cast());\r
+    return $((NodeList<Element>) n.getChildNodes().cast()).as(Events).addLiveEvents();\r
   }\r
 \r
   protected static <S> Object data(Element item, String name, S value) {\r
@@ -463,7 +463,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
                return $wnd;\r
   }-*/;\r
 \r
-  private String currentSelector;\r
+  protected String currentSelector;\r
 \r
   private NodeList<Element> elements = JavaScriptObject.createArray().cast();\r
 \r
@@ -772,7 +772,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
     } else if (plugins != null) {\r
       Plugin<?> p = plugins.get(plugin);\r
       if (p != null) {\r
-        return (T) p.init(this);\r
+        return (T) p.init(this).setSelector(currentSelector);\r
       }\r
     }\r
     throw new RuntimeException("No plugin registered for class "\r
@@ -788,7 +788,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   public GQuery attr(Properties properties) {\r
     for (Element e : elements()) {\r
       for (String name : properties.keys()) {\r
-        e.setAttribute(name, properties.get(name));\r
+        e.setAttribute(name, properties.getStr(name));\r
       }\r
     }\r
     return this;\r
@@ -957,7 +957,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
     for (Element e : elements()) {\r
       result.addNode(e.cloneNode(true));\r
     }\r
-    return new GQuery(result);\r
+    return new GQuery(result).as(Events).addLiveEvents();\r
   }\r
 \r
   /**\r
@@ -1067,7 +1067,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    */\r
   public GQuery css(Properties properties) {\r
     for (String property : properties.keys()) {\r
-      css(property, properties.get(property));\r
+      css(property, properties.getStr(property));\r
     }\r
     return this;\r
   }\r
@@ -1283,6 +1283,15 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
     return remove(filter, false);\r
   }\r
   \r
+  /**\r
+   * Remove all event handlers previously attached using live()\r
+   * The selector used with it must match exactly the selector initially\r
+   * used with live().\r
+   */\r
+  public GQuery die(int eventbits) {\r
+    return as(Events).die(eventbits);\r
+  }\r
+  \r
   /**\r
    * Run one or more Functions over each element of the GQuery. You have to\r
    * override one of these funcions: public void f(Element e) public String\r
@@ -1626,7 +1635,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       }\r
       e.setInnerHTML(html);\r
     }\r
-    return this;\r
+    return as(Events).addLiveEvents();\r
   }\r
 \r
   /**\r
@@ -1795,6 +1804,14 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   public int length() {\r
     return size();\r
   }\r
+  \r
+  /**\r
+   * Add events to all elements which match the current selector,\r
+   * now and in the future.\r
+   */\r
+  public GQuery live(int eventBits, Function... funcs) {\r
+    return as(Events).live(eventBits, funcs);\r
+  }\r
 \r
   /**\r
    * Bind a function to the load event of each matched element.\r
@@ -1818,6 +1835,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    */\r
   @SuppressWarnings("unchecked")\r
   public <W> List<W> map(Function f) {\r
+    @SuppressWarnings("rawtypes")\r
     ArrayList ret = new ArrayList();\r
     for (int i = 0; i < elements().length; i++) {\r
       Object o = f.f(elements()[i], i);\r
@@ -2594,8 +2612,9 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
     this.previousObject = previousObject;\r
   }\r
 \r
-  public void setSelector(String selector) {\r
+  public GQuery setSelector(String selector) {\r
     this.currentSelector = selector;\r
+    return this;\r
   }\r
 \r
   /**\r
@@ -3398,4 +3417,5 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       dataCache.delete(id);\r
     }\r
   }\r
+\r
 }\r
index b9417e2812cca394577f727a43341d01d25bca08..402d782fc5bd818cb7002ee96408f4761d00d541 100644 (file)
@@ -621,6 +621,13 @@ public interface LazyGQuery<T> extends LazyBase<T>{
    */
   LazyGQuery<T> 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().
+   */
+  LazyGQuery<T> die(int eventbits);
+
   /**
    * 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
@@ -938,6 +945,12 @@ public interface LazyGQuery<T> extends LazyBase<T>{
    */
   int length();
 
+  /**
+   * Add events to all elements which match the current selector,
+   * now and in the future.
+   */
+  LazyGQuery<T> live(int eventBits, Function... funcs);
+
   /**
    * Bind a function to the load event of each matched element.
    */
@@ -1387,7 +1400,7 @@ public interface LazyGQuery<T> extends LazyBase<T>{
 
   void setPreviousObject(GQuery previousObject);
 
-  void setSelector(String selector);
+  LazyGQuery<T> setSelector(String selector);
 
   /**
    * Make all matched elements visible
index 9c5f3a90f300ef60624b00f7a7a53f15b2f4cd24..c95d40052f05a70f567bf2f061981e3d7243b305 100644 (file)
@@ -34,6 +34,10 @@ public class Properties extends JavaScriptObject {
       return (Properties) createImpl("({})");\r
     }\r
   }\r
+  \r
+  public static Properties create() {\r
+    return (Properties) createImpl("({})");\r
+  }\r
 \r
   public static final native JavaScriptObject createImpl(String properties) /*-{\r
      return eval(properties);\r
@@ -66,10 +70,14 @@ public class Properties extends JavaScriptObject {
     return this[name] != undefined;  \r
   }-*/;\r
 \r
-  public final native String get(String name) /*-{\r
+  public final native <T> T get(String name) /*-{\r
     return this[name];\r
   }-*/;\r
 \r
+  public final native String getStr(String name) /*-{\r
+    return String(this[name]);\r
+  }-*/;\r
+\r
   public final native float getFloat(String name) /*-{\r
     return this[name];\r
   }-*/;\r
@@ -99,14 +107,14 @@ public class Properties extends JavaScriptObject {
     return keys;\r
   }-*/;\r
 \r
-  public final native void set(String key, String val) /*-{\r
+  public final native void set(String key, Object val) /*-{\r
     this[key]=val;\r
   }-*/;\r
   \r
   public final String tostring() {\r
     String ret = "";\r
     for (String k : keys()){\r
-      ret += k + ": '" + get(k) + "', ";\r
+      ret += k + ": '" + getStr(k) + "', ";\r
     }\r
     return "({" + ret.replaceAll("[, ]+$","") + "})";\r
   }\r
index 1848f34941a9cba9cac71fe7ad7ca31dfa363e67..a805bc6cd122c03c1ca3b1e897df54cbf09d419b 100644 (file)
@@ -1,6 +1,7 @@
 package com.google.gwt.query.client.js;
 
 import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
 
  /**
    * A Lightweight JSO class to store data.
@@ -9,6 +10,10 @@ public class JsCache extends JavaScriptObject {
 
   protected JsCache() {
   }
+  
+  public static JsCache create() {
+    return createObject().cast();
+  }
 
   public final native void concat(Object ary) /*-{
     if (ary) this.concat(ary);
@@ -29,15 +34,19 @@ public class JsCache extends JavaScriptObject {
                delete this[name];
   }-*/;
 
+  public final native boolean exists(String name) /*-{
+    return !!this[name];
+  }-*/;
+  
   public final native boolean exists(int id) /*-{
                return !!this[id];
   }-*/;
 
-  public final native Object get(int id) /*-{
+  public final native <T> T get(int id) /*-{
                return this[id] || null;
   }-*/;
 
-  public final native Object get(String id) /*-{
+  public final native <T> T get(String id) /*-{
                return this[id] || null;
   }-*/;
 
@@ -87,4 +96,49 @@ public class JsCache extends JavaScriptObject {
   public final native int length() /*-{
     return this.length;
   }-*/;
+  
+  public final int[] indexes() {
+    JsArrayString a = keysImpl();
+    int[] ret = new int[a.length()];
+    for (int i = 0; i < a.length(); i++) {
+      try {
+        ret[i] = Integer.valueOf(a.get(i));
+      } catch (Exception e) {
+        ret[i] = i;
+      }
+    }
+    return ret;
+  }
+  
+  public final String[] keys() {
+    JsArrayString a = keysImpl();
+    String[] ret = new String[a.length()];
+    for (int i = 0; i < a.length(); i++) {
+      ret[i] = a.get(i);
+    }
+    return ret;
+  }
+  
+  public final Object[] elements() {
+    String[] keys = keys();
+    Object[] ret = new Object[keys.length];
+    int i=0;
+    for (String s: keys) {
+      ret[i++] = get(s);
+    }
+    return ret;
+  }
+  
+  public final native Object[] elemImpl() /*-{
+    var key, ret=[];
+    for(key in this) ret.push(this[key]);
+    return ret;
+  }-*/;
+
+
+  public final native JsArrayString keysImpl() /*-{
+    var key, keys=[];
+    for(key in this) keys.push("" + key);
+    return keys;
+  }-*/;
 }
index 2931a66a0dc48c3f8f3ded9c776d3998e4fa919b..41ab52d8628d06dcb923d3b548ef1c817e9a7de3 100644 (file)
@@ -16,6 +16,7 @@
 package com.google.gwt.query.client.js;
 
 import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayString;
 
 
 /**
@@ -42,5 +43,9 @@ final public class JsMap<S, T> extends JavaScriptObject {
   public void put(S key, T val) {
     c().put(key.hashCode(), val);
   }
+  
+  public final String[] keys() {
+    return c().keys();
+  }
 
 }
index 839292d3b2398af6e2d71227fb2f5c1b0b7e9124..81a7290f06629960c6c1c443d7945905c8cacd84 100644 (file)
@@ -15,6 +15,9 @@
  */
 package com.google.gwt.query.client.js;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+
 import com.google.gwt.core.client.JavaScriptObject;
 
 /**
@@ -33,8 +36,10 @@ public final class JsObjectArray<T> extends JavaScriptObject {
     return cast();
   }
 
-  public void add(T val) {
-    c().put(length(), val);
+  public void add(T...vals) {
+    for (T t: vals) {
+      c().put(length(), t);
+    }
   }
 
   public void add(int i, T val) {
@@ -61,4 +66,5 @@ public final class JsObjectArray<T> extends JavaScriptObject {
   public void pushAll(JavaScriptObject prevElem) {
     c().pushAll(prevElem);
   }
+
 }
index 2dc8f7855a6f55acd89db286fdc72e5c0cc2b32d..d8e5d52b7db48a5e704ea332cbb49c073043037b 100644 (file)
@@ -19,6 +19,8 @@ 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;
 
@@ -28,6 +30,8 @@ import com.google.gwt.user.client.Event;
 public class Events extends GQuery {
 
   public static final Class<Events> Events = Events.class;
+  
+  protected static final String LIVE_ID_DATA = "_lid_";
 
   static {
     GQuery.registerPlugin(Events.class, new Plugin<Events>() {
@@ -98,6 +102,53 @@ public class Events extends GQuery {
     return this;
   }
   
+  /**
+   * Remove all event handlers previously attached using live()
+   * The selector used with it must match exactly the selector initially
+   * used with live().
+   */
+  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);
+    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<Function> functions = cache.get(eventBits);
+    if (functions == null) {
+      functions = JsObjectArray.create().cast();
+      cache.put(eventBits, functions);
+    }
+    functions.add(funcs);
+    bind(eventBits, null, funcs);
+    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.
@@ -167,7 +218,6 @@ public class Events extends GQuery {
       triggerHtmlEvent("submit");
     return this;
   }
-  
 
   /**
    * Trigger a html event in all matched elements.
@@ -224,4 +274,23 @@ public class Events extends GQuery {
       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<Function> functions = cache.get(eventBits);
+            for (int j = 0; j<functions.length(); j++) {
+              g.bind(eventBits, null, functions.get(j));
+            }
+          }
+        }
+      }
+    }
+    return this;
+  }
 }
index 1b79330793e3b3c900416d4c6712c94d6776697d..4b5108c970a41a0117c47b5a90d42318ef22bdf6 100644 (file)
@@ -18,6 +18,8 @@ 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;
 import com.google.gwt.query.client.LazyBase;
@@ -67,6 +69,19 @@ public interface LazyEvents<T> extends LazyBase<T>{
    */  
   LazyEvents<T> 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);
+
+  /**
+   * Add events to all elements which match the current selector,
+   * now and in the future.
+   */
+  GQuery live(int eventBits, Function... funcs);
+
   /**
    * Binds a handler to a particular Event (like Event.ONCLICK) for each matched
    * element. The handler is executed only once for each element.
index a5669535654d98dad5a11c8aeedc152766ce1906..e681da13bd73dbe6f6a453646f14ab8bcd9f2db0 100755 (executable)
@@ -187,7 +187,7 @@ public class PropertiesAnimation extends Animation {
     Effect fx;\r
     //g.show();\r
     for (String key : prps.keys()) {\r
-      String val = prps.get(key);\r
+      String val = prps.getStr(key);\r
       if ((fx = computeFxProp(e, key, val, hidden)) != null) {\r
         effects.add(fx);\r
         resize = resize || "height".equals(key) || "width".equals(key);\r
index 2dcd4517984c8b83563aad92be1c3df5add0358a..b3f04364f9e9f4a6a5822148d212b4a66d79bf50 100644 (file)
@@ -490,11 +490,11 @@ public class GQueryCoreTest extends GWTTestCase {
   public void testProperties() {
     Properties p = $$("border:'1px solid black'");
     assertEquals(1, p.keys().length);
-    assertNotNull(p.get("border"));
+    assertNotNull(p.getStr("border"));
 
     p = $$("({border:'1px solid black'})");
     assertEquals(1, p.keys().length);
-    assertNotNull(p.get("border"));
+    assertNotNull(p.getStr("border"));
   }
 
   public void testRelativeMethods() {
@@ -1163,5 +1163,5 @@ public class GQueryCoreTest extends GWTTestCase {
     assertEquals(expectedHtml, $(e).html());
     
   }
-
 }
index a98833628796284f1dc085da15be31433abc430a..eb4a9e80757d86b68127ee738259176c9be3b9b5 100644 (file)
@@ -185,6 +185,30 @@ public class GQueryEventsTest extends GWTTestCase {
     assertEquals("abc", $("input", e).val());
   }
 
+  public void testLive() {
+    $(e).html("<div class='clickMe'>Content 1</div>");
+    $(".clickMe").live(Event.ONCLICK, new Function(){
+      public void f(Element e) {
+        $(e).css("color", "red");
+      }
+    });
+    $(e).append("<p class='clickMe'>Content 2</p>");
+    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("<span class='clickMe'>Content 3</span>");
+    
+    $(".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));
     assertEquals("white", $(e).css("color"));
@@ -354,6 +378,6 @@ public class GQueryEventsTest extends GWTTestCase {
     $("#test").focus(new Function(){});
     
     assertEquals($("#test").attr("tabIndex"), "2");
-    
   }
+
 }