summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/DOMHelpers.jsm
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /devtools/client/shared/DOMHelpers.jsm
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'devtools/client/shared/DOMHelpers.jsm')
-rw-r--r--devtools/client/shared/DOMHelpers.jsm166
1 files changed, 166 insertions, 0 deletions
diff --git a/devtools/client/shared/DOMHelpers.jsm b/devtools/client/shared/DOMHelpers.jsm
new file mode 100644
index 000000000..9c861006e
--- /dev/null
+++ b/devtools/client/shared/DOMHelpers.jsm
@@ -0,0 +1,166 @@
+/* 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/. */
+
+"use strict";
+
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+const nodeFilterConstants = require("devtools/shared/dom-node-filter-constants");
+
+this.EXPORTED_SYMBOLS = ["DOMHelpers"];
+
+/**
+ * DOMHelpers
+ * Makes DOM traversal easier. Goes through iframes.
+ *
+ * @constructor
+ * @param nsIDOMWindow aWindow
+ * The content window, owning the document to traverse.
+ */
+this.DOMHelpers = function DOMHelpers(aWindow) {
+ if (!aWindow) {
+ throw new Error("window can't be null or undefined");
+ }
+ this.window = aWindow;
+};
+
+DOMHelpers.prototype = {
+ getParentObject: function Helpers_getParentObject(node)
+ {
+ let parentNode = node ? node.parentNode : null;
+
+ if (!parentNode) {
+ // Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
+ // and Notation. top level windows have no parentNode
+ if (node && node == this.window.Node.DOCUMENT_NODE) {
+ // document type
+ if (node.defaultView) {
+ let embeddingFrame = node.defaultView.frameElement;
+ if (embeddingFrame)
+ return embeddingFrame.parentNode;
+ }
+ }
+ // a Document object without a parentNode or window
+ return null; // top level has no parent
+ }
+
+ if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
+ if (parentNode.defaultView) {
+ return parentNode.defaultView.frameElement;
+ }
+ // parent is document element, but no window at defaultView.
+ return null;
+ }
+
+ if (!parentNode.localName)
+ return null;
+
+ return parentNode;
+ },
+
+ getChildObject: function Helpers_getChildObject(node, index, previousSibling,
+ showTextNodesWithWhitespace)
+ {
+ if (!node)
+ return null;
+
+ if (node.contentDocument) {
+ // then the node is a frame
+ if (index == 0) {
+ return node.contentDocument.documentElement; // the node's HTMLElement
+ }
+ return null;
+ }
+
+ if (node.getSVGDocument) {
+ let svgDocument = node.getSVGDocument();
+ if (svgDocument) {
+ // then the node is a frame
+ if (index == 0) {
+ return svgDocument.documentElement; // the node's SVGElement
+ }
+ return null;
+ }
+ }
+
+ let child = null;
+ if (previousSibling) // then we are walking
+ child = this.getNextSibling(previousSibling);
+ else
+ child = this.getFirstChild(node);
+
+ if (showTextNodesWithWhitespace)
+ return child;
+
+ for (; child; child = this.getNextSibling(child)) {
+ if (!this.isWhitespaceText(child))
+ return child;
+ }
+
+ return null; // we have no children worth showing.
+ },
+
+ getFirstChild: function Helpers_getFirstChild(node)
+ {
+ let SHOW_ALL = nodeFilterConstants.SHOW_ALL;
+ this.treeWalker = node.ownerDocument.createTreeWalker(node,
+ SHOW_ALL, null);
+ return this.treeWalker.firstChild();
+ },
+
+ getNextSibling: function Helpers_getNextSibling(node)
+ {
+ let next = this.treeWalker.nextSibling();
+
+ if (!next)
+ delete this.treeWalker;
+
+ return next;
+ },
+
+ isWhitespaceText: function Helpers_isWhitespaceText(node)
+ {
+ return node.nodeType == this.window.Node.TEXT_NODE &&
+ !/[^\s]/.exec(node.nodeValue);
+ },
+
+ destroy: function Helpers_destroy()
+ {
+ delete this.window;
+ delete this.treeWalker;
+ },
+
+ /**
+ * A simple way to be notified (once) when a window becomes
+ * interactive (DOMContentLoaded).
+ *
+ * It is based on the chromeEventHandler. This is useful when
+ * chrome iframes are loaded in content docshells (in Firefox
+ * tabs for example).
+ */
+ onceDOMReady: function Helpers_onLocationChange(callback, targetURL) {
+ let window = this.window;
+ let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIWebNavigation)
+ .QueryInterface(Ci.nsIDocShell);
+ let onReady = function (event) {
+ if (event.target == window.document) {
+ docShell.chromeEventHandler.removeEventListener("DOMContentLoaded", onReady, false);
+ // If in `callback` the URL of the window is changed and a listener to DOMContentLoaded
+ // is attached, the event we just received will be also be caught by the new listener.
+ // We want to avoid that so we execute the callback in the next queue.
+ Services.tm.mainThread.dispatch(callback, 0);
+ }
+ };
+ if ((window.document.readyState == "complete" ||
+ window.document.readyState == "interactive") &&
+ window.location.href == targetURL) {
+ Services.tm.mainThread.dispatch(callback, 0);
+ } else {
+ docShell.chromeEventHandler.addEventListener("DOMContentLoaded", onReady, false);
+ }
+ }
+};