From 19162b28d641772d19c12974333a25d06e8299dd Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Mon, 28 Mar 2011 14:55:52 +0000 Subject: [PATCH] Call rebind whenenver an element is reattached to the DOM, and clean events and data only if the remove method is called with "true" arg --- .../com/google/gwt/query/client/GQuery.java | 31 +++++--- .../client/plugins/events/EventsListener.java | 77 ++++++++++++------- .../gwt/query/client/GQueryEventsTest.java | 22 +++++- 3 files changed, 90 insertions(+), 40 deletions(-) diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java index bfa35e91..e66cc950 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 @@ -1058,17 +1058,15 @@ public class GQuery implements Lazy { * whenever you create a new iframe and you want to add dynamic content to it. */ public GQuery empty() { - // TODO: add memory leak cleanup, remove event handlers for (Element e : elements()) { if (e.getNodeType() == Element.DOCUMENT_NODE) { emptyDocument(e. cast()); } else { Node c = e.getFirstChild(); while (c != null) { - $(c).unbind(0); removeData(c.cast(), null); GqUi.detachWidget(getAssociatedWidget(e)); - Widget w = getAssociatedWidget(e); + EventsListener.getInstance(c.cast()).clean(); e.removeChild(c); c = e.getFirstChild(); } @@ -1989,18 +1987,28 @@ public class GQuery implements Lazy { */ public GQuery remove() { for (Element e : elements()) { - $(e).unbind(0); - removeData(e, null); Widget w = getAssociatedWidget(e); - if (w != null && w.isAttached()) { + if (w != null) { w.removeFromParent(); - } else if (e.getParentNode() != null) { - e.getParentNode().removeChild(e); + } else { + e.removeFromParent(); } } return this; } + /** + * Removes all matched elements from the DOM and cleans their data and bound events. + */ + public GQuery remove(boolean clean) { + for (Element e : elements()) { + EventsListener.getInstance(e).clean(); + removeData(e, null); + } + remove(); + return this; + } + /** * Remove the named attribute from every element in the matched set. */ @@ -2871,8 +2879,8 @@ public class GQuery implements Lazy { e = e. cast().getBody(); } for (int j = 0; j < g.size(); j++) { - /*Widget w = getAssociatedWidget(g.get(j)); - GqUi.detachWidget(w);*/ +// Widget w = getAssociatedWidget(g.get(j)); +// GqUi.detachWidget(w); Node n = g.get(j); if (g.size() > 1) { n = n.cloneNode(true); @@ -2892,7 +2900,8 @@ public class GQuery implements Lazy { newNodes.addNode(e.getParentNode().insertBefore(n, e)); break; } - //GqUi.attachWidget(w); + EventsListener.getInstance(n.cast()).rebind(); +// GqUi.attachWidget(w); } } if (newNodes.size() > g.size()) { 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 69efd260..1e15efbc 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 @@ -74,21 +74,32 @@ public class EventsListener implements EventListener { public static int ONSUBMIT = 0x08000; public static EventsListener getInstance(Element e) { - EventsListener ret = getGQueryEventLinstener(e); + EventsListener ret = getGQueryEventListener(e); return ret != null ? ret : new EventsListener(e); } - private static native EventsListener getGQueryEventLinstener(Element elem) /*-{ + private static native EventsListener getGQueryEventListener(Element elem) /*-{ return elem.__gqueryevent; }-*/; - private static native EventListener getOriginalEventListener(Element elem) /*-{ - return elem.__listener; + 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) /*-{ - 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 @@ -106,22 +117,17 @@ public class EventsListener implements EventListener { elem.attachEvent("onsubmit", handle); }-*/; - double lastEvnt=0; - int lastType=0; - + double lastEvnt = 0; + int lastType = 0; + int eventBits = 0; private Element element; private JsObjectArray elementEvents = JsObjectArray .createArray().cast(); - private EventListener originalEventListener; - private EventsListener(Element element) { this.element = element; - originalEventListener = getOriginalEventListener(element); - setGQueryEventListener(element, this); - DOM.setEventListener((com.google.gwt.user.client.Element) element, this); } public void bind(int eventbits, final Object data, Function...funcs) { @@ -145,17 +151,8 @@ public class EventsListener implements EventListener { unbind(eventbits, namespace); return; } - - 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)); - - } + eventBits |= eventbits; + sink(); elementEvents.add(new BindFunction(eventbits, namespace, function, data, times)); } @@ -173,6 +170,21 @@ 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); @@ -193,10 +205,11 @@ public class EventsListener implements EventListener { * own event handler. */ public EventListener getOriginalEventListener() { - return originalEventListener; + return getGwtEventListener(element); } public void onBrowserEvent(Event event) { + System.out.println(event.getType() + " " + element.getTagName()); // Workaround for Issue_20 if (lastType == event.getTypeInt() && lastEvnt - Duration.currentTimeMillis() < 10 @@ -207,8 +220,9 @@ public class EventsListener implements EventListener { lastType = event.getTypeInt(); // Execute the original Gwt listener - if (originalEventListener != null) { - originalEventListener.onBrowserEvent(event); + if (getOriginalEventListener() != null) { + System.out.println("original"); + getOriginalEventListener().onBrowserEvent(event); } dispatchEvent(event); @@ -244,4 +258,13 @@ public class EventsListener implements EventListener { } unbind(b, nameSpace); } + + public void rebind() { + sink(); + } + + public void clean() { + cleanGQListeners(); + elementEvents = JsObjectArray.createArray().cast(); + } } 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 c62323c2..a9883362 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 @@ -287,12 +287,30 @@ public class GQueryEventsTest extends GWTTestCase { } }); RootPanel.get().add(b); - $("button").click(lazy().css(CSS.COLOR.with(RGBColor.RED)).done()); + $(b).click(lazy().css(CSS.COLOR.with(RGBColor.RED)).done()); - $("button").click(); + $(b).click(); assertEquals("red", $("button").css("color")); assertEquals("black", $("button").css("background-color")); RootPanel.get().remove(b); + + $(e).append($(b)); + $(b).css(CSS.COLOR.with(RGBColor.YELLOW), CSS.BACKGROUND_COLOR.with(RGBColor.BLUE)); + $(b).click(); + assertEquals("red", $("button").css("color")); + assertEquals("black", $("button").css("background-color")); + } + + 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 testUnbindMultipleEvents() { -- 2.39.5