Bug 572038 - Create new Tree Panel for Inspector, r=gavin, a=blocking2.0
This commit is contained in:
@@ -41,6 +41,8 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#endif
|
||||
|
||||
#include insideOutBox.js
|
||||
|
||||
const INSPECTOR_INVISIBLE_ELEMENTS = {
|
||||
"head": true,
|
||||
"base": true,
|
||||
@@ -272,7 +274,7 @@ PanelHighlighter.prototype = {
|
||||
let visibleWidth = this.win.innerWidth;
|
||||
let visibleHeight = this.win.innerHeight;
|
||||
|
||||
return ((0 <= aRect.left) && (aRect.right <= visibleWidth) &&
|
||||
return ((0 <= aRect.left) && (aRect.right <= visibleWidth) &&
|
||||
(0 <= aRect.top) && (aRect.bottom <= visibleHeight))
|
||||
},
|
||||
|
||||
@@ -322,169 +324,6 @@ PanelHighlighter.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// InspectorTreeView
|
||||
|
||||
/**
|
||||
* TreeView object to manage the view of the DOM tree. Wraps and provides an
|
||||
* interface to an inIDOMView object
|
||||
*
|
||||
* @param aWindow
|
||||
* a top-level window object
|
||||
*/
|
||||
function InspectorTreeView(aWindow)
|
||||
{
|
||||
this.tree = document.getElementById("inspector-tree");
|
||||
this.treeBody = document.getElementById("inspector-tree-body");
|
||||
this.view = Cc["@mozilla.org/inspector/dom-view;1"]
|
||||
.createInstance(Ci.inIDOMView);
|
||||
this.view.showSubDocuments = true;
|
||||
this.view.whatToShow = NodeFilter.SHOW_ALL;
|
||||
this.tree.view = this.view;
|
||||
this.contentWindow = aWindow;
|
||||
this.view.rootNode = aWindow.document;
|
||||
this.view.rebuild();
|
||||
}
|
||||
|
||||
InspectorTreeView.prototype = {
|
||||
get editable() { return false; },
|
||||
get selection() { return this.view.selection; },
|
||||
|
||||
/**
|
||||
* Destroy the view.
|
||||
*/
|
||||
destroy: function ITV_destroy()
|
||||
{
|
||||
this.tree.view = null;
|
||||
this.view = null;
|
||||
this.tree = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the cell text at a given row and column.
|
||||
*
|
||||
* @param aRow
|
||||
* The row index of the desired cell.
|
||||
* @param aCol
|
||||
* The column index of the desired cell.
|
||||
* @returns string
|
||||
*/
|
||||
getCellText: function ITV_getCellText(aRow, aCol)
|
||||
{
|
||||
return this.view.getCellText(aRow, aCol);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the index of the selected row.
|
||||
*
|
||||
* @returns number -1 if there is no row selected.
|
||||
*/
|
||||
get selectionIndex()
|
||||
{
|
||||
return this.selection ? this.selection.currentIndex : -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the corresponding node for the currently-selected row in the tree.
|
||||
*
|
||||
* @returns DOMNode|null
|
||||
*/
|
||||
get selectedNode()
|
||||
{
|
||||
let rowIndex = this.selectionIndex;
|
||||
return rowIndex > -1 ? this.view.getNodeFromRowIndex(rowIndex) : null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the selected row in the table to the specified index.
|
||||
*
|
||||
* @param anIndex
|
||||
* The index to set the selection to.
|
||||
*/
|
||||
set selectedRow(anIndex)
|
||||
{
|
||||
this.view.selection.select(anIndex);
|
||||
this.tree.treeBoxObject.ensureRowIsVisible(anIndex);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the selected node to the specified document node.
|
||||
*
|
||||
* @param aNode
|
||||
* The document node to select in the tree.
|
||||
*/
|
||||
set selectedNode(aNode)
|
||||
{
|
||||
let rowIndex = this.view.getRowIndexFromNode(aNode);
|
||||
if (rowIndex > -1) {
|
||||
this.selectedRow = rowIndex;
|
||||
} else {
|
||||
this.selectElementInTree(aNode);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Select the given node in the tree, searching for and expanding rows
|
||||
* as-needed.
|
||||
*
|
||||
* @param aNode
|
||||
* The document node to select in the three.
|
||||
* @returns boolean
|
||||
* Whether a node was selected or not if not found.
|
||||
*/
|
||||
selectElementInTree: function ITV_selectElementInTree(aNode)
|
||||
{
|
||||
if (!aNode) {
|
||||
this.view.selection.select(null);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep searching until a pre-created ancestor is found, then
|
||||
// open each ancestor until the found element is created.
|
||||
let domUtils = Cc["@mozilla.org/inspector/dom-utils;1"].
|
||||
getService(Ci.inIDOMUtils);
|
||||
let line = [];
|
||||
let parent = aNode;
|
||||
let index = null;
|
||||
|
||||
while (parent) {
|
||||
index = this.view.getRowIndexFromNode(parent);
|
||||
line.push(parent);
|
||||
if (index < 0) {
|
||||
// Row for this node hasn't been created yet.
|
||||
parent = domUtils.getParentForNode(parent,
|
||||
this.view.showAnonymousContent);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We have all the ancestors, now open them one-by-one from the top
|
||||
// to bottom.
|
||||
let lastIndex;
|
||||
let view = this.tree.treeBoxObject.view;
|
||||
|
||||
for (let i = line.length - 1; i >= 0; --i) {
|
||||
index = this.view.getRowIndexFromNode(line[i]);
|
||||
if (index < 0) {
|
||||
// Can't find the row, so stop trying to descend.
|
||||
break;
|
||||
}
|
||||
if (i > 0 && !view.isContainerOpen(index)) {
|
||||
view.toggleOpenState(index);
|
||||
}
|
||||
lastIndex = index;
|
||||
}
|
||||
|
||||
if (lastIndex >= 0) {
|
||||
this.selectedRow = lastIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// InspectorUI
|
||||
|
||||
@@ -494,6 +333,7 @@ InspectorTreeView.prototype = {
|
||||
var InspectorUI = {
|
||||
browser: null,
|
||||
selectEventsSuppressed: false,
|
||||
showTextNodesWithWhitespace: false,
|
||||
inspecting: false,
|
||||
|
||||
/**
|
||||
@@ -504,7 +344,7 @@ var InspectorUI = {
|
||||
*/
|
||||
toggleInspectorUI: function IUI_toggleInspectorUI(aEvent)
|
||||
{
|
||||
if (this.isPanelOpen) {
|
||||
if (this.isTreePanelOpen) {
|
||||
this.closeInspectorUI(true);
|
||||
} else {
|
||||
this.openInspectorUI();
|
||||
@@ -533,8 +373,8 @@ var InspectorUI = {
|
||||
this.stylePanel.hidePopup();
|
||||
} else {
|
||||
this.openStylePanel();
|
||||
if (this.treeView.selectedNode) {
|
||||
this.updateStylePanel(this.treeView.selectedNode);
|
||||
if (this.selection) {
|
||||
this.updateStylePanel(this.selection);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -549,8 +389,8 @@ var InspectorUI = {
|
||||
} else {
|
||||
this.clearDOMPanel();
|
||||
this.openDOMPanel();
|
||||
if (this.treeView.selectedNode) {
|
||||
this.updateDOMPanel(this.treeView.selectedNode);
|
||||
if (this.selection) {
|
||||
this.updateDOMPanel(this.selection);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -560,7 +400,7 @@ var InspectorUI = {
|
||||
*
|
||||
* @returns boolean
|
||||
*/
|
||||
get isPanelOpen()
|
||||
get isTreePanelOpen()
|
||||
{
|
||||
return this.treePanel && this.treePanel.state == "open";
|
||||
},
|
||||
@@ -585,26 +425,145 @@ var InspectorUI = {
|
||||
return this.domPanel && this.domPanel.state == "open";
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the default selection element for the inspected document.
|
||||
*/
|
||||
get defaultSelection()
|
||||
{
|
||||
let doc = this.win.document;
|
||||
return doc.documentElement.lastElementChild;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the inspector's tree panel and initialize it.
|
||||
*/
|
||||
openTreePanel: function IUI_openTreePanel()
|
||||
{
|
||||
if (!this.treePanel) {
|
||||
this.treePanel = document.getElementById("inspector-panel");
|
||||
this.treePanel = document.getElementById("inspector-tree-panel");
|
||||
this.treePanel.hidden = false;
|
||||
}
|
||||
if (!this.isPanelOpen) {
|
||||
const panelWidthRatio = 7 / 8;
|
||||
const panelHeightRatio = 1 / 5;
|
||||
let bar = document.getElementById("status-bar");
|
||||
this.treePanel.openPopupAtScreen(this.win.screenX + 80,
|
||||
this.win.outerHeight + this.win.screenY);
|
||||
this.treePanel.sizeTo(this.win.outerWidth * panelWidthRatio,
|
||||
this.win.outerHeight * panelHeightRatio);
|
||||
this.tree = document.getElementById("inspector-tree");
|
||||
this.createDocumentModel();
|
||||
|
||||
const panelWidthRatio = 7 / 8;
|
||||
const panelHeightRatio = 1 / 5;
|
||||
this.treePanel.openPopup(this.browser, "overlap", 80, this.win.innerHeight,
|
||||
false, false);
|
||||
this.treePanel.sizeTo(this.win.outerWidth * panelWidthRatio,
|
||||
this.win.outerHeight * panelHeightRatio);
|
||||
|
||||
this.treeIFrame = document.getElementById("inspector-tree-iframe");
|
||||
this.treeBrowserDocument = this.treeIFrame.contentDocument;
|
||||
this.treePanelDiv = this.treeBrowserDocument.createElement("div");
|
||||
this.treeBrowserDocument.body.appendChild(this.treePanelDiv);
|
||||
this.treePanelDiv.ownerPanel = this;
|
||||
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
|
||||
this.ioBox.createObjectBox(this.win.document.documentElement);
|
||||
},
|
||||
|
||||
createObjectBox: function IUI_createObjectBox(object, isRoot)
|
||||
{
|
||||
let tag = this.domplateUtils.getNodeTag(object);
|
||||
if (tag)
|
||||
return tag.replace({object: object}, this.treeBrowserDocument);
|
||||
},
|
||||
|
||||
getParentObject: function IUI_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 == 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 == Node.DOCUMENT_NODE) {
|
||||
if (parentNode.defaultView) {
|
||||
return parentNode.defaultView.frameElement;
|
||||
}
|
||||
if (this.embeddedBrowserParents) {
|
||||
let skipParent = this.embeddedBrowserParents[node];
|
||||
// HTML element? could be iframe?
|
||||
if (skipParent)
|
||||
return skipParent;
|
||||
} else // parent is document element, but no window at defaultView.
|
||||
return null;
|
||||
} else if (!parentNode.localName) {
|
||||
return null;
|
||||
}
|
||||
return parentNode;
|
||||
},
|
||||
|
||||
getChildObject: function IUI_getChildObject(node, index, previousSibling)
|
||||
{
|
||||
if (!node)
|
||||
return null;
|
||||
|
||||
if (node.contentDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
if (!this.embeddedBrowserParents)
|
||||
this.embeddedBrowserParents = {};
|
||||
let skipChild = node.contentDocument.documentElement;
|
||||
this.embeddedBrowserParents[skipChild] = node;
|
||||
return skipChild; // the node's HTMLElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node instanceof GetSVGDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
if (!this.embeddedBrowserParents)
|
||||
this.embeddedBrowserParents = {};
|
||||
let skipChild = node.getSVGDocument().documentElement;
|
||||
this.embeddedBrowserParents[skipChild] = node;
|
||||
return skipChild; // 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 (this.showTextNodesWithWhitespace)
|
||||
return child;
|
||||
|
||||
for (; child; child = this.getNextSibling(child)) {
|
||||
if (!this.domplateUtils.isWhitespaceText(child))
|
||||
return child;
|
||||
}
|
||||
|
||||
return null; // we have no children worth showing.
|
||||
},
|
||||
|
||||
getFirstChild: function IUI_getFirstChild(node)
|
||||
{
|
||||
this.treeWalker = node.ownerDocument.createTreeWalker(node,
|
||||
NodeFilter.SHOW_ALL, null, false);
|
||||
return this.treeWalker.firstChild();
|
||||
},
|
||||
|
||||
getNextSibling: function IUI_getNextSibling(node)
|
||||
{
|
||||
let next = this.treeWalker.nextSibling();
|
||||
|
||||
if (!next)
|
||||
delete this.treeWalker;
|
||||
|
||||
return next;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -664,6 +623,10 @@ var InspectorUI = {
|
||||
this.browser = gBrowser.selectedBrowser;
|
||||
this.win = this.browser.contentWindow;
|
||||
this.winID = this.getWindowID(this.win);
|
||||
if (!this.domplate) {
|
||||
Cu.import("resource:///modules/domplate.jsm", this);
|
||||
this.domplateUtils.setDOM(window);
|
||||
}
|
||||
|
||||
// DOM panel initialization and loading (via PropertyPanel.jsm)
|
||||
let objectPanelTitle = this.strings.
|
||||
@@ -693,29 +656,16 @@ var InspectorUI = {
|
||||
// setup highlighter and start inspecting
|
||||
this.initializeHighlighter();
|
||||
|
||||
if (!InspectorStore.hasID(this.winID) ||
|
||||
InspectorStore.getValue(this.winID, "inspecting")) {
|
||||
// Setup the InspectorStore or restore state
|
||||
this.initializeStore();
|
||||
|
||||
if (InspectorStore.getValue(this.winID, "inspecting"))
|
||||
this.startInspecting();
|
||||
}
|
||||
|
||||
this.win.document.addEventListener("scroll", this, false);
|
||||
this.win.addEventListener("resize", this, false);
|
||||
this.inspectCmd.setAttribute("checked", true);
|
||||
|
||||
if (InspectorStore.isEmpty()) {
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
|
||||
}
|
||||
|
||||
if (InspectorStore.hasID(this.winID)) {
|
||||
let selectedNode = InspectorStore.getValue(this.winID, "selectedNode");
|
||||
if (selectedNode) {
|
||||
this.inspectNode(selectedNode);
|
||||
}
|
||||
} else {
|
||||
InspectorStore.addStore(this.winID);
|
||||
InspectorStore.setValue(this.winID, "selectedNode", null);
|
||||
this.win.addEventListener("pagehide", this, true);
|
||||
}
|
||||
document.addEventListener("popupshown", this, false);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -726,6 +676,30 @@ var InspectorUI = {
|
||||
this.highlighter = new PanelHighlighter(this.browser);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialize the InspectorStore.
|
||||
*/
|
||||
initializeStore: function IUI_initializeStore()
|
||||
{
|
||||
// First time opened, add the TabSelect listener
|
||||
if (InspectorStore.isEmpty())
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
|
||||
|
||||
// Has this windowID been inspected before?
|
||||
if (InspectorStore.hasID(this.winID)) {
|
||||
let selectedNode = InspectorStore.getValue(this.winID, "selectedNode");
|
||||
if (selectedNode) {
|
||||
this.inspectNode(selectedNode);
|
||||
}
|
||||
} else {
|
||||
// First time inspecting, set state to no selection + live inspection.
|
||||
InspectorStore.addStore(this.winID);
|
||||
InspectorStore.setValue(this.winID, "selectedNode", null);
|
||||
InspectorStore.setValue(this.winID, "inspecting", true);
|
||||
this.win.addEventListener("pagehide", this, true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Close inspector UI and associated panels. Unhighlight and stop inspecting.
|
||||
* Remove event listeners for document scrolling, resize,
|
||||
@@ -736,13 +710,21 @@ var InspectorUI = {
|
||||
*/
|
||||
closeInspectorUI: function IUI_closeInspectorUI(aClearStore)
|
||||
{
|
||||
if (this.closing || !this.win || !this.browser) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.closing = true;
|
||||
|
||||
if (aClearStore) {
|
||||
InspectorStore.deleteStore(this.winID);
|
||||
this.win.removeEventListener("pagehide", this, true);
|
||||
} else {
|
||||
// Update the store before closing.
|
||||
InspectorStore.setValue(this.winID, "selectedNode",
|
||||
this.treeView.selectedNode);
|
||||
if (this.selection) {
|
||||
InspectorStore.setValue(this.winID, "selectedNode",
|
||||
this.selection);
|
||||
}
|
||||
InspectorStore.setValue(this.winID, "inspecting", this.inspecting);
|
||||
}
|
||||
|
||||
@@ -756,10 +738,28 @@ var InspectorUI = {
|
||||
if (this.highlighter && this.highlighter.isHighlighting) {
|
||||
this.highlighter.unhighlight();
|
||||
}
|
||||
if (this.isPanelOpen) {
|
||||
|
||||
if (this.isTreePanelOpen)
|
||||
this.treePanel.hidePopup();
|
||||
this.treeView.destroy();
|
||||
if (this.treePanelDiv) {
|
||||
this.treePanelDiv.ownerPanel = null;
|
||||
let parent = this.treePanelDiv.parentNode;
|
||||
parent.removeChild(this.treePanelDiv);
|
||||
delete this.treePanelDiv;
|
||||
delete this.treeBrowserDocument;
|
||||
}
|
||||
|
||||
if (this.treeIFrame)
|
||||
delete this.treeIFrame;
|
||||
delete this.ioBox;
|
||||
|
||||
if (this.domplate) {
|
||||
this.domplateUtils.setDOM(null);
|
||||
delete this.domplate;
|
||||
delete this.HTMLTemplates;
|
||||
delete this.domplateUtils;
|
||||
}
|
||||
|
||||
if (this.isStylePanelOpen) {
|
||||
this.stylePanel.hidePopup();
|
||||
}
|
||||
@@ -772,6 +772,9 @@ var InspectorUI = {
|
||||
this.inspectCmd.setAttribute("checked", false);
|
||||
this.browser = this.win = null; // null out references to browser and window
|
||||
this.winID = null;
|
||||
this.selection = null;
|
||||
this.closing = false;
|
||||
Services.obs.notifyObservers(null, "inspector-closed", null);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -798,23 +801,40 @@ var InspectorUI = {
|
||||
this.inspecting = false;
|
||||
this.toggleDimForPanel(this.stylePanel);
|
||||
this.toggleDimForPanel(this.domPanel);
|
||||
if (this.treeView.selection) {
|
||||
this.updateStylePanel(this.treeView.selectedNode);
|
||||
this.updateDOMPanel(this.treeView.selectedNode);
|
||||
if (this.highlighter.node) {
|
||||
this.select(this.highlighter.node, true, true);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Select an object in the tree view.
|
||||
* @param aNode
|
||||
* node to inspect
|
||||
* @param forceUpdate
|
||||
* force an update?
|
||||
* @param aScroll
|
||||
* force scroll?
|
||||
*/
|
||||
select: function IUI_select(aNode, forceUpdate, aScroll)
|
||||
{
|
||||
if (!aNode)
|
||||
aNode = this.defaultSelection;
|
||||
|
||||
if (forceUpdate || aNode != this.selection) {
|
||||
this.selection = aNode;
|
||||
let box = this.ioBox.createObjectBox(this.selection);
|
||||
if (!this.inspecting) {
|
||||
this.highlighter.highlightNode(this.selection);
|
||||
this.updateStylePanel(this.selection);
|
||||
this.updateDOMPanel(this.selection);
|
||||
}
|
||||
this.ioBox.select(aNode, true, true, aScroll);
|
||||
}
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//// Model Creation Methods
|
||||
|
||||
/**
|
||||
* Create treeView object from content window.
|
||||
*/
|
||||
createDocumentModel: function IUI_createDocumentModel()
|
||||
{
|
||||
this.treeView = new InspectorTreeView(this.win);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a new item to the style panel listbox.
|
||||
*
|
||||
@@ -879,8 +899,8 @@ var InspectorUI = {
|
||||
createStyleItems: function IUI_createStyleItems(aRules, aSections)
|
||||
{
|
||||
this.createStyleRuleItems(aRules);
|
||||
let inheritedString =
|
||||
this.strings.GetStringFromName("style.inheritedFrom");
|
||||
let inheritedString =
|
||||
this.strings.GetStringFromName("style.inheritedFrom");
|
||||
aSections.forEach(function(section) {
|
||||
let sectionTitle = section.element.tagName;
|
||||
if (section.element.id)
|
||||
@@ -954,19 +974,34 @@ var InspectorUI = {
|
||||
{
|
||||
let winID = null;
|
||||
let win = null;
|
||||
let inspectorClosed = false;
|
||||
|
||||
switch (event.type) {
|
||||
case "popupshown":
|
||||
if (event.target.id == "inspector-tree-panel" ||
|
||||
event.target.id == "inspector-style-panel" ||
|
||||
event.target.id == "inspector-dom-panel")
|
||||
if (this.isTreePanelOpen && this.isStylePanelOpen && this.isDOMPanelOpen) {
|
||||
document.removeEventListener("popupshowing", this, false);
|
||||
Services.obs.notifyObservers(null, "inspector-opened", null);
|
||||
}
|
||||
break;
|
||||
case "TabSelect":
|
||||
winID = this.getWindowID(gBrowser.selectedBrowser.contentWindow);
|
||||
if (this.isPanelOpen && winID != this.winID) {
|
||||
if (this.isTreePanelOpen && winID != this.winID) {
|
||||
this.closeInspectorUI(false);
|
||||
inspectorClosed = true;
|
||||
}
|
||||
|
||||
if (winID && InspectorStore.hasID(winID)) {
|
||||
this.openInspectorUI();
|
||||
}
|
||||
|
||||
if (InspectorStore.isEmpty()) {
|
||||
if (inspectorClosed && this.closing) {
|
||||
Services.obs.addObserver(function () {
|
||||
InspectorUI.openInspectorUI();
|
||||
}, "inspector-closed", false);
|
||||
} else {
|
||||
this.openInspectorUI();
|
||||
}
|
||||
} else if (InspectorStore.isEmpty()) {
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
|
||||
}
|
||||
break;
|
||||
@@ -1014,24 +1049,31 @@ var InspectorUI = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Event fired when a tree row is selected in the tree panel.
|
||||
* Handle click events in the html tree panel.
|
||||
* @param aEvent
|
||||
* The mouse event.
|
||||
*/
|
||||
onTreeSelected: function IUI_onTreeSelected()
|
||||
onTreeClick: function IUI_onTreeClick(aEvent)
|
||||
{
|
||||
if (this.selectEventsSuppressed) {
|
||||
return false;
|
||||
let node;
|
||||
let target = aEvent.target;
|
||||
let hitTwisty = false;
|
||||
if (this.hasClass(target, "twisty")) {
|
||||
node = this.getRepObject(aEvent.target.nextSibling);
|
||||
hitTwisty = true;
|
||||
} else {
|
||||
node = this.getRepObject(aEvent.target);
|
||||
}
|
||||
|
||||
let node = this.treeView.selectedNode;
|
||||
this.highlighter.highlightNode(node);
|
||||
this.stopInspecting();
|
||||
this.updateStylePanel(node);
|
||||
this.updateDOMPanel(node);
|
||||
return true;
|
||||
if (node) {
|
||||
if (hitTwisty)
|
||||
this.ioBox.toggleObject(node);
|
||||
this.select(node, false, false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach event listeners to content window and child windows to enable
|
||||
* Attach event listeners to content window and child windows to enable
|
||||
* highlighting and click to stop inspection.
|
||||
*/
|
||||
attachPageListeners: function IUI_attachPageListeners()
|
||||
@@ -1066,14 +1108,14 @@ var InspectorUI = {
|
||||
{
|
||||
this.highlighter.highlightNode(aNode);
|
||||
this.selectEventsSuppressed = true;
|
||||
this.treeView.selectedNode = aNode;
|
||||
this.select(aNode, true, true);
|
||||
this.selectEventsSuppressed = false;
|
||||
this.updateStylePanel(aNode);
|
||||
this.updateDOMPanel(aNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Find an element from the given coordinates. This method descends through
|
||||
* Find an element from the given coordinates. This method descends through
|
||||
* frames to find the element the user clicked inside frames.
|
||||
*
|
||||
* @param DOMDocument aDocument the document to look into.
|
||||
@@ -1104,6 +1146,47 @@ var InspectorUI = {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// Utility functions
|
||||
|
||||
/**
|
||||
* Does the given object have a class attribute?
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
* @returns boolean
|
||||
*/
|
||||
hasClass: function IUI_hasClass(aNode, aClass)
|
||||
{
|
||||
if (!(aNode instanceof Element))
|
||||
return false;
|
||||
return aNode.classList.contains(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the class name to the given object.
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
*/
|
||||
addClass: function IUI_addClass(aNode, aClass)
|
||||
{
|
||||
if (aNode instanceof Element)
|
||||
aNode.classList.add(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the class name from the given object
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
*/
|
||||
removeClass: function IUI_removeClass(aNode, aClass)
|
||||
{
|
||||
if (aNode instanceof Element)
|
||||
aNode.classList.remove(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the unique ID of a window object.
|
||||
*
|
||||
@@ -1127,7 +1210,32 @@ var InspectorUI = {
|
||||
},
|
||||
|
||||
/**
|
||||
* debug logging facility
|
||||
* Get the "repObject" from the HTML panel's domplate-constructed DOM node.
|
||||
* In this system, a "repObject" is the Object being Represented by the box
|
||||
* object. It is the "real" object that we're building our facade around.
|
||||
*
|
||||
* @param element
|
||||
* The element in the HTML panel the user clicked.
|
||||
* @returns either a real node or null
|
||||
*/
|
||||
getRepObject: function IUI_getRepObject(element)
|
||||
{
|
||||
let target = null;
|
||||
for (let child = element; child; child = child.parentNode) {
|
||||
if (this.hasClass(child, "repTarget"))
|
||||
target = child;
|
||||
|
||||
if (child.repObject) {
|
||||
if (!target && this.hasClass(child.repObject, "repIgnore"))
|
||||
break;
|
||||
else
|
||||
return child.repObject;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* text message to send to the log
|
||||
*/
|
||||
@@ -1215,7 +1323,11 @@ var InspectorStore = {
|
||||
*/
|
||||
getValue: function IS_getValue(aID, aKey)
|
||||
{
|
||||
return aID in this.store ? this.store[aID][aKey] : null;
|
||||
if (!this.hasID(aID))
|
||||
return null;
|
||||
if (aKey in this.store[aID])
|
||||
return this.store[aID][aKey];
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user