/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * Client side of a node list as returned by querySelectorAll()
*/ class NodeListFront extends FrontClassWithSpec(nodeListSpec) {
marshallPool() { returnthis.getParent();
}
// Update the object given a form representation off the wire.
form(json) { this.length = json.length;
}
/** * Convenience API for building a list of attribute modifications * for the `modifyAttributes` request.
*/ class AttributeModificationList {
constructor(node) { this.node = node; this.modifications = [];
}
apply() { const ret = this.node.modifyAttributes(this.modifications); return ret;
}
/** * Client side of the node actor. * * Node fronts are strored in a tree that mirrors the DOM tree on the * server, but with a few key differences: * - Not all children will be necessary loaded for each node. * - The order of children isn't guaranteed to be the same as the DOM. * Children are stored in a doubly-linked list, to make addition/removal * and traversal quick. * * Due to the order/incompleteness of the child list, it is safe to use * the parent node from clients, but the `children` request should be used * to traverse children.
*/ class NodeFront extends FrontClassWithSpec(nodeSpec) {
constructor(conn, targetFront, parentFront) { super(conn, targetFront, parentFront); // The parent node this._parent = null; // The first child of this node. this._child = null; // The next sibling of this node. this._next = null; // The previous sibling of this node. this._prev = null; // Store the flag to use it after destroy, where targetFront is set to null. this._hasParentProcessTarget = targetFront.isParentProcess;
}
/** * Destroy a node front. The node must have been removed from the * ownership tree before this is called, unless the whole walker front * is being destroyed.
*/
destroy() { super.destroy();
}
// Update the object given a form representation off the wire.
form(form, ctx) { // backward-compatibility: shortValue indicates we are connected to old server if (form.shortValue) { // If the value is not complete, set nodeValue to null, it will be fetched // when calling getNodeValue()
form.nodeValue = form.incompleteValue ? null : form.shortValue;
}
this.traits = form.traits || {};
// Shallow copy of the form. We could just store a reference, but // eventually we'll want to update some of the data. this._form = Object.assign({}, form); this._form.attrs = this._form.attrs ? this._form.attrs.slice() : [];
if (form.parent) { // Get the owner actor for this actor (the walker), and find the // parent node of this actor from it, creating a standin node if // necessary. const owner = ctx.marshallPool(); if (typeof owner.ensureDOMNodeFront === "function") { const parentNodeFront = owner.ensureDOMNodeFront(form.parent); this.reparent(parentNodeFront);
}
}
if (form.host) { const owner = ctx.marshallPool(); if (typeof owner.ensureDOMNodeFront === "function") { this.host = owner.ensureDOMNodeFront(form.host);
}
}
/** * Returns the parent NodeFront for this NodeFront.
*/
parentNode() { returnthis._parent;
}
/** * Returns the NodeFront corresponding to the parentNode of this NodeFront, or the * NodeFront corresponding to the host element for shadowRoot elements.
*/
parentOrHost() { returnthis.isShadowRoot ? this.host : this._parent;
}
/** * Returns the owner DocumentElement|ShadowRootElement NodeFront for this NodeFront, * or null if such element can't be found. * * @returns {NodeFront|null}
*/
getOwnerRootNodeFront() {
let currentNode = this; while (currentNode) { if (
currentNode.isShadowRoot ||
currentNode.nodeType === Node.DOCUMENT_NODE
) { return currentNode;
}
currentNode = currentNode.parentNode();
}
returnnull;
}
/** * Process a mutation entry as returned from the walker's `getMutations` * request. Only tries to handle changes of the node's contents * themselves (character data and attribute changes), the walker itself * will keep the ownership tree up to date.
*/
updateMutation(change) { if (change.type === "attributes") { // We'll need to lazily reparse the attributes after this change. this._attrMap = undefined;
// Update any already-existing attributes.
let found = false; for (let i = 0; i < this.attributes.length; i++) { const attr = this.attributes[i]; if (
attr.name == change.attributeName &&
attr.namespace == change.attributeNamespace
) { if (change.newValue !== null) {
attr.value = change.newValue;
} else { this.attributes.splice(i, 1);
}
found = true; break;
}
} // This is a new attribute. The null check is because of Bug 1192270, // in the case of a newly added then removed attribute if (!found && change.newValue !== null) { this.attributes.push({
name: change.attributeName,
namespace: change.attributeNamespace,
value: change.newValue,
});
}
} elseif (change.type === "characterData") { this._form.nodeValue = change.newValue;
} elseif (change.type === "pseudoClassLock") { this._form.pseudoClassLocks = change.pseudoClassLocks;
} elseif (change.type === "events") { this._form.hasEventListeners = change.hasEventListeners;
} elseif (change.type === "mutationBreakpoint") { this._form.mutationBreakpoints = change.mutationBreakpoints;
}
}
// Some accessors to make NodeFront feel more like a Node
get id() { returnthis.getAttribute("id");
}
get nodeType() { returnthis._form.nodeType;
}
get namespaceURI() { returnthis._form.namespaceURI;
}
get nodeName() { returnthis._form.nodeName;
}
get displayName() { const { displayName, nodeName } = this._form;
get browsingContextID() { returnthis._form.browsingContextID;
}
get className() { returnthis.getAttribute("class") || "";
}
// Check if the node has children but the current DevTools session is unable // to retrieve them. // Typically: a <frame> or <browser> element which loads a document in another // process, but the toolbox' configuration prevents to inspect it (eg the // parent-process only Browser Toolbox).
get childrenUnavailable() { return ( // If form.useChildTargetToFetchChildren is true, it means the node HAS // children in another target. // Note: useChildTargetToFetchChildren might be undefined, force // conversion to boolean. See Bug 1783613 to try and improve this.
!!this._form.useChildTargetToFetchChildren && // But if useChildTargetToFetchChildren is false, it means the client // configuration prevents from displaying such children. // This is the only case where children are considered as unavailable: // they exist, but can't be retrieved by configuration.
!this.useChildTargetToFetchChildren
);
}
get hasChildren() { returnthis.numChildren > 0;
}
get numChildren() { if (this.childrenUnavailable) { return 0;
}
returnthis._form.numChildren;
}
get useChildTargetToFetchChildren() { if ( this._hasParentProcessTarget &&
browserToolboxScope != BROWSER_TOOLBOX_SCOPE_EVERYTHING
) { returnfalse;
}
return !!this._form.useChildTargetToFetchChildren;
}
get hasEventListeners() { returnthis._form.hasEventListeners;
}
get isMarkerPseudoElement() { returnthis._form.isMarkerPseudoElement;
}
get isBeforePseudoElement() { returnthis._form.isBeforePseudoElement;
}
get isAfterPseudoElement() { returnthis._form.isAfterPseudoElement;
}
get isPseudoElement() { return ( this.isBeforePseudoElement || this.isAfterPseudoElement || this.isMarkerPseudoElement
);
}
get isAnonymous() { returnthis._form.isAnonymous;
}
get isInHTMLDocument() { returnthis._form.isInHTMLDocument;
}
get tagName() { returnthis.nodeType === nodeConstants.ELEMENT_NODE ? this.nodeName : null;
}
get isDocumentElement() { return !!this._form.isDocumentElement;
}
get isTopLevelDocument() { returnthis._form.isTopLevelDocument;
}
get isShadowRoot() { returnthis._form.isShadowRoot;
}
get shadowRootMode() { returnthis._form.shadowRootMode;
}
get isShadowHost() { returnthis._form.isShadowHost;
}
get customElementLocation() { returnthis._form.customElementLocation;
}
get isDirectShadowHostChild() { returnthis._form.isDirectShadowHostChild;
}
// doctype properties
get name() { returnthis._form.name;
}
get publicId() { returnthis._form.publicId;
}
get systemId() { returnthis._form.systemId;
}
get displayType() { returnthis._form.displayType;
}
get isDisplayed() { returnthis._form.isDisplayed;
}
get isScrollable() { returnthis._form.isScrollable;
}
get causesOverflow() { returnthis._form.causesOverflow;
}
get containerType() { returnthis._form.containerType;
}
get isTreeDisplayed() {
let parent = this; while (parent) { if (!parent.isDisplayed) { returnfalse;
}
parent = parent.parentNode();
} returntrue;
}
get inspectorFront() { returnthis.parentFront.parentFront;
}
get walkerFront() { returnthis.parentFront;
}
getNodeValue() { // backward-compatibility: if nodevalue is null and shortValue is defined, the actual // value of the node needs to be fetched on the server. if (this._form.nodeValue === null && this._form.shortValue) { returnsuper.getNodeValue();
}
/** * Set this node's parent. Note that the children saved in * this tree are unordered and incomplete, so shouldn't be used * instead of a `children` request.
*/
reparent(parent) { if (this._parent === parent) { return;
}
if (this._parent && this._parent._child === this) { this._parent._child = this._next;
} if (this._prev) { this._prev._next = this._next;
} if (this._next) { this._next._prev = this._prev;
} this._next = null; this._prev = null; this._parent = parent; if (!parent) { // Subtree is disconnected, we're done return;
} this._next = parent._child; if (this._next) { this._next._prev = this;
}
parent._child = this;
}
/** * Return all the known children of this node.
*/
treeChildren() { const ret = []; for (let child = this._child; child != null; child = child._next) {
ret.push(child);
} return ret;
}
/** * Do we use a local target? * Useful to know if a rawNode is available or not. * * This will, one day, be removed. External code should * not need to know if the target is remote or not.
*/
isLocalToBeDeprecated() { return !!this.conn._transport._serverConnection;
}
/** * Get a Node for the given node front. This only works locally, * and is only intended as a stopgap during the transition to the remote * protocol. If you depend on this you're likely to break soon.
*/
rawNode() { if (!this.isLocalToBeDeprecated()) {
console.warn("Tried to use rawNode on a remote connection."); returnnull;
} const {
DevToolsServer,
} = require("resource://devtools/server/devtools-server.js"); const actor = DevToolsServer.searchAllConnectionsForActor(this.actorID); if (!actor) { // Can happen if we try to get the raw node for an already-expired // actor. returnnull;
} return actor.rawNode;
}
async connectToFrame() { if (!this.useChildTargetToFetchChildren) {
console.warn("Tried to open connection to an invalid frame."); returnnull;
} if ( this._childBrowsingContextTarget &&
!this._childBrowsingContextTarget.isDestroyed()
) { returnthis._childBrowsingContextTarget;
}
// Get the target for this frame element this._childBrowsingContextTarget =
await this.targetFront.getWindowGlobalTarget( this._form.browsingContextID
);
// Bug 1776250: When the target is destroyed, we need to easily find the // parent node front so that we can update its frontend container in the // markup-view. this._childBrowsingContextTarget.setParentNodeFront(this);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.