/* 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/. */
/** * like win.frameElement, but goes through mozbrowsers and mozapps iframes. * * @param {DOMWindow} win * The window to get the frame for * @return {DOMNode} * The element in which the window is embedded.
*/ const getFrameElement = win => { const isTopWindow = win && DevToolsUtils.getTopWindow(win) === win; return isTopWindow ? null : win.browsingContext.embedderElement;
};
exports.getFrameElement = getFrameElement;
/** * Get the x/y offsets for of all the parent frames of a given node, limited to * the boundary window given. * * @param {DOMWindow} boundaryWindow * The window where to stop to iterate. If `null` is given, the top * window is used. * @param {DOMNode} node * The node for which we are to get the offset * @return {Array} * The frame offset [x, y]
*/ function getFrameOffsets(boundaryWindow, node) {
let xOffset = 0;
let yOffset = 0;
let frameWin = getWindowFor(node); const scale = getCurrentZoom(node);
if (boundaryWindow === null) {
boundaryWindow = DevToolsUtils.getTopWindow(frameWin);
} elseif (typeof boundaryWindow === "undefined") { thrownew Error("No boundaryWindow given. Use null for the default one.");
}
while (frameWin !== boundaryWindow) { const frameElement = getFrameElement(frameWin); if (!frameElement) { break;
}
// We are in an iframe. // We take into account the parent iframe position and its // offset (borders and padding). const frameRect = frameElement.getBoundingClientRect();
/** * Get box quads adjusted for iframes and zoom level. * * Warning: this function returns things that look like DOMQuad objects but * aren't (they resemble an old version of the spec). Unlike the return value * of node.getBoxQuads, they have a .bounds property and not a .getBounds() * method. * * @param {DOMWindow} boundaryWindow * The window where to stop to iterate. If `null` is given, the top * window is used. * @param {DOMNode} node * The node for which we are to get the box model region * quads. * @param {String} region * The box model region to return: "content", "padding", "border" or * "margin". * @param {Object} [options.ignoreZoom=false] * Ignore zoom used in the context of e.g. canvas. * @return {Array} * An array of objects that have the same structure as quads returned by * getBoxQuads. An empty array if the node has no quads or is invalid.
*/ function getAdjustedQuads(
boundaryWindow,
node,
region,
{ ignoreZoom, ignoreScroll } = {}
) { if (!node || !node.getBoxQuads) { return [];
}
/** * Compute the absolute position and the dimensions of a node, relativalely * to the root window.
* @param {DOMWindow} boundaryWindow * The window where to stop to iterate. If `null` is given, the top * window is used. * @param {DOMNode} node * a DOM element to get the bounds for * @param {DOMWindow} contentWindow * the content window holding the node * @return {Object} * A rect object with the {top, left, width, height} properties
*/ function getRect(boundaryWindow, node, contentWindow) {
let frameWin = node.ownerDocument.defaultView; const clientRect = node.getBoundingClientRect();
if (boundaryWindow === null) {
boundaryWindow = DevToolsUtils.getTopWindow(frameWin);
} elseif (typeof boundaryWindow === "undefined") { thrownew Error("No boundaryWindow given. Use null for the default one.");
}
// Go up in the tree of frames to determine the correct rectangle. // clientRect is read-only, we need to be able to change properties. const rect = {
top: clientRect.top + contentWindow.pageYOffset,
left: clientRect.left + contentWindow.pageXOffset,
width: clientRect.width,
height: clientRect.height,
};
// We iterate through all the parent windows. while (frameWin !== boundaryWindow) { const frameElement = getFrameElement(frameWin); if (!frameElement) { break;
}
// We are in an iframe. // We take into account the parent iframe position and its // offset (borders and padding). const frameRect = frameElement.getBoundingClientRect();
/** * Get the 4 bounding points for a node taking iframes into account. * Note that for transformed nodes, this will return the untransformed bound. * * @param {DOMWindow} boundaryWindow * The window where to stop to iterate. If `null` is given, the top * window is used. * @param {DOMNode} node * @return {Object} * An object with p1,p2,p3,p4 properties being {x,y} objects
*/ function getNodeBounds(boundaryWindow, node) { if (!node) { returnnull;
} const { scrollX, scrollY } = boundaryWindow; const scale = getCurrentZoom(node);
// Find out the offset of the node in its current frame
let offsetLeft = 0;
let offsetTop = 0;
let el = node; while (el?.parentNode) {
offsetLeft += el.offsetLeft;
offsetTop += el.offsetTop;
el = el.offsetParent;
}
// Also take scrolled containers into account
el = node; while (el?.parentNode) { if (el.scrollTop) {
offsetTop -= el.scrollTop;
} if (el.scrollLeft) {
offsetLeft -= el.scrollLeft;
}
el = el.parentNode;
}
// And add the potential frame offset if the node is nested
let [xOffset, yOffset] = getFrameOffsets(boundaryWindow, node);
xOffset += (offsetLeft + scrollX) * scale;
yOffset += (offsetTop + scrollY) * scale;
// Get the width and height const width = node.offsetWidth * scale; const height = node.offsetHeight * scale;
/** * Same as doing iframe.contentWindow but works with all types of container * elements that act like frames (e.g. <embed>), where 'contentWindow' isn't a * property that can be accessed. * This uses the inIDeepTreeWalker instead. * @param {DOMNode} frame * @return {Window}
*/ function safelyGetContentWindow(frame) { if (frame.contentWindow) { return frame.contentWindow;
}
const document = walker.nextNode(); if (!document || !document.defaultView) { thrownew Error("Couldn't get the content window inside frame " + frame);
}
return document.defaultView;
}
/** * Returns a frame's content offset (frame border + padding). * Note: this function shouldn't need to exist, had the platform provided a * suitable API for determining the offset between the frame's content and * its bounding client rect. Bug 626359 should provide us with such an API. * * @param {DOMNode} frame * The frame. * @return {Array} [offsetTop, offsetLeft] * offsetTop is the distance from the top of the frame and the top of * the content document. * offsetLeft is the distance from the left of the frame and the left * of the content document.
*/ function getFrameContentOffset(frame) { const style = safelyGetContentWindow(frame).getComputedStyle(frame);
// In some cases, the computed style is null if (!style) { return [0, 0];
}
/** * Check if a node and its document are still alive * and attached to the window. * * @param {DOMNode} node * @return {Boolean}
*/ function isNodeConnected(node) { if (!node.ownerDocument || !node.ownerDocument.defaultView) { returnfalse;
}
/** * Determine whether a node is a shadow host, ie. an element that has a shadowRoot * attached to itself. * * @param {DOMNode} node * @return {Boolean}
*/ function isShadowHost(node) { const shadowRoot = node.openOrClosedShadowRoot; return shadowRoot && shadowRoot.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
}
exports.isShadowHost = isShadowHost;
/** * Determine whether a node is a child of a shadow host. Even if the element has been * assigned to a slot in the attached shadow DOM, the parent node for this element is * still considered to be the "host" element, and we need to walk them differently. * * @param {DOMNode} node * @return {Boolean}
*/ function isDirectShadowHostChild(node) { // Pseudo elements and native anonymous elements are always part of the anonymous tree. if (
isMarkerPseudoElement(node) ||
isBeforePseudoElement(node) ||
isAfterPseudoElement(node) ||
node.isNativeAnonymous
) { returnfalse;
}
/** * Determine whether a node is a ::marker pseudo. * * @param {DOMNode} node * @return {Boolean}
*/ function isMarkerPseudoElement(node) { return node.nodeName === "_moz_generated_content_marker";
}
exports.isMarkerPseudoElement = isMarkerPseudoElement;
/** * Determine whether a node is a ::before pseudo. * * @param {DOMNode} node * @return {Boolean}
*/ function isBeforePseudoElement(node) { return node.nodeName === "_moz_generated_content_before";
}
exports.isBeforePseudoElement = isBeforePseudoElement;
/** * Determine whether a node is a ::after pseudo. * * @param {DOMNode} node * @return {Boolean}
*/ function isAfterPseudoElement(node) { return node.nodeName === "_moz_generated_content_after";
}
exports.isAfterPseudoElement = isAfterPseudoElement;
/** * Get the current zoom factor applied to the container window of a given node. * @param {DOMNode|DOMWindow} * The node for which the zoom factor should be calculated, or its * owner window. * @return {Number}
*/ function getCurrentZoom(node) { const win = getWindowFor(node);
if (!win) { thrownew Error("Unable to get the zoom from the given argument.");
}
/** * Get the display pixel ratio for a given window. * The `devicePixelRatio` property is affected by the zoom (see bug 809788), so we have to * divide by the zoom value in order to get just the display density, expressed as pixel * ratio (the physical display pixel compares to a pixel on a “normal” density screen). * * @param {DOMNode|DOMWindow} * The node for which the zoom factor should be calculated, or its * owner window. * @return {Number}
*/ function getDisplayPixelRatio(node) { const win = getWindowFor(node); return win.devicePixelRatio / getCurrentZoom(node);
}
exports.getDisplayPixelRatio = getDisplayPixelRatio;
/** * Returns the window's dimensions for the `window` given. * * @return {Object} An object with `width` and `height` properties, representing the * number of pixels for the document's size.
*/ function getWindowDimensions(window) { // First we'll try without flushing layout, because it's way faster. const { windowUtils } = window;
let { width, height } = windowUtils.getRootBounds();
if (!width || !height) { // We need a flush after all :'(
width = window.innerWidth + window.scrollMaxX - window.scrollMinX;
height = window.innerHeight + window.scrollMaxY - window.scrollMinY;
/** * Returns the viewport's dimensions for the `window` given. * * @return {Object} An object with `width` and `height` properties, representing the * number of pixels for the viewport's size.
*/ function getViewportDimensions(window) { const { windowUtils } = window;
/** * Return the default view for a given node, where node can be: * - a DOM node * - the document node * - the window itself * @param {DOMNode|DOMWindow|DOMDocument} node The node to get the window for. * @return {DOMWindow}
*/ function getWindowFor(node) { if (Node.isInstance(node)) { if (node.nodeType === node.DOCUMENT_NODE) { return node.defaultView;
} return node.ownerDocument.defaultView;
} elseif (node instanceof Ci.nsIDOMWindow) { return node;
} returnnull;
}
/** * Synchronously loads a style sheet from `uri` and adds it to the list of * additional style sheets of the document. * The sheets added takes effect immediately, and only on the document of the * `window` given. * * @param {DOMWindow} window * @param {String} url * @param {String} [type="agent"]
*/ function loadSheet(window, url, type = "agent") { if (!(type in SHEET_TYPE)) {
type = "agent";
}
const { windowUtils } = window; try {
windowUtils.loadSheetUsingURIString(url, windowUtils[SHEET_TYPE[type]]);
} catch (e) { // The method fails if the url is already loaded.
}
}
exports.loadSheet = loadSheet;
/** * Remove the document style sheet at `sheetURI` from the list of additional * style sheets of the document. The removal takes effect immediately. * * @param {DOMWindow} window * @param {String} url * @param {String} [type="agent"]
*/ function removeSheet(window, url, type = "agent") { if (!(type in SHEET_TYPE)) {
type = "agent";
}
const { windowUtils } = window; try {
windowUtils.removeSheetUsingURIString(url, windowUtils[SHEET_TYPE[type]]);
} catch (e) { // The method fails if the url is already removed.
}
}
exports.removeSheet = removeSheet;
/** * Get the untransformed coordinates for a node. * * @param {DOMNode} node * The node for which the DOMQuad is to be returned. * @param {String} region * The box model region to return: "content", "padding", "border" or * "margin". * @return {DOMQuad} * A DOMQuad representation of the node.
*/ function getUntransformedQuad(node, region = "border") { // Get the inverse transformation matrix for the node. const matrix = node.getTransformToViewport(); const inverse = matrix.inverse(); const win = node.ownerGlobal;
// Get the adjusted quads for the node (including scroll offsets). const quads = getAdjustedQuads(win, node, region, {
ignoreZoom: true,
});
// Create DOMPoints from the transformed node position. const p1 = new DOMPoint(quads[0].p1.x, quads[0].p1.y); const p2 = new DOMPoint(quads[0].p2.x, quads[0].p2.y); const p3 = new DOMPoint(quads[0].p3.x, quads[0].p3.y); const p4 = new DOMPoint(quads[0].p4.x, quads[0].p4.y);
// Apply the inverse transformation matrix to the points to get the // untransformed points. const ip1 = inverse.transformPoint(p1); const ip2 = inverse.transformPoint(p2); const ip3 = inverse.transformPoint(p3); const ip4 = inverse.transformPoint(p4);
// Save the results in a DOMQuad. const quad = new DOMQuad(
{ x: ip1.x, y: ip1.y },
{ x: ip2.x, y: ip2.y },
{ x: ip3.x, y: ip3.y },
{ x: ip4.x, y: ip4.y }
);
// Remove the border offsets because we include them when calculating // offsets in the while loop. const style = win.getComputedStyle(node); const leftAdjustment = parseInt(style.borderLeftWidth, 10) || 0; const topAdjustment = parseInt(style.borderTopWidth, 10) || 0;
/** * Calculate the total of the node and all of its ancestor's scrollTop and * scrollLeft values. * * @param {DOMNode} node * The node for which the absolute scroll offsets should be calculated. * @return {Object} object * An object containing scrollTop and scrollLeft values. * @return {Number} object.scrollLeft * The total scrollLeft values of the node and all of its ancestors. * @return {Number} object.scrollTop * The total scrollTop values of the node and all of its ancestors.
*/ function getAbsoluteScrollOffsetsForNode(node) { const doc = node.ownerDocument;
// Our walker will only iterate up to document.body so we start by saving the // scroll values for `document.documentElement`.
let scrollTop = doc.documentElement.scrollTop;
let scrollLeft = doc.documentElement.scrollLeft; const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_ELEMENT);
walker.currentNode = node;
let currentNode = walker.currentNode;
// Iterate from `node` up the tree to `document.body` adding scroll offsets // as we go. while (currentNode) { const nodeScrollTop = currentNode.scrollTop; const nodeScrollLeft = currentNode.scrollLeft;
/** * Check if the provided node is a <frame> or <iframe> element. * * @param {DOMNode} node * @returns {Boolean}
*/ function isFrame(node) { const className = ChromeUtils.getClassName(node); return className == "HTMLIFrameElement" || className == "HTMLFrameElement";
}
/** * Check if the provided node is representing a remote <browser> element. * * @param {DOMNode} node * @return {Boolean}
*/ function isRemoteBrowserElement(node) { return (
ChromeUtils.getClassName(node) == "XULFrameElement" &&
!node.childNodes.length &&
node.getAttribute("remote") == "true"
);
}
exports.isRemoteBrowserElement = isRemoteBrowserElement;
/** * Check if the provided node is representing a remote frame. * * - In the context of the browser toolbox, a remote frame can be the <browser remote> * element found inside each tab. * - In the context of the content toolbox, a remote frame can be a <iframe> that contains * a different origin document. * * @param {DOMNode} node * @return {Boolean}
*/ function isRemoteFrame(node) { if (isFrame(node)) { return node.frameLoader?.isRemoteFrame;
}
/** * Check if the provided node is representing a frame that has its own dedicated child target. * * @param {BrowsingContextTargetActor} targetActor * @param {DOMNode} node * @returns {Boolean}
*/ function isFrameWithChildTarget(targetActor, node) { // If the iframe is blocked because of CSP, it won't have a document (and no associated targets) if (isFrameBlockedByCSP(node)) { returnfalse;
}
/** * Check if the provided node is representing a frame that is blocked by CSP. * * @param {DOMNode} node * @returns {Boolean}
*/ function isFrameBlockedByCSP(node) { if (!isFrame(node)) { returnfalse;
}
if (!node.src) { returnfalse;
}
let uri; try {
uri = lazy.NetUtil.newURI(node.src);
} catch (e) { returnfalse;
}
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.