зеркало из https://github.com/mozilla/gecko-dev.git
Bug 879520 - Remote the inspector breadcrumbs. r=paul
This commit is contained in:
Родитель
41f96a13b0
Коммит
ef61965785
|
@ -12,6 +12,9 @@ const ENSURE_SELECTION_VISIBLE_DELAY = 50; // ms
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
|
||||
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
let promise = require("sdk/core/promise");
|
||||
|
||||
const LOW_PRIORITY_ELEMENTS = {
|
||||
"HEAD": true,
|
||||
|
@ -25,6 +28,18 @@ 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
|
||||
|
||||
|
@ -53,6 +68,8 @@ function HTMLBreadcrumbs(aInspector)
|
|||
exports.HTMLBreadcrumbs = HTMLBreadcrumbs;
|
||||
|
||||
HTMLBreadcrumbs.prototype = {
|
||||
get walker() this.inspector.walker,
|
||||
|
||||
_init: function BC__init()
|
||||
{
|
||||
this.container = this.chromeDoc.getElementById("inspector-breadcrumbs");
|
||||
|
@ -83,12 +100,37 @@ HTMLBreadcrumbs.prototype = {
|
|||
|
||||
this.update = this.update.bind(this);
|
||||
this.updateSelectors = this.updateSelectors.bind(this);
|
||||
this.selection.on("new-node", this.update);
|
||||
this.selection.on("new-node-front", this.update);
|
||||
this.selection.on("pseudoclass", this.updateSelectors);
|
||||
this.selection.on("attribute-changed", this.updateSelectors);
|
||||
this.update();
|
||||
},
|
||||
|
||||
/**
|
||||
* Include in a promise's then() chain to reject the chain
|
||||
* when the breadcrumbs' selection has changed while the promise
|
||||
* was outstanding.
|
||||
*/
|
||||
selectionGuard: function() {
|
||||
let selection = this.selection.nodeFront;
|
||||
return (result) => {
|
||||
if (selection != this.selection.nodeFront) {
|
||||
return promise.reject("selection-changed");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Print any errors (except selection guard errors).
|
||||
*/
|
||||
selectionGuardEnd: function(err) {
|
||||
if (err != "selection-changed") {
|
||||
console.error(err);
|
||||
}
|
||||
promise.reject(err);
|
||||
},
|
||||
|
||||
/**
|
||||
* Build a string that represents the node: tagName#id.class1.class2.
|
||||
*
|
||||
|
@ -101,12 +143,19 @@ HTMLBreadcrumbs.prototype = {
|
|||
if (aNode.id) {
|
||||
text += "#" + aNode.id;
|
||||
}
|
||||
for (let i = 0; i < aNode.classList.length; i++) {
|
||||
text += "." + aNode.classList[i];
|
||||
|
||||
if (aNode.className) {
|
||||
let classList = aNode.className.split(/\s+/);
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
text += "." + classList[i];
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: needs updating when pseudoclass-lock is remotable
|
||||
let rawNode = aNode.rawNode();
|
||||
for (let i = 0; i < PSEUDO_CLASSES.length; i++) {
|
||||
let pseudo = PSEUDO_CLASSES[i];
|
||||
if (DOMUtils.hasPseudoClassLock(aNode, pseudo)) {
|
||||
if (DOMUtils.hasPseudoClassLock(rawNode, pseudo)) {
|
||||
text += pseudo;
|
||||
}
|
||||
}
|
||||
|
@ -143,14 +192,20 @@ HTMLBreadcrumbs.prototype = {
|
|||
tagLabel.textContent = aNode.tagName.toLowerCase();
|
||||
idLabel.textContent = aNode.id ? ("#" + aNode.id) : "";
|
||||
|
||||
let classesText = "";
|
||||
for (let i = 0; i < aNode.classList.length; i++) {
|
||||
classesText += "." + aNode.classList[i];
|
||||
if (aNode.className) {
|
||||
let classesText = "";
|
||||
let classList = aNode.className.split(/\s+/);
|
||||
for (let i = 0; i < classList.length; i++) {
|
||||
classesText += "." + classList[i];
|
||||
}
|
||||
classesLabel.textContent = classesText;
|
||||
}
|
||||
classesLabel.textContent = classesText;
|
||||
|
||||
// XXX: Until we have pseudoclass lock in the node.
|
||||
let rawNode = aNode.rawNode();
|
||||
|
||||
let pseudos = PSEUDO_CLASSES.filter(function(pseudo) {
|
||||
return DOMUtils.hasPseudoClassLock(aNode, pseudo);
|
||||
return DOMUtils.hasPseudoClassLock(rawNode, pseudo);
|
||||
}, this);
|
||||
pseudosLabel.textContent = pseudos.join("");
|
||||
|
||||
|
@ -173,7 +228,7 @@ HTMLBreadcrumbs.prototype = {
|
|||
// We make sure that the targeted node is selected
|
||||
// because we want to use the nodemenu that only works
|
||||
// for inspector.selection
|
||||
this.selection.setNode(aNode, "breadcrumbs");
|
||||
this.selection.setNodeFront(aNode, "breadcrumbs");
|
||||
|
||||
let title = this.chromeDoc.createElement("menuitem");
|
||||
title.setAttribute("label", this.inspector.strings.GetStringFromName("breadcrumbs.siblings"));
|
||||
|
@ -183,9 +238,11 @@ HTMLBreadcrumbs.prototype = {
|
|||
|
||||
let items = [title, separator];
|
||||
|
||||
let nodes = aNode.parentNode.childNodes;
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
if (nodes[i].nodeType == aNode.ELEMENT_NODE) {
|
||||
this.walker.siblings(aNode, {
|
||||
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) {
|
||||
item.setAttribute("disabled", "true");
|
||||
|
@ -198,14 +255,14 @@ HTMLBreadcrumbs.prototype = {
|
|||
let selection = this.selection;
|
||||
item.onmouseup = (function(aNode) {
|
||||
return function() {
|
||||
selection.setNode(aNode, "breadcrumbs");
|
||||
selection.setNodeFront(aNode, "breadcrumbs");
|
||||
}
|
||||
})(nodes[i]);
|
||||
|
||||
items.push(item);
|
||||
this.inspector.showNodeMenu(aButton, "before_start", items);
|
||||
}
|
||||
}
|
||||
this.inspector.showNodeMenu(aButton, "before_start", items);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -252,33 +309,40 @@ HTMLBreadcrumbs.prototype = {
|
|||
|
||||
if (event.type == "keypress" && this.selection.isElementNode()) {
|
||||
let node = null;
|
||||
switch (event.keyCode) {
|
||||
case this.chromeWin.KeyEvent.DOM_VK_LEFT:
|
||||
if (this.currentIndex != 0) {
|
||||
node = this.nodeHierarchy[this.currentIndex - 1].node;
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_RIGHT:
|
||||
if (this.currentIndex < this.nodeHierarchy.length - 1) {
|
||||
node = this.nodeHierarchy[this.currentIndex + 1].node;
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_UP:
|
||||
node = this.selection.node.previousSibling;
|
||||
while (node && (node.nodeType != node.ELEMENT_NODE)) {
|
||||
node = node.previousSibling;
|
||||
}
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_DOWN:
|
||||
node = this.selection.node.nextSibling;
|
||||
while (node && (node.nodeType != node.ELEMENT_NODE)) {
|
||||
node = node.nextSibling;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (node) {
|
||||
this.selection.setNode(node, "breadcrumbs");
|
||||
}
|
||||
});
|
||||
});
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
@ -290,12 +354,18 @@ HTMLBreadcrumbs.prototype = {
|
|||
destroy: function BC_destroy()
|
||||
{
|
||||
this.nodeHierarchy.forEach(function(crumb) {
|
||||
if (LayoutHelpers.isNodeConnected(crumb.node)) {
|
||||
DOMUtils.clearPseudoClassLocks(crumb.node);
|
||||
// This node might have already been destroyed during
|
||||
// shutdown. Will clean this up when pseudo-class lock
|
||||
// is ported to the walker.
|
||||
if (crumb.node.actorID) {
|
||||
let rawNode = crumb.node.rawNode();
|
||||
if (LayoutHelpers.isNodeConnected(rawNode)) {
|
||||
DOMUtils.clearPseudoClassLocks(rawNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.selection.off("new-node", this.update);
|
||||
this.selection.off("new-node-front", this.update);
|
||||
this.selection.off("pseudoclass", this.updateSelectors);
|
||||
this.selection.off("attribute-changed", this.updateSelectors);
|
||||
|
||||
|
@ -401,7 +471,7 @@ HTMLBreadcrumbs.prototype = {
|
|||
}
|
||||
|
||||
button.onBreadcrumbsClick = function onBreadcrumbsClick() {
|
||||
this.selection.setNode(aNode, "breadcrumbs");
|
||||
this.selection.setNodeFront(aNode, "breadcrumbs");
|
||||
}.bind(this);
|
||||
|
||||
button.onclick = (function _onBreadcrumbsRightClick(event) {
|
||||
|
@ -437,7 +507,7 @@ HTMLBreadcrumbs.prototype = {
|
|||
fragment.insertBefore(button, lastButtonInserted);
|
||||
lastButtonInserted = button;
|
||||
this.nodeHierarchy.splice(originalLength, 0, {node: toAppend, button: button});
|
||||
toAppend = this.DOMHelpers.getParentObject(toAppend);
|
||||
toAppend = toAppend.parentNode();
|
||||
}
|
||||
this.container.appendChild(fragment, this.container.firstChild);
|
||||
},
|
||||
|
@ -451,24 +521,37 @@ HTMLBreadcrumbs.prototype = {
|
|||
*/
|
||||
getInterestingFirstNode: function BC_getInterestingFirstNode(aNode)
|
||||
{
|
||||
let nextChild = this.DOMHelpers.getChildObject(aNode, 0);
|
||||
let fallback = null;
|
||||
let deferred = promise.defer();
|
||||
|
||||
while (nextChild) {
|
||||
if (nextChild.nodeType == aNode.ELEMENT_NODE) {
|
||||
if (!(nextChild.tagName in LOW_PRIORITY_ELEMENTS)) {
|
||||
return nextChild;
|
||||
var fallback = null;
|
||||
|
||||
var moreChildren = () => {
|
||||
this.walker.children(aNode, {
|
||||
start: fallback,
|
||||
maxNodes: 10,
|
||||
whatToShow: Ci.nsIDOMNodeFilter.SHOW_ELEMENT
|
||||
}).then(this.selectionGuard()).then(response => {
|
||||
for (let node of response.nodes) {
|
||||
if (!(node.tagName in LOW_PRIORITY_ELEMENTS)) {
|
||||
deferred.resolve(node);
|
||||
return;
|
||||
}
|
||||
if (!fallback) {
|
||||
fallback = node;
|
||||
}
|
||||
}
|
||||
if (!fallback) {
|
||||
fallback = nextChild;
|
||||
if (response.hasLast) {
|
||||
deferred.resolve(fallback);
|
||||
return;
|
||||
} else {
|
||||
moreChildren();
|
||||
}
|
||||
}
|
||||
nextChild = this.DOMHelpers.getNextSibling(nextChild);
|
||||
}).then(null, this.selectionGuardEnd);
|
||||
}
|
||||
return fallback;
|
||||
moreChildren();
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Find the "youngest" ancestor of a node which is already in the breadcrumbs.
|
||||
*
|
||||
|
@ -483,7 +566,7 @@ HTMLBreadcrumbs.prototype = {
|
|||
if (idx > -1) {
|
||||
return idx;
|
||||
} else {
|
||||
node = this.DOMHelpers.getParentObject(node);
|
||||
node = node.parentNode();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
@ -498,13 +581,16 @@ HTMLBreadcrumbs.prototype = {
|
|||
// If the last displayed node is the selected node
|
||||
if (this.currentIndex == this.nodeHierarchy.length - 1) {
|
||||
let node = this.nodeHierarchy[this.currentIndex].node;
|
||||
let child = this.getInterestingFirstNode(node);
|
||||
// If the node has a child
|
||||
if (child) {
|
||||
// Show this child
|
||||
this.expand(child);
|
||||
}
|
||||
return this.getInterestingFirstNode(node).then(child => {
|
||||
// If the node has a child
|
||||
if (child) {
|
||||
// Show this child
|
||||
this.expand(child);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return resolveNextTick(true);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -560,7 +646,7 @@ HTMLBreadcrumbs.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
let idx = this.indexOf(this.selection.node);
|
||||
let idx = this.indexOf(this.selection.nodeFront);
|
||||
|
||||
// Is the node already displayed in the breadcrumbs?
|
||||
if (idx > -1) {
|
||||
|
@ -571,24 +657,32 @@ HTMLBreadcrumbs.prototype = {
|
|||
if (this.nodeHierarchy.length > 0) {
|
||||
// No. We drop all the element that are not direct ancestors
|
||||
// of the selection
|
||||
let parent = this.DOMHelpers.getParentObject(this.selection.node);
|
||||
let parent = this.selection.nodeFront.parentNode();
|
||||
let idx = this.getCommonAncestor(parent);
|
||||
this.cutAfter(idx);
|
||||
}
|
||||
// we append the missing button between the end of the breadcrumbs display
|
||||
// and the current node.
|
||||
this.expand(this.selection.node);
|
||||
this.expand(this.selection.nodeFront);
|
||||
|
||||
// we select the current node button
|
||||
idx = this.indexOf(this.selection.node);
|
||||
idx = this.indexOf(this.selection.nodeFront);
|
||||
this.setCursor(idx);
|
||||
}
|
||||
// Add the first child of the very last node of the breadcrumbs if possible.
|
||||
this.ensureFirstChild();
|
||||
this.updateSelectors();
|
||||
|
||||
// Make sure the selected node and its neighbours are visible.
|
||||
this.scroll();
|
||||
let doneUpdating = this.inspector.updating("breadcrumbs");
|
||||
// Add the first child of the very last node of the breadcrumbs if possible.
|
||||
this.ensureFirstChild().then(this.selectionGuard()).then(() => {
|
||||
this.updateSelectors();
|
||||
|
||||
// Make sure the selected node and its neighbours are visible.
|
||||
this.scroll();
|
||||
this.inspector.emit("breadcrumbs-updated", this.selection.nodeFront);
|
||||
doneUpdating();
|
||||
}).then(null, err => {
|
||||
doneUpdating(this.selection.nodeFront);
|
||||
this.selectionGuardEnd(err);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ InspectorPanel.prototype = {
|
|||
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", this.onBeforeNewSelection);
|
||||
this.selection.on("before-new-node-front", this.onBeforeNewSelection);
|
||||
this.onDetached = this.onDetached.bind(this);
|
||||
this.selection.on("detached-front", this.onDetached);
|
||||
|
||||
|
@ -309,6 +309,69 @@ InspectorPanel.prototype = {
|
|||
*/
|
||||
onNewSelection: function InspectorPanel_onNewSelection() {
|
||||
this.cancelLayoutChange();
|
||||
|
||||
// Wait for all the known tools to finish updating and then let the
|
||||
// client know.
|
||||
let selection = this.selection.nodeFront;
|
||||
let selfUpdate = this.updating("inspector-panel");
|
||||
Services.tm.mainThread.dispatch(() => {
|
||||
try {
|
||||
selfUpdate(selection);
|
||||
} catch(ex) {
|
||||
console.error(ex);
|
||||
}
|
||||
}, Ci.nsIThread.DISPATCH_NORMAL);
|
||||
},
|
||||
|
||||
/**
|
||||
* Delay the "inspector-updated" notification while a tool
|
||||
* is updating itself. Returns a function that must be
|
||||
* invoked when the tool is done updating with the node
|
||||
* that the tool is viewing.
|
||||
*/
|
||||
updating: function(name) {
|
||||
if (this._updateProgress && this._updateProgress.node != this.selection.nodeFront) {
|
||||
this.cancelUpdate();
|
||||
}
|
||||
|
||||
if (!this._updateProgress) {
|
||||
// Start an update in progress.
|
||||
var self = this;
|
||||
this._updateProgress = {
|
||||
node: this.selection.nodeFront,
|
||||
outstanding: new Set(),
|
||||
checkDone: function() {
|
||||
if (this !== self._updateProgress) {
|
||||
return;
|
||||
}
|
||||
if (this.node !== self.selection.nodeFront) {
|
||||
self.cancelUpdate();
|
||||
return;
|
||||
}
|
||||
if (this.outstanding.size !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
self._updateProgress = null;
|
||||
self.emit("inspector-updated");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let progress = this._updateProgress;
|
||||
let done = function() {
|
||||
progress.outstanding.delete(done);
|
||||
progress.checkDone();
|
||||
};
|
||||
progress.outstanding.add(done);
|
||||
return done;
|
||||
},
|
||||
|
||||
/**
|
||||
* Cancel notification of inspector updates.
|
||||
*/
|
||||
cancelUpdate: function() {
|
||||
this._updateProgress = null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -345,6 +408,7 @@ InspectorPanel.prototype = {
|
|||
this._destroyPromise = Promise.resolve(null);
|
||||
}
|
||||
|
||||
this.cancelUpdate();
|
||||
this.cancelLayoutChange();
|
||||
|
||||
if (this.browser) {
|
||||
|
@ -376,6 +440,7 @@ InspectorPanel.prototype = {
|
|||
this.searchSuggestions.destroy();
|
||||
this.selection.off("new-node-front", this.onNewSelection);
|
||||
this.selection.off("before-new-node", this.onBeforeNewSelection);
|
||||
this.selection.off("before-new-node-front", this.onBeforeNewSelection);
|
||||
this.selection.off("detached-front", this.onDetached);
|
||||
this._destroyMarkup();
|
||||
this._selection.destroy();
|
||||
|
@ -517,7 +582,7 @@ InspectorPanel.prototype = {
|
|||
if (this.selection.isElementNode()) {
|
||||
if (DOMUtils.hasPseudoClassLock(this.selection.node, aPseudo)) {
|
||||
this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
|
||||
DOMUtils.removePseudoClassLock(crumb.node, aPseudo);
|
||||
DOMUtils.removePseudoClassLock(crumb.node.rawNode(), aPseudo);
|
||||
});
|
||||
} else {
|
||||
let hierarchical = aPseudo == ":hover" || aPseudo == ":active";
|
||||
|
@ -538,7 +603,7 @@ InspectorPanel.prototype = {
|
|||
clearPseudoClasses: function InspectorPanel_clearPseudoClasses() {
|
||||
this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
|
||||
try {
|
||||
DOMUtils.clearPseudoClassLocks(crumb.node);
|
||||
DOMUtils.clearPseudoClassLocks(crumb.node.rawNode());
|
||||
} catch(e) {
|
||||
// Ignore dead nodes after navigation.
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ function test()
|
|||
{
|
||||
inspector = aInspector;
|
||||
cursor = 0;
|
||||
inspector.selection.on("new-node", nodeSelected);
|
||||
inspector.on("breadcrumbs-updated", nodeSelected);
|
||||
executeSoon(function() {
|
||||
inspector.selection.setNode(nodes[0].node);
|
||||
});
|
||||
|
@ -52,18 +52,16 @@ function test()
|
|||
|
||||
function nodeSelected()
|
||||
{
|
||||
executeSoon(function() {
|
||||
performTest();
|
||||
cursor++;
|
||||
performTest();
|
||||
cursor++;
|
||||
|
||||
if (cursor >= nodes.length) {
|
||||
inspector.selection.off("new-node", nodeSelected);
|
||||
finishUp();
|
||||
} else {
|
||||
let node = nodes[cursor].node;
|
||||
inspector.selection.setNode(node);
|
||||
}
|
||||
});
|
||||
if (cursor >= nodes.length) {
|
||||
inspector.off("breadcrumbs-updated", nodeSelected);
|
||||
finishUp();
|
||||
} else {
|
||||
let node = nodes[cursor].node;
|
||||
inspector.selection.setNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
function performTest()
|
||||
|
|
|
@ -34,11 +34,12 @@ function test()
|
|||
{
|
||||
inspector = aInspector;
|
||||
|
||||
executeSoon(function() {
|
||||
inspector.selection.once("new-node", highlightHeaderNode);
|
||||
// Test that navigating around without a selected node gets us to the
|
||||
// head element.
|
||||
node = doc.querySelector("h1");
|
||||
// Make sure the body element is selected initially.
|
||||
node = doc.querySelector("body");
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node, node, "Body should be selected initially.");
|
||||
node = doc.querySelector("h1")
|
||||
inspector.once("inspector-updated", highlightHeaderNode);
|
||||
let bc = inspector.breadcrumbs;
|
||||
bc.nodeHierarchy[bc.currentIndex].button.focus();
|
||||
EventUtils.synthesizeKey("VK_RIGHT", { });
|
||||
|
@ -50,7 +51,7 @@ function test()
|
|||
is(inspector.selection.node, node, "selected h1 element");
|
||||
|
||||
executeSoon(function() {
|
||||
inspector.selection.once("new-node", highlightParagraphNode);
|
||||
inspector.once("inspector-updated", highlightParagraphNode);
|
||||
// Test that moving to the next sibling works.
|
||||
node = doc.querySelector("p");
|
||||
EventUtils.synthesizeKey("VK_DOWN", { });
|
||||
|
@ -62,7 +63,7 @@ function test()
|
|||
is(inspector.selection.node, node, "selected p element");
|
||||
|
||||
executeSoon(function() {
|
||||
inspector.selection.once("new-node", highlightHeaderNodeAgain);
|
||||
inspector.once("inspector-updated", highlightHeaderNodeAgain);
|
||||
// Test that moving to the previous sibling works.
|
||||
node = doc.querySelector("h1");
|
||||
EventUtils.synthesizeKey("VK_UP", { });
|
||||
|
@ -74,7 +75,7 @@ function test()
|
|||
is(inspector.selection.node, node, "selected h1 element");
|
||||
|
||||
executeSoon(function() {
|
||||
inspector.selection.once("new-node", highlightParentNode);
|
||||
inspector.once("inspector-updated", highlightParentNode);
|
||||
// Test that moving to the parent works.
|
||||
node = doc.querySelector("body");
|
||||
EventUtils.synthesizeKey("VK_LEFT", { });
|
||||
|
|
|
@ -40,27 +40,29 @@ function startInspectorTests(toolbox)
|
|||
let p = doc.querySelector("p");
|
||||
|
||||
inspector.selection.setNode(p);
|
||||
inspector.once("inspector-updated", () => {
|
||||
testHighlighter(p);
|
||||
testMarkupView(p);
|
||||
testBreadcrumbs(p);
|
||||
|
||||
testHighlighter(p);
|
||||
testMarkupView(p);
|
||||
testBreadcrumbs(p);
|
||||
let span = doc.querySelector("span");
|
||||
span.scrollIntoView();
|
||||
|
||||
let span = doc.querySelector("span");
|
||||
span.scrollIntoView();
|
||||
inspector.selection.setNode(span);
|
||||
inspector.once("inspector-updated", () => {
|
||||
testHighlighter(span);
|
||||
testMarkupView(span);
|
||||
testBreadcrumbs(span);
|
||||
|
||||
inspector.selection.setNode(span);
|
||||
|
||||
testHighlighter(span);
|
||||
testMarkupView(span);
|
||||
testBreadcrumbs(span);
|
||||
|
||||
toolbox.once("destroyed", function() {
|
||||
ok("true", "'destroyed' notification received.");
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
ok(!gDevTools.getToolbox(target), "Toolbox destroyed.");
|
||||
executeSoon(runContextMenuTest);
|
||||
toolbox.once("destroyed", function() {
|
||||
ok("true", "'destroyed' notification received.");
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
ok(!gDevTools.getToolbox(target), "Toolbox destroyed.");
|
||||
executeSoon(runContextMenuTest);
|
||||
});
|
||||
toolbox.destroy();
|
||||
});
|
||||
});
|
||||
toolbox.destroy();
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,7 +81,7 @@ function testMarkupView(node)
|
|||
function testBreadcrumbs(node)
|
||||
{
|
||||
let b = getActiveInspector().breadcrumbs;
|
||||
let expectedText = b.prettyPrintNodeAsText(node);
|
||||
let expectedText = b.prettyPrintNodeAsText(getNodeFront(node));
|
||||
let button = b.container.querySelector("button[checked=true]");
|
||||
ok(button, "A crumbs is checked=true");
|
||||
is(button.getAttribute("tooltiptext"), expectedText, "Crumb refers to the right node");
|
||||
|
|
|
@ -31,21 +31,23 @@ function test() {
|
|||
function checkDocTypeMenuItems() {
|
||||
info("Checking context menu entries for doctype node");
|
||||
inspector.selection.setNode(doc.doctype);
|
||||
let docTypeNode = getMarkupTagNodeContaining("<!DOCTYPE html>");
|
||||
inspector.once("inspector-updated", () => {
|
||||
let docTypeNode = getMarkupTagNodeContaining("<!DOCTYPE html>");
|
||||
|
||||
// Right-click doctype tag
|
||||
contextMenuClick(docTypeNode);
|
||||
// Right-click doctype tag
|
||||
contextMenuClick(docTypeNode);
|
||||
|
||||
checkDisabled("node-menu-copyinner");
|
||||
checkDisabled("node-menu-copyouter");
|
||||
checkDisabled("node-menu-copyuniqueselector");
|
||||
checkDisabled("node-menu-delete");
|
||||
checkDisabled("node-menu-copyinner");
|
||||
checkDisabled("node-menu-copyouter");
|
||||
checkDisabled("node-menu-copyuniqueselector");
|
||||
checkDisabled("node-menu-delete");
|
||||
|
||||
for (let name of ["hover", "active", "focus"]) {
|
||||
checkDisabled("node-menu-pseudo-" + name);
|
||||
}
|
||||
for (let name of ["hover", "active", "focus"]) {
|
||||
checkDisabled("node-menu-pseudo-" + name);
|
||||
}
|
||||
|
||||
checkElementMenuItems();
|
||||
checkElementMenuItems();
|
||||
});
|
||||
}
|
||||
|
||||
function checkElementMenuItems() {
|
||||
|
|
|
@ -51,11 +51,11 @@ function createDocument()
|
|||
function selectNode(aInspector)
|
||||
{
|
||||
inspector = aInspector;
|
||||
inspector.selection.setNode(div);
|
||||
inspector.sidebar.once("ruleview-ready", function() {
|
||||
ruleview = inspector.sidebar.getWindowForTab("ruleview").ruleview.view;
|
||||
inspector.sidebar.select("ruleview");
|
||||
performTests();
|
||||
inspector.selection.setNode(div);
|
||||
inspector.once("inspector-updated", performTests);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -75,29 +75,37 @@ function performTests()
|
|||
// toggle it back on
|
||||
inspector.togglePseudoClass(pseudo);
|
||||
|
||||
testNavigate();
|
||||
|
||||
// close the inspector
|
||||
finishUp();
|
||||
testNavigate(() => {
|
||||
// close the inspector
|
||||
finishUp();
|
||||
});
|
||||
}
|
||||
|
||||
function testNavigate()
|
||||
function testNavigate(callback)
|
||||
{
|
||||
inspector.selection.setNode(parentDiv);
|
||||
inspector.once("inspector-updated", () => {
|
||||
|
||||
// make sure it's still on after naving to parent
|
||||
is(DOMUtils.hasPseudoClassLock(div, pseudo), true,
|
||||
"pseudo-class lock is still applied after inspecting ancestor");
|
||||
// make sure it's still on after naving to parent
|
||||
is(DOMUtils.hasPseudoClassLock(div, pseudo), true,
|
||||
"pseudo-class lock is still applied after inspecting ancestor");
|
||||
|
||||
inspector.selection.setNode(div2);
|
||||
inspector.selection.setNode(div2);
|
||||
|
||||
// make sure it's removed after naving to a non-hierarchy node
|
||||
is(DOMUtils.hasPseudoClassLock(div, pseudo), false,
|
||||
"pseudo-class lock is removed after inspecting sibling node");
|
||||
inspector.once("inspector-updated", () => {
|
||||
|
||||
// toggle it back on
|
||||
inspector.selection.setNode(div);
|
||||
inspector.togglePseudoClass(pseudo);
|
||||
// make sure it's removed after naving to a non-hierarchy node
|
||||
is(DOMUtils.hasPseudoClassLock(div, pseudo), false,
|
||||
"pseudo-class lock is removed after inspecting sibling node");
|
||||
|
||||
// toggle it back on
|
||||
inspector.selection.setNode(div);
|
||||
inspector.once("inspector-updated", () => {
|
||||
inspector.togglePseudoClass(pseudo);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function testAdded()
|
||||
|
|
|
@ -26,6 +26,12 @@ let console = tempScope.console;
|
|||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "../../../commandline/test/helpers.js", this);
|
||||
|
||||
SimpleTest.registerCleanupFunction(() => {
|
||||
console.error("Here we are\n")
|
||||
let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
console.error("DebuggerServer open connections: " + Object.getOwnPropertyNames(DebuggerServer._connections).length);
|
||||
});
|
||||
|
||||
function openInspector(callback)
|
||||
{
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
|
@ -40,6 +46,12 @@ function getActiveInspector()
|
|||
return gDevTools.getToolbox(target).getPanel("inspector");
|
||||
}
|
||||
|
||||
function getNodeFront(node)
|
||||
{
|
||||
let inspector = getActiveInspector();
|
||||
return inspector.walker.frontForRawNode(node);
|
||||
}
|
||||
|
||||
function isHighlighting()
|
||||
{
|
||||
let outline = getActiveInspector().highlighter.outline;
|
||||
|
|
Загрузка…
Ссылка в новой задаче