documentimpl.java
来自「JAVA 所有包」· Java 代码 · 共 1,302 行 · 第 1/4 页
JAVA
1,302 行
*/ 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.total == 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> * Similar to code in dispatchingEventToSubtree however this method * is only used on the target node and does not start a dispatching chain * on the sibling of the target node as this is not part of the subtree * ***** 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 n target node (that was directly inserted or removed) * @param e event to be sent to that node and its subtree */ protected void dispatchEventToSubtree(Node n, Event e) { ((NodeImpl) n).dispatchEvent(e); if (n.getNodeType() == Node.ELEMENT_NODE) { NamedNodeMap a = n.getAttributes(); for (int i = a.getLength() - 1; i >= 0; --i) dispatchingEventToSubtree(a.item(i), e); } dispatchingEventToSubtree(n.getFirstChild(), e); } // dispatchEventToSubtree(NodeImpl,Node,Event) :void /** * Dispatches event to the target node's descendents recursively * * @param n node to dispatch to * @param e event to be sent to that node and its subtree */ protected void dispatchingEventToSubtree(Node n, Event e) { if (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) dispatchingEventToSubtree(a.item(i), e); } dispatchingEventToSubtree(n.getFirstChild(), e); dispatchingEventToSubtree(n.getNextSibling(), e); } /** * 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 { private static final long serialVersionUID = 3257001077260759859L; 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.total > 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.total > 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. if (enclosingAttr != null) { dispatchEvent(enclosingAttr, me); if (owner != null) dispatchEvent(owner, me); } else dispatchEvent(node, me); } } // dispatchAggregateEvents(NodeImpl, AttrImpl,String) :void /** * NON-DOM INTERNAL: Pre-mutation context check, in * preparation for later generating DOMAttrModified events. * Determines whether this node is within an Attr * @param node node to get enclosing attribute for * @return either a description of that Attr, or null if none such. */ protected void saveEnclosingAttr(NodeImpl node) { savedEnclosingAttr = null; // MUTATION PREPROCESSING AND PRE-EVENTS: // If we're within the scope of an Attr and DOMAttrModified // was requested, we need to preserve its previous value for // that event. LCount lc = LCount.lookup(MutationEventImpl.DOM_ATTR_MODIFIED); if (lc.total > 0) { NodeImpl eventAncestor = node; while (true) { if (eventAncestor == null) return; int type = eventAncestor.getNodeType();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?