mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-22 01:35:35 +00:00
Bug 966787 - 1 - Code cleanup in breadcrumbs.js; r=bgrins
For a better consistency with the rest of the DevTools codebase. --HG-- extra : rebase_source : 7bf01b3c7bc42809fbc8c0aacbceccc23e311c77
This commit is contained in:
parent
8c91148df6
commit
b97af70f4e
@ -4,20 +4,22 @@
|
||||
* 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 {Cc, Cu, Ci} = require("chrome");
|
||||
|
||||
const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
|
||||
const ENSURE_SELECTION_VISIBLE_DELAY = 50; // ms
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
const {Promise: promise} = require("resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
|
||||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
});
|
||||
|
||||
const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
|
||||
const ENSURE_SELECTION_VISIBLE_DELAY = 50; // ms
|
||||
const ELLIPSIS = Services.prefs.getComplexValue("intl.ellipsis", Ci.nsIPrefLocalizedString).data;
|
||||
const MAX_LABEL_LENGTH = 40;
|
||||
|
||||
let promise = require("resource://gre/modules/Promise.jsm").Promise;
|
||||
|
||||
const LOW_PRIORITY_ELEMENTS = {
|
||||
"HEAD": true,
|
||||
"BASE": true,
|
||||
@ -30,21 +32,6 @@ const LOW_PRIORITY_ELEMENTS = {
|
||||
"TITLE": true,
|
||||
};
|
||||
|
||||
function resolveNextTick(value) {
|
||||
let deferred = promise.defer();
|
||||
Services.tm.mainThread.dispatch(() => {
|
||||
try {
|
||||
deferred.resolve(value);
|
||||
} catch(ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// HTML Breadcrumbs
|
||||
|
||||
/**
|
||||
* Display the ancestors of the current node and its children.
|
||||
* Only one "branch" of children are displayed (only one line).
|
||||
@ -52,14 +39,15 @@ function resolveNextTick(value) {
|
||||
* FIXME: Bug 822388 - Use the BreadcrumbsWidget in the Inspector.
|
||||
*
|
||||
* Mechanism:
|
||||
* . If no nodes displayed yet:
|
||||
* then display the ancestor of the selected node and the selected node;
|
||||
* - If no nodes displayed yet:
|
||||
* then display the ancestor of the selected node and the selected node;
|
||||
* else select the node;
|
||||
* . If the selected node is the last node displayed, append its first (if any).
|
||||
* - If the selected node is the last node displayed, append its first (if any).
|
||||
*
|
||||
* @param {InspectorPanel} inspector The inspector hosting this widget.
|
||||
*/
|
||||
function HTMLBreadcrumbs(aInspector)
|
||||
{
|
||||
this.inspector = aInspector;
|
||||
function HTMLBreadcrumbs(inspector) {
|
||||
this.inspector = inspector;
|
||||
this.selection = this.inspector.selection;
|
||||
this.chromeWin = this.inspector.panelWin;
|
||||
this.chromeDoc = this.inspector.panelDoc;
|
||||
@ -72,8 +60,7 @@ exports.HTMLBreadcrumbs = HTMLBreadcrumbs;
|
||||
HTMLBreadcrumbs.prototype = {
|
||||
get walker() this.inspector.walker,
|
||||
|
||||
_init: function BC__init()
|
||||
{
|
||||
_init: function() {
|
||||
this.container = this.chromeDoc.getElementById("inspector-breadcrumbs");
|
||||
|
||||
// These separators are used for CSS purposes only, and are positioned
|
||||
@ -139,6 +126,7 @@ HTMLBreadcrumbs.prototype = {
|
||||
|
||||
/**
|
||||
* Warn if rejection was caused by selection change, print an error otherwise.
|
||||
* @param {Error} err
|
||||
*/
|
||||
selectionGuardEnd: function(err) {
|
||||
if (err === "selection-changed") {
|
||||
@ -150,47 +138,42 @@ HTMLBreadcrumbs.prototype = {
|
||||
|
||||
/**
|
||||
* Build a string that represents the node: tagName#id.class1.class2.
|
||||
*
|
||||
* @param aNode The node to pretty-print
|
||||
* @returns a string
|
||||
* @param {NodeFront} node The node to pretty-print
|
||||
* @return {String}
|
||||
*/
|
||||
prettyPrintNodeAsText: function BC_prettyPrintNodeText(aNode)
|
||||
{
|
||||
let text = aNode.tagName.toLowerCase();
|
||||
if (aNode.isPseudoElement) {
|
||||
text = aNode.isBeforePseudoElement ? "::before" : "::after";
|
||||
prettyPrintNodeAsText: function(node) {
|
||||
let text = node.tagName.toLowerCase();
|
||||
if (node.isPseudoElement) {
|
||||
text = node.isBeforePseudoElement ? "::before" : "::after";
|
||||
}
|
||||
|
||||
if (aNode.id) {
|
||||
text += "#" + aNode.id;
|
||||
if (node.id) {
|
||||
text += "#" + node.id;
|
||||
}
|
||||
|
||||
if (aNode.className) {
|
||||
let classList = aNode.className.split(/\s+/);
|
||||
if (node.className) {
|
||||
let classList = node.className.split(/\s+/);
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
text += "." + classList[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (let pseudo of aNode.pseudoClassLocks) {
|
||||
for (let pseudo of node.pseudoClassLocks) {
|
||||
text += pseudo;
|
||||
}
|
||||
|
||||
return text;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Build <label>s that represent the node:
|
||||
* <label class="breadcrumbs-widget-item-tag">tagName</label>
|
||||
* <label class="breadcrumbs-widget-item-id">#id</label>
|
||||
* <label class="breadcrumbs-widget-item-classes">.class1.class2</label>
|
||||
*
|
||||
* @param aNode The node to pretty-print
|
||||
* @returns a document fragment.
|
||||
* @param {NodeFront} node The node to pretty-print
|
||||
* @returns {DocumentFragment}
|
||||
*/
|
||||
prettyPrintNodeAsXUL: function BC_prettyPrintNodeXUL(aNode)
|
||||
{
|
||||
prettyPrintNodeAsXUL: function(node) {
|
||||
let fragment = this.chromeDoc.createDocumentFragment();
|
||||
|
||||
let tagLabel = this.chromeDoc.createElement("label");
|
||||
@ -205,22 +188,22 @@ HTMLBreadcrumbs.prototype = {
|
||||
let pseudosLabel = this.chromeDoc.createElement("label");
|
||||
pseudosLabel.className = "breadcrumbs-widget-item-pseudo-classes plain";
|
||||
|
||||
let tagText = aNode.tagName.toLowerCase();
|
||||
if (aNode.isPseudoElement) {
|
||||
tagText = aNode.isBeforePseudoElement ? "::before" : "::after";
|
||||
let tagText = node.tagName.toLowerCase();
|
||||
if (node.isPseudoElement) {
|
||||
tagText = node.isBeforePseudoElement ? "::before" : "::after";
|
||||
}
|
||||
let idText = aNode.id ? ("#" + aNode.id) : "";
|
||||
let idText = node.id ? ("#" + node.id) : "";
|
||||
let classesText = "";
|
||||
|
||||
if (aNode.className) {
|
||||
let classList = aNode.className.split(/\s+/);
|
||||
if (node.className) {
|
||||
let classList = node.className.split(/\s+/);
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
classesText += "." + classList[i];
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: Until we have pseudoclass lock in the node.
|
||||
for (let pseudo of aNode.pseudoClassLocks) {
|
||||
for (let pseudo of node.pseudoClassLocks) {
|
||||
|
||||
}
|
||||
|
||||
@ -244,7 +227,7 @@ HTMLBreadcrumbs.prototype = {
|
||||
tagLabel.textContent = tagText;
|
||||
idLabel.textContent = idText;
|
||||
classesLabel.textContent = classesText;
|
||||
pseudosLabel.textContent = aNode.pseudoClassLocks.join("");
|
||||
pseudosLabel.textContent = node.pseudoClassLocks.join("");
|
||||
|
||||
fragment.appendChild(tagLabel);
|
||||
fragment.appendChild(idLabel);
|
||||
@ -256,16 +239,14 @@ HTMLBreadcrumbs.prototype = {
|
||||
|
||||
/**
|
||||
* Open the sibling menu.
|
||||
*
|
||||
* @param aButton the button representing the node.
|
||||
* @param aNode the node we want the siblings from.
|
||||
* @param {DOMNode} button the button representing the node.
|
||||
* @param {NodeFront} node the node we want the siblings from.
|
||||
*/
|
||||
openSiblingMenu: function BC_openSiblingMenu(aButton, aNode)
|
||||
{
|
||||
openSiblingMenu: function(button, node) {
|
||||
// We make sure that the targeted node is selected
|
||||
// because we want to use the nodemenu that only works
|
||||
// for inspector.selection
|
||||
this.selection.setNodeFront(aNode, "breadcrumbs");
|
||||
this.selection.setNodeFront(node, "breadcrumbs");
|
||||
|
||||
let title = this.chromeDoc.createElement("menuitem");
|
||||
title.setAttribute("label", this.inspector.strings.GetStringFromName("breadcrumbs.siblings"));
|
||||
@ -275,13 +256,13 @@ HTMLBreadcrumbs.prototype = {
|
||||
|
||||
let items = [title, separator];
|
||||
|
||||
this.walker.siblings(aNode, {
|
||||
this.walker.siblings(node, {
|
||||
whatToShow: Ci.nsIDOMNodeFilter.SHOW_ELEMENT
|
||||
}).then(siblings => {
|
||||
let nodes = siblings.nodes;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
let item = this.chromeDoc.createElement("menuitem");
|
||||
if (nodes[i] === aNode) {
|
||||
if (nodes[i] === node) {
|
||||
item.setAttribute("disabled", "true");
|
||||
item.setAttribute("checked", "true");
|
||||
}
|
||||
@ -290,117 +271,135 @@ HTMLBreadcrumbs.prototype = {
|
||||
item.setAttribute("label", this.prettyPrintNodeAsText(nodes[i]));
|
||||
|
||||
let selection = this.selection;
|
||||
item.onmouseup = (function(aNode) {
|
||||
item.onmouseup = (function(node) {
|
||||
return function() {
|
||||
selection.setNodeFront(aNode, "breadcrumbs");
|
||||
selection.setNodeFront(node, "breadcrumbs");
|
||||
}
|
||||
})(nodes[i]);
|
||||
|
||||
items.push(item);
|
||||
this.inspector.showNodeMenu(aButton, "before_start", items);
|
||||
this.inspector.showNodeMenu(button, "before_start", items);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Generic event handler.
|
||||
*
|
||||
* @param nsIDOMEvent event
|
||||
* The DOM event object.
|
||||
* @param {DOMEvent} event.
|
||||
*/
|
||||
handleEvent: function BC_handleEvent(event)
|
||||
{
|
||||
handleEvent: function(event) {
|
||||
if (event.type == "mousedown" && event.button == 0) {
|
||||
// on Click and Hold, open the Siblings menu
|
||||
|
||||
let timer;
|
||||
let container = this.container;
|
||||
|
||||
function openMenu(event) {
|
||||
cancelHold();
|
||||
let target = event.originalTarget;
|
||||
if (target.tagName == "button") {
|
||||
target.onBreadcrumbsHold();
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(event) {
|
||||
cancelHold();
|
||||
let target = event.originalTarget;
|
||||
if (target.tagName == "button") {
|
||||
target.onBreadcrumbsClick();
|
||||
}
|
||||
}
|
||||
|
||||
let window = this.chromeWin;
|
||||
function cancelHold(event) {
|
||||
window.clearTimeout(timer);
|
||||
container.removeEventListener("mouseout", cancelHold, false);
|
||||
container.removeEventListener("mouseup", handleClick, false);
|
||||
}
|
||||
|
||||
container.addEventListener("mouseout", cancelHold, false);
|
||||
container.addEventListener("mouseup", handleClick, false);
|
||||
timer = window.setTimeout(openMenu, 500, event);
|
||||
}
|
||||
|
||||
if (event.type == "keypress" && this.selection.isElementNode()) {
|
||||
let node = null;
|
||||
|
||||
|
||||
this._keyPromise = this._keyPromise || promise.resolve(null);
|
||||
|
||||
this._keyPromise = (this._keyPromise || promise.resolve(null)).then(() => {
|
||||
switch (event.keyCode) {
|
||||
case this.chromeWin.KeyEvent.DOM_VK_LEFT:
|
||||
if (this.currentIndex != 0) {
|
||||
node = promise.resolve(this.nodeHierarchy[this.currentIndex - 1].node);
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_RIGHT:
|
||||
if (this.currentIndex < this.nodeHierarchy.length - 1) {
|
||||
node = promise.resolve(this.nodeHierarchy[this.currentIndex + 1].node);
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_UP:
|
||||
node = this.walker.previousSibling(this.selection.nodeFront, {
|
||||
whatToShow: Ci.nsIDOMNodeFilter.SHOW_ELEMENT
|
||||
});
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_DOWN:
|
||||
node = this.walker.nextSibling(this.selection.nodeFront, {
|
||||
whatToShow: Ci.nsIDOMNodeFilter.SHOW_ELEMENT
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return node.then((node) => {
|
||||
if (node) {
|
||||
this.selection.setNodeFront(node, "breadcrumbs");
|
||||
}
|
||||
});
|
||||
});
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (event.type == "mouseover") {
|
||||
let target = event.originalTarget;
|
||||
if (target.tagName == "button") {
|
||||
target.onBreadcrumbsHover();
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type == "mouseleave") {
|
||||
this.inspector.toolbox.highlighterUtils.unhighlight();
|
||||
this.handleMouseDown(event);
|
||||
} else if (event.type == "keypress" && this.selection.isElementNode()) {
|
||||
this.handleKeyPress(event);
|
||||
} else if (event.type == "mouseover") {
|
||||
this.handleMouseOver(event);
|
||||
} else if (event.type == "mouseleave") {
|
||||
this.handleMouseLeave(event);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove nodes and delete properties.
|
||||
* On click and hold, open the siblings menu.
|
||||
* @param {DOMEvent} event.
|
||||
*/
|
||||
destroy: function BC_destroy()
|
||||
{
|
||||
handleMouseDown: function(event) {
|
||||
let timer;
|
||||
let container = this.container;
|
||||
|
||||
function openMenu(event) {
|
||||
cancelHold();
|
||||
let target = event.originalTarget;
|
||||
if (target.tagName == "button") {
|
||||
target.onBreadcrumbsHold();
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick(event) {
|
||||
cancelHold();
|
||||
let target = event.originalTarget;
|
||||
if (target.tagName == "button") {
|
||||
target.onBreadcrumbsClick();
|
||||
}
|
||||
}
|
||||
|
||||
let window = this.chromeWin;
|
||||
function cancelHold(event) {
|
||||
window.clearTimeout(timer);
|
||||
container.removeEventListener("mouseout", cancelHold, false);
|
||||
container.removeEventListener("mouseup", handleClick, false);
|
||||
}
|
||||
|
||||
container.addEventListener("mouseout", cancelHold, false);
|
||||
container.addEventListener("mouseup", handleClick, false);
|
||||
timer = window.setTimeout(openMenu, 500, event);
|
||||
},
|
||||
|
||||
/**
|
||||
* On mouse over, highlight the corresponding content DOM Node.
|
||||
* @param {DOMEvent} event.
|
||||
*/
|
||||
handleMouseOver: function(event) {
|
||||
let target = event.originalTarget;
|
||||
if (target.tagName == "button") {
|
||||
target.onBreadcrumbsHover();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* On mouse leave, make sure to unhighlight.
|
||||
* @param {DOMEvent} event.
|
||||
*/
|
||||
handleMouseLeave: function(event) {
|
||||
this.inspector.toolbox.highlighterUtils.unhighlight();
|
||||
},
|
||||
|
||||
/**
|
||||
* On key press, navigate the node hierarchy.
|
||||
* @param {DOMEvent} event.
|
||||
*/
|
||||
handleKeyPress: function(event) {
|
||||
let node = null;
|
||||
this._keyPromise = this._keyPromise || promise.resolve(null);
|
||||
|
||||
this._keyPromise = (this._keyPromise || promise.resolve(null)).then(() => {
|
||||
switch (event.keyCode) {
|
||||
case this.chromeWin.KeyEvent.DOM_VK_LEFT:
|
||||
if (this.currentIndex != 0) {
|
||||
node = promise.resolve(this.nodeHierarchy[this.currentIndex - 1].node);
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_RIGHT:
|
||||
if (this.currentIndex < this.nodeHierarchy.length - 1) {
|
||||
node = promise.resolve(this.nodeHierarchy[this.currentIndex + 1].node);
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_UP:
|
||||
node = this.walker.previousSibling(this.selection.nodeFront, {
|
||||
whatToShow: Ci.nsIDOMNodeFilter.SHOW_ELEMENT
|
||||
});
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_DOWN:
|
||||
node = this.walker.nextSibling(this.selection.nodeFront, {
|
||||
whatToShow: Ci.nsIDOMNodeFilter.SHOW_ELEMENT
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return node.then((node) => {
|
||||
if (node) {
|
||||
this.selection.setNodeFront(node, "breadcrumbs");
|
||||
}
|
||||
});
|
||||
});
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove nodes and clean up.
|
||||
*/
|
||||
destroy: function() {
|
||||
this.selection.off("new-node-front", this.update);
|
||||
this.selection.off("pseudoclass", this.updateSelectors);
|
||||
this.selection.off("attribute-changed", this.updateSelectors);
|
||||
@ -408,18 +407,17 @@ HTMLBreadcrumbs.prototype = {
|
||||
|
||||
this.container.removeEventListener("underflow", this.onscrollboxreflow, false);
|
||||
this.container.removeEventListener("overflow", this.onscrollboxreflow, false);
|
||||
this.onscrollboxreflow = null;
|
||||
|
||||
this.empty();
|
||||
this.container.removeEventListener("mousedown", this, true);
|
||||
this.container.removeEventListener("keypress", this, true);
|
||||
this.container.removeEventListener("mouseover", this, true);
|
||||
this.container.removeEventListener("mouseleave", this, true);
|
||||
this.container = null;
|
||||
|
||||
this.empty();
|
||||
this.separators.remove();
|
||||
this.separators = null;
|
||||
|
||||
this.onscrollboxreflow = null;
|
||||
this.container = null;
|
||||
this.separators = null;
|
||||
this.nodeHierarchy = null;
|
||||
|
||||
this.isDestroyed = true;
|
||||
@ -428,43 +426,38 @@ HTMLBreadcrumbs.prototype = {
|
||||
/**
|
||||
* Empty the breadcrumbs container.
|
||||
*/
|
||||
empty: function BC_empty()
|
||||
{
|
||||
empty: function() {
|
||||
while (this.container.hasChildNodes()) {
|
||||
this.container.removeChild(this.container.firstChild);
|
||||
this.container.firstChild.remove();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set which button represent the selected node.
|
||||
*
|
||||
* @param aIdx Index of the displayed-button to select
|
||||
* @param {Number} index Index of the displayed-button to select.
|
||||
*/
|
||||
setCursor: function BC_setCursor(aIdx)
|
||||
{
|
||||
setCursor: function(index) {
|
||||
// Unselect the previously selected button
|
||||
if (this.currentIndex > -1 && this.currentIndex < this.nodeHierarchy.length) {
|
||||
this.nodeHierarchy[this.currentIndex].button.removeAttribute("checked");
|
||||
}
|
||||
if (aIdx > -1) {
|
||||
this.nodeHierarchy[aIdx].button.setAttribute("checked", "true");
|
||||
if (index > -1) {
|
||||
this.nodeHierarchy[index].button.setAttribute("checked", "true");
|
||||
if (this.hadFocus)
|
||||
this.nodeHierarchy[aIdx].button.focus();
|
||||
this.nodeHierarchy[index].button.focus();
|
||||
}
|
||||
this.currentIndex = aIdx;
|
||||
this.currentIndex = index;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the index of the node in the cache.
|
||||
*
|
||||
* @param aNode
|
||||
* @returns integer the index, -1 if not found
|
||||
* @param {NodeFront} node.
|
||||
* @returns {Number} The index for this node or -1 if not found.
|
||||
*/
|
||||
indexOf: function BC_indexOf(aNode)
|
||||
{
|
||||
indexOf: function(node) {
|
||||
let i = this.nodeHierarchy.length - 1;
|
||||
for (let i = this.nodeHierarchy.length - 1; i >= 0; i--) {
|
||||
if (this.nodeHierarchy[i].node === aNode) {
|
||||
if (this.nodeHierarchy[i].node === node) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@ -472,14 +465,12 @@ HTMLBreadcrumbs.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all the buttons and their references in the cache
|
||||
* after a given index.
|
||||
*
|
||||
* @param aIdx
|
||||
* Remove all the buttons and their references in the cache after a given
|
||||
* index.
|
||||
* @param {Number} index.
|
||||
*/
|
||||
cutAfter: function BC_cutAfter(aIdx)
|
||||
{
|
||||
while (this.nodeHierarchy.length > (aIdx + 1)) {
|
||||
cutAfter: function(index) {
|
||||
while (this.nodeHierarchy.length > (index + 1)) {
|
||||
let toRemove = this.nodeHierarchy.pop();
|
||||
this.container.removeChild(toRemove.button);
|
||||
}
|
||||
@ -487,17 +478,15 @@ HTMLBreadcrumbs.prototype = {
|
||||
|
||||
/**
|
||||
* Build a button representing the node.
|
||||
*
|
||||
* @param aNode The node from the page.
|
||||
* @returns aNode The <button>.
|
||||
* @param {NodeFront} node The node from the page.
|
||||
* @return {DOMNode} The <button> for this node.
|
||||
*/
|
||||
buildButton: function BC_buildButton(aNode)
|
||||
{
|
||||
buildButton: function(node) {
|
||||
let button = this.chromeDoc.createElement("button");
|
||||
button.appendChild(this.prettyPrintNodeAsXUL(aNode));
|
||||
button.appendChild(this.prettyPrintNodeAsXUL(node));
|
||||
button.className = "breadcrumbs-widget-item";
|
||||
|
||||
button.setAttribute("tooltiptext", this.prettyPrintNodeAsText(aNode));
|
||||
button.setAttribute("tooltiptext", this.prettyPrintNodeAsText(node));
|
||||
|
||||
button.onkeypress = function onBreadcrumbsKeypress(e) {
|
||||
if (e.charCode == Ci.nsIDOMKeyEvent.DOM_VK_SPACE ||
|
||||
@ -506,68 +495,63 @@ HTMLBreadcrumbs.prototype = {
|
||||
}
|
||||
|
||||
button.onBreadcrumbsClick = () => {
|
||||
this.selection.setNodeFront(aNode, "breadcrumbs");
|
||||
this.selection.setNodeFront(node, "breadcrumbs");
|
||||
};
|
||||
|
||||
button.onBreadcrumbsHover = () => {
|
||||
this.inspector.toolbox.highlighterUtils.highlightNodeFront(aNode);
|
||||
this.inspector.toolbox.highlighterUtils.highlightNodeFront(node);
|
||||
};
|
||||
|
||||
button.onclick = (function _onBreadcrumbsRightClick(event) {
|
||||
button.focus();
|
||||
if (event.button == 2) {
|
||||
this.openSiblingMenu(button, aNode);
|
||||
this.openSiblingMenu(button, node);
|
||||
}
|
||||
}).bind(this);
|
||||
|
||||
button.onBreadcrumbsHold = (function _onBreadcrumbsHold() {
|
||||
this.openSiblingMenu(button, aNode);
|
||||
this.openSiblingMenu(button, node);
|
||||
}).bind(this);
|
||||
return button;
|
||||
},
|
||||
|
||||
/**
|
||||
* Connecting the end of the breadcrumbs to a node.
|
||||
*
|
||||
* @param aNode The node to reach.
|
||||
* @param {NodeFront} node The node to reach.
|
||||
*/
|
||||
expand: function BC_expand(aNode)
|
||||
{
|
||||
let fragment = this.chromeDoc.createDocumentFragment();
|
||||
let toAppend = aNode;
|
||||
let lastButtonInserted = null;
|
||||
let originalLength = this.nodeHierarchy.length;
|
||||
let stopNode = null;
|
||||
if (originalLength > 0) {
|
||||
stopNode = this.nodeHierarchy[originalLength - 1].node;
|
||||
expand: function(node) {
|
||||
let fragment = this.chromeDoc.createDocumentFragment();
|
||||
let lastButtonInserted = null;
|
||||
let originalLength = this.nodeHierarchy.length;
|
||||
let stopNode = null;
|
||||
if (originalLength > 0) {
|
||||
stopNode = this.nodeHierarchy[originalLength - 1].node;
|
||||
}
|
||||
while (node && node != stopNode) {
|
||||
if (node.tagName) {
|
||||
let button = this.buildButton(node);
|
||||
fragment.insertBefore(button, lastButtonInserted);
|
||||
lastButtonInserted = button;
|
||||
this.nodeHierarchy.splice(originalLength, 0, {node, button});
|
||||
}
|
||||
while (toAppend && toAppend != stopNode) {
|
||||
if (toAppend.tagName) {
|
||||
let button = this.buildButton(toAppend);
|
||||
fragment.insertBefore(button, lastButtonInserted);
|
||||
lastButtonInserted = button;
|
||||
this.nodeHierarchy.splice(originalLength, 0, {node: toAppend, button: button});
|
||||
}
|
||||
toAppend = toAppend.parentNode();
|
||||
}
|
||||
this.container.appendChild(fragment, this.container.firstChild);
|
||||
node = node.parentNode();
|
||||
}
|
||||
this.container.appendChild(fragment, this.container.firstChild);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a child of a node that can be displayed in the breadcrumbs
|
||||
* and that is probably visible. See LOW_PRIORITY_ELEMENTS.
|
||||
*
|
||||
* @param aNode The parent node.
|
||||
* @returns nsIDOMNode|null
|
||||
* Get a child of a node that can be displayed in the breadcrumbs and that is
|
||||
* probably visible. See LOW_PRIORITY_ELEMENTS.
|
||||
* @param {NodeFront} node The parent node.
|
||||
* @return {Promise} Resolves to the NodeFront.
|
||||
*/
|
||||
getInterestingFirstNode: function BC_getInterestingFirstNode(aNode)
|
||||
{
|
||||
getInterestingFirstNode: function(node) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
var fallback = null;
|
||||
let fallback = null;
|
||||
|
||||
var moreChildren = () => {
|
||||
this.walker.children(aNode, {
|
||||
let moreChildren = () => {
|
||||
this.walker.children(node, {
|
||||
start: fallback,
|
||||
maxNodes: 10,
|
||||
whatToShow: Ci.nsIDOMNodeFilter.SHOW_ELEMENT
|
||||
@ -588,20 +572,18 @@ HTMLBreadcrumbs.prototype = {
|
||||
moreChildren();
|
||||
}
|
||||
}).then(null, this.selectionGuardEnd);
|
||||
}
|
||||
};
|
||||
|
||||
moreChildren();
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the "youngest" ancestor of a node which is already in the breadcrumbs.
|
||||
*
|
||||
* @param aNode
|
||||
* @returns Index of the ancestor in the cache
|
||||
* @param {NodeFront} node.
|
||||
* @return {Number} Index of the ancestor in the cache, or -1 if not found.
|
||||
*/
|
||||
getCommonAncestor: function BC_getCommonAncestor(aNode)
|
||||
{
|
||||
let node = aNode;
|
||||
getCommonAncestor: function(node) {
|
||||
while (node) {
|
||||
let idx = this.indexOf(node);
|
||||
if (idx > -1) {
|
||||
@ -616,9 +598,9 @@ HTMLBreadcrumbs.prototype = {
|
||||
/**
|
||||
* Make sure that the latest node in the breadcrumbs is not the selected node
|
||||
* if the selected node still has children.
|
||||
* @return {Promise}
|
||||
*/
|
||||
ensureFirstChild: function BC_ensureFirstChild()
|
||||
{
|
||||
ensureFirstChild: function() {
|
||||
// If the last displayed node is the selected node
|
||||
if (this.currentIndex == this.nodeHierarchy.length - 1) {
|
||||
let node = this.nodeHierarchy[this.currentIndex].node;
|
||||
@ -637,8 +619,7 @@ HTMLBreadcrumbs.prototype = {
|
||||
/**
|
||||
* Ensure the selected node is visible.
|
||||
*/
|
||||
scroll: function BC_scroll()
|
||||
{
|
||||
scroll: function() {
|
||||
// FIXME bug 684352: make sure its immediate neighbors are visible too.
|
||||
|
||||
let scrollbox = this.container;
|
||||
@ -652,8 +633,10 @@ HTMLBreadcrumbs.prototype = {
|
||||
}, ENSURE_SELECTION_VISIBLE_DELAY);
|
||||
},
|
||||
|
||||
updateSelectors: function BC_updateSelectors()
|
||||
{
|
||||
/**
|
||||
* Update all button outputs.
|
||||
*/
|
||||
updateSelectors: function() {
|
||||
if (this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@ -662,7 +645,7 @@ HTMLBreadcrumbs.prototype = {
|
||||
let crumb = this.nodeHierarchy[i];
|
||||
let button = crumb.button;
|
||||
|
||||
while(button.hasChildNodes()) {
|
||||
while (button.hasChildNodes()) {
|
||||
button.removeChild(button.firstChild);
|
||||
}
|
||||
button.appendChild(this.prettyPrintNodeAsXUL(crumb.node));
|
||||
@ -672,9 +655,9 @@ HTMLBreadcrumbs.prototype = {
|
||||
|
||||
/**
|
||||
* Update the breadcrumbs display when a new node is selected.
|
||||
* @param {String} reason The reason for the update, if any.
|
||||
*/
|
||||
update: function BC_update(reason)
|
||||
{
|
||||
update: function(reason) {
|
||||
if (this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
@ -744,6 +727,17 @@ HTMLBreadcrumbs.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
|
||||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
});
|
||||
/**
|
||||
* Returns a promise that resolves at the next main thread tick.
|
||||
*/
|
||||
function resolveNextTick(value) {
|
||||
let deferred = promise.defer();
|
||||
Services.tm.mainThread.dispatch(() => {
|
||||
try {
|
||||
deferred.resolve(value);
|
||||
} catch(e) {
|
||||
deferred.reject(e);
|
||||
}
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user