| /* | 
 |  * 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); | 
 | }-*/; | 
 |  | 
 | } |