diff options
author | Manolo Carrasco <manolo@apache.org> | 2014-12-21 08:30:53 +0100 |
---|---|---|
committer | Manolo Carrasco <manolo@apache.org> | 2014-12-21 08:48:32 +0100 |
commit | 7a54cd8a80b59cfbe6f69bc782e14a23fa83625a (patch) | |
tree | 82510a2ab430da7360a65c5a0b3119061081c7be | |
parent | 8d14bba23b22cc88312dcefd6e2a8e9cabfb37b2 (diff) | |
download | gwtquery-7a54cd8a80b59cfbe6f69bc782e14a23fa83625a.tar.gz gwtquery-7a54cd8a80b59cfbe6f69bc782e14a23fa83625a.zip |
Implement API based on jQuery for special events
- SpecialEvents have an API with three methods: setup tearDown add remove
- Migrated mouse special events to use this API
7 files changed, 160 insertions, 146 deletions
diff --git a/devtest/pom.xml b/devtest/pom.xml index 2ba90061..36100cde 100644 --- a/devtest/pom.xml +++ b/devtest/pom.xml @@ -33,29 +33,12 @@ </dependency> </dependencies> <build> - <resources> - <resource> - <directory>${basedir}/src/main/java</directory> - </resource> - <resource> - <directory>${basedir}/src/main/resources</directory> - </resource> - </resources> - <testResources> - <testResource> - <directory>${basedir}/src/test/java</directory> - </testResource> - <testResource> - <directory>${basedir}/src/test/resources</directory> - </testResource> - </testResources> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>gwt-maven-plugin</artifactId> <version>${gwtmaven}</version> <configuration> - <!-- <style>PRETTY</style> --> <gwtVersion>${gwtversion}</gwtVersion> <modules> <module>com.google.gwt.query.DevTestRunner</module> @@ -73,22 +56,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-eclipse-plugin</artifactId> - <configuration> - <downloadSources>true</downloadSources> - <downloadJavadocs>false</downloadJavadocs> - <additionalBuildcommands> - <buildCommand> - <name>com.google.gwt.eclipse.core.gwtProjectValidator</name> - </buildCommand> - </additionalBuildcommands> - <additionalProjectnatures> - <projectnature>com.google.gwt.eclipse.core.gwtNature</projectnature> - </additionalProjectnatures> - </configuration> - </plugin> </plugins> <outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</outputDirectory> </build> diff --git a/devtest/src/main/java/com/google/gwt/query/DevTestRunner.gwt.xml b/devtest/src/main/java/com/google/gwt/query/DevTestRunner.gwt.xml index b3ce809f..373d2f15 100644 --- a/devtest/src/main/java/com/google/gwt/query/DevTestRunner.gwt.xml +++ b/devtest/src/main/java/com/google/gwt/query/DevTestRunner.gwt.xml @@ -2,5 +2,6 @@ <inherits name='com.google.gwt.query.Query'/> <entry-point class='com.google.gwt.query.client.DevTestRunner'/> <set-property name="compiler.useSourceMaps" value="false"/> + <add-linker name="xsiframe"/> </module> 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 098cb2da..3702f010 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 @@ -2503,7 +2503,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { * Since GQuery 1.4.0, this method binds handlers for both mouseenter and mouseleave events. */ public GQuery hover(Function fover, Function fout) { - return bind("mouseenter", null, fover).bind("mouseleave", null, fout); + return bind("mouseenter", fover).bind("mouseleave", fout); } /** @@ -2856,7 +2856,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { */ @Deprecated public GQuery load(Function f) { - return bind(Event.ONLOAD, null, f); + return bind(Event.ONLOAD, f); } /** 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 101ae0b9..a16230f0 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 @@ -288,18 +288,7 @@ public class Events extends GQuery { * @functions a set of function to run if the event is not canceled. */ public Events triggerHtmlEvent(String htmlEvent, Object[] datas, final Function... functions) { - SpecialEvent specialEvent = EventsListener.special.get(htmlEvent); - boolean isSpecialEvent = specialEvent != null; - - String originalEventName = htmlEvent; - String delegateEventName = isSpecialEvent ? specialEvent.getDelegateType() : htmlEvent; - - NativeEvent e = document.createHtmlEvent(delegateEventName, true, true); - - if (isSpecialEvent) { - GqEvent.setOriginalEventType(e, originalEventName); - } - + NativeEvent e = document.createHtmlEvent(htmlEvent, true, true); if ("submit".equals(htmlEvent)){ Function submitFunction = new Function() { public void f(Element e) { diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java index aef9d876..94182385 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 @@ -13,6 +13,8 @@ */ 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; @@ -29,10 +31,9 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; -import static com.google.gwt.query.client.GQuery.$; - /** * This class implements an event queue instance for one Element. The queue instance is configured * as the default event listener in GWT. @@ -46,78 +47,112 @@ import static com.google.gwt.query.client.GQuery.$; public class EventsListener implements EventListener { public interface SpecialEvent { - String getDelegateType(); + boolean tearDown(EventsListener l); - String getOriginalType(); + boolean setup(EventsListener l); - Function createDelegateHandler(Function originalHandler); + boolean remove(EventsListener l, String nameSpace, Function f); + + boolean add(EventsListener l, String nameSpace, Object data, Function f); + + String getDelegateType(); + + boolean hasHandlers(EventsListener l); } /** * Used for simulating mouseenter and mouseleave events */ public static class MouseSpecialEvent implements SpecialEvent { - private String originalType; private String delegateType; - + + HashMap<EventListener, MouseSpecialFunction> handlers = new HashMap<EventListener, MouseSpecialFunction>(); + + private class MouseSpecialFunction extends Function { + final EventsListener listener; + public MouseSpecialFunction(EventsListener l) { + listener = l; + } + + public boolean f(Event e, Object... arg) { + EventTarget eventTarget = e.getCurrentEventTarget(); + Element target = eventTarget != null ? eventTarget.<Element> cast() : null; + + EventTarget relatedEventTarget = e.getRelatedEventTarget(); + Element related = relatedEventTarget != null ? relatedEventTarget.<Element> cast() : null; + + if (related == null || (related != target && !GQuery.contains(target, related))) { + for (int i = 0, l = listener.elementEvents.length(); i < l ; i ++) { + BindFunction function = listener.elementEvents.get(i); + if (function.isTypeOf(originalType) && !function.fire(e, arg)) { + return false; + } + } + } + return true; + }; + } + public MouseSpecialEvent(String originalType, String delegateType) { this.originalType = originalType; this.delegateType = delegateType; } - public String getDelegateType() { - return delegateType; + @Override + public boolean add(EventsListener l, String nameSpace, Object data, Function f) { + l.bind(BITLESS, nameSpace, originalType, null, null, f, -1); + return false; } - public String getOriginalType() { - return originalType; + @Override + public boolean remove(EventsListener l, String nameSpace, Function f) { + l.elementEvents = unbindFunctions(l.elementEvents, BITLESS, nameSpace, delegateType, null, f); + return false; } - - public HandlerWrapperFunction createDelegateHandler(Function originalHandler) { - return new HandlerWrapperFunction(originalHandler); + + @Override + public boolean setup(EventsListener l) { + MouseSpecialFunction handler = new MouseSpecialFunction(l); + handlers.put(l, handler); + int b = Event.getTypeInt(delegateType); + l.bind(b, null, delegateType, originalType, null, handler, -1); + return false; } - } - - public interface HandlerWrapper { - Function getOriginalHandler(); - } - - public static class HandlerWrapperFunction extends Function implements HandlerWrapper { - - private Function delegateHandler; - - public HandlerWrapperFunction(Function originalHandler) { - this.delegateHandler = originalHandler; + + @Override + public boolean tearDown(EventsListener l) { + MouseSpecialFunction handler = handlers.remove(l); + if (handler != null) { + int b = Event.getTypeInt(delegateType); + l.unbind(b, null, delegateType, originalType, handler); + } + return false; } @Override - public boolean f(Event e, Object... data) { - EventTarget eventTarget = e.getCurrentEventTarget(); - Element target = eventTarget != null ? eventTarget.<Element> cast() : null; - - EventTarget relatedEventTarget = e.getRelatedEventTarget(); - Element related = relatedEventTarget != null ? relatedEventTarget.<Element> cast() : null; + public String getDelegateType() { + return delegateType; + } - // For mousenter/leave call the handler if related is outside the target. - if (related == null || (related != target && !GQuery.contains(target, related))) { - return delegateHandler != null ? delegateHandler.f(e, data) : false; + @Override + public boolean hasHandlers(EventsListener l) { + for (int i = 0, j = l.elementEvents.length(); i < j; i++) { + BindFunction function = l.elementEvents.get(i); + if (function.isTypeOf(delegateType)) { + return true; + } } - return false; } - - public Function getOriginalHandler() { - return delegateHandler; - } } + private static class BindFunction { Object data; Function function; String nameSpace; - // for special event like mouseleave, mouseenter String originalEventType; int times; int type; @@ -130,7 +165,7 @@ public class EventsListener implements EventListener { this.type = type; this.function = function; this.data = data; - this.originalEventType = originalEventType; +// this.originalEventType = originalEventType; this.nameSpace = nameSpace != null ? nameSpace : ""; } @@ -149,7 +184,10 @@ public class EventsListener implements EventListener { } else { arguments = eventData; } - return function.fe(event, arguments); + // FIXME(manolo): figure out when this is null, and fix or comment it. + if (function != null) { + return function.fe(event, arguments); + } } return true; } @@ -157,6 +195,7 @@ public class EventsListener implements EventListener { public boolean hasEventType(int etype) { return type != BITLESS && etype != BITLESS && (type & etype) != 0; } + public boolean isTypeOf(String eName) { return eventName != null && eventName.equalsIgnoreCase(eName); @@ -185,10 +224,7 @@ public class EventsListener implements EventListener { public boolean isEquals(Function f) { assert f != null : "function f cannot be null"; - Function functionToCompare = - function instanceof HandlerWrapper ? ((HandlerWrapper) function).getOriginalHandler() - : function; - return f.equals(functionToCompare); + return f.equals(function); } public Object getOriginalEventType() { @@ -380,10 +416,10 @@ public class EventsListener implements EventListener { public static String MOUSEENTER = "mouseenter"; public static String MOUSELEAVE = "mouseleave"; - public static JsMap<String, SpecialEvent> special; + public static HashMap<String, SpecialEvent> special; static { - special = JsMap.create(); + special = new HashMap<String, SpecialEvent>(); special.put(MOUSEENTER, new MouseSpecialEvent(MOUSEENTER, "mouseover")); special.put(MOUSELEAVE, new MouseSpecialEvent(MOUSELEAVE, "mouseout")); } @@ -505,26 +541,31 @@ public class EventsListener implements EventListener { //handle special event like mouseenter or mouseleave SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; - - int b = Event.getTypeInt(eventName); + if (hook != null && !hook.hasHandlers(this)) { + hook.setup(this); + } for (Function function : funcs) { - Function handler = hook != null ? hook.createDelegateHandler(function) : function; - bind(b, nameSpace, eventName, originalEventName, data, handler, -1); + if (hook == null) { + int b = Event.getTypeInt(eventName); + if (function != null) { + bind(b, nameSpace, eventName, null, data, function, -1); + } else { + unbind(b, nameSpace, eventName, null, null); + } + } else { + if (function != null) { + hook.add(this, nameSpace, data, function); + } else { + hook.remove(this, nameSpace, function); + } + } } } } - private void bind(int eventbits, String namespace, String eventName, String originalEventType, + public void bind(int eventbits, String namespace, String eventName, String originalEventType, Object data, Function function, int times) { - if (function == null) { - unbind(eventbits, namespace, eventName, originalEventType, null); - return; - } - sink(eventbits, eventName); - elementEvents.add(new BindFunction(eventbits, eventName, namespace, originalEventType, function, data, times)); } @@ -547,15 +588,17 @@ public class EventsListener implements EventListener { //handle special event like mouseenter or mouseleave SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; - + if (hook != null) { + hook.remove(this, nameSpace, null); + if (!hook.hasHandlers(this)) { + hook.tearDown(this); + } + // TODO: MCM handle correctly this + return; + } int b = Event.getTypeInt(eventName); - - die(b, nameSpace, eventName, originalEventName, cssSelector); + die(b, nameSpace, eventName, null, cssSelector); } - - } public void die(int eventbits, String nameSpace, String eventName, String originalEventName, @@ -607,13 +650,10 @@ public class EventsListener implements EventListener { public void dispatchEvent(Event event) { String ename = event.getType(); int etype = Event.getTypeInt(ename); - String originalEventType = GqEvent.getOriginalEventType(event); Object[] handlerData = $(element).data(EVENT_DATA); - for (int i = 0, l = elementEvents.length(); i < l; i++) { BindFunction listener = elementEvents.get(i); - if (listener != null && (listener.hasEventType(etype) || listener.isTypeOf(ename)) - && (originalEventType == null || originalEventType.equals(listener.getOriginalEventType()))) { + if (listener != null && (listener.hasEventType(etype) || listener.isTypeOf(ename))) { if (!listener.fire(event, handlerData)) { event.stopPropagation(); event.preventDefault(); @@ -649,13 +689,16 @@ public class EventsListener implements EventListener { //handle special event like mouseenter or mouseleave SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; + if (hook != null) { +// eventName = hook != null ? hook.getDelegateType() : eventName; +// String originalEventName = hook != null ? hook.getOriginalType() : null; + // FIXME: MCM handle live + return; + } int b = Event.getTypeInt(eventName); for (Function function : funcs) { - Function handler = hook != null ? hook.createDelegateHandler(function) : function; - live(b, nameSpace, eventName, originalEventName, cssSelector, data, handler); + live(b, nameSpace, eventName, null, cssSelector, data, function); } } } @@ -730,13 +773,17 @@ public class EventsListener implements EventListener { public void unbind(int eventbits) { unbind(eventbits, null, null, null, null); } - + public void unbind(int eventbits, String namespace, String eventName, String originalEventType, Function f) { + elementEvents = unbindFunctions(elementEvents, eventbits, namespace, eventName, originalEventType, f); + } + public static JsObjectArray<BindFunction> unbindFunctions(JsObjectArray<BindFunction> list, + int eventbits, String namespace, String eventName, String originalEventType, Function f) { JsObjectArray<BindFunction> newList = JsObjectArray.createArray().cast(); - for (int i = 0; i < elementEvents.length(); i++) { - BindFunction listener = elementEvents.get(i); + for (int i = 0; i < list.length(); i++) { + BindFunction listener = list.get(i); boolean matchNS = isNullOrEmpty(namespace) || listener.nameSpace.equals(namespace); boolean matchEV = eventbits <= 0 || listener.hasEventType(eventbits); @@ -748,7 +795,6 @@ public class EventsListener implements EventListener { if (matchNS && matchEV && matchEVN && matchFC && matchOEVT) { int currentEventbits = listener.unsink(eventbits); - if (currentEventbits == 0) { // the BindFunction doesn't listen anymore on any events continue; @@ -757,11 +803,10 @@ public class EventsListener implements EventListener { newList.add(listener); } - elementEvents = newList; - + return newList; } - private boolean isNullOrEmpty(String s) { + private static boolean isNullOrEmpty(String s) { return s == null || s.isEmpty(); } @@ -783,13 +828,27 @@ public class EventsListener implements EventListener { } //handle special event - SpecialEvent hook = special.get(eventName); - eventName = hook != null ? hook.getDelegateType() : eventName; - String originalEventName = hook != null ? hook.getOriginalType() : null; - + // TODO(manolo): maybe we can remove this + if (!isNullOrEmpty(nameSpace) && isNullOrEmpty(eventName)) { + for (SpecialEvent hook : special.values()) { + hook.remove(this, nameSpace, f); + if (!hook.hasHandlers(this)) { + hook.tearDown(this); + } + } + } else { + SpecialEvent hook = special.get(eventName); + if (hook != null) { + hook.remove(this, nameSpace, f); + if (!hook.hasHandlers(this)) { + hook.tearDown(this); + } + return; + } + } + int b = Event.getTypeInt(eventName); - - unbind(b, nameSpace, eventName, originalEventName, f); + unbind(b, nameSpace, eventName, null, f); } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java index 1a92374f..d6475c1f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java @@ -23,14 +23,6 @@ import com.google.gwt.user.client.Event; */ public class GqEvent extends Event { - public static native void setOriginalEventType(NativeEvent evt, String originalEventName)/*-{ - evt["__gwtquery_originalEventName"] = originalEventName; - }-*/; - - public static native String getOriginalEventType(Event evt)/*-{ - return evt["__gwtquery_originalEventName"] || null; - }-*/; - // Gwt Events class has not this event defined, // so we have to select one power of 2 which is unused in Event class public static int ONSUBMIT = 0x10000000; diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java index 98700235..33e185e3 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java @@ -43,6 +43,7 @@ import com.google.gwt.query.client.plugins.Events; import com.google.gwt.query.client.plugins.events.EventsListener; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; @@ -383,7 +384,7 @@ public class GQueryEventsTestGwt extends GWTTestCase { $("p", e).click(); assertEquals("white", $("p", e).css("color", false)); - // hover (mouseover, mouseout) + // hover (mouseenter, mouseleave) $("p", e).hover(new Function() { public void f(Element elem) { $(elem).css(CSS.BACKGROUND_COLOR.with(RGBColor.YELLOW)); @@ -397,6 +398,11 @@ public class GQueryEventsTestGwt extends GWTTestCase { assertEquals("yellow", $("p", e).css("background-color", false)); $("p", e).trigger(Event.ONMOUSEOUT); assertEquals("white", $("p", e).css("background-color", false)); + + $("p", e).css(CSS.COLOR.with(RGBColor.WHITE)); + $("p", e).hover(null, null); + $("p", e).trigger(Event.ONMOUSEOVER); + assertEquals("white", $("p", e).css("background-color", false)); // key events $(e).html("<input type='text'/>"); |