This commit is contained in:
Tim Taubert 2012-07-10 11:04:59 +02:00
Родитель a9d0f1da9e 9606b0cee8
Коммит 225d52918d
14 изменённых файлов: 372 добавлений и 54 удалений

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

@ -1477,7 +1477,9 @@ var gBrowserInit = {
#ifdef MENUBAR_CAN_AUTOHIDE
document.getElementById("appmenu_styleeditor").hidden = false;
#endif
document.getElementById("developer-toolbar-styleeditor").hidden = false;
// We don't show the Style Editor button in the developer toolbar for now.
// See bug 771203
// document.getElementById("developer-toolbar-styleeditor").hidden = false;
}
#ifdef MENUBAR_CAN_AUTOHIDE

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

@ -98,11 +98,11 @@ Cell.prototype = {
* Handles all cell events.
*/
handleEvent: function Cell_handleEvent(aEvent) {
// We're not responding to external drag/drop events
// We're not responding to external drag/drop events
// when our parent window is in private browsing mode.
if (inPrivateBrowsingMode && !gDrag.draggedSite)
if (inPrivateBrowsingMode() && !gDrag.draggedSite)
return;
if (aEvent.type != "dragexit" && !gDrag.isValid(aEvent))
return;

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

@ -22,19 +22,6 @@ let {
blockedLinks: gBlockedLinks
} = NewTabUtils;
let chromeWin = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.wrappedJSObject;
let inPrivateBrowsingMode = false;
if ("gPrivateBrowsingUI" in chromeWin)
inPrivateBrowsingMode = chromeWin.gPrivateBrowsingUI.privateWindow;
XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
return Services.strings.
createBundle("chrome://browser/locale/newTab.properties");
@ -42,6 +29,21 @@ XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
function inPrivateBrowsingMode() {
let chromeWin = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow)
.wrappedJSObject;
if ("gPrivateBrowsingUI" in chromeWin)
return chromeWin.gPrivateBrowsingUI.privateWindow;
return false;
}
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
#include batch.js

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

@ -214,12 +214,13 @@ InsideOutBox.prototype =
this.selectObjectBox(objectBox, forceOpen);
if (makeBoxVisible) {
this.openObjectBox(objectBox);
if (scrollIntoView) {
// We want to center the label of the element, not the whole tag
// (which includes all of its children, and is vertically huge).
LayoutHelpers.scrollIntoViewIfNeeded(objectBox.firstElementChild);
}
}
if (scrollIntoView) {
// We want to center the label of the element, not the whole tag
// (which includes all of its children, and is vertically huge).
LayoutHelpers.scrollIntoViewIfNeeded(objectBox.firstElementChild);
}
return objectBox;
},
@ -340,6 +341,141 @@ InsideOutBox.prototype =
}
},
/**
* Returns the next object box in the tree for navigation purposes.
*/
nextObjectBox: function IOBox_nextObjectBox(aBoxObject)
{
let candidate;
let boxObject = aBoxObject || this.selectedObjectBox;
if (!boxObject)
return this.rootObjectBox;
// If expanded, return the first child.
let isOpen = this.view.hasClass(boxObject, "open");
let childObjectBox = this.getChildObjectBox(boxObject);
if (isOpen && childObjectBox && childObjectBox.firstChild) {
candidate = childObjectBox.firstChild;
} else {
// Otherwise we get the next available sibling.
while (boxObject) {
if (boxObject.nextSibling) {
boxObject = boxObject.nextSibling;
break;
}
boxObject = this.getParentObjectBox(boxObject);
}
candidate = boxObject;
}
// If the node is not an element (comments or text nodes), we
// jump to the next line.
if (candidate &&
candidate.repObject.nodeType != candidate.repObject.ELEMENT_NODE) {
return this.nextObjectBox(candidate);
}
return candidate;
},
/**
* Returns the next object in the tree for navigation purposes.
*/
nextObject: function IOBox_nextObject()
{
let next = this.nextObjectBox();
return next ? next.repObject : null;
},
/**
* Returns the object that is below the selection.
*
* @param aDistance Number of lines to jump.
*/
farNextObject: function IOBox_farPreviousProject(aDistance)
{
let boxObject = this.selectedObjectBox;
while (aDistance-- > 0) {
let newBoxObject = this.nextObjectBox(boxObject);
if (!newBoxObject) {
break;
}
boxObject = newBoxObject;
}
return boxObject ? boxObject.repObject : null;
},
/**
* Returns the last visible child box of an object box.
*/
lastVisible: function IOBox_lastVisibleChild(aNode)
{
if (!this.view.hasClass(aNode, "open"))
return aNode;
let childBox = this.getChildObjectBox(aNode);
if (!childBox || !childBox.lastChild)
return aNode;
return this.lastVisible(childBox.lastChild);
},
/**
* Returns the previous object box in the tree for navigation purposes.
*/
previousObjectBox: function IOBox_previousObjectBox(aBoxObject)
{
let boxObject = aBoxObject || this.selectedObjectBox;
if (!boxObject)
return this.rootObjectBox;
let candidate;
let sibling = boxObject.previousSibling;
if (sibling) {
candidate = this.lastVisible(sibling);
} else {
candidate = this.getParentObjectBox(boxObject);
}
// If the node is not an element (comments or text nodes), we
// jump to the previous line.
if (candidate &&
candidate.repObject.nodeType != candidate.repObject.ELEMENT_NODE) {
return this.previousObjectBox(candidate);
}
return candidate;
},
/**
* Returns the previous object in the tree for navigation purposes.
*/
previousObject: function IOBox_previousObject()
{
let boxObject = this.previousObjectBox();
return boxObject ? boxObject.repObject : null;
},
/**
* Returns the object that is above the selection.
*
* @param aDistance Number of lines to jump.
*/
farPreviousObject: function IOBox_farPreviousProject(aDistance)
{
let boxObject = this.selectedObjectBox;
while (aDistance-- > 0) {
let newBoxObject = this.previousObjectBox(boxObject);
if (!newBoxObject) {
break;
}
boxObject = newBoxObject;
if (boxObject === this.rootObjectBox)
break;
}
return boxObject ? boxObject.repObject : null;
},
/**
* Open the ancestors of the given object box.
* @param aObjectBox

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

@ -5,11 +5,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const Cu = Components.utils;
const Ci = Components.interfaces;
Cu.import("resource:///modules/domplate.jsm");
Cu.import("resource:///modules/InsideOutBox.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/inspector.jsm");
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
var EXPORTED_SYMBOLS = ["TreePanel", "DOMHelpers"];
@ -80,6 +82,8 @@ TreePanel.prototype = {
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
this.ioBox.createObjectBox(this.IUI.win.document.documentElement);
this.treeLoaded = true;
this._boundTreeKeyPress = this.onTreeKeyPress.bind(this);
this.treeIFrame.addEventListener("keypress", this._boundTreeKeyPress.bind(this), true);
this.treeIFrame.addEventListener("click", this.onTreeClick.bind(this), false);
this.treeIFrame.addEventListener("dblclick", this.onTreeDblClick.bind(this), false);
this.treeIFrame.focus();
@ -182,6 +186,7 @@ TreePanel.prototype = {
this.treePanelDiv.ownerPanel = null;
let parent = this.treePanelDiv.parentNode;
parent.removeChild(this.treePanelDiv);
this.treeIFrame.removeEventListener("keypress", this._boundTreeKeyPress, true);
delete this.treePanelDiv;
delete this.treeBrowserDocument;
}
@ -272,8 +277,7 @@ TreePanel.prototype = {
if (this.IUI.inspecting) {
this.IUI.stopInspecting(true);
} else {
this.IUI.select(node, true, false);
this.IUI.highlighter.highlight(node);
this.navigate(node);
}
}
}
@ -316,6 +320,52 @@ TreePanel.prototype = {
}
},
navigate: function TP_navigate(node)
{
if (!node)
return;
this.ioBox.select(node, false, false, true);
if (this.IUI.highlighter.isNodeHighlightable(node)) {
this.IUI.select(node, true, false, "treepanel");
this.IUI.highlighter.highlight(node);
}
},
onTreeKeyPress: function TP_onTreeKeyPress(aEvent)
{
let handled = true;
switch(aEvent.keyCode) {
case Ci.nsIDOMKeyEvent.DOM_VK_LEFT:
this.ioBox.contractObjectBox(this.ioBox.selectedObjectBox);
break;
case Ci.nsIDOMKeyEvent.DOM_VK_RIGHT:
this.ioBox.expandObjectBox(this.ioBox.selectedObjectBox);
break;
case Ci.nsIDOMKeyEvent.DOM_VK_UP:
this.navigate(this.ioBox.previousObject());
break;
case Ci.nsIDOMKeyEvent.DOM_VK_DOWN:
this.navigate(this.ioBox.nextObject());
break;
case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP:
this.navigate(this.ioBox.farPreviousObject(10));
break;
case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN:
this.navigate(this.ioBox.farNextObject(10));
break;
case Ci.nsIDOMKeyEvent.DOM_VK_HOME:
this.navigate(this.ioBox.rootObject);
break;
default:
handled = false;
}
if (handled) {
aEvent.stopPropagation();
aEvent.preventDefault();
}
},
/**
* Starts the editor for an attribute name or value.
* @param aAttrObj
@ -542,10 +592,10 @@ TreePanel.prototype = {
* @param aNode the DOM node in the content document to select.
* @param aScroll boolean scroll to the visible node?
*/
select: function TP_select(aNode, aScroll)
select: function TP_select(aNode, aScroll, aFrom)
{
if (this.ioBox) {
this.ioBox.select(aNode, true, true, aScroll);
this.ioBox.select(aNode, true, aFrom != "treepanel", aScroll);
} else {
this.pendingSelection = { node: aNode, scroll: aScroll };
}

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

@ -440,7 +440,7 @@ InspectorUI.prototype = {
/**
* Toggle the TreePanel.
*/
toggleHTMLPanel: function TP_toggleHTMLPanel()
toggleHTMLPanel: function IUI_toggleHTMLPanel()
{
if (this.treePanel.isOpen()) {
this.treePanel.close();
@ -653,15 +653,10 @@ InspectorUI.prototype = {
setupNavigationKeys: function IUI_setupNavigationKeys()
{
// UI elements that are arrow keys sensitive:
// - highlighter veil;
// - content window (when the highlighter `veil is pointer-events:none`;
// - the Inspector toolbar.
this.onKeypress = this.onKeypress.bind(this);
this.highlighter.highlighterContainer.addEventListener("keypress",
this.onKeypress, true);
this.win.addEventListener("keypress", this.onKeypress, true);
this.toolbar.addEventListener("keypress", this.onKeypress, true);
},
@ -670,9 +665,6 @@ InspectorUI.prototype = {
*/
removeNavigationKeys: function IUI_removeNavigationKeys()
{
this.highlighter.highlighterContainer.removeEventListener("keypress",
this.onKeypress, true);
this.win.removeEventListener("keypress", this.onKeypress, true);
this.toolbar.removeEventListener("keypress", this.onKeypress, true);
},
@ -857,7 +849,7 @@ InspectorUI.prototype = {
this.breadcrumbs.update();
this.chromeWin.Tilt.update(aNode);
this.treePanel.select(aNode, aScroll);
this.treePanel.select(aNode, aScroll, aFrom);
this._notifySelected(aFrom);
},
@ -1924,7 +1916,7 @@ HTMLBreadcrumbs.prototype = {
let classesLabel = this.IUI.chromeDoc.createElement("label");
classesLabel.className = "inspector-breadcrumbs-classes plain";
let pseudosLabel = this.IUI.chromeDoc.createElement("label");
pseudosLabel.className = "inspector-breadcrumbs-pseudo-classes plain";
@ -2153,6 +2145,7 @@ HTMLBreadcrumbs.prototype = {
};
button.onclick = (function _onBreadcrumbsRightClick(aEvent) {
button.focus();
if (aEvent.button == 2) {
this.openSiblingMenu(button, aNode);
}

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

@ -42,6 +42,8 @@ _BROWSER_FILES = \
browser_inspector_pseudoClass_menu.js \
browser_inspector_destroyselection.html \
browser_inspector_destroyselection.js \
browser_inspector_treePanel_navigation.html \
browser_inspector_treePanel_navigation.js \
head.js \
$(NULL)

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

@ -42,6 +42,8 @@ function test()
// Test that navigating around without a selected node gets us to the
// body element.
node = doc.querySelector("body");
let bc = InspectorUI.breadcrumbs;
bc.nodeHierarchy[bc.currentIndex].button.focus();
EventUtils.synthesizeKey("VK_RIGHT", { });
});
}

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

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="html">
<meta charset=utf-8 />
<body class="body">
<div class="node0">
<p class="node1">line1</p>
<p class="node2">line2</p>
<p class="node3">line3</p>
<!-- A comment -->
<p class="node4">line4
<span class="node5">line5</span>
<span class="node6">line6</span>
<!-- A comment -->
<a class="node7">line7<span class="node8">line8</span></a>
<span class="node9">line9</span>
<span class="node10">line10</span>
<span class="node11">line11</span>
<a class="node12">line12<span class="node13">line13</span></a>
</p>
<p class="node14">line14</p>
<p class="node15">line15</p>
</div>
</body>
</html>

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

@ -0,0 +1,103 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let doc;
let keySequence = "right down right ";
keySequence += "down down down down right ";
keySequence += "down down down right ";
keySequence += "down down down down down right ";
keySequence += "down down down down down ";
keySequence += "up up up left down home ";
keySequence += "pagedown left down down pageup pageup left down";
keySequence = keySequence.split(" ");
let keySequenceRes = "body node0 node0 ";
keySequenceRes += "node1 node2 node3 node4 node4 ";
keySequenceRes += "node5 node6 node7 node7 ";
keySequenceRes += "node8 node9 node10 node11 node12 node12 ";
keySequenceRes += "node13 node14 node15 node15 node15 ";
keySequenceRes += "node14 node13 node12 node12 node14 html ";
keySequenceRes += "node7 node7 node9 node10 body html html html";
keySequenceRes = keySequenceRes.split(" ");
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/highlighter/test/browser_inspector_treePanel_navigation.html";
function setupTest() {
Services.obs.addObserver(runTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runTests() {
Services.obs.removeObserver(runTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(startNavigation, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.select(doc.body, true, true, true);
InspectorUI.toggleHTMLPanel();
}
function startNavigation() {
Services.obs.removeObserver(startNavigation, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
nextStep(0);
}
function nextStep(cursor) {
let key = keySequence[cursor];
let className = keySequenceRes[cursor];
switch(key) {
case "right":
EventUtils.synthesizeKey("VK_RIGHT", {});
break;
case "down":
EventUtils.synthesizeKey("VK_DOWN", {});
break;
case "left":
EventUtils.synthesizeKey("VK_LEFT", {});
break;
case "up":
EventUtils.synthesizeKey("VK_UP", {});
break;
case "pageup":
EventUtils.synthesizeKey("VK_PAGE_UP", {});
break;
case "pagedown":
EventUtils.synthesizeKey("VK_PAGE_DOWN", {});
break;
case "home":
EventUtils.synthesizeKey("VK_HOME", {});
break;
}
executeSoon(function() {
if (cursor >= keySequence.length) {
Services.obs.addObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI();
} else {
let node = InspectorUI.treePanel.ioBox.selectedObjectBox.repObject;
is(node.className, className, "[" + cursor + "] right node selected: " + className);
nextStep(cursor + 1);
}
});
}
function finishUp() {
Services.obs.removeObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
doc = null;
gBrowser.removeCurrentTab();
finish();
}
}

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

@ -112,11 +112,13 @@ function ResponsiveUI(aWindow, aTab)
// Events
this.tab.addEventListener("TabClose", this);
this.tabContainer.addEventListener("TabSelect", this);
this.mainWindow.addEventListener("keypress", this.bound_onKeypress, true);
this.mainWindow.document.addEventListener("keypress", this.bound_onKeypress, false);
this.buildUI();
this.checkMenus();
this.inspectorWasOpen = this.mainWindow.InspectorUI.isInspectorOpen;
try {
if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
this.rotate();
@ -140,6 +142,10 @@ ResponsiveUI.prototype = {
* Destroy the nodes. Remove listeners. Reset the style.
*/
close: function RUI_unload() {
if (this.closing)
return;
this.closing = true;
this.unCheckMenus();
// Reset style of the stack.
let style = "max-width: none;" +
@ -154,7 +160,7 @@ ResponsiveUI.prototype = {
this.saveCurrentPreset();
// Remove listeners.
this.mainWindow.removeEventListener("keypress", this.bound_onKeypress, true);
this.mainWindow.document.removeEventListener("keypress", this.bound_onKeypress, false);
this.menulist.removeEventListener("select", this.bound_presetSelected, true);
this.tab.removeEventListener("TabClose", this);
this.tabContainer.removeEventListener("TabSelect", this);
@ -195,9 +201,17 @@ ResponsiveUI.prototype = {
onKeypress: function RUI_onKeypress(aEvent) {
if (aEvent.keyCode == this.mainWindow.KeyEvent.DOM_VK_ESCAPE &&
this.mainWindow.gBrowser.selectedBrowser == this.browser) {
aEvent.preventDefault();
aEvent.stopPropagation();
this.close();
// If the inspector wasn't open at first but is open now,
// we don't want to close the Responsive Mode on Escape.
// We let the inspector close first.
let isInspectorOpen = this.mainWindow.InspectorUI.isInspectorOpen;
if (this.inspectorWasOpen || !isInspectorOpen) {
aEvent.preventDefault();
aEvent.stopPropagation();
this.close();
}
}
},

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

@ -274,10 +274,6 @@
list-style-image: url("chrome://browser/skin/devtools/debugger-step-out.png");
}
#step-over {
list-style-image: url("chrome://browser/skin/devtools/debugger-step-over.png");
}
#debugger-controls > toolbarbutton {
border-width: 0;
-moz-border-end-width: 1px;

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

@ -274,10 +274,6 @@
list-style-image: url("chrome://browser/skin/devtools/debugger-step-out.png");
}
#step-over {
list-style-image: url("chrome://browser/skin/devtools/debugger-step-over.png");
}
#debugger-controls > toolbarbutton {
border-width: 0;
-moz-border-end-width: 1px;

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

@ -277,10 +277,6 @@
list-style-image: url("chrome://browser/skin/devtools/debugger-step-out.png");
}
#step-over {
list-style-image: url("chrome://browser/skin/devtools/debugger-step-over.png");
}
#debugger-controls > toolbarbutton {
border-width: 0;
-moz-border-end-width: 1px;