]> source.dussan.org Git - gwtquery.git/commitdiff
add detach method.
authorJulien Dramaix <julien.dramaix@gmail.com>
Mon, 28 Mar 2011 21:13:39 +0000 (21:13 +0000)
committerJulien Dramaix <julien.dramaix@gmail.com>
Mon, 28 Mar 2011 21:13:39 +0000 (21:13 +0000)
refactoring of the remove() method to be compliant with jQuery documentation
add test for remove and detach methods.
Don't try to clean GQuery events if no one EventListener exists + correct bug in event cleaning

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/plugins/events/EventsListener.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTest.java

index e66cc950d5f7dc1731be63c6c468c96ca0712281..9eee6b24a79daaaee6527c8b50ccc2460172357b 100644 (file)
@@ -1064,9 +1064,9 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       } else {\r
         Node c = e.getFirstChild();\r
         while (c != null) {\r
-          removeData(c.<Element>cast(), null);\r
+          removeData(c.<Element> cast(), null);\r
           GqUi.detachWidget(getAssociatedWidget(e));\r
-          EventsListener.getInstance(c.<Element>cast()).clean();\r
+          EventsListener.clean(c.<Element> cast());\r
           e.removeChild(c);\r
           c = e.getFirstChild();\r
         }\r
@@ -1165,26 +1165,26 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    * filters at once.\r
    */\r
   public GQuery filter(String... filters) {\r
-    \r
+\r
     JsNodeArray array = JsNodeArray.create();\r
-    \r
+\r
     for (String f : filters) {\r
       for (Element e : elements()) {\r
         boolean ghostParent = false;\r
-        \r
-        if (e.getParentNode() == null){\r
+\r
+        if (e.getParentNode() == null) {\r
           DOM.createDiv().appendChild(e);\r
           ghostParent = true;\r
         }\r
-        \r
+\r
         for (Element c : $(f, e.getParentNode()).elements()) {\r
           if (c == e) {\r
             array.addNode(c);\r
             break;\r
           }\r
         }\r
-        \r
-        if(ghostParent){\r
+\r
+        if (ghostParent) {\r
           e.removeFromParent();\r
         }\r
       }\r
@@ -1240,6 +1240,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    * negative index is counted from the end of the matched set.\r
    * \r
    * Example:\r
+   * \r
    * <pre>\r
    *  $("div").get(0) will return the first matched div\r
    *  $("div").get(1) will return the second matched div\r
@@ -1562,7 +1563,6 @@ 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
@@ -1986,26 +1986,62 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    * Removes all matched elements from the DOM.\r
    */\r
   public GQuery remove() {\r
-    for (Element e : elements()) {\r
-      Widget w = getAssociatedWidget(e);\r
-      if (w != null) {\r
-        w.removeFromParent();\r
-      } else {\r
-        e.removeFromParent();\r
-      }\r
-    }\r
-    return this;\r
+    return remove(null, true);\r
+  }\r
+\r
+  /**\r
+   * Removes from the DOM all matched elements filtered by the\r
+   * <code>filter</code>.\r
+   */\r
+  public GQuery remove(String filter) {\r
+    return remove(filter, true);\r
   }\r
 \r
   /**\r
-   * Removes all matched elements from the DOM and cleans their data and bound events.\r
+   * Detach all matched elements from the DOM. This method is the same than\r
+   * {@link #remove()} method except all data and event handlers are not remove\r
+   * from the element. This method is useful when removed elements are to be\r
+   * reinserted into the DOM at a later time.\r
    */\r
-  public GQuery remove(boolean clean) {\r
+  public GQuery detach() {\r
+    return remove(null, false);\r
+  }\r
+\r
+  /**\r
+   * Detach from the DOM all matched elements filtered by the\r
+   * <code>filter</code>.. This method is the same than {@link #remove(String)}\r
+   * method except all data and event handlers are not remove from the element.\r
+   * This method is useful when removed elements are to be reinserted into the\r
+   * DOM at a later time.\r
+   */\r
+  public GQuery detach(String filter) {\r
+    return remove(filter, false);\r
+  }\r
+\r
+  /**\r
+   * Removes all matched elements from the DOM and cleans their data and bound\r
+   * events if the value of <code>clean</code> parameter is set to true. The\r
+   * <code> filter</code> parameter allows to filter the matched set to remove.\r
+   */\r
+  protected GQuery remove(String filter, boolean clean) {\r
+     \r
     for (Element e : elements()) {\r
-      EventsListener.getInstance(e).clean();\r
-      removeData(e, null);\r
+      if (filter == null || $(e).filter(filter).length() == 1) {\r
+        if (clean) {\r
+          //clean data linked to the children\r
+          cleanGQData($(e.getElementsByTagName("*")).elements());\r
+          //clean data linked to the element itself\r
+          cleanGQData(e);\r
+        }\r
+        Widget w = getAssociatedWidget(e);\r
+        if (w != null) {\r
+          w.removeFromParent();\r
+        } else {\r
+          e.removeFromParent();\r
+        }\r
+      }\r
     }\r
-    remove();\r
+\r
     return this;\r
   }\r
 \r
@@ -2877,10 +2913,10 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       // e.getOwnerDocument();\r
       if (e.getNodeType() == Node.DOCUMENT_NODE) {\r
         e = e.<Document> cast().getBody();\r
-      }  \r
+      }\r
       for (int j = 0; j < g.size(); j++) {\r
-//        Widget w = getAssociatedWidget(g.get(j));\r
-//        GqUi.detachWidget(w);\r
+        // Widget w = getAssociatedWidget(g.get(j));\r
+        // GqUi.detachWidget(w);\r
         Node n = g.get(j);\r
         if (g.size() > 1) {\r
           n = n.cloneNode(true);\r
@@ -2900,8 +2936,8 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
             newNodes.addNode(e.getParentNode().insertBefore(n, e));\r
             break;\r
         }\r
-        EventsListener.getInstance(n.<Element>cast()).rebind();\r
-//        GqUi.attachWidget(w);\r
+        EventsListener.getInstance(n.<Element> cast()).rebind();\r
+        // GqUi.attachWidget(w);\r
       }\r
     }\r
     if (newNodes.size() > g.size()) {\r
@@ -2959,4 +2995,11 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       dataCache.delete(id);\r
     }\r
   }\r
+  \r
+  private void cleanGQData(Element... elements){\r
+    for (Element el : elements){\r
+      EventsListener.clean(el);\r
+      removeData(el, null);\r
+    }\r
+  }\r
 }\r
index 98d3d0358e5ec5a44af3d58ab059fa45730703c4..ef43e69d1bbb34475297725ab25ef7c635993d51 100644 (file)
@@ -523,6 +523,7 @@ public interface LazyGQuery<T> extends LazyBase<T>{
    * negative index is counted from the end of the matched set.
    * 
    * Example:
+   * 
    * <pre>
    *  $("div").get(0) will return the first matched div
    *  $("div").get(1) will return the second matched div
@@ -965,6 +966,29 @@ public interface LazyGQuery<T> extends LazyBase<T>{
    */
   LazyGQuery<T> remove();
 
+  /**
+   * Removes from the DOM all matched elements filtered by the
+   * <code>filter</code>.
+   */
+  LazyGQuery<T> remove(String filter);
+
+  /**
+   * Detach all matched elements from the DOM. This method is the same than
+   * {@link #remove()} method except all data and event handlers are not remove
+   * from the element. This method is useful when removed elements are to be
+   * reinserted into the DOM at a later time.
+   */
+  LazyGQuery<T> detach();
+
+  /**
+   * Detach from the DOM all matched elements filtered by the
+   * <code>filter</code>.. This method is the same than {@link #remove(String)}
+   * method except all data and event handlers are not remove from the element.
+   * This method is useful when removed elements are to be reinserted into the
+   * DOM at a later time.
+   */
+  LazyGQuery<T> detach(String filter);
+
   /**
    * Remove the named attribute from every element in the matched set.
    */
index 9bbae7ce03eea18acfd64cd4424478dee35eb418..3903794d6b2e9e38a4e019e4cab1cfde7384749e 100644 (file)
@@ -73,25 +73,35 @@ public class EventsListener implements EventListener {
   // 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){
+      ret.clean();
+    } 
+  }
+
   public static EventsListener getInstance(Element e) {
     EventsListener ret = getGQueryEventListener(e);
     return ret != null ? ret : new EventsListener(e);
   }
 
+  private static native void cleanGQListeners(Element elem) /*-{
+               if (elem.__gwtlistener) {
+                       elem.__listener = elem.__gwtlistener;
+               }
+               elem.__gquerysubmit = null;
+               elem.__gqueryevent = null
+
+  }-*/;
+  
   private static native EventsListener getGQueryEventListener(Element elem) /*-{
     return elem.__gqueryevent;
   }-*/;
-
+  
   private static native EventListener getGwtEventListener(Element elem) /*-{
     return elem.__gwtlistener;
   }-*/;
-  
-  private static native void cleanGQListeners() /*-{
-    elem.__listener = elem.__gwtlistener;
-    elem.__gquerysubmit = null;
-    elem.__gqueryevent = null;
-  }-*/;
-  
+
   private static native void setGQueryEventListener(Element elem,
       EventsListener gqevent) /*-{
     if (elem.__gqueryevent) {
@@ -116,16 +126,16 @@ public class EventsListener implements EventListener {
     else
       elem.attachEvent("onsubmit", handle);
   }-*/;
-
+  int eventBits = 0;
   double lastEvnt = 0;
+
   int lastType = 0;
-  int eventBits = 0;
 
   private Element element;
 
   private JsObjectArray<BindFunction> elementEvents = JsObjectArray
       .createArray().cast();
-
+  
   private EventsListener(Element element) {
     this.element = element;
   }
@@ -133,12 +143,12 @@ public class EventsListener implements EventListener {
   public void bind(int eventbits, final Object data, Function...funcs) {
     bind(eventbits, null, data, funcs);
   }
-  
+
   public void bind(int eventbits, final Object data, final Function function,
       int times) {
     bind(eventbits, null, data, function, times);
   }
-
+  
   public void bind(int eventbits, String name, final Object data, Function...funcs) {
     for (Function function: funcs) {
       bind(eventbits, name, data, function, -1);
@@ -170,21 +180,6 @@ public class EventsListener implements EventListener {
     }
   }
   
-  private void sink() {
-    setGQueryEventListener(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) {
-        element.setAttribute("tabIndex", "0");
-      }
-      DOM.sinkEvents((com.google.gwt.user.client.Element) element, eventBits
-          | DOM.getEventsSunk((com.google.gwt.user.client.Element) element));
-      
-    }
-  }
-  
   public void dispatchEvent(Event event) {
     int etype = "submit".equalsIgnoreCase(event.getType()) ? ONSUBMIT
         : DOM.eventGetType(event);
@@ -226,6 +221,10 @@ public class EventsListener implements EventListener {
     dispatchEvent(event);
   }
   
+  public void rebind() {
+    sink();
+  }
+  
   public void unbind(int eventbits) {
     unbind(eventbits, null);
   }
@@ -257,12 +256,23 @@ public class EventsListener implements EventListener {
     unbind(b, nameSpace);
   }
   
-  public void rebind() {
-    sink();
-  }
-
-  public void clean() {
-    cleanGQListeners();
+  private void clean(){
+    cleanGQListeners(element);
     elementEvents =  JsObjectArray.createArray().cast();
   }
+  
+  private void sink() {
+    setGQueryEventListener(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) {
+        element.setAttribute("tabIndex", "0");
+      }
+      DOM.sinkEvents((com.google.gwt.user.client.Element) element, eventBits
+          | DOM.getEventsSunk((com.google.gwt.user.client.Element) element));
+      
+    }
+  }
 }
index 21365a0172d09e7c5855702991475e6869ca6e07..1a53a88bb874cef53edd486206724f58c9484889 100644 (file)
@@ -978,5 +978,115 @@ public class GQueryCoreTest extends GWTTestCase {
     Assert.assertNull($((String) null).get(-1));
     Assert.assertEquals(0, $((String) null).eq(0).size());
   }
+  
+  public void testRemoveMethod(){
+    String html = "<div id='parent'>parent<div id='child'>child</div></div>";
+    $(e).html(html);
+    
+    Function failCallback = new Function(){
+      @Override
+      public void f() {
+        fail("Event binding not removed");
+      }
+    };
+    
+    Element parent = $("#parent", e).get(0);
+    Element child = $("#child", e).get(0);
+    
+    $("#child", e).data("key", "child");
+    $("#child", e).click(failCallback);
+    $("#parent", e).data("key", "parent");
+    $("#parent", e).click(failCallback);
+    
+    $("#parent", e).remove();
+    
+    assertNull($(child).data("key"));
+    assertNull($(parent).data("key"));
+    //if failCallback is always binded, test fails...
+    $(child).click();
+    $(parent).click();
+    
+    
+    
+  }
+
+  public void testRemoveMethodWithFilter(){
+    String html = "<div id='parent'>parent<div id='child'>child</div></div>";
+    $(e).html(html);
+    
+    Function failCallback = new Function(){
+      @Override
+      public void f() {
+        fail("Event binding not removed");
+      }
+    };
+    
+    Function noFailCallback = new Function(){
+      @Override
+      public void f(Element e) {
+        $(e).css(CSS.BACKGROUND_COLOR.with(RGBColor.RED));
+      }
+    };
+    
+    Element parent = $("#parent", e).get(0);
+    Element child = $("#child", e).get(0);
+    
+    $("#child", e).data("key", "child");
+    $("#child", e).click(failCallback);
+    $("#parent", e).data("key", "parent");
+    $("#parent", e).click(noFailCallback);
+    
+    $("div", e).remove("#child");
+    
+    assertNull($(child).data("key"));
+    assertEquals("parent",$(parent).data("key"));
+    
+    //if failCallback is always binded, test fails...
+    $(child).click();
+    
+    
+    $(parent).click();
+    assertEquals("red", $(parent).css(CSS.BACKGROUND_COLOR));
+    
+    
+  }
+  
+  public void testDetachMethod(){
+    String html = "<div id='parent'>parent<div id='child'>child</div></div>";
+    $(e).html(html);
+    
+    Function noFailCallback = new Function(){
+      @Override
+      public void f(Element e) {
+        $(e).css(CSS.BACKGROUND_COLOR.with(RGBColor.RED));
+      }
+    };
+    
+    Element parent = $("#parent", e).get(0);
+    Element child = $("#child", e).get(0);
+    
+    $("#child", e).data("key", "child");
+    $("#child", e).click(noFailCallback);
+    $("#parent", e).data("key", "parent");
+    $("#parent", e).click(noFailCallback);
+    
+    GQuery $parent = $("#parent", e).detach();
+    
+    assertEquals("child",$(child).data("key"));
+    assertEquals("parent",$(parent).data("key"));
+    
+    $(e).append($parent);
+    
+    assertEquals("child",$("#child", e).data("key"));
+    assertEquals("parent",$("#parent", e).data("key"));
+    
+    $("#child", e).click();
+    assertEquals("red", $(child).css(CSS.BACKGROUND_COLOR));
+    $("#parent", e).click();
+    assertEquals("red", $(parent).css(CSS.BACKGROUND_COLOR));
+    
+    
+    
+  }
 
 }