All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cobraparser.html.js.EventTargetManager Maven / Gradle / Ivy

There is a newer version: 1.0.2
Show newest version
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();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy