Paul Rouget 2012-12-19 14:00:54 +01:00
Родитель 45e064e121
Коммит bfbc18cd8b
9 изменённых файлов: 27 добавлений и 374 удалений

Просмотреть файл

@ -12,7 +12,6 @@ const Ci = Components.interfaces;
const PAGE_SIZE = 10;
const PREVIEW_AREA = 700;
const DEFAULT_MAX_CHILDREN = 100;
this.EXPORTED_SYMBOLS = ["MarkupView"];
@ -21,7 +20,6 @@ Cu.import("resource:///modules/devtools/CssRuleView.jsm");
Cu.import("resource:///modules/devtools/Templater.jsm");
Cu.import("resource:///modules/devtools/Undo.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
/**
* Vocabulary for the purposes of this file:
@ -48,12 +46,6 @@ this.MarkupView = function MarkupView(aInspector, aFrame, aControllerWindow)
this.doc = this._frame.contentDocument;
this._elt = this.doc.querySelector("#root");
try {
this.maxChildren = Services.prefs.getIntPref("devtools.markup.pagesize");
} catch(ex) {
this.maxChildren = DEFAULT_MAX_CHILDREN;
}
this.undo = new UndoStack();
this.undo.installController(aControllerWindow);
@ -77,7 +69,7 @@ this.MarkupView = function MarkupView(aInspector, aFrame, aControllerWindow)
MarkupView.prototype = {
_selectedContainer: null,
template: function MT_template(aName, aDest, aOptions={stack: "markup-view.xhtml"})
template: function MT_template(aName, aDest, aOptions)
{
let node = this.doc.getElementById("template-" + aName).cloneNode(true);
node.removeAttribute("id");
@ -296,6 +288,7 @@ MarkupView.prototype = {
let walker = documentWalker(aNode);
let parent = walker.parentNode();
if (parent) {
// Make sure parents of this node are imported too.
var container = new MarkupContainer(this, aNode);
} else {
var container = new RootContainer(this, aNode);
@ -305,15 +298,12 @@ MarkupView.prototype = {
// Fake a childList mutation here.
this._mutationObserver([{target: aEvent.target, type: "childList"}]);
}.bind(this), true);
}
this._containers.set(aNode, container);
// FIXME: set an expando to prevent the the wrapper from disappearing
// See bug 819131 for details.
aNode.__preserveHack = true;
container.expanded = aExpand;
container.childrenDirty = true;
this._updateChildren(container);
if (parent) {
@ -337,7 +327,6 @@ MarkupView.prototype = {
if (mutation.type === "attributes" || mutation.type === "characterData") {
container.update();
} else if (mutation.type === "childList") {
container.childrenDirty = true;
this._updateChildren(container);
}
}
@ -350,12 +339,10 @@ MarkupView.prototype = {
*/
showNode: function MT_showNode(aNode, centered)
{
let container = this.importNode(aNode);
this._updateChildren(container);
this.importNode(aNode);
let walker = documentWalker(aNode);
let parent;
while (parent = walker.parentNode()) {
this._updateChildren(this.getContainer(parent));
this.expandNode(parent);
}
LayoutHelpers.scrollIntoViewIfNeeded(this._containers.get(aNode).editor.elt, centered);
@ -434,33 +421,9 @@ MarkupView.prototype = {
this._selectedContainer.selected = true;
}
this._ensureSelectionVisible();
this._selectedContainer.focus();
return true;
},
/**
* Make sure that every ancestor of the selection are updated
* and included in the list of visible children.
*/
_ensureSelectionVisible: function MT_ensureSelectionVisible()
{
let node = this._selectedContainer.node;
let walker = documentWalker(node);
while (node) {
let container = this._containers.get(node);
let parent = walker.parentNode();
if (!container.elt.parentNode) {
let parentContainer = this._containers.get(parent);
parentContainer.childrenDirty = true;
this._updateChildren(parentContainer, node);
}
node = parent;
}
},
/**
* Unmark selected node (no node selected).
*/
@ -485,139 +448,29 @@ MarkupView.prototype = {
/**
* Make sure all children of the given container's node are
* imported and attached to the container in the right order.
* @param aCentered If provided, this child will be included
* in the visible subset, and will be roughly centered
* in that list.
*/
_updateChildren: function MT__updateChildren(aContainer, aCentered)
_updateChildren: function MT__updateChildren(aContainer)
{
if (!aContainer.childrenDirty) {
return false;
}
// Get a tree walker pointing at the first child of the node.
let treeWalker = documentWalker(aContainer.node);
let child = treeWalker.firstChild();
aContainer.hasChildren = !!child;
if (aContainer.expanded) {
let lastContainer = null;
while (child) {
let container = this.importNode(child, false);
if (!aContainer.expanded) {
return;
}
aContainer.childrenDirty = false;
let children = this._getVisibleChildren(aContainer, aCentered);
let fragment = this.doc.createDocumentFragment();
for (child of children.children) {
let container = this.importNode(child, false);
fragment.appendChild(container.elt);
}
while (aContainer.children.firstChild) {
aContainer.children.removeChild(aContainer.children.firstChild);
}
if (!(children.hasFirst && children.hasLast)) {
let data = {
showing: this.strings.GetStringFromName("markupView.more.showing"),
showAll: this.strings.formatStringFromName(
"markupView.more.showAll",
[aContainer.node.children.length.toString()], 1),
allButtonClick: function() {
aContainer.maxChildren = -1;
aContainer.childrenDirty = true;
this._updateChildren(aContainer);
}.bind(this)
};
if (!children.hasFirst) {
let span = this.template("more-nodes", data);
fragment.insertBefore(span, fragment.firstChild);
// Make sure children are in the right order.
let before = lastContainer ? lastContainer.nextSibling : aContainer.children.firstChild;
aContainer.children.insertBefore(container.elt, before);
lastContainer = container.elt;
child = treeWalker.nextSibling();
}
if (!children.hasLast) {
let span = this.template("more-nodes", data);
fragment.appendChild(span);
while (aContainer.children.lastChild != lastContainer) {
aContainer.children.removeChild(aContainer.children.lastChild);
}
}
aContainer.children.appendChild(fragment);
return true;
},
/**
* Return a list of the children to display for this container.
*/
_getVisibleChildren: function MV__getVisibleChildren(aContainer, aCentered)
{
let maxChildren = aContainer.maxChildren || this.maxChildren;
if (maxChildren == -1) {
maxChildren = Number.MAX_VALUE;
}
let firstChild = documentWalker(aContainer.node).firstChild();
let lastChild = documentWalker(aContainer.node).lastChild();
if (!firstChild) {
// No children, we're done.
return { hasFirst: true, hasLast: true, children: [] };
}
// By default try to put the selected child in the middle of the list.
let start = aCentered || firstChild;
// Start by reading backward from the starting point....
let nodes = [];
let backwardWalker = documentWalker(start);
if (backwardWalker.previousSibling()) {
let backwardCount = Math.floor(maxChildren / 2);
let backwardNodes = this._readBackward(backwardWalker, backwardCount);
nodes = backwardNodes;
}
// Then read forward by any slack left in the max children...
let forwardWalker = documentWalker(start);
let forwardCount = maxChildren - nodes.length;
nodes = nodes.concat(this._readForward(forwardWalker, forwardCount));
// If there's any room left, it means we've run all the way to the end.
// In that case, there might still be more items at the front.
let remaining = maxChildren - nodes.length;
if (remaining > 0 && nodes[0] != firstChild) {
let firstNodes = this._readBackward(backwardWalker, remaining);
// Then put it all back together.
nodes = firstNodes.concat(nodes);
}
return {
hasFirst: nodes[0] == firstChild,
hasLast: nodes[nodes.length - 1] == lastChild,
children: nodes
};
},
_readForward: function MV__readForward(aWalker, aCount)
{
let ret = [];
let node = aWalker.currentNode;
do {
ret.push(node);
node = aWalker.nextSibling();
} while (node && --aCount);
return ret;
},
_readBackward: function MV__readBackward(aWalker, aCount)
{
let ret = [];
let node = aWalker.currentNode;
do {
ret.push(node);
node = aWalker.previousSibling();
} while(node && --aCount);
ret.reverse();
return ret;
},
/**
@ -765,7 +618,9 @@ function MarkupContainer(aMarkupView, aNode)
this.expander = null;
this.codeBox = null;
this.children = null;
this.markup.template("container", this);
let options = { stack: "markup-view.xhtml" };
this.markup.template("container", this, options);
this.elt.container = this;
this.expander.addEventListener("click", function() {
@ -879,7 +734,7 @@ MarkupContainer.prototype = {
if (focusable) {
focusable.focus();
}
},
}
}
/**
@ -986,12 +841,13 @@ function ElementEditor(aContainer, aNode)
this.attrList = null;
this.newAttr = null;
this.closeElt = null;
let options = { stack: "markup-view.xhtml" };
// Create the main editor
this.template("element", this);
this.template("element", this, options);
// Create the closing tag
this.template("elementClose", this);
this.template("elementClose", this, options);
// Make the tag name editable (unless this is a document element)
if (aNode != aNode.ownerDocument.documentElement) {
@ -1071,7 +927,8 @@ ElementEditor.prototype = {
let data = {
attrName: aAttr.name,
};
this.template("attribute", data);
let options = { stack: "markup-view.xhtml" };
this.template("attribute", data, options);
var {attr, inner, name, val} = data;
// Figure out where we should place the attribute.
@ -1403,8 +1260,3 @@ function whitespaceTextFilter(aNode)
return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
}
}
XPCOMUtils.defineLazyGetter(MarkupView.prototype, "strings", function () {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/inspector.properties");
});

Просмотреть файл

@ -16,8 +16,6 @@
<div id="templates" style="display:none">
<ul>
<li id="template-container" save="${elt}" class="container"><span save="${expander}" class="expander"></span><span save="${codeBox}" class="codebox"><ul save="${children}" class="children"></ul></span></li>
<li id="template-more-nodes" class="more-nodes devtools-class-comment" save="${elt}"><span>${showing}</span> <button href="#" onclick="${allButtonClick}">${showAll}</button></li>
</ul>
<span id="template-element" save="${elt}" class="editor"><span>&lt;</span><span save="${tag}" class="tagname devtools-theme-tagname"></span><span save="${attrList}"></span><span save="${newAttr}" class="newattr" tabindex="0"></span>&gt;</span>

Просмотреть файл

@ -17,9 +17,7 @@ _BROWSER_FILES = \
browser_inspector_markup_mutation.html \
browser_inspector_markup_mutation.js \
browser_inspector_markup_edit.html \
browser_inspector_markup_edit.js \
browser_inspector_markup_subset.html \
browser_inspector_markup_subset.js \
browser_inspector_markup_edit.js \
head.js \
$(NULL)

Просмотреть файл

@ -1,32 +0,0 @@
<!DOCTYPE html>
<html class="html">
<body class="body">
<div id="a"></div>
<div id="b"></div>
<div id="c"></div>
<div id="d"></div>
<div id="e"></div>
<div id="f"></div>
<div id="g"></div>
<div id="h"></div>
<div id="i"></div>
<div id="j"></div>
<div id="k"></div>
<div id="l"></div>
<div id="m"></div>
<div id="n"></div>
<div id="o"></div>
<div id="p"></div>
<div id="q"></div>
<div id="r"></div>
<div id="s"></div>
<div id="t"></div>
<div id="u"></div>
<div id="v"></div>
<div id="w"></div>
<div id="x"></div>
<div id="y"></div>
<div id="z"></div>
</body>
</html>

Просмотреть файл

@ -1,145 +0,0 @@
/* Any copyright", " is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that the markup view loads only as many nodes as specified
* by the devtools.markup.pagesize preference.
*/
registerCleanupFunction(function() {
Services.prefs.clearUserPref("devtools.markup.pagesize");
});
Services.prefs.setIntPref("devtools.markup.pagesize", 5);
function test() {
waitForExplicitFinish();
// Will hold the doc we're viewing
let doc;
let inspector;
// Holds the MarkupTool object we're testing.
let markup;
function assertChildren(expected)
{
let container = markup.getContainer(doc.querySelector("body"));
let found = [];
for (let child of container.children.children) {
if (child.classList.contains("more-nodes")) {
found += "*more*";
} else {
found += child.container.node.getAttribute("id");
}
}
is(expected, found, "Got the expected children.");
}
function forceReload()
{
let container = markup.getContainer(doc.querySelector("body"));
container.childrenDirty = true;
}
let selections = [
{
desc: "Select the first item",
selector: "#a",
before: function() {
},
after: function() {
assertChildren("abcde*more*");
}
},
{
desc: "Select the last item",
selector: "#z",
before: function() {},
after: function() {
assertChildren("*more*vwxyz");
}
},
{
desc: "Select an already-visible item",
selector: "#v",
before: function() {},
after: function() {
// Because "v" was already visible, we shouldn't have loaded
// a different page.
assertChildren("*more*vwxyz");
},
},
{
desc: "Verify childrenDirty reloads the page",
selector: "#w",
before: function() {
forceReload();
},
after: function() {
// But now that we don't already have a loaded page, selecting
// w should center around w.
assertChildren("*more*uvwxy*more*");
},
},
];
// Create the helper tab for parsing...
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
doc = content.document;
waitForFocus(setupTest, content);
}, true);
content.location = "http://mochi.test:8888/browser/browser/devtools/markupview/test/browser_inspector_markup_subset.html";
function setupTest() {
var target = TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.openToolboxForTab(target, "inspector");
toolbox.once("inspector-selected", function SE_selected(id, aInspector) {
inspector = aInspector;
markup = inspector.markup;
runNextSelection();
});
}
function runTests() {
inspector.selection.once("new-node", startTests);
executeSoon(function() {
inspector.selection.setNode(doc.body);
});
}
function runNextSelection() {
let selection = selections.shift();
if (!selection) {
clickMore();
return;
}
info(selection.desc);
selection.before();
inspector.selection.once("new-node", function() {
selection.after();
runNextSelection();
});
inspector.selection.setNode(doc.querySelector(selection.selector));
}
function clickMore() {
info("Check that clicking more loads the whole thing.");
// Make sure that clicking the "more" button loads all the nodes.
let container = markup.getContainer(doc.querySelector("body"));
let button = container.elt.querySelector("button");
button.click();
assertChildren("abcdefghijklmnopqrstuvwxyz");
finishUp();
}
function finishUp() {
doc = inspector = null;
gBrowser.removeCurrentTab();
finish();
}
}

Просмотреть файл

@ -34,9 +34,3 @@ inspector.label=Inspector
inspector.commandkey=I
inspector.accesskey=I
inspector.tooltip=DOM and Style Inspector
# LOCALIZATION NOTE (markupView.more.*)
# When there are too many nodes to load at once, we will offer to
# show all the nodes.
markupView.more.showing=Some nodes were hidden.
markupView.more.showAll=Show All %S Nodes

Просмотреть файл

@ -49,10 +49,6 @@ li.container {
-moz-appearance: treetwistyopen;
}
.more-nodes {
padding-left: 16px;
}
.styleinspector-propertyeditor {
border: 1px solid #CCC;
}

Просмотреть файл

@ -52,10 +52,6 @@ li.container {
-moz-appearance: treetwistyopen;
}
.more-nodes {
padding-left: 16px;
}
.styleinspector-propertyeditor {
border: 1px solid #CCC;
}

Просмотреть файл

@ -54,10 +54,6 @@ li.container {
background-image: url("chrome://global/skin/tree/twisty-open.png");
}
.more-nodes {
padding-left: 16px;
}
.styleinspector-propertyeditor {
border: 1px solid #CCC;
}