browser/devtools/shared/DOMHelpers.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 const Ci = Components.interfaces;
michael@0 6 const Cu = Components.utils;
michael@0 7 Cu.import("resource://gre/modules/Services.jsm");
michael@0 8
michael@0 9 this.EXPORTED_SYMBOLS = ["DOMHelpers"];
michael@0 10
michael@0 11 /**
michael@0 12 * DOMHelpers
michael@0 13 * Makes DOM traversal easier. Goes through iframes.
michael@0 14 *
michael@0 15 * @constructor
michael@0 16 * @param nsIDOMWindow aWindow
michael@0 17 * The content window, owning the document to traverse.
michael@0 18 */
michael@0 19 this.DOMHelpers = function DOMHelpers(aWindow) {
michael@0 20 if (!aWindow) {
michael@0 21 throw new Error("window can't be null or undefined");
michael@0 22 }
michael@0 23 this.window = aWindow;
michael@0 24 };
michael@0 25
michael@0 26 DOMHelpers.prototype = {
michael@0 27 getParentObject: function Helpers_getParentObject(node)
michael@0 28 {
michael@0 29 let parentNode = node ? node.parentNode : null;
michael@0 30
michael@0 31 if (!parentNode) {
michael@0 32 // Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
michael@0 33 // and Notation. top level windows have no parentNode
michael@0 34 if (node && node == this.window.Node.DOCUMENT_NODE) {
michael@0 35 // document type
michael@0 36 if (node.defaultView) {
michael@0 37 let embeddingFrame = node.defaultView.frameElement;
michael@0 38 if (embeddingFrame)
michael@0 39 return embeddingFrame.parentNode;
michael@0 40 }
michael@0 41 }
michael@0 42 // a Document object without a parentNode or window
michael@0 43 return null; // top level has no parent
michael@0 44 }
michael@0 45
michael@0 46 if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
michael@0 47 if (parentNode.defaultView) {
michael@0 48 return parentNode.defaultView.frameElement;
michael@0 49 }
michael@0 50 // parent is document element, but no window at defaultView.
michael@0 51 return null;
michael@0 52 }
michael@0 53
michael@0 54 if (!parentNode.localName)
michael@0 55 return null;
michael@0 56
michael@0 57 return parentNode;
michael@0 58 },
michael@0 59
michael@0 60 getChildObject: function Helpers_getChildObject(node, index, previousSibling,
michael@0 61 showTextNodesWithWhitespace)
michael@0 62 {
michael@0 63 if (!node)
michael@0 64 return null;
michael@0 65
michael@0 66 if (node.contentDocument) {
michael@0 67 // then the node is a frame
michael@0 68 if (index == 0) {
michael@0 69 return node.contentDocument.documentElement; // the node's HTMLElement
michael@0 70 }
michael@0 71 return null;
michael@0 72 }
michael@0 73
michael@0 74 if (node.getSVGDocument) {
michael@0 75 let svgDocument = node.getSVGDocument();
michael@0 76 if (svgDocument) {
michael@0 77 // then the node is a frame
michael@0 78 if (index == 0) {
michael@0 79 return svgDocument.documentElement; // the node's SVGElement
michael@0 80 }
michael@0 81 return null;
michael@0 82 }
michael@0 83 }
michael@0 84
michael@0 85 let child = null;
michael@0 86 if (previousSibling) // then we are walking
michael@0 87 child = this.getNextSibling(previousSibling);
michael@0 88 else
michael@0 89 child = this.getFirstChild(node);
michael@0 90
michael@0 91 if (showTextNodesWithWhitespace)
michael@0 92 return child;
michael@0 93
michael@0 94 for (; child; child = this.getNextSibling(child)) {
michael@0 95 if (!this.isWhitespaceText(child))
michael@0 96 return child;
michael@0 97 }
michael@0 98
michael@0 99 return null; // we have no children worth showing.
michael@0 100 },
michael@0 101
michael@0 102 getFirstChild: function Helpers_getFirstChild(node)
michael@0 103 {
michael@0 104 let SHOW_ALL = Components.interfaces.nsIDOMNodeFilter.SHOW_ALL;
michael@0 105 this.treeWalker = node.ownerDocument.createTreeWalker(node,
michael@0 106 SHOW_ALL, null);
michael@0 107 return this.treeWalker.firstChild();
michael@0 108 },
michael@0 109
michael@0 110 getNextSibling: function Helpers_getNextSibling(node)
michael@0 111 {
michael@0 112 let next = this.treeWalker.nextSibling();
michael@0 113
michael@0 114 if (!next)
michael@0 115 delete this.treeWalker;
michael@0 116
michael@0 117 return next;
michael@0 118 },
michael@0 119
michael@0 120 isWhitespaceText: function Helpers_isWhitespaceText(node)
michael@0 121 {
michael@0 122 return node.nodeType == this.window.Node.TEXT_NODE &&
michael@0 123 !/[^\s]/.exec(node.nodeValue);
michael@0 124 },
michael@0 125
michael@0 126 destroy: function Helpers_destroy()
michael@0 127 {
michael@0 128 delete this.window;
michael@0 129 delete this.treeWalker;
michael@0 130 },
michael@0 131
michael@0 132 /**
michael@0 133 * A simple way to be notified (once) when a window becomes
michael@0 134 * interactive (DOMContentLoaded).
michael@0 135 *
michael@0 136 * It is based on the chromeEventHandler. This is useful when
michael@0 137 * chrome iframes are loaded in content docshells (in Firefox
michael@0 138 * tabs for example).
michael@0 139 */
michael@0 140 onceDOMReady: function Helpers_onLocationChange(callback) {
michael@0 141 let window = this.window;
michael@0 142 let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
michael@0 143 .getInterface(Ci.nsIWebNavigation)
michael@0 144 .QueryInterface(Ci.nsIDocShell);
michael@0 145 let onReady = function(event) {
michael@0 146 if (event.target == window.document) {
michael@0 147 docShell.chromeEventHandler.removeEventListener("DOMContentLoaded", onReady, false);
michael@0 148 // If in `callback` the URL of the window is changed and a listener to DOMContentLoaded
michael@0 149 // is attached, the event we just received will be also be caught by the new listener.
michael@0 150 // We want to avoid that so we execute the callback in the next queue.
michael@0 151 Services.tm.mainThread.dispatch(callback, 0);
michael@0 152 }
michael@0 153 }
michael@0 154 docShell.chromeEventHandler.addEventListener("DOMContentLoaded", onReady, false);
michael@0 155 }
michael@0 156 };

mercurial