org.cobraparser.html.js.EventTargetManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Cobra Show documentation
Show all versions of Cobra Show documentation
Cobra is the rendering engine designed for LoboBrowser
package org.cobraparser.html.js;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.cobraparser.html.domimpl.NodeImpl;
import org.cobraparser.html.js.Window.JSRunnableTask;
import org.mozilla.javascript.Function;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.events.EventException;
import org.w3c.dom.events.EventListener;
public final class EventTargetManager {
private final Map>> nodeOnEventListeners = new IdentityHashMap<>();
private final Window window;
public EventTargetManager(final Window window) {
this.window = window;
}
public void addEventListener(final NodeImpl node, final String type, final EventListener listener, final boolean useCapture) {
final List handlerList = getListenerList(type, node, true);
handlerList.add(listener);
}
private List getListenerList(final String type, final NodeImpl node, final boolean createIfNotExist) {
final Map> onEventListeners = getEventListeners(node, createIfNotExist);
if (onEventListeners != null) {
if (onEventListeners.containsKey(type)) {
return onEventListeners.get(type);
} else if (createIfNotExist) {
final List handlerList = new ArrayList<>();
onEventListeners.put(type, handlerList);
return handlerList;
} else {
return null;
}
} else {
return null;
}
}
private Map> getEventListeners(final NodeImpl node, final boolean createIfNotExist) {
if (nodeOnEventListeners.containsKey(node)) {
return nodeOnEventListeners.get(node);
} else {
if (createIfNotExist) {
final Map> onEventListeners = new HashMap<>();
nodeOnEventListeners.put(node, onEventListeners);
return onEventListeners;
} else {
return null;
}
}
}
public void removeEventListener(final NodeImpl node, final String type, final EventListener listener, final boolean useCapture) {
final Map> onEventListeners = getEventListeners(node, false);
if (onEventListeners != null) {
if (onEventListeners.containsKey(type)) {
onEventListeners.get(type).remove(listener);
}
}
}
private List getFunctionList(final String type, final NodeImpl node, final boolean createIfNotExist) {
final Map> onEventListeners = getEventFunctions(node, createIfNotExist);
if (onEventListeners != null) {
if (onEventListeners.containsKey(type)) {
return onEventListeners.get(type);
} else if (createIfNotExist) {
final List handlerList = new ArrayList<>();
onEventListeners.put(type, handlerList);
return handlerList;
} else {
return null;
}
} else {
return null;
}
}
private Map> getEventFunctions(final NodeImpl node, final boolean createIfNotExist) {
if (nodeOnEventFunctions.containsKey(node)) {
return nodeOnEventFunctions.get(node);
} else {
if (createIfNotExist) {
final Map> onEventListeners = new HashMap<>();
nodeOnEventFunctions.put(node, onEventListeners);
return onEventListeners;
} else {
return null;
}
}
}
public boolean dispatchEvent(final NodeImpl node, final Event evt) throws EventException {
// dispatchEventToHandlers(node, evt, onEventListeners.get(evt.getType()));
// dispatchEventToJSHandlers(node, evt, onEventHandlers.get(evt.getType()));
// TODO: Event Bubbling
// TODO: get Window into the propagation path
final List propagationPath = getPropagationPath(node);
// TODO: Capture phase, and distinction between target phase and bubbling phase
evt.setPhase(org.w3c.dom.events.Event.AT_TARGET);
// TODO: The JS Task should be added with the correct base URL
window.addJSTask(new JSRunnableTask(0, "Event dispatch for " + evt, () -> {
for (int i = 0; (i < propagationPath.size()) && !evt.isPropagationStopped(); i++) {
final NodeImpl currNode = propagationPath.get(i);
// System.out.println("Dipatching " + i + " to: " + currNode);
// TODO: Make request manager checks here.
dispatchEventToHandlers(currNode, evt);
dispatchEventToJSHandlers(currNode, evt);
evt.setPhase(org.w3c.dom.events.Event.BUBBLING_PHASE);
}
}
));
// dispatchEventToHandlers(node, evt);
// dispatchEventToJSHandlers(node, evt);
return false;
}
private static List getPropagationPath(NodeImpl node) {
final List nodes = new LinkedList<>();
while (node != null) {
if ((node instanceof Element) || (node instanceof Document)) { // TODO || node instanceof Window) {
nodes.add(node);
}
node = (NodeImpl) node.getParentNode();
}
// TODO
// nodes.add(window);
return nodes;
}
// private void dispatchEventToHandlers(final NodeImpl node, final Event event, final List handlers) {
private void dispatchEventToHandlers(final NodeImpl node, final Event event) {
final List handlers = getListenerList(event.getType(), node, false);
if (handlers != null) {
// We clone the collection and check if original collection still contains
// the handler before dispatching
// This is to avoid ConcurrentModificationException during dispatch
final ArrayList handlersCopy = new ArrayList<>(handlers);
for (final EventListener h : handlersCopy) {
// TODO: Not sure if we should stop calling handlers after propagation is stopped
// if (event.isPropagationStopped()) {
// return;
// }
if (handlers.contains(h)) {
// window.addJSTask(new JSRunnableTask(0, "Event dispatch for: " + event, new Runnable(){
// public void run() {
h.handleEvent(event);
// }
// }));
// h.handleEvent(event);
// Executor.executeFunction(node, h, event);
}
}
}
}
// protected void dispatchEventToJSHandlers(final NodeImpl node, final Event event, final List handlers) {
protected void dispatchEventToJSHandlers(final NodeImpl node, final Event event) {
final List handlers = getFunctionList(event.getType(), node, false);
if (handlers != null) {
// We clone the collection and check if original collection still contains
// the handler before dispatching
// This is to avoid ConcurrentModificationException during dispatch
final ArrayList handlersCopy = new ArrayList<>(handlers);
for (final Function h : handlersCopy) {
// TODO: Not sure if we should stop calling handlers after propagation is stopped
// if (event.isPropagationStopped()) {
// return;
// }
if (handlers.contains(h)) {
// window.addJSTask(new JSRunnableTask(0, "Event dispatch for " + event, new Runnable(){
// public void run() {
Executor.executeFunction(node, h, event, window.getContextFactory());
// }
// }));
// Executor.executeFunction(node, h, event);
}
}
}
}
// private final Map> onEventHandlers = new HashMap<>();
private final Map>> nodeOnEventFunctions = new IdentityHashMap<>();
public void addEventListener(final NodeImpl node, final String type, final Function listener) {
addEventListener(node, type, listener, false);
}
public void addEventListener(final NodeImpl node, final String type, final Function listener, final boolean useCapture) {
// TODO
// System.out.println("node by name: " + node.getNodeName() + " adding Event listener of type: " + type);
/*
List handlerList = null;
if (onEventHandlers.containsKey(type)) {
handlerList = onEventHandlers.get(type);
} else {
handlerList = new ArrayList<>();
onEventHandlers.put(type, handlerList);
}*/
// final Map> handlerList = getEventFunctions(node, true);
final List handlerList = getFunctionList(type, node, true);
handlerList.add(listener);
}
public void removeEventListener(final NodeImpl node, final String type, final Function listener, final boolean useCapture) {
final Map> onEventListeners = getEventFunctions(node, false);
if (onEventListeners != null) {
if (onEventListeners.containsKey(type)) {
onEventListeners.get(type).remove(listener);
}
}
}
public void reset() {
nodeOnEventFunctions.clear();
nodeOnEventListeners.clear();
}
}