📄 domnode.java
字号:
return new DomIterator(DomNode.this, NodeFilter.SHOW_ELEMENT, this, /* filter */ true /* expand entity refs */ ); } public void handleEvent(Event e) { MutationEvent mutation = (MutationEvent) e; Node related = mutation.getRelatedNode(); // XXX if it's got children ... check all kids too, they // will invalidate our saved index if (related.getNodeType() != Node.ELEMENT_NODE || related.getNodeName() != elementName || related.getNamespaceURI() != elementURI) { return; } current = null; } public Node item(int index) { if (current == null) { current = createIterator(); lastIndex = -1; } // last node or before? go backwards if (index <= lastIndex) { while (index != lastIndex) { current.previousNode (); lastIndex--; } Node ret = current.previousNode (); current = null; return ret; } // somewhere after last node while (++lastIndex != index) current.nextNode (); Node ret = current.nextNode (); current = null; return ret; } public int getLength() { int retval = 0; NodeIterator iter = createIterator(); while (iter.nextNode() != null) { retval++; } current = null; return retval; } } // // EventTarget support // static final class ListenerRecord { String type; EventListener listener; boolean useCapture; // XXX use JDK 1.2 java.lang.ref.WeakReference to listener, // and we can both get rid of "shadow" classes and remove // the need for applications to apply similar trix ... but // JDK 1.2 support isn't generally available yet ListenerRecord(String type, EventListener listener, boolean useCapture) { this.type = type.intern(); this.listener = listener; this.useCapture = useCapture; } boolean equals(ListenerRecord rec) { return listener == rec.listener && useCapture == rec.useCapture && type == rec.type; } } /** * <b>DOM L2 (Events)</b> * Returns an instance of the specified type of event object. * Understands about DOM Mutation, HTML, and UI events. * * <p>If the name of the event type begins with "USER-", then an object * implementing the "Event" class will be returned; this provides a * limited facility for application-defined events to use the DOM event * infrastructure. Alternatively, use one of the standard DOM event * classes and initialize it using use such a "USER-" event type name; * or defin, instantiate, and initialize an application-specific subclass * of DomEvent and pass that to dispatchEvent(). * * @param eventType Identifies the particular DOM feature module * defining the type of event, such as "MutationEvents". * <em>The event "name" is a different kind of "type".</em> */ public Event createEvent(String eventType) { eventType = eventType.toLowerCase(); if ("mutationevents".equals(eventType)) { return new DomEvent.DomMutationEvent(null); } if ("htmlevents".equals(eventType) || "events".equals(eventType) || "user-events".equals(eventType)) { return new DomEvent(null); } if ("uievents".equals(eventType)) { return new DomEvent.DomUIEvent(null); } // mouse events throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, eventType, null, 0); } /** * <b>DOM L2 (Events)</b> * Registers an event listener's interest in a class of events. */ public final void addEventListener(String type, EventListener listener, boolean useCapture) { if (listeners == null) { listeners = new ListenerRecord[1]; } else if (nListeners == listeners.length) { ListenerRecord[] newListeners = new ListenerRecord[listeners.length + NKIDS_DELTA]; System.arraycopy(listeners, 0, newListeners, 0, nListeners); listeners = newListeners; } // prune duplicates ListenerRecord record; record = new ListenerRecord(type, listener, useCapture); for (int i = 0; i < nListeners; i++) { if (record.equals(listeners[i])) { return; } } listeners [nListeners++] = record; } // XXX this exception should be discarded from DOM // this class can be instantiated, unlike the one in the spec static final class DomEventException extends EventException { DomEventException() { super(UNSPECIFIED_EVENT_TYPE_ERR, "unspecified event type"); } } /** * <b>DOM L2 (Events)</b> * Delivers an event to all relevant listeners, returning true if the * caller should perform their default action. Note that the event * must have been provided by the createEvent() method on this * class, else it can't be dispatched. * * @see #createEvent * * @exception NullPointerException When a null event is passed. * @exception ClassCastException When the event wasn't provided by * the createEvent method, or otherwise isn't a DomEvent. * @exception EventException If the event type wasn't specified */ public final boolean dispatchEvent(Event event) throws EventException { DomEvent e = (DomEvent) event; DomNode[] ancestors = null; int ancestorMax = 0; boolean haveDispatchDataLock = false; if (e.type == null) { throw new DomEventException(); } e.doDefault = true; e.target = this; // // Typical case: one nonrecursive dispatchEvent call at a time // for this class. If that's our case, we can avoid allocating // garbage, which is overall a big win. Even with advanced GCs // that deal well with short-lived garbage, and wayfast allocators, // it still helps. // // Remember -- EVERY mutation goes though here at least once. // // When populating a DOM tree, trying to send mutation events is // the primary cost; this dominates the critical path. // try { DomNode current; int index; boolean haveAncestorRegistrations = false; ListenerRecord[] notificationSet; int ancestorLen; synchronized (lockNode) { if (!dispatchDataLock) { haveDispatchDataLock = dispatchDataLock = true; notificationSet = DomNode.notificationSet; ancestors = DomNode.ancestors; } else { notificationSet = new ListenerRecord[NOTIFICATIONS_INIT]; ancestors = new DomNode[ANCESTORS_INIT]; } ancestorLen = ancestors.length; } // XXX autogrow ancestors ... based on statistics // Climb to the top of this subtree and handle capture, letting // each node (from the top down) capture until one stops it or // until we get to this one. for (index = 0, current = parent; current != null && index < ancestorLen; index++, current = current.parent) { if (current.nListeners != 0) { haveAncestorRegistrations = true; } ancestors [index] = current; } if (current != null) { throw new RuntimeException("dispatchEvent capture stack size"); } ancestorMax = index; e.stop = false; if (haveAncestorRegistrations) { e.eventPhase = Event.CAPTURING_PHASE; while (!e.stop && index-- > 0) { current = ancestors [index]; if (current.nListeners != 0) { notifyNode(e, current, true, notificationSet); } } } // Always deliver events to the target node (this) // unless stopPropagation was called. If we saw // no registrations yet (typical!), we never will. if (!e.stop && nListeners != 0) { e.eventPhase = Event.AT_TARGET; notifyNode (e, this, false, notificationSet); } else if (!haveAncestorRegistrations) { e.stop = true; } // If the event bubbles and propagation wasn't halted, // walk back up the ancestor list. Stop bubbling when // any bubbled event handler stops it. if (!e.stop && e.bubbles) { e.eventPhase = Event.BUBBLING_PHASE; for (index = 0; !e.stop && index < ancestorMax && (current = ancestors[index]) != null; index++) { if (current.nListeners != 0) { notifyNode(e, current, false, notificationSet); } } } e.eventPhase = 0; // Caller chooses whether to perform the default // action based on return from this method. return e.doDefault; } finally { if (haveDispatchDataLock) { // synchronize to force write ordering synchronized (lockNode) { // null out refs to ensure they'll be GC'd for (int i = 0; i < ancestorMax; i++) { ancestors [i] = null; } // notificationSet handled by notifyNode dispatchDataLock = false; } } } } private void notifyNode(DomEvent e, DomNode current, boolean capture, ListenerRecord[] notificationSet) { int count = 0; // do any of this set of listeners get notified? for (int i = 0; i < current.nListeners; i++) { ListenerRecord rec = current.listeners[i]; if (rec.useCapture != capture) { continue; } if (!e.type.equals (rec.type)) { continue; } if (count >= notificationSet.length) { // very simple growth algorithm int len = Math.max(notificationSet.length, 1); ListenerRecord[] tmp = new ListenerRecord[len * 2]; System.arraycopy(notificationSet, 0, tmp, 0, notificationSet.length); notificationSet = tmp; } notificationSet[count++] = rec; } // Notify just those listeners e.currentNode = current; for (int i = 0; i < count; i++) { try { // Late in the DOM CR process (3rd or 4th CR?) the // removeEventListener spec became asymmetric with respect // to addEventListener ... effect is now immediate. for (int j = 0; j < current.nListeners; j++) { if (current.listeners[j].equals(notificationSet[i])) { notificationSet[i].listener.handleEvent(e); break; } } } catch (Exception x) { // ignore all exceptions } notificationSet[i] = null; // free for GC } } /** * <b>DOM L2 (Events)</b> * Unregisters an event listener. */ public final void removeEventListener(String type, EventListener listener, boolean useCapture) { for (int i = 0; i < nListeners; i++) { if (listeners[i].listener != listener) { continue; } if (listeners[i].useCapture != useCapture) { continue; } if (!listeners[i].type.equals(type)) { continue; } if (nListeners == 1) { listeners = null; nListeners = 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -