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.

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

mercurial