Bug 756888 - Rollup of a bunch of small GCLI changes; r=dcamp

--HG--
rename : browser/devtools/commandline/gcliblank.xhtml => browser/devtools/commandline/gclitooltip.xhtml
This commit is contained in:
Joe Walker 2012-05-22 08:50:02 +01:00
parent e8361cf126
commit 43a8a58584
10 changed files with 256 additions and 115 deletions

View File

@ -6201,7 +6201,7 @@ var eagerHelperSettingSpec = {
{ name: 'always', value: Eagerness.ALWAYS },
]
},
defaultValue: 1,
defaultValue: Eagerness.SOMETIMES,
description: l10n.lookup('eagerHelperDesc'),
ignoreTypeDifference: true
};
@ -6346,7 +6346,8 @@ FocusManager.prototype.removeMonitoredElement = function(element, where) {
FocusManager.prototype.updatePosition = function(dimensions) {
var ev = {
tooltipVisible: this.isTooltipVisible,
outputVisible: this.isOutputVisible
outputVisible: this.isOutputVisible,
dimensions: dimensions
};
this.onVisibilityChange(ev);
};

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
[
<!ENTITY % webConsoleDTD SYSTEM "chrome://browser/locale/devtools/webConsole.dtd">
%webConsoleDTD;
]
>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is GCLI.
-
- The Initial Developer of the Original Code is
- Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2012
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Joe Walker <jwalker@mozilla.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="chrome://global/skin/global.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
</head>
<body class="gcli-body">
<div id="gcli-output-root"></div>
</body>
</html>

View File

@ -19,8 +19,8 @@
<link rel="stylesheet" href="chrome://browser/content/devtools/gcli.css" type="text/css"/>
<link rel="stylesheet" href="chrome://browser/skin/devtools/gcli.css" type="text/css"/>
</head>
<body id="gclichrome-body">
<div>
</div>
<body class="gcli-body">
<div id="gcli-tooltip-root"></div>
<div id="gcli-tooltip-connector"></div>
</body>
</html>

View File

@ -23,4 +23,5 @@ browser.jar:
content/browser/debugger-controller.js (debugger/debugger-controller.js)
content/browser/debugger-view.js (debugger/debugger-view.js)
content/browser/devtools/gcli.css (commandline/gcli.css)
content/browser/devtools/gcliblank.xhtml (commandline/gcliblank.xhtml)
content/browser/devtools/gclioutput.xhtml (commandline/gclioutput.xhtml)
content/browser/devtools/gclitooltip.xhtml (commandline/gclitooltip.xhtml)

View File

@ -7,7 +7,6 @@
const EXPORTED_SYMBOLS = [ "DeveloperToolbar" ];
const NS_XHTML = "http://www.w3.org/1999/xhtml";
const URI_GCLIBLANK = "chrome://browser/content/devtools/gcliblank.xhtml";
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
@ -79,7 +78,6 @@ DeveloperToolbar.prototype.toggle = function DT_toggle()
this.hide();
} else {
this.show();
this._input.focus();
}
};
@ -154,9 +152,11 @@ DeveloperToolbar.prototype._onload = function DT_onload()
this.display.onOutput.add(this.outputPanel._outputChanged, this.outputPanel);
this._chromeWindow.getBrowser().tabContainer.addEventListener("TabSelect", this, false);
this._chromeWindow.getBrowser().addEventListener("load", this, true);
this._chromeWindow.getBrowser().addEventListener("load", this, true);
this._chromeWindow.addEventListener("resize", this, false);
this._element.hidden = false;
this._input.focus();
this._notify(NOTIFICATIONS.SHOW);
if (this._pendingShowCallback) {
@ -263,65 +263,10 @@ DeveloperToolbar.prototype.handleEvent = function DT_handleEvent(aEvent)
});
}
}
};
/**
* Add class="gcli-panel-inner-arrowcontent" to a panel's
* |<xul:box class="panel-inner-arrowcontent">| so we can alter the styling
* without complex CSS expressions.
* @param aPanel The panel to affect
*/
function getContentBox(aPanel)
{
let container = aPanel.ownerDocument.getAnonymousElementByAttribute(
aPanel, "anonid", "container");
return container.querySelector(".panel-inner-arrowcontent");
}
/**
* Helper function to calculate the sum of the vertical padding and margins
* between a nested node |aNode| and an ancestor |aRoot|. Iff all of the
* children of aRoot are 'only-childs' until you get to aNode then to avoid
* scroll-bars, the 'correct' height of aRoot is verticalSpacing + aNode.height.
* @param aNode The child node whose height is known.
* @param aRoot The parent height whose height we can affect.
* @return The sum of the vertical padding/margins in between aNode and aRoot.
*/
function getVerticalSpacing(aNode, aRoot)
{
let win = aNode.ownerDocument.defaultView;
function pxToNum(styles, property) {
return parseInt(styles.getPropertyValue(property).replace(/px$/, ''), 10);
else if (aEvent.type == "resize") {
this.outputPanel._resize();
}
let vertSpacing = 0;
do {
let styles = win.getComputedStyle(aNode);
vertSpacing += pxToNum(styles, "padding-top");
vertSpacing += pxToNum(styles, "padding-bottom");
vertSpacing += pxToNum(styles, "margin-top");
vertSpacing += pxToNum(styles, "margin-bottom");
vertSpacing += pxToNum(styles, "border-top-width");
vertSpacing += pxToNum(styles, "border-bottom-width");
let prev = aNode.previousSibling;
while (prev != null) {
vertSpacing += prev.clientHeight;
prev = prev.previousSibling;
}
let next = aNode.nextSibling;
while (next != null) {
vertSpacing += next.clientHeight;
next = next.nextSibling;
}
aNode = aNode.parentNode;
} while (aNode !== aRoot);
return vertSpacing + 9;
}
};
/**
* Panel to handle command line output.
@ -332,32 +277,31 @@ function getVerticalSpacing(aNode, aRoot)
function OutputPanel(aChromeDoc, aInput, aLoadCallback)
{
this._input = aInput;
this._anchor = aChromeDoc.getElementById("developer-toolbar");
this._toolbar = aChromeDoc.getElementById("developer-toolbar");
this._loadCallback = aLoadCallback;
/*
<panel id="gcli-output"
type="arrow"
noautofocus="true"
noautohide="true"
class="gcli-panel">
<iframe id="gcli-output-frame"
src=URI_GCLIBLANK
flex="1"/>
<html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
id="gcli-output-frame"
src="chrome://browser/content/devtools/gclioutput.xhtml"
flex="1"/>
</panel>
*/
this._panel = aChromeDoc.createElement("panel");
this._panel.id = "gcli-output";
this._panel.classList.add("gcli-panel");
this._panel.setAttribute("type", "arrow");
this._panel.setAttribute("noautofocus", "true");
this._panel.setAttribute("noautohide", "true");
this._anchor.parentElement.insertBefore(this._panel, this._anchor);
this._toolbar.parentElement.insertBefore(this._panel, this._toolbar);
this._frame = aChromeDoc.createElement("iframe");
this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
this._frame.id = "gcli-output-frame";
this._frame.setAttribute("src", URI_GCLIBLANK);
this._frame.setAttribute("src", "chrome://browser/content/devtools/gclioutput.xhtml");
this._frame.setAttribute("flex", "1");
this._panel.appendChild(this._frame);
@ -377,13 +321,9 @@ OutputPanel.prototype._onload = function OP_onload()
this._frame.removeEventListener("load", this._onload, true);
delete this._onload;
this._content = getContentBox(this._panel);
this._content.classList.add("gcli-panel-inner-arrowcontent");
this.document = this._frame.contentDocument;
this.document.body.classList.add("gclichrome-output");
this._div = this.document.querySelector("div");
this._div = this.document.getElementById("gcli-output-root");
this._div.classList.add('gcli-row-out');
this._div.setAttribute('aria-live', 'assertive');
@ -399,12 +339,15 @@ OutputPanel.prototype._onload = function OP_onload()
*/
OutputPanel.prototype.show = function OP_show()
{
// This is nasty, but displaying the panel causes it to re-flow, which can
// change the size it should be, so we need to resize the iframe after the
// panel has displayed
this._panel.ownerDocument.defaultView.setTimeout(function() {
this._resize();
}.bind(this), 0);
this._panel.openPopup(this._input, "before_start", 0, 0, false, false, null);
this._resize();
this._panel.openPopup(this._anchor, "before_end", -300, 0, false, false, null);
this._input.focus();
};
@ -415,9 +358,12 @@ OutputPanel.prototype.show = function OP_show()
*/
OutputPanel.prototype._resize = function CLP_resize()
{
let vertSpacing = getVerticalSpacing(this._content, this._panel);
let idealHeight = this.document.body.scrollHeight + vertSpacing;
this._panel.sizeTo(400, Math.min(idealHeight, 500));
if (this._panel == null || this.document == null || !this._panel.state == "closed") {
return
}
this._frame.height = this.document.body.scrollHeight;
this._frame.width = this._input.clientWidth + 2;
};
/**
@ -476,10 +422,10 @@ OutputPanel.prototype.destroy = function OP_destroy()
this.remove();
this._panel.removeChild(this._frame);
this._anchor.parentElement.removeChild(this._panel);
this._toolbar.parentElement.removeChild(this._panel);
delete this._input;
delete this._anchor;
delete this._toolbar;
delete this._panel;
delete this._frame;
delete this._content;
@ -510,7 +456,8 @@ OutputPanel.prototype._visibilityChanged = function OP_visibilityChanged(aEvent)
function TooltipPanel(aChromeDoc, aInput, aLoadCallback)
{
this._input = aInput;
this._anchor = aChromeDoc.getElementById("developer-toolbar");
this._toolbar = aChromeDoc.getElementById("developer-toolbar");
this._dimensions = { start: 0, end: 0 };
this._onload = this._onload.bind(this);
this._loadCallback = aLoadCallback;
@ -520,22 +467,22 @@ function TooltipPanel(aChromeDoc, aInput, aLoadCallback)
noautofocus="true"
noautohide="true"
class="gcli-panel">
<iframe id="gcli-tooltip-frame"
src=URI_GCLIBLANK
flex="1"/>
<html:iframe xmlns:html="http://www.w3.org/1999/xhtml"
id="gcli-tooltip-frame"
src="chrome://browser/content/devtools/gclitooltip.xhtml"
flex="1"/>
</panel>
*/
this._panel = aChromeDoc.createElement("panel");
this._panel.id = "gcli-tooltip";
this._panel.classList.add("gcli-panel");
this._panel.setAttribute("type", "arrow");
this._panel.setAttribute("noautofocus", "true");
this._panel.setAttribute("noautohide", "true");
this._anchor.parentElement.insertBefore(this._panel, this._anchor);
this._toolbar.parentElement.insertBefore(this._panel, this._toolbar);
this._frame = aChromeDoc.createElement("iframe");
this._frame = aChromeDoc.createElementNS(NS_XHTML, "iframe");
this._frame.id = "gcli-tooltip-frame";
this._frame.setAttribute("src", URI_GCLIBLANK);
this._frame.setAttribute("src", "chrome://browser/content/devtools/gclitooltip.xhtml");
this._frame.setAttribute("flex", "1");
this._panel.appendChild(this._frame);
@ -550,13 +497,9 @@ TooltipPanel.prototype._onload = function TP_onload()
{
this._frame.removeEventListener("load", this._onload, true);
this._content = getContentBox(this._panel);
this._content.classList.add("gcli-panel-inner-arrowcontent");
this.document = this._frame.contentDocument;
this.document.body.classList.add("gclichrome-tooltip");
this.hintElement = this.document.querySelector("div");
this.hintElement = this.document.getElementById("gcli-tooltip-root");
this._connector = this.document.getElementById("gcli-tooltip-connector");
this.loaded = true;
@ -569,16 +512,58 @@ TooltipPanel.prototype._onload = function TP_onload()
/**
* Display the TooltipPanel.
*/
TooltipPanel.prototype.show = function TP_show()
TooltipPanel.prototype.show = function TP_show(aDimensions)
{
let vertSpacing = getVerticalSpacing(this._content, this._panel);
let idealHeight = this.document.body.scrollHeight + vertSpacing;
this._panel.sizeTo(350, Math.min(idealHeight, 500));
this._panel.openPopup(this._anchor, "before_start", 0, 0, false, false, null);
if (!aDimensions) {
aDimensions = { start: 0, end: 0 };
}
this._dimensions = aDimensions;
// This is nasty, but displaying the panel causes it to re-flow, which can
// change the size it should be, so we need to resize the iframe after the
// panel has displayed
this._panel.ownerDocument.defaultView.setTimeout(function() {
this._resize();
}.bind(this), 0);
this._resize();
this._panel.openPopup(this._input, "before_start", aDimensions.start * 10, 0, false, false, null);
this._input.focus();
};
/**
* One option is to spend lots of time taking an average width of characters
* in the current font, dynamically, and weighting for the frequency of use of
* various characters, or even to render the given string off screen, and then
* measure the width.
* Or we could do this...
*/
const AVE_CHAR_WIDTH = 4.5;
/**
* Display the TooltipPanel.
*/
TooltipPanel.prototype._resize = function TP_resize()
{
if (this._panel == null || this.document == null || !this._panel.state == "closed") {
return
}
let offset = 10 + Math.floor(this._dimensions.start * AVE_CHAR_WIDTH);
this._frame.style.marginLeft = offset + "px";
/*
// Bug 744906: UX review - Not sure if we want this code to fatten connector
// with param width
let width = Math.floor(this._dimensions.end * AVE_CHAR_WIDTH);
width = Math.min(width, 100);
width = Math.max(width, 10);
this._connector.style.width = width + "px";
*/
this._frame.height = this.document.body.scrollHeight;
};
/**
* Hide the TooltipPanel.
*/
@ -595,13 +580,15 @@ TooltipPanel.prototype.destroy = function TP_destroy()
this.remove();
this._panel.removeChild(this._frame);
this._anchor.parentElement.removeChild(this._panel);
this._toolbar.parentElement.removeChild(this._panel);
delete this._connector;
delete this._dimensions;
delete this._input;
delete this._onload;
delete this._panel;
delete this._frame;
delete this._anchor;
delete this._toolbar;
delete this._content;
delete this.document;
delete this.hintElement;
@ -614,7 +601,7 @@ TooltipPanel.prototype.destroy = function TP_destroy()
TooltipPanel.prototype._visibilityChanged = function TP_visibilityChanged(aEvent)
{
if (aEvent.tooltipVisible === true) {
this.show();
this.show(aEvent.dimensions);
} else {
this._panel.hidePopup();
}

View File

@ -18,6 +18,7 @@ _BROWSER_TEST_FILES = \
browser_require_basic.js \
browser_templater_basic.js \
browser_toolbar_basic.js \
browser_toolbar_tooltip.js \
head.js \
$(NULL)

View File

@ -9,10 +9,10 @@ registerCleanupFunction(function() {
imported = {};
});
const URL = "http://example.com/browser/browser/devtools/shared/test/browser_toolbar_basic.html";
const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_toolbar_basic.html";
function test() {
addTab(URL, function(browser, tab) {
addTab(TEST_URI, function(browser, tab) {
info("Starting browser_toolbar_basic.js");
runTest();
});

View File

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the developer toolbar works properly
const TEST_URI = "data:text/html;charset=utf-8,<p>Tooltip Tests</p>";
function test() {
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
runTest();
finish();
});
}
function runTest() {
let tooltipPanel = DeveloperToolbar.tooltipPanel;
DeveloperToolbar.display.focusManager.helpRequest();
DeveloperToolbar.display.inputter.setInput('help help');
DeveloperToolbar.display.inputter.setCursor({ start: 'help help'.length });
is(tooltipPanel._dimensions.start, 'help '.length,
'search param start, when cursor at end');
ok(getLeftMargin() > 30, 'tooltip offset, when cursor at end')
DeveloperToolbar.display.inputter.setCursor({ start: 'help'.length });
is(tooltipPanel._dimensions.start, 0,
'search param start, when cursor at end of command');
ok(getLeftMargin() > 9, 'tooltip offset, when cursor at end of command')
DeveloperToolbar.display.inputter.setCursor({ start: 'help help'.length - 1 });
is(tooltipPanel._dimensions.start, 'help '.length,
'search param start, when cursor at penultimate position');
ok(getLeftMargin() > 30, 'tooltip offset, when cursor at penultimate position')
DeveloperToolbar.display.inputter.setCursor({ start: 0 });
is(tooltipPanel._dimensions.start, 0,
'search param start, when cursor at start');
ok(getLeftMargin() > 9, 'tooltip offset, when cursor at start')
}
function getLeftMargin() {
let style = DeveloperToolbar.tooltipPanel._frame.style.marginLeft;
return parseInt(style.slice(0, -2), 10);
}

View File

@ -67,7 +67,55 @@ let DeveloperToolbarTest = {
DeveloperToolbar.display.inputter.setInput("");
DeveloperToolbar.hide();
}
}
},
/**
* Quick wrapper around the things you need to do to run DeveloperToolbar
* command tests:
* - Set the pref 'devtools.toolbar.enabled' to true
* - Add a tab pointing at |uri|
* - Open the DeveloperToolbar
* - Register a cleanup function to undo the above
* - Run the tests
*
* @param uri The uri of a page to load. Can be 'about:blank' or 'data:...'
* @param testFunc A function containing the tests to run. This should
* arrange for 'finish()' to be called on completion.
*/
test: function DTT_test(uri, testFunc) {
let menuItem = document.getElementById("menu_devToolbar");
let command = document.getElementById("Tools:DevToolbar");
let appMenuItem = document.getElementById("appmenu_devToolbar");
registerCleanupFunction(function() {
DeveloperToolbarTest.hide();
// a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled");
if (menuItem) menuItem.hidden = true;
if (command) command.setAttribute("disabled", "true");
if (appMenuItem) appMenuItem.hidden = true;
});
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
if (menuItem) menuItem.hidden = false;
if (command) command.removeAttribute("disabled");
if (appMenuItem) appMenuItem.hidden = false;
addTab(uri, function(browser, tab) {
DeveloperToolbarTest.show(function() {
try {
testFunc(browser, tab);
}
catch (ex) {
ok(false, "" + ex);
console.error(ex);
finish();
throw ex;
}
});
});
},
};
function catchFail(func) {

View File

@ -229,9 +229,9 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
<!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
<!ENTITY devToolbarMenu.label "Developer Toolbar">
<!ENTITY devToolbarMenu.accesskey "v">
<!ENTITY devToolbar.commandkey "v">
<!ENTITY devToolbarMenu.label "Developer Toolbar">
<!ENTITY devToolbarMenu.accesskey "v">
<!ENTITY devToolbar.commandkey "v">
<!ENTITY webConsoleButton.label "Web Console">
<!ENTITY inspectorButton.label "Inspector">