documentimpl.java
来自「JAVA的一些源码 JAVA2 STANDARD EDITION DEVELO」· Java 代码 · 共 1,275 行 · 第 1/4 页
JAVA
1,275 行
* <ol> * <li>Event is dispatched to a particular target node, which invokes * this code. Note that the event's stopPropagation flag is * cleared when dispatch begins; thereafter, if it has * been set before processing of a node commences, we instead * immediately advance to the DEFAULT phase. * <li>The node's ancestors are established as destinations for events. * For capture and bubble purposes, node ancestry is determined at * the time dispatch starts. If an event handler alters the document * tree, that does not change which nodes will be informed of the event. * <li>CAPTURING_PHASE: Ancestors are scanned, root to target, for * Capturing listeners. If found, they are invoked (see below). * <li>AT_TARGET: * Event is dispatched to NON-CAPTURING listeners on the * target node. Note that capturing listeners on this node are _not_ * invoked. * <li>BUBBLING_PHASE: Ancestors are scanned, target to root, for * non-capturing listeners. * <li>Default processing: Some DOMs have default behaviors bound to * specific nodes. If this DOM does, and if the event's preventDefault * flag has not been set, we now return to the target node and process * its default handler for this event, if any. * </ol> * <p> * Note that registration of handlers during processing of an event does * not take effect during this phase of this event; they will not be called * until the next time this node is visited by dispatchEvent. On the other * hand, removals take effect immediately. * <p> * If an event handler itself causes events to be dispatched, they are * processed synchronously, before processing resumes * on the event which triggered them. Please be aware that this may * result in events arriving at listeners "out of order" relative * to the actual sequence of requests. * <p> * Note that our implementation resets the event's stop/prevent flags * when dispatch begins. * I believe the DOM's intent is that event objects be redispatchable, * though it isn't stated in those terms. * @param node node to dispatch to * @param event the event object to be dispatched to * registered EventListeners * @return true if the event's <code>preventDefault()</code> * method was invoked by an EventListener; otherwise false. */ protected boolean dispatchEvent(NodeImpl node, Event event) { if (event == null) return false; // Can't use anyone else's implementation, since there's no public // API for setting the event's processing-state fields. EventImpl evt = (EventImpl)event; // VALIDATE -- must have been initialized at least once, must have // a non-null non-blank name. if(!evt.initialized || evt.type == null || evt.type.equals("")) { String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "UNSPECIFIED_EVENT_TYPE_ERR", null); throw new EventException(EventException.UNSPECIFIED_EVENT_TYPE_ERR, msg); } // If nobody is listening for this event, discard immediately LCount lc = LCount.lookup(evt.getType()); if (lc.captures + lc.bubbles + lc.defaults == 0) return evt.preventDefault; // INITIALIZE THE EVENT'S DISPATCH STATUS // (Note that Event objects are reusable in our implementation; // that doesn't seem to be explicitly guaranteed in the DOM, but // I believe it is the intent.) evt.target = node; evt.stopPropagation = false; evt.preventDefault = false; // Capture pre-event parentage chain, not including target; // use pre-event-dispatch ancestors even if event handlers mutate // document and change the target's context. // Note that this is parents ONLY; events do not // cross the Attr/Element "blood/brain barrier". // DOMAttrModified. which looks like an exception, // is issued to the Element rather than the Attr // and causes a _second_ DOMSubtreeModified in the Element's // tree. Vector pv = new Vector(10,10); Node p = node; Node n = p.getParentNode(); while (n != null) { pv.addElement(n); p = n; n = n.getParentNode(); } // CAPTURING_PHASE: if (lc.captures > 0) { evt.eventPhase = Event.CAPTURING_PHASE; // Ancestors are scanned, root to target, for // Capturing listeners. for (int j = pv.size() - 1; j >= 0; --j) { if (evt.stopPropagation) break; // Someone set the flag. Phase ends. // Handle all capturing listeners on this node NodeImpl nn = (NodeImpl) pv.elementAt(j); evt.currentTarget = nn; Vector nodeListeners = getEventListeners(nn); if (nodeListeners != null) { Vector nl = (Vector) nodeListeners.clone(); // call listeners in the order in which they got registered int nlsize = nl.size(); for (int i = 0; i < nlsize; i++) { LEntry le = (LEntry) nl.elementAt(i); if (le.useCapture && le.type.equals(evt.type) && nodeListeners.contains(le)) { try { le.listener.handleEvent(evt); } catch (Exception e) { // All exceptions are ignored. } } } } } } // Both AT_TARGET and BUBBLE use non-capturing listeners. if (lc.bubbles > 0) { // AT_TARGET PHASE: Event is dispatched to NON-CAPTURING listeners // on the target node. Note that capturing listeners on the target // node are _not_ invoked, even during the capture phase. evt.eventPhase = Event.AT_TARGET; evt.currentTarget = node; Vector nodeListeners = getEventListeners(node); if (!evt.stopPropagation && nodeListeners != null) { Vector nl = (Vector) nodeListeners.clone(); // call listeners in the order in which they got registered int nlsize = nl.size(); for (int i = 0; i < nlsize; i++) { LEntry le = (LEntry) nl.elementAt(i); if (!le.useCapture && le.type.equals(evt.type) && nodeListeners.contains(le)) { try { le.listener.handleEvent(evt); } catch (Exception e) { // All exceptions are ignored. } } } } // BUBBLING_PHASE: Ancestors are scanned, target to root, for // non-capturing listeners. If the event's preventBubbling flag // has been set before processing of a node commences, we // instead immediately advance to the default phase. // Note that not all events bubble. if (evt.bubbles) { evt.eventPhase = Event.BUBBLING_PHASE; int pvsize = pv.size(); for (int j = 0; j < pvsize; j++) { if (evt.stopPropagation) break; // Someone set the flag. Phase ends. // Handle all bubbling listeners on this node NodeImpl nn = (NodeImpl) pv.elementAt(j); evt.currentTarget = nn; nodeListeners = getEventListeners(nn); if (nodeListeners != null) { Vector nl = (Vector) nodeListeners.clone(); // call listeners in the order in which they got // registered int nlsize = nl.size(); for (int i = 0; i < nlsize; i++) { LEntry le = (LEntry) nl.elementAt(i); if (!le.useCapture && le.type.equals(evt.type) && nodeListeners.contains(le)) { try { le.listener.handleEvent(evt); } catch (Exception e) { // All exceptions are ignored. } } } } } } } // DEFAULT PHASE: Some DOMs have default behaviors bound to specific // nodes. If this DOM does, and if the event's preventDefault flag has // not been set, we now return to the target node and process its // default handler for this event, if any. // No specific phase value defined, since this is DOM-internal if (lc.defaults > 0 && (!evt.cancelable || !evt.preventDefault)) { // evt.eventPhase = Event.DEFAULT_PHASE; // evt.currentTarget = node; // DO_DEFAULT_OPERATION } return evt.preventDefault; } // dispatchEvent(NodeImpl,Event) :boolean /** * NON-DOM INTERNAL: DOMNodeInsertedIntoDocument and ...RemovedFrom... * are dispatched to an entire subtree. This is the distribution code * therefor. They DO NOT bubble, thanks be, but may be captured. * <p> * ***** At the moment I'm being sloppy and using the normal * capture dispatcher on every node. This could be optimized hugely * by writing a capture engine that tracks our position in the tree to * update the capture chain without repeated chases up to root. * @param node node to dispatch to * @param n node which was directly inserted or removed * @param e event to be sent to that node and its subtree */ protected void dispatchEventToSubtree(NodeImpl node, Node n, Event e) { Vector nodeListeners = getEventListeners(node); if (nodeListeners == null || n == null) return; // ***** Recursive implementation. This is excessively expensive, // and should be replaced in conjunction with optimization // mentioned above. ((NodeImpl) n).dispatchEvent(e); if (n.getNodeType() == Node.ELEMENT_NODE) { NamedNodeMap a = n.getAttributes(); for (int i = a.getLength() - 1; i >= 0; --i) dispatchEventToSubtree(node, a.item(i), e); } dispatchEventToSubtree(node, n.getFirstChild(), e); dispatchEventToSubtree(node, n.getNextSibling(), e); } // dispatchEventToSubtree(NodeImpl,Node,Event) :void /** * NON-DOM INTERNAL: Return object for getEnclosingAttr. Carries * (two values, the Attr node affected (if any) and its previous * string value. Simple struct, no methods. */ class EnclosingAttr implements Serializable { AttrImpl node; String oldvalue; } EnclosingAttr savedEnclosingAttr; /** * NON-DOM INTERNAL: Convenience wrapper for calling * dispatchAggregateEvents when the context was established * by <code>savedEnclosingAttr</code>. * @param node node to dispatch to * @param ea description of Attr affected by current operation */ protected void dispatchAggregateEvents(NodeImpl node, EnclosingAttr ea) { if (ea != null) dispatchAggregateEvents(node, ea.node, ea.oldvalue, MutationEvent.MODIFICATION); else dispatchAggregateEvents(node, null, null, (short) 0); } // dispatchAggregateEvents(NodeImpl,EnclosingAttr) :void /** * NON-DOM INTERNAL: Generate the "aggregated" post-mutation events * DOMAttrModified and DOMSubtreeModified. * Both of these should be issued only once for each user-requested * mutation operation, even if that involves multiple changes to * the DOM. * For example, if a DOM operation makes multiple changes to a single * Attr before returning, it would be nice to generate only one * DOMAttrModified, and multiple changes over larger scope but within * a recognizable single subtree might want to generate only one * DOMSubtreeModified, sent to their lowest common ancestor. * <p> * To manage this, use the "internal" versions of insert and remove * with MUTATION_LOCAL, then make an explicit call to this routine * at the higher level. Some examples now exist in our code. * * @param node The node to dispatch to * @param enclosingAttr The Attr node (if any) whose value has been changed * as a result of the DOM operation. Null if none such. * @param oldValue The String value previously held by the * enclosingAttr. Ignored if none such. * @param change Type of modification to the attr. See * MutationEvent.attrChange */ protected void dispatchAggregateEvents(NodeImpl node, AttrImpl enclosingAttr, String oldvalue, short change) { // We have to send DOMAttrModified. NodeImpl owner = null; if (enclosingAttr != null) { LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); owner = (NodeImpl) enclosingAttr.getOwnerElement(); if (lc.captures + lc.bubbles + lc.defaults > 0) { if (owner != null) { MutationEventImpl me = new MutationEventImpl(); me.initMutationEvent(MutationEventImpl.DOM_ATTR_MODIFIED, true, false, enclosingAttr, oldvalue, enclosingAttr.getNodeValue(), enclosingAttr.getNodeName(), change); owner.dispatchEvent(me); } } } // DOMSubtreeModified gets sent to the lowest common root of a // set of changes. // "This event is dispatched after all other events caused by the // mutation have been fired." LCount lc = LCount.lookup(MutationEventImpl.DOM_SUBTREE_MODIFIED); if (lc.captures + lc.bubbles + lc.defaults > 0) { MutationEvent me = new MutationEventImpl(); me.initMutationEvent(MutationEventImpl.DOM_SUBTREE_MODIFIED, true, false, null, null, null, null, (short) 0); // If we're within an Attr, DStM gets sent to the Attr // and to its owningElement. Otherwise we dispatch it // locally.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?