/*
* Copyright (C) 2016 Red Hat, Inc. and/or its affiliates.
*
* 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 org.jboss.errai.common.client.util;
import org.jboss.errai.common.client.dom.HTMLElement;
import org.jboss.errai.common.client.ui.ElementWrapperWidget;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.user.client.ui.HasValue;
/**
* Contains utility methods for intercepting calls to add and remove web browser event listeners necessary for tests
* with certain versions of HTMLUnit.
*
* @author Max Barkley <mbarkley@redhat.com>
*/
public abstract class EventTestingUtil {
private EventTestingUtil() {}
/**
* This is a really disgusting workaround for the inability to
* dispatch native browser events in the version of HtmlUnit currently
* bundled in gwt-dev.
*
* What does this do?
* This replaces "addEventListener" and "removeEventListener"
* in the HTMLElement prototype with functions that intercept
* and store registered listeners.
*
* Why does it do it?
* So that subsequent calls to "invokeEventListeners" can
* manually call any functions added with "addEventListener".
*
* In short because we cannot dispatch browser events, to test
* binding of native elements we must store and then manually invoke
* all event listeners.
*/
public static native void setupAddEventListenerInterceptor() /*-{
console.log("Setting up event listener interceptors.");
function ListenerMap() {
var map = new Map();
this.add = function(element, type, listener) {
var curList = this.get(element, type);
console.debug("Adding listener for " + type + " event in " + element + ". Total of " + (curList.length + 1) + " listeners.");
curList.push(listener);
};
this.remove = function(element, type, listener) {
var listeners = this.get(element, type);
var index = listeners.indexOf(listener);
if (index > -1) {
listeners.splice(index, 1);
}
};
this.get = function(element, type) {
if (map.get(element) === undefined) {
map.set(element, new Map());
}
if (map.get(element).get(type) === undefined) {
map.get(element).set(type, []);
}
return map.get(element).get(type);
};
};
if ($wnd.HTMLElement.prototype._addEventListener === undefined) {
listeners = new ListenerMap();
$wnd.HTMLElement.prototype._addEventListener = $wnd.HTMLElement.prototype.addEventListener;
$wnd.HTMLElement.prototype._removeEventListener = $wnd.HTMLElement.prototype.removeEventListener;
console.log("Replacing addEventListener.");
$wnd.HTMLElement.prototype.addEventListener = function(type, listener, capture) {
console.debug("Intercepted addEventListener(" + this + ", " + type + ", " + capture + ")");
listeners.add(this, type, listener);
this._addEventListener(type, listener, capture);
};
console.log("Replacing removeEventListener.");
$wnd.HTMLElement.prototype.removeEventListener = function(type, listener, capture) {
console.debug("Intercepted removeEventListener for " + this + " with type " + type);
listeners.remove(this, type, listener);
this._removeEventListener(type, listener, capture);
};
}
}-*/;
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void invokeEventListeners(final HTMLElement element, final String eventType) {
invokeEventListeners((Object) element, eventType);
if ("change".equals(eventType)) {
final ElementWrapperWidget elem = ElementWrapperWidget.getWidget(element);
if (elem instanceof HasValue) {
ValueChangeEvent.fire(((HasValue) elem), ((HasValue) elem).getValue());
}
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void invokeEventListeners(final Element element, final String eventType) {
invokeEventListeners((Object) element, eventType);
if ("change".equals(eventType)) {
final ElementWrapperWidget elem = ElementWrapperWidget.getWidget(element);
if (elem instanceof HasValue) {
ValueChangeEvent.fire(((HasValue) elem), ((HasValue) elem).getValue());
}
}
}
public static void invokeEventListeners(final Object element, final String eventType) {
final NativeEvent event = Document.get().createHtmlEvent(eventType, true, true);
invokeEventListeners(element, eventType, event);
}
public static native void invokeEventListeners(Object element, String type, Object evt) /*-{
var foundListeners = listeners.get(element, type);
console.debug("Found " + foundListeners.length + " for " + type + " event on element " + element);
foundListeners.forEach(function(l) { l(evt); });
}-*/;
}