blob: c894b69491116e35c343458779398d049a8b2e19 [file] [log] [blame]
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package $PACKAGE;
$IMPORTS
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import elemental.events.*;
import elemental.util.*;
import elemental.dom.*;
import elemental.html.*;
import elemental.svg.*;
import elemental.js.util.JsElementalBase;
import java.util.Date;
/**
* A base class containing all of the IDL interfaces which are shared
* between disjoint type hierarchies. Because of the GWT compiler
* SingleJsoImpl restriction that only a single JavaScriptObject
* may implement a given interface, we hoist all of the explicit
* mixin classes into a base JSO used by all of elemental.
*/
public class JsElementalMixinBase $EXTENDS $IMPLEMENTS {
protected JsElementalMixinBase() {}
$!MEMBERS
private static class Remover implements EventRemover {
private final EventTarget target;
private final String type;
private final JavaScriptObject handler;
private final boolean useCapture;
private Remover(EventTarget target, String type, JavaScriptObject handler,
boolean useCapture) {
this.target = target;
this.type = type;
this.handler = handler;
this.useCapture = useCapture;
}
@Override
public void remove() {
removeEventListener(target, type, handler, useCapture);
}
private static Remover create(EventTarget target, String type, JavaScriptObject handler,
boolean useCapture) {
return new Remover(target, type, handler, useCapture);
}
}
// NOTES:
// - This handler/listener structure is currently the same in DevMode and ProdMode but it is
// subject to change. In fact, I would like to use:
// { listener : listener, handleEvent : function() }
// but Firefox doesn't properly support that form of handler for onEvent type events.
// - The handler property on listener can be removed when removeEventListener is removed.
private native static JavaScriptObject createHandler(EventListener listener) /*-{
var handler = listener.handler;
if (!handler) {
handler = $entry(function(event) {
@elemental.js.dom.JsElementalMixinBase::handleEvent(Lelemental/events/EventListener;Lelemental/events/Event;)(listener, event);
});
handler.listener = listener;
// TODO(knorton): Remove at Christmas when removeEventListener is removed.
listener.handler = handler;
}
return handler;
}-*/;
private static class ForDevMode {
private static java.util.Map<EventListener, JavaScriptObject> handlers;
static {
if (!com.google.gwt.core.client.GWT.isScript()) {
handlers = new java.util.HashMap<EventListener, JavaScriptObject>();
}
}
private static JavaScriptObject getHandlerFor(EventListener listener) {
if (listener == null) {
return null;
}
JavaScriptObject handler = handlers.get(listener);
if (handler == null) {
handler = createHandler(listener);
handlers.put(listener, handler);
}
return handler;
}
private native static JavaScriptObject createHandler(EventListener listener) /*-{
var handler = $entry(function(event) {
@elemental.js.dom.JsElementalMixinBase::handleEvent(Lelemental/events/EventListener;Lelemental/events/Event;)(listener, event);
});
handler.listener = listener;
return handler;
}-*/;
private native static EventListener getListenerFor(JavaScriptObject handler) /*-{
return handler && handler.listener;
}-*/;
}
private static class ForProdMode {
private static JavaScriptObject getHandlerFor(EventListener listener) {
return listener == null ? null : createHandler(listener);
}
private native static EventListener getListenerFor(JavaScriptObject handler) /*-{
return handler && handler.listener;
}-*/;
}
private static void handleEvent(EventListener listener, Event event) {
listener.handleEvent(event);
}
private static EventListener getListenerFor(JavaScriptObject handler) {
return com.google.gwt.core.client.GWT.isScript()
? ForProdMode.getListenerFor(handler)
: ForDevMode.getListenerFor(handler);
}
private static JavaScriptObject getHandlerFor(EventListener listener) {
return com.google.gwt.core.client.GWT.isScript()
? ForProdMode.getHandlerFor(listener)
: ForDevMode.getHandlerFor(listener);
}
public native final EventRemover addEventListener(String type, EventListener listener, boolean useCapture) /*-{
var handler = @elemental.js.dom.JsElementalMixinBase::getHandlerFor(Lelemental/events/EventListener;)(listener);
this.addEventListener(type, handler, useCapture);
return @elemental.js.dom.JsElementalMixinBase.Remover::create(Lelemental/events/EventTarget;Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;Z)
(this, type, handler, useCapture);
}-*/;
public final EventRemover addEventListener(String type, EventListener listener) {
return addEventListener(type, listener, false);
}
@Deprecated
public final void removeEventListener(String type, EventListener listener, boolean useCapture) {
final JavaScriptObject handler = getHandlerFor(listener);
if (handler != null) {
removeEventListener(this, type, handler, useCapture);
}
}
@Deprecated
public final void removeEventListener(String type, EventListener listener) {
final JavaScriptObject handler = getHandlerFor(listener);
if (handler != null) {
removeEventListener(this, type, handler);
}
}
private static native void removeEventListener(EventTarget target, String type,
JavaScriptObject handler, boolean useCapture) /*-{
target.removeEventListener(type, handler, useCapture);
}-*/;
private static native void removeEventListener(EventTarget target, String type,
JavaScriptObject handler) /*-{
target.removeEventListener(type, handler);
}-*/;
}