зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1592517 - Migrate devtools DOMHelpers.jsm from JSM to plain JS module r=ochameau
Depends on D51054 Summary of the changes here: - move DOMHelpers.jsm to dom-helpers.js - remove all unused methods - converted to a static helper to avoid instanciating DOMHelpers objects for no reason - updated call sites accordingly Differential Revision: https://phabricator.services.mozilla.com/D51065 --HG-- rename : devtools/shared/DOMHelpers.jsm => devtools/shared/dom-helpers.js extra : moz-landing-system : lando
This commit is contained in:
Родитель
be1867fdfd
Коммит
3f0e2f4c4f
|
@ -7,7 +7,7 @@
|
||||||
const EventEmitter = require("devtools/shared/event-emitter");
|
const EventEmitter = require("devtools/shared/event-emitter");
|
||||||
const promise = require("promise");
|
const promise = require("promise");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const { DOMHelpers } = require("resource://devtools/shared/DOMHelpers.jsm");
|
const { DOMHelpers } = require("devtools/shared/dom-helpers");
|
||||||
|
|
||||||
loader.lazyRequireGetter(
|
loader.lazyRequireGetter(
|
||||||
this,
|
this,
|
||||||
|
@ -78,12 +78,11 @@ BottomHost.prototype = {
|
||||||
this.frame.setAttribute("src", "about:blank");
|
this.frame.setAttribute("src", "about:blank");
|
||||||
|
|
||||||
const frame = await new Promise(resolve => {
|
const frame = await new Promise(resolve => {
|
||||||
const domHelper = new DOMHelpers(this.frame.contentWindow);
|
|
||||||
const frameLoad = () => {
|
const frameLoad = () => {
|
||||||
this.emit("ready", this.frame);
|
this.emit("ready", this.frame);
|
||||||
resolve(this.frame);
|
resolve(this.frame);
|
||||||
};
|
};
|
||||||
domHelper.onceDOMReady(frameLoad);
|
DOMHelpers.onceDOMReady(this.frame.contentWindow, frameLoad);
|
||||||
focusTab(this.hostTab);
|
focusTab(this.hostTab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -174,12 +173,11 @@ class SidebarHost {
|
||||||
this.frame.setAttribute("src", "about:blank");
|
this.frame.setAttribute("src", "about:blank");
|
||||||
|
|
||||||
const frame = await new Promise(resolve => {
|
const frame = await new Promise(resolve => {
|
||||||
const domHelper = new DOMHelpers(this.frame.contentWindow);
|
|
||||||
const frameLoad = () => {
|
const frameLoad = () => {
|
||||||
this.emit("ready", this.frame);
|
this.emit("ready", this.frame);
|
||||||
resolve(this.frame);
|
resolve(this.frame);
|
||||||
};
|
};
|
||||||
domHelper.onceDOMReady(frameLoad);
|
DOMHelpers.onceDOMReady(this.frame.contentWindow, frameLoad);
|
||||||
focusTab(this.hostTab);
|
focusTab(this.hostTab);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ var EventEmitter = require("devtools/shared/event-emitter");
|
||||||
const Selection = require("devtools/client/framework/selection");
|
const Selection = require("devtools/client/framework/selection");
|
||||||
var Telemetry = require("devtools/client/shared/telemetry");
|
var Telemetry = require("devtools/client/shared/telemetry");
|
||||||
const { getUnicodeUrl } = require("devtools/client/shared/unicode-url");
|
const { getUnicodeUrl } = require("devtools/client/shared/unicode-url");
|
||||||
var { DOMHelpers } = require("resource://devtools/shared/DOMHelpers.jsm");
|
var { DOMHelpers } = require("devtools/shared/dom-helpers");
|
||||||
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
const { KeyCodes } = require("devtools/client/shared/keycodes");
|
||||||
var Startup = Cc["@mozilla.org/devtools/startup-clh;1"].getService(
|
var Startup = Cc["@mozilla.org/devtools/startup-clh;1"].getService(
|
||||||
Ci.nsISupports
|
Ci.nsISupports
|
||||||
|
@ -727,11 +727,14 @@ Toolbox.prototype = {
|
||||||
this._debugTargetData = this._getDebugTargetData();
|
this._debugTargetData = this._getDebugTargetData();
|
||||||
}
|
}
|
||||||
|
|
||||||
const domHelper = new DOMHelpers(this.win);
|
|
||||||
const domReady = new Promise(resolve => {
|
const domReady = new Promise(resolve => {
|
||||||
domHelper.onceDOMReady(() => {
|
DOMHelpers.onceDOMReady(
|
||||||
|
this.win,
|
||||||
|
() => {
|
||||||
resolve();
|
resolve();
|
||||||
}, this._URL);
|
},
|
||||||
|
this._URL
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Optimization: fire up a few other things before waiting on
|
// Optimization: fire up a few other things before waiting on
|
||||||
|
@ -2479,8 +2482,7 @@ Toolbox.prototype = {
|
||||||
// on the DOM node every time because this won't work
|
// on the DOM node every time because this won't work
|
||||||
// if the (xul chrome) iframe is loaded in a content docshell.
|
// if the (xul chrome) iframe is loaded in a content docshell.
|
||||||
if (iframe.contentWindow) {
|
if (iframe.contentWindow) {
|
||||||
const domHelper = new DOMHelpers(iframe.contentWindow);
|
DOMHelpers.onceDOMReady(iframe.contentWindow, onLoad);
|
||||||
domHelper.onceDOMReady(onLoad);
|
|
||||||
} else {
|
} else {
|
||||||
const callback = () => {
|
const callback = () => {
|
||||||
iframe.removeEventListener("DOMContentLoaded", callback);
|
iframe.removeEventListener("DOMContentLoaded", callback);
|
||||||
|
|
|
@ -200,11 +200,10 @@ async function testClickInInnerIframe(doc) {
|
||||||
|
|
||||||
iframe.srcdoc = "<div id=test style='height:50px'></div>";
|
iframe.srcdoc = "<div id=test style='height:50px'></div>";
|
||||||
await new Promise(r => {
|
await new Promise(r => {
|
||||||
const domHelper = new DOMHelpers(iframe.contentWindow);
|
|
||||||
const frameLoad = () => {
|
const frameLoad = () => {
|
||||||
r();
|
r();
|
||||||
};
|
};
|
||||||
domHelper.onceDOMReady(frameLoad);
|
DOMHelpers.onceDOMReady(iframe.contentWindow, frameLoad);
|
||||||
});
|
});
|
||||||
|
|
||||||
await waitUntil(() => iframe.contentWindow.document.getElementById("test"));
|
await waitUntil(() => iframe.contentWindow.document.getElementById("test"));
|
||||||
|
|
|
@ -13,9 +13,7 @@ Services.scriptloader.loadSubScript(
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
|
||||||
const { DOMHelpers } = ChromeUtils.import(
|
const { DOMHelpers } = require("devtools/shared/dom-helpers");
|
||||||
"resource://devtools/shared/DOMHelpers.jsm"
|
|
||||||
);
|
|
||||||
const { Hosts } = require("devtools/client/framework/toolbox-hosts");
|
const { Hosts } = require("devtools/client/framework/toolbox-hosts");
|
||||||
|
|
||||||
const TEST_URI_ROOT = "http://example.com/browser/devtools/client/shared/test/";
|
const TEST_URI_ROOT = "http://example.com/browser/devtools/client/shared/test/";
|
||||||
|
@ -119,9 +117,8 @@ const createHost = async function(
|
||||||
const iframe = await host.create();
|
const iframe = await host.create();
|
||||||
|
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
const domHelper = new DOMHelpers(iframe.contentWindow);
|
|
||||||
iframe.setAttribute("src", src);
|
iframe.setAttribute("src", src);
|
||||||
domHelper.onceDOMReady(resolve);
|
DOMHelpers.onceDOMReady(iframe.contentWindow, resolve);
|
||||||
});
|
});
|
||||||
|
|
||||||
return [host, iframe.contentWindow, iframe.contentDocument];
|
return [host, iframe.contentWindow, iframe.contentDocument];
|
||||||
|
|
|
@ -8,7 +8,7 @@ const {
|
||||||
} = require("devtools/client/shared/widgets/view-helpers");
|
} = require("devtools/client/shared/widgets/view-helpers");
|
||||||
const { getCurrentZoom } = require("devtools/shared/layout/utils");
|
const { getCurrentZoom } = require("devtools/shared/layout/utils");
|
||||||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||||
const { DOMHelpers } = require("resource://devtools/shared/DOMHelpers.jsm");
|
const { DOMHelpers } = require("devtools/shared/dom-helpers");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
|
||||||
|
|
||||||
|
@ -1293,8 +1293,7 @@ AbstractCanvasGraph.createIframe = function(url, parent, callback) {
|
||||||
|
|
||||||
// Use DOMHelpers to wait for the frame load. DOMHelpers relies on chromeEventHandler
|
// Use DOMHelpers to wait for the frame load. DOMHelpers relies on chromeEventHandler
|
||||||
// so this will still work if DevTools are loaded in a content frame.
|
// so this will still work if DevTools are loaded in a content frame.
|
||||||
const domHelper = new DOMHelpers(iframe.contentWindow);
|
DOMHelpers.onceDOMReady(iframe.contentWindow, function() {
|
||||||
domHelper.onceDOMReady(function() {
|
|
||||||
callback(iframe);
|
callback(iframe);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ loader.lazyRequireGetter(
|
||||||
loader.lazyRequireGetter(
|
loader.lazyRequireGetter(
|
||||||
this,
|
this,
|
||||||
"DOMHelpers",
|
"DOMHelpers",
|
||||||
"resource://devtools/shared/DOMHelpers.jsm",
|
"devtools/shared/dom-helpers",
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -742,8 +742,7 @@ const NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
|
||||||
const { contentDocument, contentWindow } = this.rawNode;
|
const { contentDocument, contentWindow } = this.rawNode;
|
||||||
if (contentDocument && contentDocument.readyState !== "complete") {
|
if (contentDocument && contentDocument.readyState !== "complete") {
|
||||||
await new Promise(resolve => {
|
await new Promise(resolve => {
|
||||||
const domHelper = new DOMHelpers(contentWindow);
|
DOMHelpers.onceDOMReady(contentWindow, resolve);
|
||||||
domHelper.onceDOMReady(resolve);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,174 +0,0 @@
|
||||||
/* 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 { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
|
||||||
const { require } = ChromeUtils.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 win
|
|
||||||
* The content window, owning the document to traverse.
|
|
||||||
*/
|
|
||||||
this.DOMHelpers = function DOMHelpers(win) {
|
|
||||||
if (!win) {
|
|
||||||
throw new Error("window can't be null or undefined");
|
|
||||||
}
|
|
||||||
this.window = win;
|
|
||||||
};
|
|
||||||
|
|
||||||
DOMHelpers.prototype = {
|
|
||||||
getParentObject: function(node) {
|
|
||||||
const 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) {
|
|
||||||
const 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(
|
|
||||||
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) {
|
|
||||||
const 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(node) {
|
|
||||||
const SHOW_ALL = nodeFilterConstants.SHOW_ALL;
|
|
||||||
this.treeWalker = node.ownerDocument.createTreeWalker(node, SHOW_ALL, null);
|
|
||||||
return this.treeWalker.firstChild();
|
|
||||||
},
|
|
||||||
|
|
||||||
getNextSibling: function(node) {
|
|
||||||
const next = this.treeWalker.nextSibling();
|
|
||||||
|
|
||||||
if (!next) {
|
|
||||||
delete this.treeWalker;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
|
||||||
},
|
|
||||||
|
|
||||||
isWhitespaceText: function(node) {
|
|
||||||
return (
|
|
||||||
node.nodeType == this.window.Node.TEXT_NODE &&
|
|
||||||
!/[^\s]/.exec(node.nodeValue)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
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(callback, targetURL) {
|
|
||||||
const window = this.window;
|
|
||||||
const docShell = window.docShell;
|
|
||||||
const onReady = function(event) {
|
|
||||||
if (event.target == window.document) {
|
|
||||||
docShell.chromeEventHandler.removeEventListener(
|
|
||||||
"DOMContentLoaded",
|
|
||||||
onReady
|
|
||||||
);
|
|
||||||
// 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.dispatchToMainThread(callback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (
|
|
||||||
(window.document.readyState == "complete" ||
|
|
||||||
window.document.readyState == "interactive") &&
|
|
||||||
window.location.href == targetURL
|
|
||||||
) {
|
|
||||||
Services.tm.dispatchToMainThread(callback);
|
|
||||||
} else {
|
|
||||||
docShell.chromeEventHandler.addEventListener("DOMContentLoaded", onReady);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* 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 Services = require("Services");
|
||||||
|
|
||||||
|
exports.DOMHelpers = {
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*
|
||||||
|
* @param nsIDOMWindow win
|
||||||
|
* The content window, owning the document to traverse.
|
||||||
|
* @param Function callback
|
||||||
|
* The method to call when the frame is loaded.
|
||||||
|
* @param String targetURL
|
||||||
|
* (optional) Check that the frame URL corresponds to the provided URL
|
||||||
|
* before calling the callback.
|
||||||
|
*/
|
||||||
|
onceDOMReady: function(win, callback, targetURL) {
|
||||||
|
if (!win) {
|
||||||
|
throw new Error("window can't be null or undefined");
|
||||||
|
}
|
||||||
|
const docShell = win.docShell;
|
||||||
|
const onReady = function(event) {
|
||||||
|
if (event.target == win.document) {
|
||||||
|
docShell.chromeEventHandler.removeEventListener(
|
||||||
|
"DOMContentLoaded",
|
||||||
|
onReady
|
||||||
|
);
|
||||||
|
// 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.dispatchToMainThread(callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (
|
||||||
|
(win.document.readyState == "complete" ||
|
||||||
|
win.document.readyState == "interactive") &&
|
||||||
|
win.location.href == targetURL
|
||||||
|
) {
|
||||||
|
Services.tm.dispatchToMainThread(callback);
|
||||||
|
} else {
|
||||||
|
docShell.chromeEventHandler.addEventListener("DOMContentLoaded", onReady);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
|
@ -53,9 +53,9 @@ DevToolsModules(
|
||||||
'debounce.js',
|
'debounce.js',
|
||||||
'defer.js',
|
'defer.js',
|
||||||
'DevToolsUtils.js',
|
'DevToolsUtils.js',
|
||||||
|
'dom-helpers.js',
|
||||||
'dom-node-constants.js',
|
'dom-node-constants.js',
|
||||||
'dom-node-filter-constants.js',
|
'dom-node-filter-constants.js',
|
||||||
'DOMHelpers.jsm',
|
|
||||||
'event-emitter.js',
|
'event-emitter.js',
|
||||||
'execution-point-utils.js',
|
'execution-point-utils.js',
|
||||||
'extend.js',
|
'extend.js',
|
||||||
|
|
Загрузка…
Ссылка в новой задаче