]> source.dussan.org Git - gwtquery.git/commitdiff
Implement API based on jQuery for special events
authorManolo Carrasco <manolo@apache.org>
Sun, 21 Dec 2014 07:30:53 +0000 (08:30 +0100)
committerManolo Carrasco <manolo@apache.org>
Sun, 21 Dec 2014 07:48:32 +0000 (08:48 +0100)
- SpecialEvents have an API with three methods: setup tearDown add remove
- Migrated mouse special events to use this API

devtest/pom.xml
devtest/src/main/java/com/google/gwt/query/DevTestRunner.gwt.xml
gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.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/events/EventsListener.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java

index 2ba9006186856f7d2e8223d984ae0b0b0bc7b6e9..36100cdef6f90b59e367063ab16f2a9a27dd3e5e 100644 (file)
         </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>
                 </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>
index b3ce809fee994537dc0c9cd38e8493b54ae8d098..373d2f1593e4a2488eeba81ca07bd73096d46a8c 100644 (file)
@@ -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>
 
index 098cb2da89e7e329cf301b3f54c192d3e894d28b..3702f010892d0f21565fa4732a390c4907a11509 100644 (file)
@@ -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);
   }
 
   /**
index 101ae0b997f5e47a992235b44f7a0fc4feb4e9e0..a16230f05e3c26b6573355efb7a2993e7a6ca746 100644 (file)
@@ -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) {
index aef9d87618e5434895aa67bb8450e898d946bbd4..9418238569999b2f10125b4f3babd2636ac74f5b 100644 (file)
@@ -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);
     }
   }
 
index 1a92374f65e9f0d03662ba06de2c60b6a5cc2045..d6475c1fba47df133f915e058a73c12a7b9225bf 100644 (file)
@@ -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;
index 98700235b5766bff36b6c0636b131bacfd2a2f3f..33e185e35de253698a42714d734012f1e74fbf73 100644 (file)
@@ -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'/>");