在Firefox中,在modules / devtools / inspector / inspector-panel.js的开头,你会看到一些对“walker”的引用,显示在这个片段的末尾:
...
/**
* Represents an open instance of the Inspector for a tab.
* The inspector controls the highlighter, the breadcrumbs,
* the markup view, and the sidebar (computed view, rule view
* and layout view).
*
* Events:
* - ready
* Fired when the inspector panel is opened for the first time and ready to
* use
* - new-root
* Fired after a new root (navigation to a new page) event was fired by
* the walker, and taken into account by the inspector (after the markup
* view has been reloaded)
* - markuploaded
* Fired when the markup-view frame has loaded
* - layout-change
* Fired when the layout of the inspector changes
* - breadcrumbs-updated
* Fired when the breadcrumb widget updates to a new node
* - layoutview-updated
* Fired when the layoutview (box model) updates to a new node
* - markupmutation
* Fired after markup mutations have been processed by the markup-view
* - computed-view-refreshed
* Fired when the computed rules view updates to a new node
* - computed-view-property-expanded
* Fired when a property is expanded in the computed rules view
* - computed-view-property-collapsed
* Fired when a property is collapsed in the computed rules view
* - rule-view-refreshed
* Fired when the rule view updates to a new node
*/
function InspectorPanel(iframeWindow, toolbox) {
this._toolbox = toolbox;
this._target = toolbox._target;
this.panelDoc = iframeWindow.document;
this.panelWin = iframeWindow;
this.panelWin.inspector = this;
this._inspector = null;
this._onBeforeNavigate = this._onBeforeNavigate.bind(this);
this._target.on("will-navigate", this._onBeforeNavigate);
EventEmitter.decorate(this);
}
exports.InspectorPanel = InspectorPanel;
InspectorPanel.prototype = {
/**
* open is effectively an asynchronous constructor
*/
open: function InspectorPanel_open() {
return this.target.makeRemote().then(() => {
return this._getWalker();
}).then(() => {
return this._getDefaultNodeForSelection();
}).then(defaultSelection => {
return this._deferredOpen(defaultSelection);
}).then(null, console.error);
},
get inspector() {
if (!this._target.form) {
throw new Error("Target.inspector requires an initialized remote actor.");
}
if (!this._inspector) {
this._inspector = InspectorFront(this._target.client, this._target.form);
}
return this._inspector;
},
_deferredOpen: function(defaultSelection) {
let deferred = promise.defer();
this.outerHTMLEditable = this._target.client.traits.editOuterHTML;
this.onNewRoot = this.onNewRoot.bind(this);
this.walker.on("new-root", this.onNewRoot);
this.nodemenu = this.panelDoc.getElementById("inspector-node-popup");
this.lastNodemenuItem = this.nodemenu.lastChild;
this._setupNodeMenu = this._setupNodeMenu.bind(this);
this._resetNodeMenu = this._resetNodeMenu.bind(this);
this.nodemenu.addEventListener("popupshowing", this._setupNodeMenu, true);
this.nodemenu.addEventListener("popuphiding", this._resetNodeMenu, true);
// Create an empty selection
this._selection = new Selection(this.walker);
this.onNewSelection = this.onNewSelection.bind(this);
this.selection.on("new-node-front", this.onNewSelection);
this.onBeforeNewSelection = this.onBeforeNewSelection.bind(this);
this.selection.on("before-new-node-front", this.onBeforeNewSelection);
this.onDetached = this.onDetached.bind(this);
this.selection.on("detached-front", this.onDetached);
this.breadcrumbs = new HTMLBreadcrumbs(this);
if (this.target.isLocalTab) {
this.browser = this.target.tab.linkedBrowser;
this.scheduleLayoutChange = this.scheduleLayoutChange.bind(this);
this.browser.addEventListener("resize", this.scheduleLayoutChange, true);
// Show a warning when the debugger is paused.
// We show the warning only when the inspector
// is selected.
this.updateDebuggerPausedWarning = function() {
let notificationBox = this._toolbox.getNotificationBox();
let notification = notificationBox.getNotificationWithValue("inspector-script-paused");
if (!notification && this._toolbox.currentToolId == "inspector" &&
this.target.isThreadPaused) {
let message = this.strings.GetStringFromName("debuggerPausedWarning.message");
notificationBox.appendNotification(message,
"inspector-script-paused", "", notificationBox.PRIORITY_WARNING_HIGH);
}
if (notification && this._toolbox.currentToolId != "inspector") {
notificationBox.removeNotification(notification);
}
if (notification && !this.target.isThreadPaused) {
notificationBox.removeNotification(notification);
}
}.bind(this);
this.target.on("thread-paused", this.updateDebuggerPausedWarning);
this.target.on("thread-resumed", this.updateDebuggerPausedWarning);
this._toolbox.on("select", this.updateDebuggerPausedWarning);
this.updateDebuggerPausedWarning();
}
this.highlighter = new Highlighter(this.target, this, this._toolbox);
let button = this.panelDoc.getElementById("inspector-inspect-toolbutton");
this.onLockStateChanged = function() {
if (this.highlighter.locked) {
button.removeAttribute("checked");
this._toolbox.raise();
} else {
button.setAttribute("checked", "true");
}
}.bind(this);
this.highlighter.on("locked", this.onLockStateChanged);
this.highlighter.on("unlocked", this.onLockStateChanged);
this._initMarkup();
this.isReady = false;
this.once("markuploaded", function() {
this.isReady = true;
// All the components are initialized. Let's select a node.
this._selection.setNodeFront(defaultSelection);
this.markup.expandNode(this.selection.nodeFront);
this.emit("ready");
deferred.resolve(this);
}.bind(this));
this.setupSearchBox();
this.setupSidebar();
return deferred.promise;
},
_onBeforeNavigate: function() {
this._defaultNode = null;
this.selection.setNodeFront(null);
this._destroyMarkup();
this.isDirty = false;
},
_getWalker: function() {
return this.inspector.getWalker().then(walker => {
this.walker = walker;
return this.inspector.getPageStyle();
}).then(pageStyle => {
this.pageStyle = pageStyle;
});
},
...
我没有在Addon APIs的任何地方看到这个Promise有记录,是否有任何文档(甚至源代码注释)是什么,以及如何使用它?
是否可以用它来添加特殊样式或在Firefox DevTools Inspector的DOM树视图中为某些元素添加一些图标?
答案 0 :(得分:1)
每当" walker"在devtools代码中提到,它通常是指工具包/ devtools / server / actors / inspector.js中的 WalkerActor 类。
演员是javascript类,专门用于从当前检查的页面和上下文中获取信息或操纵它们。
您看作用户的工具的UI部分不会直接执行此操作。实际上,devtools使用客户端 - 服务器协议在工具箱(托管您使用的所有面板)和作为被检查页面的一部分运行的actor之间进行通信。这是允许使用工具检查远程设备的原因。
特别是对于WalkerActor,它的作用是遍历DOM树并将有关节点的信息提供给检查器面板,以便它可以显示在工具中。
在页面上打开devtools检查器时看到的内容是DOM树的一部分(只是因为它尚未完全展开而且尚未检索到折叠的节点)由WalkerActor检索并(通过协议)发送到检查员面板。
面板的实际UI渲染在客户端上完成(这意味着,工具箱端,与演员/页面端相比),在browser / devtools / markupview / markup中完成-view.js
在此文件中,MarkupView和MarkupContainer类特别负责显示节点。它们并不是Addons API的特定组成部分,但由于特权代码可以访问gDevTools
全局变量,所以它应该相对容易掌握它们:
Cu.import("resource://gre/modules/devtools/Loader.jsm");
let target = devtools.TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.getToolbox(target);
let inspectorPanel = toolbox.getPanel("inspector");
inspector.markup // Returns the instance of MarkupView that is currently loaded in the inspector