Browse Source

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
tags/gwtquery-project-1.4.3
Manolo Carrasco 9 years ago
parent
commit
7a54cd8a80

+ 0
- 33
devtest/pom.xml View File

@@ -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>

+ 1
- 0
devtest/src/main/java/com/google/gwt/query/DevTestRunner.gwt.xml View 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>


+ 2
- 2
gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java View 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);
}

/**

+ 1
- 12
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java View 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) {

+ 149
- 90
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java View 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);
}
}


+ 0
- 8
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java View 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;

+ 7
- 1
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTestGwt.java View 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'/>");

Loading…
Cancel
Save