Merge mozilla-central and mozilla-inbound

This commit is contained in:
Ed Morley 2011-11-04 14:33:49 +00:00
commit 360d4cbee5
22 changed files with 1017 additions and 515 deletions

View File

@ -145,12 +145,8 @@
<commandset id="inspectorCommands">
<command id="Inspector:Inspect"
oncommand="InspectorUI.toggleInspection();"/>
<command id="Inspector:Previous"
oncommand="InspectorUI.inspectPrevious();"
disabled="true"/>
<command id="Inspector:Next"
oncommand="InspectorUI.inspectNext();"
disabled="true"/>
<command id="Inspector:Sidebar"
oncommand="InspectorUI.toggleSidebar();"/>
</commandset>
<broadcasterset id="mainBroadcasterSet">

View File

@ -966,6 +966,12 @@
onclick="return contentAreaClick(event, false);"/>
<statuspanel id="statusbar-display" inactive="true"/>
</vbox>
<splitter id="devtools-side-splitter" hidden="true"/>
<vbox id="devtools-sidebar-box" hidden="true" flex="1"
style="min-width: 18em; width: 22em; max-width: 42em;" persist="width">
<toolbar id="devtools-sidebar-toolbar" nowindowdrag="true"/>
<deck id="devtools-sidebar-deck" flex="1"/>
</vbox>
<vbox id="browser-border-end" hidden="true" layer="true"/>
</hbox>
@ -1000,6 +1006,10 @@
flex="1" orient="horizontal"
clicktoscroll="true"/>
<hbox id="inspector-tools">
<toolbarbutton id="inspector-style-button"
label="&inspectStyleButton.label;"
accesskey="&inspectStyleButton.accesskey;"
command="Inspector:Sidebar"/>
<!-- registered tools go here -->
</hbox>
#ifndef XP_MACOSX

View File

@ -2432,7 +2432,7 @@
#else
if (aEvent.ctrlKey && !aEvent.shiftKey && !aEvent.metaKey &&
aEvent.keyCode == KeyEvent.DOM_VK_F4 &&
this.mTabBox.handleCtrlPageUpDown) {
!this.mCurrentTab.pinned) {
this.removeCurrentTab({animate: true});
aEvent.stopPropagation();
aEvent.preventDefault();

View File

@ -2263,17 +2263,33 @@ SessionStoreService.prototype = {
_extractHostsForCookies:
function sss__extractHostsForCookies(aEntry, aHosts, aCheckPrivacy, aIsPinned) {
// _host and _scheme may not be set (for about: urls for example), in which
// case testing _scheme will be sufficient.
if (/https?/.test(aEntry._scheme) && !aHosts[aEntry._host] &&
let host = aEntry._host,
scheme = aEntry._scheme;
// If host & scheme aren't defined, then we are likely here in the startup
// process via _splitCookiesFromWindow. In that case, we'll turn aEntry.url
// into an nsIURI and get host/scheme from that. This will throw for about:
// urls in which case we don't need to do anything.
if (!host && !scheme) {
try {
let uri = this._getURIFromString(aEntry.url);
host = uri.host;
scheme = uri.scheme;
}
catch(ex) { }
}
// host and scheme may not be set (for about: urls for example), in which
// case testing scheme will be sufficient.
if (/https?/.test(scheme) && !aHosts[host] &&
(!aCheckPrivacy ||
this._checkPrivacyLevel(aEntry._scheme == "https", aIsPinned))) {
this._checkPrivacyLevel(scheme == "https", aIsPinned))) {
// By setting this to true or false, we can determine when looking at
// the host in _updateCookies if we should check for privacy.
aHosts[aEntry._host] = aIsPinned;
aHosts[host] = aIsPinned;
}
else if (aEntry._scheme == "file") {
aHosts[aEntry._host] = true;
else if (scheme == "file") {
aHosts[host] = true;
}
if (aEntry.children) {
@ -4022,6 +4038,9 @@ SessionStoreService.prototype = {
// By creating a regex we reduce overhead and there is only one loop pass
// through either array (cookieHosts and aWinState.cookies).
let hosts = Object.keys(cookieHosts).join("|").replace("\\.", "\\.", "g");
// If we don't actually have any hosts, then we don't want to do anything.
if (!hosts.length)
return;
let cookieRegex = new RegExp(".*(" + hosts + ")");
for (let cIndex = 0; cIndex < aWinState.cookies.length;) {
if (cookieRegex.test(aWinState.cookies[cIndex].host)) {

View File

@ -758,6 +758,57 @@ InspectorUI.prototype = {
}
},
/**
* Show the Sidebar.
*/
showSidebar: function IUI_showSidebar()
{
this.sidebarBox.removeAttribute("hidden");
this.sidebarSplitter.removeAttribute("hidden");
this.stylingButton.checked = true;
// Activate the first tool in the sidebar, only if none previously-
// selected. We'll want to do a followup to remember selected tool-states.
if (!Array.some(this.sidebarToolbar.children,
function(btn) btn.hasAttribute("checked"))) {
let firstButtonId = this.getToolbarButtonId(this.sidebarTools[0].id);
this.chromeDoc.getElementById(firstButtonId).click();
}
},
/**
* Hide the Sidebar.
*/
hideSidebar: function IUI_hideSidebar()
{
this.sidebarBox.setAttribute("hidden", "true");
this.sidebarSplitter.setAttribute("hidden", "true");
this.stylingButton.checked = false;
},
/**
* Show or hide the sidebar. Called from the Styling button on the
* highlighter toolbar.
*/
toggleSidebar: function IUI_toggleSidebar()
{
if (!this.isSidebarOpen) {
this.showSidebar();
} else {
this.hideSidebar();
}
},
/**
* Getter to test if the Sidebar is open or not.
*/
get isSidebarOpen()
{
return this.stylingButton.checked &&
!this.sidebarBox.hidden &&
!this.sidebarSplitter.hidden;
},
/**
* Toggle the status of the inspector, starting or stopping it. Invoked
* from the toolbar's Inspect button.
@ -955,6 +1006,9 @@ InspectorUI.prototype = {
this.unregisterTool(aTool);
}.bind(this));
// close the sidebar
this.hideSidebar();
if (this.highlighter) {
this.highlighter.highlighterContainer.removeEventListener("keypress",
this,
@ -1366,13 +1420,25 @@ InspectorUI.prototype = {
return "inspector-" + anId + "-toolbutton";
},
/**
* Save a registered tool's callback for a specified event.
* @param aWidget xul:widget
* @param aEvent a DOM event name
* @param aCallback Function the click event handler for the button
*/
bindToolEvent: function IUI_bindToolEvent(aWidget, aEvent, aCallback)
{
this.toolEvents[aWidget.id + "_" + aEvent] = aCallback;
aWidget.addEventListener(aEvent, aCallback, false);
},
/**
* Register an external tool with the inspector.
*
* aRegObj = {
* id: "toolname",
* context: myTool,
* label: "Button label",
* label: "Button or tab label",
* icon: "chrome://somepath.png",
* tooltiptext: "Button tooltip",
* accesskey: "S",
@ -1382,7 +1448,8 @@ InspectorUI.prototype = {
* hide: object.method, called to hide the tool when button is pressed.
* dim: object.method, called to disable a tool during highlighting.
* unregister: object.method, called when tool should be destroyed.
* panel: myTool.panel
* panel: myTool.panel, set if tool is in a separate panel, null otherwise.
* sidebar: boolean, true if tool lives in sidebar tab.
* }
*
* @param aRegObj Object
@ -1398,28 +1465,24 @@ InspectorUI.prototype = {
this.tools[aRegObj.id] = aRegObj;
let buttonContainer = this.chromeDoc.getElementById("inspector-tools");
let btn = this.chromeDoc.createElement("toolbarbutton");
let btn;
// if this is a sidebar tool, create the sidebar features for it and bail.
if (aRegObj.sidebar) {
this.createSidebarTool(aRegObj);
return;
}
btn = this.chromeDoc.createElement("toolbarbutton");
let buttonId = this.getToolbarButtonId(aRegObj.id);
btn.setAttribute("id", buttonId);
btn.setAttribute("label", aRegObj.label);
btn.setAttribute("tooltiptext", aRegObj.tooltiptext);
btn.setAttribute("accesskey", aRegObj.accesskey);
btn.setAttribute("image", aRegObj.icon || "");
buttonContainer.appendChild(btn);
buttonContainer.insertBefore(btn, this.stylingButton);
/**
* Save a registered tool's callback for a specified event.
* @param aWidget xul:widget
* @param aEvent a DOM event name
* @param aCallback Function the click event handler for the button
*/
let toolEvents = this.toolEvents;
function bindToolEvent(aWidget, aEvent, aCallback) {
toolEvents[aWidget.id + "_" + aEvent] = aCallback;
aWidget.addEventListener(aEvent, aCallback, false);
}
bindToolEvent(btn, "click",
this.bindToolEvent(btn, "click",
function IUI_toolButtonClick(aEvent) {
if (btn.checked) {
this.toolHide(aRegObj);
@ -1428,14 +1491,85 @@ InspectorUI.prototype = {
}
}.bind(this));
// if the tool has a panel, register the popuphiding event
if (aRegObj.panel) {
bindToolEvent(aRegObj.panel, "popuphiding",
this.bindToolEvent(aRegObj.panel, "popuphiding",
function IUI_toolPanelHiding() {
btn.checked = false;
});
}
},
get sidebarBox()
{
return this.chromeDoc.getElementById("devtools-sidebar-box");
},
get sidebarToolbar()
{
return this.chromeDoc.getElementById("devtools-sidebar-toolbar");
},
get sidebarDeck()
{
return this.chromeDoc.getElementById("devtools-sidebar-deck");
},
get sidebarSplitter()
{
return this.chromeDoc.getElementById("devtools-side-splitter");
},
get stylingButton()
{
return this.chromeDoc.getElementById("inspector-style-button");
},
/**
* Creates a tab and tabpanel for our tool to reside in.
* @param {Object} aRegObj the Registration Object for our tool.
*/
createSidebarTool: function IUI_createSidebarTab(aRegObj)
{
// toolbutton elements
let btn = this.chromeDoc.createElement("toolbarbutton");
let buttonId = this.getToolbarButtonId(aRegObj.id);
btn.id = buttonId;
btn.setAttribute("label", aRegObj.label);
btn.setAttribute("tooltiptext", aRegObj.tooltiptext);
btn.setAttribute("accesskey", aRegObj.accesskey);
btn.setAttribute("image", aRegObj.icon || "");
btn.setAttribute("type", "radio");
btn.setAttribute("group", "sidebar-tools");
this.sidebarToolbar.appendChild(btn);
// create tool iframe
let iframe = this.chromeDoc.createElement("iframe");
iframe.id = "devtools-sidebar-iframe-" + aRegObj.id;
iframe.setAttribute("flex", "1");
this.sidebarDeck.appendChild(iframe);
// wire up button to show the iframe
this.bindToolEvent(btn, "click", function showIframe() {
let visible = this.sidebarDeck.selectedPanel == iframe;
if (!visible) {
sidebarDeck.selectedPanel = iframe;
}
this.toolShow(aRegObj);
}.bind(this));
},
/**
* Return the registered object's iframe.
* @param aRegObj see registerTool function.
* @return iframe or null
*/
getToolIframe: function IUI_getToolIFrame(aRegObj)
{
return this.chromeDoc.getElementById("devtools-sidebar-iframe-" + aRegObj.id);
},
/**
* Show the specified tool.
* @param aTool Object (see comment for IUI_registerTool)
@ -1443,7 +1577,9 @@ InspectorUI.prototype = {
toolShow: function IUI_toolShow(aTool)
{
aTool.show.call(aTool.context, this.selection);
this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id)).checked = true;
let btn = this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id));
btn.setAttribute("checked", "true");
},
/**
@ -1453,7 +1589,21 @@ InspectorUI.prototype = {
toolHide: function IUI_toolHide(aTool)
{
aTool.hide.call(aTool.context);
this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id)).checked = false;
let btn = this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id));
btn.removeAttribute("checked");
},
/**
* Unregister the events associated with the registered tool's widget.
* @param aWidget XUL:widget (toolbarbutton|panel).
* @param aEvent a DOM event.
*/
unbindToolEvent: function IUI_unbindToolEvent(aWidget, aEvent)
{
let toolEvent = aWidget.id + "_" + aEvent;
aWidget.removeEventListener(aEvent, this.toolEvents[toolEvent], false);
delete this.toolEvents[toolEvent]
},
/**
@ -1464,28 +1614,50 @@ InspectorUI.prototype = {
*/
unregisterTool: function IUI_unregisterTool(aRegObj)
{
// if this is a sidebar tool, use the sidebar unregistration method
if (aRegObj.sidebar) {
this.unregisterSidebarTool(aRegObj);
return;
}
let button = this.chromeDoc.getElementById(this.getToolbarButtonId(aRegObj.id));
/**
* Unregister the events associated with the registered tool's widget.
* @param aWidget XUL:widget (toolbarbutton|panel).
* @param aEvent a DOM event.
*/
let toolEvents = this.toolEvents;
function unbindToolEvent(aWidget, aEvent) {
let toolEvent = aWidget.id + "_" + aEvent;
aWidget.removeEventListener(aEvent, toolEvents[toolEvent], false);
delete toolEvents[toolEvent]
};
let buttonContainer = this.chromeDoc.getElementById("inspector-tools");
unbindToolEvent(button, "click");
// unbind click events on button
this.unbindToolEvent(button, "click");
// unbind panel popuphiding events if present.
if (aRegObj.panel)
unbindToolEvent(aRegObj.panel, "popuphiding");
this.unbindToolEvent(aRegObj.panel, "popuphiding");
// remove the button from its container
buttonContainer.removeChild(button);
// call unregister callback and remove from collection
if (aRegObj.unregister)
aRegObj.unregister.call(aRegObj.context);
delete this.tools[aRegObj.id];
},
/**
* Unregister the registered sidebar tool, unbinding click events for the
* button.
* @param aRegObj Object
* The registration object used to register the tool.
*/
unregisterSidebarTool: function IUI_unregisterSidebarTool(aRegObj)
{
// unbind tool button click event
let buttonId = this.getToolbarButtonId(aRegObj.id);
let btn = this.chromeDoc.getElementById(buttonId);
this.unbindToolEvent(btn, "click");
// remove sidebar buttons and tools
this.sidebarToolbar.removeChild(btn);
// call unregister callback and remove from collection, this also removes
// the iframe.
if (aRegObj.unregister)
aRegObj.unregister.call(aRegObj.context);
@ -1520,6 +1692,9 @@ InspectorUI.prototype = {
if (openTools) {
this.toolsDo(function IUI_toolsOnShow(aTool) {
if (aTool.id in openTools) {
if (aTool.sidebar && !this.isSidebarOpen) {
this.showSidebar();
}
this.toolShow(aTool);
}
}.bind(this));
@ -1566,6 +1741,18 @@ InspectorUI.prototype = {
}
},
/**
* Convenience getter to retrieve only the sidebar tools.
*/
get sidebarTools()
{
let sidebarTools = [];
for each (let tool in this.tools)
if (tool.sidebar)
sidebarTools.push(tool);
return sidebarTools;
},
/**
* Check if a tool is registered?
* @param aId The id of the tool to check

View File

@ -76,6 +76,7 @@ function runInspectorTests()
ok(!InspectorUI.toolbar.hidden, "toolbar is visible");
ok(InspectorUI.inspecting, "Inspector is inspecting");
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is not open");
ok(InspectorUI.highlighter, "Highlighter is up");
InspectorUI.inspectNode(doc.body);
InspectorUI.stopInspecting();
@ -93,7 +94,7 @@ function treePanelTests()
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
executeSoon(function() {
InspectorUI.stylePanel.open(doc.body);
InspectorUI.showSidebar();
});
}
@ -103,7 +104,7 @@ function stylePanelTests()
Services.obs.addObserver(runContextMenuTest,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(InspectorUI.stylePanel.isOpen(), "Style Panel is Open");
ok(InspectorUI.isSidebarOpen, "Inspector Sidebar is open");
ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree");
executeSoon(function() {
@ -191,6 +192,7 @@ function finishInspectorTests()
ok(!InspectorUI.highlighter, "Highlighter is gone");
ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
ok(!InspectorUI.inspecting, "Inspector is not inspecting");
ok(!InspectorUI.isSidebarOpen, "Inspector Sidebar is closed");
ok(!InspectorUI.toolbar, "toolbar is hidden");
gBrowser.removeCurrentTab();

View File

@ -313,7 +313,7 @@ var Scratchpad = {
*/
evalInContentSandbox: function SP_evalInContentSandbox(aString)
{
let result;
let error, result;
try {
result = Cu.evalInSandbox(aString, this.contentSandbox, "1.8",
"Scratchpad", 1);
@ -332,9 +332,11 @@ var Scratchpad = {
this.getInnerWindowId(contentWindow));
Services.console.logMessage(scriptError);
error = true;
}
return result;
return [error, result];
},
/**
@ -347,7 +349,7 @@ var Scratchpad = {
*/
evalInChromeSandbox: function SP_evalInChromeSandbox(aString)
{
let result;
let error, result;
try {
result = Cu.evalInSandbox(aString, this.chromeSandbox, "1.8",
"Scratchpad", 1);
@ -356,9 +358,11 @@ var Scratchpad = {
Cu.reportError(ex);
Cu.reportError(ex.stack);
this.openErrorConsole();
error = true;
}
return result;
return [error, result];
},
/**
@ -384,9 +388,9 @@ var Scratchpad = {
run: function SP_run()
{
let selection = this.selectedText || this.getText();
let result = this.evalForContext(selection);
let [error, result] = this.evalForContext(selection);
this.deselect();
return [selection, result];
return [selection, error, result];
},
/**
@ -396,9 +400,9 @@ var Scratchpad = {
*/
inspect: function SP_inspect()
{
let [selection, result] = this.run();
let [selection, error, result] = this.run();
if (result) {
if (!error) {
this.openPropertyPanel(selection, result);
}
},
@ -416,12 +420,12 @@ var Scratchpad = {
selection.end : // after selected text
this.editor.getCharCount(); // after text end
let [selectedText, result] = this.run();
if (!result) {
let [selectedText, error, result] = this.run();
if (error) {
return;
}
let newComment = "/*\n" + result.toString() + "\n*/";
let newComment = "/*\n" + result + "\n*/";
this.setText(newComment, insertionPoint, insertionPoint);
@ -459,14 +463,11 @@ var Scratchpad = {
accesskey: this.strings.
GetStringFromName("propertyPanel.updateButton.accesskey"),
oncommand: function () {
try {
let result = self.evalForContext(aEvalString);
let [error, result] = self.evalForContext(aEvalString);
if (result !== undefined) {
propPanel.treeView.data = result;
}
if (!error) {
propPanel.treeView.data = result;
}
catch (ex) { }
}
});
}

View File

@ -55,6 +55,7 @@ _BROWSER_TEST_FILES = \
browser_scratchpad_bug_660560_tab.js \
browser_scratchpad_open.js \
browser_scratchpad_restore.js \
browser_scratchpad_bug_679467_falsy.js \
libs:: $(_BROWSER_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -0,0 +1,64 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Reference to the Scratchpad chrome window object.
let gScratchpadWindow;
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
gScratchpadWindow = Scratchpad.openScratchpad();
gScratchpadWindow.addEventListener("load", testFalsy, false);
}, true);
content.location = "data:text/html,<p>test falsy display() values in Scratchpad";
}
function testFalsy(sp)
{
gScratchpadWindow.removeEventListener("load", testFalsy, false);
let sp = gScratchpadWindow.Scratchpad;
verifyFalsies(sp);
sp.setBrowserContext();
verifyFalsies(sp);
gScratchpadWindow.close();
gScratchpadWindow = null;
gBrowser.removeCurrentTab();
finish();
}
function verifyFalsies(sp)
{
sp.setText("undefined");
sp.display();
is(sp.selectedText, "/*\nundefined\n*/", "'undefined' is displayed");
sp.setText("false");
sp.display();
is(sp.selectedText, "/*\nfalse\n*/", "'false' is displayed");
sp.setText("0");
sp.display();
is(sp.selectedText, "/*\n0\n*/", "'0' is displayed");
sp.setText("null");
sp.display();
is(sp.selectedText, "/*\nnull\n*/", "'null' is displayed");
sp.setText("NaN");
sp.display();
is(sp.selectedText, "/*\nNaN\n*/", "'NaN' is displayed");
sp.setText("''");
sp.display();
is(sp.selectedText, "/*\n\n*/", "empty string is displayed");
}

View File

@ -88,31 +88,31 @@ function runTests()
ok(sp.getText(), "window.gBrowser",
"setText() worked with no end for the replace range");
is(typeof sp.run()[1].addTab, "function",
is(typeof sp.run()[2].addTab, "function",
"chrome context has access to chrome objects");
// Check that the sandbox is cached.
sp.setText("typeof foobarBug636725cache;");
is(sp.run()[1], "undefined", "global variable does not exist");
is(sp.run()[2], "undefined", "global variable does not exist");
sp.setText("var foobarBug636725cache = 'foo';");
sp.run();
sp.setText("typeof foobarBug636725cache;");
is(sp.run()[1], "string",
is(sp.run()[2], "string",
"global variable exists across two different executions");
sp.resetContext();
is(sp.run()[1], "undefined",
is(sp.run()[2], "undefined",
"global variable no longer exists after calling resetContext()");
sp.setText("var foobarBug636725cache2 = 'foo';");
sp.run();
sp.setText("typeof foobarBug636725cache2;");
is(sp.run()[1], "string",
is(sp.run()[2], "string",
"global variable exists across two different executions");
sp.setContentContext();
@ -120,7 +120,7 @@ function runTests()
is(sp.executionContext, gScratchpadWindow.SCRATCHPAD_CONTEXT_CONTENT,
"executionContext is content");
is(sp.run()[1], "undefined",
is(sp.run()[2], "undefined",
"global variable no longer exists after changing the context");
gScratchpadWindow.close();

View File

@ -32,8 +32,9 @@ function runTests()
let exec = sp.run();
is(exec[0], sp.getText(), "run()[0] is correct");
is(exec[1], content.wrappedJSObject.foobarBug636725,
"run()[1] is correct");
ok(!exec[1], "run()[1] is correct");
is(exec[2], content.wrappedJSObject.foobarBug636725,
"run()[2] is correct");
is(sp.getText(), "++window.foobarBug636725",
"run() does not change the editor content");
@ -77,8 +78,10 @@ function runTests()
is(exec[0], "window.foobarBug636725 = 'a';",
"run()[0] is correct");
is(exec[1], "a",
ok(!exec[1],
"run()[1] is correct");
is(exec[2], "a",
"run()[2] is correct");
is(sp.getText(), "window.foobarBug636725 = 'a';\n" +
"window.foobarBug636725 = 'b';",

View File

@ -97,7 +97,7 @@ function runTests3() {
// Check that the sandbox is not cached.
sp.setText("typeof foosbug653108;");
is(sp.run()[1], "undefined", "global variable does not exist");
is(sp.run()[2], "undefined", "global variable does not exist");
gScratchpadWindow.close();
gScratchpadWindow = null;

View File

@ -76,30 +76,58 @@ StyleInspector.prototype = {
// Were we invoked from the Highlighter?
if (this.IUI) {
this.createPanel(true);
this.openDocked = true;
let isOpen = this.isOpen.bind(this);
this.registrationObject = {
id: "styleinspector",
label: this.l10n("style.highlighter.button.label"),
label: this.l10n("style.highlighter.button.label1"),
tooltiptext: this.l10n("style.highlighter.button.tooltip"),
accesskey: this.l10n("style.highlighter.accesskey"),
accesskey: this.l10n("style.highlighter.accesskey1"),
context: this,
get isOpen() isOpen(),
onSelect: this.selectNode,
show: this.open,
hide: this.close,
dim: this.dimTool,
panel: this.panel,
unregister: this.destroy
panel: null,
unregister: this.destroy,
sidebar: true,
};
// Register the registrationObject with the Highlighter
this.IUI.registerTool(this.registrationObject);
this.createSidebarContent(true);
}
},
/**
* Create the iframe in the IUI sidebar's tab panel.
* @param {Boolean} aPreserveOnHide Prevents destroy from being called.
*/
createSidebarContent: function SI_createSidebarContent(aPreserveOnHide)
{
this.preserveOnHide = !!aPreserveOnHide;
let boundIframeOnLoad = function loadedInitializeIframe() {
if (this.iframe &&
this.iframe.getAttribute("src") ==
"chrome://browser/content/csshtmltree.xhtml") {
let selectedNode = this.selectedNode || null;
this.cssHtmlTree = new CssHtmlTree(this);
this.cssLogic.highlight(selectedNode);
this.cssHtmlTree.highlight(selectedNode);
this.iframe.removeEventListener("load", boundIframeOnLoad, true);
this.iframeReady = true;
Services.obs.notifyObservers(null, "StyleInspector-opened", null);
}
}.bind(this);
this.iframe = this.IUI.getToolIframe(this.registrationObject);
this.iframe.addEventListener("load", boundIframeOnLoad, true);
},
/**
* Factory method to create the actual style panel
* @param {Boolean} aPreserveOnHide Prevents destroy from being called
@ -202,7 +230,9 @@ StyleInspector.prototype = {
*/
isOpen: function SI_isOpen()
{
return this.panel && this.panel.state && this.panel.state == "open";
return this.openDocked ? this.iframeReady && this.IUI.isSidebarOpen &&
(this.IUI.sidebarDeck.selectedPanel == this.iframe) :
this.panel && this.panel.state && this.panel.state == "open";
},
/**
@ -227,12 +257,66 @@ StyleInspector.prototype = {
selectNode: function SI_selectNode(aNode)
{
this.selectedNode = aNode;
if (this.isOpen() && !this.panel.hasAttribute("dimmed")) {
if (this.isOpen() && !this.dimmed) {
this.cssLogic.highlight(aNode);
this.cssHtmlTree.highlight(aNode);
}
},
/**
* Dim or undim a panel by setting or removing a dimmed attribute.
* @param aState
* true = dim, false = undim
*/
dimTool: function SI_dimTool(aState)
{
this.dimmed = aState;
},
/**
* Open the panel.
* @param {DOMNode} aSelection the (optional) DOM node to select.
*/
open: function SI_open(aSelection)
{
this.selectNode(aSelection);
if (this.openDocked) {
if (!this.iframeReady) {
this.iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
}
} else {
this.panel.openPopup(this.window.gBrowser.selectedBrowser, "end_before", 0, 0,
false, false);
}
},
/**
* Close the panel.
*/
close: function SI_close()
{
if (this.openDocked) {
Services.obs.notifyObservers(null, "StyleInspector-closed", null);
} else {
this.panel.hidePopup();
}
},
/**
* Memoized lookup of a l10n string from a string bundle.
* @param {string} aName The key to lookup.
* @returns A localized version of the given key.
*/
l10n: function SI_l10n(aName)
{
try {
return _strings.GetStringFromName(aName);
} catch (ex) {
Services.console.logStringMessage("Error reading '" + aName + "'");
throw new Error("l10n error with " + aName);
}
},
/**
* Destroy the style panel, remove listeners etc.
*/
@ -249,72 +333,23 @@ StyleInspector.prototype = {
delete this.cssLogic;
delete this.cssHtmlTree;
this.panel.removeEventListener("popupshown", this._boundPopupShown, false);
this.panel.removeEventListener("popuphidden", this._boundPopupHidden, false);
delete this._boundPopupShown;
delete this._boundPopupHidden;
this.panel.parentNode.removeChild(this.panel);
delete this.panel;
if (this.panel) {
this.panel.removeEventListener("popupshown", this._boundPopupShown, false);
this.panel.removeEventListener("popuphidden", this._boundPopupHidden, false);
delete this._boundPopupShown;
delete this._boundPopupHidden;
this.panel.parentNode.removeChild(this.panel);
delete this.panel;
}
delete this.doc;
delete this.win;
delete CssHtmlTree.win;
Services.obs.notifyObservers(null, "StyleInspector-closed", null);
},
/**
* Dim or undim a panel by setting or removing a dimmed attribute.
* @param aState
* true = dim, false = undim
*/
dimTool: function SI_dimTool(aState)
{
if (!this.isOpen())
return;
if (aState) {
this.panel.setAttribute("dimmed", "true");
} else if (this.panel.hasAttribute("dimmed")) {
this.panel.removeAttribute("dimmed");
}
},
/**
* Open the panel.
* @param {DOMNode} aSelection the (optional) DOM node to select.
*/
open: function SI_open(aSelection)
{
this.selectNode(aSelection);
this.panel.openPopup(this.window.gBrowser.selectedBrowser, "end_before", 0, 0,
false, false);
},
/**
* Close the panel.
*/
close: function SI_close()
{
this.panel.hidePopup();
},
/**
* Memonized lookup of a l10n string from a string bundle.
* @param {string} aName The key to lookup.
* @returns A localized version of the given key.
*/
l10n: function SI_l10n(aName)
{
try {
return _strings.GetStringFromName(aName);
} catch (ex) {
Services.console.logStringMessage("Error reading '" + aName + "'");
throw new Error("l10n error with " + aName);
}
},
};
XPCOMUtils.defineLazyGetter(this, "_strings", function() Services.strings
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
.createBundle("chrome://browser/locale/devtools/styleinspector.properties"));
XPCOMUtils.defineLazyGetter(this, "CssLogic", function() {
let tmp = {};

View File

@ -6988,7 +6988,7 @@ function GcliTerm(aContentWindow, aHudId, aDocument, aConsole, aHintNode)
chromeDocument: this.document,
contentDocument: aContentWindow.document,
jsEnvironment: {
globalObject: aContentWindow,
globalObject: unwrap(aContentWindow),
evalFunction: this.evalInSandbox.bind(this)
},
inputElement: this.inputNode,

View File

@ -785,7 +785,7 @@ define('gcli/canon', ['require', 'exports', 'module' , 'gcli/util', 'gcli/l10n',
var canon = exports;
var createEvent = require('gcli/util').createEvent;
var util = require('gcli/util');
var l10n = require('gcli/l10n');
var types = require('gcli/types');
@ -1067,7 +1067,7 @@ canon.getCommandNames = function getCommandNames() {
/**
* Enable people to be notified of changes to the list of commands
*/
canon.canonChange = createEvent('canon.canonChange');
canon.canonChange = util.createEvent('canon.canonChange');
/**
* CommandOutputManager stores the output objects generated by executed
@ -1080,7 +1080,7 @@ canon.canonChange = createEvent('canon.canonChange');
* soon.
*/
function CommandOutputManager() {
this._event = createEvent('CommandOutputManager');
this._event = util.createEvent('CommandOutputManager');
}
/**
@ -1142,21 +1142,22 @@ define('gcli/util', ['require', 'exports', 'module' ], function(require, exports
/**
* Create an event.
* For use as follows:
*
* function Hat() {
* this.putOn = createEvent();
* ...
* this.putOn = createEvent();
* ...
* }
* Hat.prototype.adorn = function(person) {
* this.putOn({ hat: hat, person: person });
* ...
* this.putOn({ hat: hat, person: person });
* ...
* }
*
* var hat = new Hat();
* hat.putOn.add(function(ev) {
* console.log('The hat ', ev.hat, ' has is worn by ', ev.person);
* console.log('The hat ', ev.hat, ' has is worn by ', ev.person);
* }, scope);
* @param name Optional name that helps us work out what event this
* is when debugging.
*
* @param name Optional name to help with debugging
*/
exports.createEvent = function(name) {
var handlers = [];
@ -1236,99 +1237,11 @@ dom.createElement = function(doc, tag, ns) {
/**
* Remove all the child nodes from this node
* @param el The element that should have it's children removed
* @param elem The element that should have it's children removed
*/
dom.clearElement = function(el) {
while (el.hasChildNodes()) {
el.removeChild(el.firstChild);
}
};
if (this.document && !this.document.documentElement.classList) {
/**
* Is the given element marked with the given CSS class?
*/
dom.hasCssClass = function(el, name) {
var classes = el.className.split(/\s+/g);
return classes.indexOf(name) !== -1;
};
/**
* Add a CSS class to the list of classes on the given node
*/
dom.addCssClass = function(el, name) {
if (!dom.hasCssClass(el, name)) {
el.className += ' ' + name;
}
};
/**
* Remove a CSS class from the list of classes on the given node
*/
dom.removeCssClass = function(el, name) {
var classes = el.className.split(/\s+/g);
while (true) {
var index = classes.indexOf(name);
if (index == -1) {
break;
}
classes.splice(index, 1);
}
el.className = classes.join(' ');
};
/**
* Add the named CSS class from the element if it is not already present or
* remove it if is present.
*/
dom.toggleCssClass = function(el, name) {
var classes = el.className.split(/\s+/g), add = true;
while (true) {
var index = classes.indexOf(name);
if (index == -1) {
break;
}
add = false;
classes.splice(index, 1);
}
if (add) {
classes.push(name);
}
el.className = classes.join(' ');
return add;
};
} else {
/*
* classList shim versions of methods above.
* See the functions above for documentation
*/
dom.hasCssClass = function(el, name) {
return el.classList.contains(name);
};
dom.addCssClass = function(el, name) {
el.classList.add(name);
};
dom.removeCssClass = function(el, name) {
el.classList.remove(name);
};
dom.toggleCssClass = function(el, name) {
return el.classList.toggle(name);
};
}
/**
* Add or remove a CSS class from the list of classes on the given node
* depending on the value of <tt>include</tt>
*/
dom.setCssClass = function(node, className, include) {
if (include) {
dom.addCssClass(node, className);
} else {
dom.removeCssClass(node, className);
dom.clearElement = function(elem) {
while (elem.hasChildNodes()) {
elem.removeChild(elem.firstChild);
}
};
@ -1350,78 +1263,27 @@ dom.importCss = function(cssText, doc) {
return style;
};
/**
* Shim for window.getComputedStyle
*/
dom.computedStyle = function(element, style) {
var win = element.ownerDocument.defaultView;
if (win.getComputedStyle) {
var styles = win.getComputedStyle(element, '') || {};
return styles[style] || '';
}
else {
return element.currentStyle[style];
}
};
/**
* Using setInnerHtml(foo) rather than innerHTML = foo allows us to enable
* tweaks in XHTML documents.
*/
dom.setInnerHtml = function(el, html) {
if (!this.document || el.namespaceURI === NS_XHTML) {
dom.setInnerHtml = function(elem, html) {
if (!this.document || elem.namespaceURI === NS_XHTML) {
try {
dom.clearElement(el);
var range = el.ownerDocument.createRange();
dom.clearElement(elem);
var range = elem.ownerDocument.createRange();
html = '<div xmlns="' + NS_XHTML + '">' + html + '</div>';
el.appendChild(range.createContextualFragment(html));
elem.appendChild(range.createContextualFragment(html));
}
catch (ex) {
el.innerHTML = html;
elem.innerHTML = html;
}
}
else {
el.innerHTML = html;
elem.innerHTML = html;
}
};
/**
* Shim to textarea.selectionStart
*/
dom.getSelectionStart = function(textarea) {
try {
return textarea.selectionStart || 0;
}
catch (e) {
return 0;
}
};
/**
* Shim to textarea.selectionStart
*/
dom.setSelectionStart = function(textarea, start) {
return textarea.selectionStart = start;
};
/**
* Shim to textarea.selectionEnd
*/
dom.getSelectionEnd = function(textarea) {
try {
return textarea.selectionEnd || 0;
} catch (e) {
return 0;
}
};
/**
* Shim to textarea.selectionEnd
*/
dom.setSelectionEnd = function(textarea, end) {
return textarea.selectionEnd = end;
};
exports.dom = dom;
@ -1432,57 +1294,6 @@ exports.dom = dom;
*/
var event = {};
/**
* Shim for lack of addEventListener on old IE.
*/
event.addListener = function(elem, type, callback) {
if (elem.addEventListener) {
return elem.addEventListener(type, callback, false);
}
if (elem.attachEvent) {
var wrapper = function() {
callback(window.event);
};
callback._wrapper = wrapper;
elem.attachEvent('on' + type, wrapper);
}
};
/**
* Shim for lack of removeEventListener on old IE.
*/
event.removeListener = function(elem, type, callback) {
if (elem.removeEventListener) {
return elem.removeEventListener(type, callback, false);
}
if (elem.detachEvent) {
elem.detachEvent('on' + type, callback._wrapper || callback);
}
};
/**
* Prevents propagation and clobbers the default action of the passed event
*/
event.stopEvent = function(e) {
event.stopPropagation(e);
if (e.preventDefault) {
e.preventDefault();
}
return false;
};
/**
* Prevents propagation of the event
*/
event.stopPropagation = function(e) {
if (e.stopPropagation) {
e.stopPropagation();
}
else {
e.cancelBubble = true;
}
};
/**
* Keyboard handling is a mess. http://unixpapa.com/js/key.html
* It would be good to use DOM L3 Keyboard events,
@ -3146,6 +2957,14 @@ exports.setGlobalObject = function(obj) {
globalObject = obj;
};
/**
* Getter for the object against which JavaScript completions happen, for use
* in testing
*/
exports.getGlobalObject = function() {
return globalObject;
};
/**
* Remove registration of object against which JavaScript completions happen
*/
@ -3172,13 +2991,16 @@ JavascriptType.prototype.stringify = function(value) {
return value;
};
/**
* When sorting out completions, there is no point in displaying millions of
* matches - this the number of matches that we aim for
*/
JavascriptType.MAX_COMPLETION_MATCHES = 10;
JavascriptType.prototype.parse = function(arg) {
var typed = arg.text;
var scope = globalObject;
// In FX-land we need to unwrap. TODO: Enable in the browser.
// scope = unwrap(scope);
// Analyze the input text and find the beginning of the last part that
// should be completed.
var beginning = this._findCompletionBeginning(typed);
@ -3210,18 +3032,24 @@ JavascriptType.prototype.parse = function(arg) {
l10n.lookup('jstypeParseScope'));
}
// TODO: Re-enable this test
// Check if prop is a getter function on obj. Functions can change other
// stuff so we can't execute them to get the next object. Stop here.
// if (isNonNativeGetter(scope, prop)) {
// return new Conversion(typed, arg);
// }
if (prop === '') {
return new Conversion(typed, arg, Status.INCOMPLETE, '');
}
// Check if prop is a getter function on 'scope'. Functions can change
// other stuff so we can't execute them to get the next object. Stop here.
if (this._isSafeProperty(scope, prop)) {
return new Conversion(typed, arg);
}
try {
scope = scope[prop];
}
catch (ex) {
return new Conversion(typed, arg, Status.ERROR, '' + ex);
// It would be nice to be able to report this error in some way but
// as it can happen just when someone types '{sessionStorage.', it
// almost doesn't really count as an error, so we ignore it
return new Conversion(typed, arg, Status.INCOMPLETE, '');
}
}
}
@ -3255,80 +3083,149 @@ JavascriptType.prototype.parse = function(arg) {
var matchLen = matchProp.length;
var prefix = matchLen === 0 ? typed : typed.slice(0, -matchLen);
var status = Status.INCOMPLETE;
var message;
var matches = [];
var message = '';
for (var prop in scope) {
if (prop.indexOf(matchProp) === 0) {
var value;
try {
value = scope[prop];
}
catch (ex) {
break;
}
var description;
var incomplete = true;
if (typeof value === 'function') {
description = '(function)';
}
if (typeof value === 'boolean' || typeof value === 'number') {
description = '= ' + value;
incomplete = false;
}
else if (typeof value === 'string') {
if (value.length > 40) {
value = value.substring(0, 37) + '...';
// We really want an array of matches (for sorting) but it's easier to
// detect existing members if we're using a map initially
var matches = {};
// We only display a maximum of MAX_COMPLETION_MATCHES, so there is no point
// in digging up the prototype chain for matches that we're never going to
// use. Initially look for matches directly on the object itself and then
// look up the chain to find more
var distUpPrototypeChain = 0;
var root = scope;
try {
while (root != null &&
Object.keys(matches).length < JavascriptType.MAX_COMPLETION_MATCHES) {
Object.keys(root).forEach(function(property) {
// Only add matching properties. Also, as we're walking up the
// prototype chain, properties on 'higher' prototypes don't override
// similarly named properties lower down
if (property.indexOf(matchProp) === 0 && !(property in matches)) {
matches[property] = {
prop: property,
distUpPrototypeChain: distUpPrototypeChain
};
}
description = '= \'' + value + '\'';
incomplete = false;
}
else {
description = '(' + typeof value + ')';
}
matches.push({
name: prefix + prop,
value: {
name: prefix + prop,
description: description
},
incomplete: incomplete
});
}
if (prop === matchProp) {
status = Status.VALID;
message = '';
distUpPrototypeChain++;
root = Object.getPrototypeOf(root);
}
}
catch (ex) {
return new Conversion(typed, arg, Status.INCOMPLETE, '');
}
// Error message if this isn't valid
if (status !== Status.VALID) {
// Convert to an array for sorting, and while we're at it, note if we got
// an exact match so we know that this input is valid
matches = Object.keys(matches).map(function(property) {
if (property === matchProp) {
status = Status.VALID;
}
return matches[property];
});
// The sort keys are:
// - Being on the object itself, not in the prototype chain
// - The lack of existence of a vendor prefix
// - The name
matches.sort(function(m1, m2) {
if (m1.distUpPrototypeChain !== m2.distUpPrototypeChain) {
return m1.distUpPrototypeChain - m2.distUpPrototypeChain;
}
// Push all vendor prefixes to the bottom of the list
return isVendorPrefixed(m1.prop) ?
(isVendorPrefixed(m2.prop) ? m1.prop.localeCompare(m2.prop) : 1) :
(isVendorPrefixed(m2.prop) ? -1 : m1.prop.localeCompare(m2.prop));
});
// Trim to size. There is a bug for doing a better job of finding matches
// (bug 682694), but in the mean time there is a performance problem
// associated with creating a large number of DOM nodes that few people will
// ever read, so trim ...
if (matches.length > JavascriptType.MAX_COMPLETION_MATCHES) {
matches = matches.slice(0, JavascriptType.MAX_COMPLETION_MATCHES - 1);
}
// Decorate the matches with:
// - a description
// - a value (for the menu) and,
// - an incomplete flag which reports if we should assume that the user isn't
// going to carry on the JS expression with this input so far
var predictions = matches.map(function(match) {
var description;
var incomplete = true;
if (this._isSafeProperty(scope, match.prop)) {
description = '(property getter)';
}
else {
try {
var value = scope[match.prop];
if (typeof value === 'function') {
description = '(function)';
}
else if (typeof value === 'boolean' || typeof value === 'number') {
description = '= ' + value;
incomplete = false;
}
else if (typeof value === 'string') {
if (value.length > 40) {
value = value.substring(0, 37) + '…';
}
description = '= \'' + value + '\'';
incomplete = false;
}
else {
description = '(' + typeof value + ')';
}
}
catch (ex) {
description = '(' + l10n.lookup('jstypeParseError') + ')';
}
}
return {
name: prefix + match.prop,
value: {
name: prefix + match.prop,
description: description
},
description: description,
incomplete: incomplete
};
}, this);
if (predictions.length === 0) {
status = Status.ERROR;
message = l10n.lookupFormat('jstypeParseMissing', [ matchProp ]);
}
// If the match is the only one possible, and its VALID, predict nothing
if (matches.length === 1 && status === Status.VALID) {
matches = undefined;
}
else {
// Can we think of a better sort order than alpha? There are certainly some
// properties that are far more commonly used ...
matches.sort(function(p1, p2) {
return p1.name.localeCompare(p2.name);
});
if (predictions.length === 1 && status === Status.VALID) {
predictions = undefined;
}
// More than 10 matches are generally not helpful. We should really do a
// better job of finding matches (bug 682694), but in the mean time there is
// a performance problem associated with creating a large number of DOM nodes
// that few people will ever read, so trim the list of matches
if (matches && matches.length > 10) {
matches = matches.slice(0, 9);
}
return new Conversion(typed, arg, status, message, matches);
return new Conversion(typed, arg, status, message, predictions);
};
/**
* Does the given property have a prefix that indicates that it is vendor
* specific?
*/
function isVendorPrefixed(name) {
return name.indexOf('moz') === 0 ||
name.indexOf('webkit') === 0 ||
name.indexOf('ms') === 0;
}
/**
* Constants used in return value of _findCompletionBeginning()
*/
var ParseState = {
NORMAL: 0,
QUOTE: 2,
@ -3436,7 +3333,7 @@ JavascriptType.prototype._findCompletionBeginning = function(text) {
/**
* Return true if the passed object is either an iterator or a generator, and
* false otherwise.
* false otherwise
* @param obj The object to check
*/
JavascriptType.prototype._isIteratorOrGenerator = function(obj) {
@ -3466,6 +3363,52 @@ JavascriptType.prototype._isIteratorOrGenerator = function(obj) {
return false;
};
/**
* Would calling 'scope[prop]' cause the invocation of a non-native (i.e. user
* defined) function property?
* Since calling functions can have side effects, it's only safe to do that if
* explicitly requested, rather than because we're trying things out for the
* purposes of completion.
*/
JavascriptType.prototype._isSafeProperty = function(scope, prop) {
if (typeof scope !== 'object') {
return false;
}
// Walk up the prototype chain of 'scope' looking for a property descriptor
// for 'prop'
var propDesc;
while (scope) {
try {
propDesc = Object.getOwnPropertyDescriptor(scope, prop);
if (propDesc) {
break;
}
}
catch (ex) {
// Native getters throw here. See bug 520882.
if (ex.name === 'NS_ERROR_XPC_BAD_CONVERT_JS' ||
ex.name === 'NS_ERROR_XPC_BAD_OP_ON_WN_PROTO') {
return false;
}
return true;
}
scope = Object.getPrototypeOf(scope);
}
if (!propDesc) {
return false;
}
if (!propDesc.get) {
return false;
}
// The property is safe if 'get' isn't a function or if the function has a
// prototype (in which case it's native)
return typeof propDesc.get !== 'function' || 'prototype' in propDesc.get;
};
JavascriptType.prototype.name = 'javascript';
exports.JavascriptType = JavascriptType;
@ -3542,7 +3485,7 @@ NodeType.prototype.stringify = function(value) {
NodeType.prototype.parse = function(arg) {
if (arg.text === '') {
return new Conversion(null, arg, Status.INCOMPLETE,
l10n.lookup('nodeParseNone'));
l10n.lookup('nodeParseNone'));
}
var nodes;
@ -3550,8 +3493,8 @@ NodeType.prototype.parse = function(arg) {
nodes = doc.querySelectorAll(arg.text);
}
catch (ex) {
console.error(ex);
return new Conversion(null, arg, Status.ERROR, l10n.lookup('nodeParseSyntax'));
return new Conversion(null, arg, Status.ERROR,
l10n.lookup('nodeParseSyntax'));
}
if (nodes.length === 0) {
@ -3616,7 +3559,7 @@ exports.flashNode = function(node, color) {
define('gcli/cli', ['require', 'exports', 'module' , 'gcli/util', 'gcli/canon', 'gcli/promise', 'gcli/types', 'gcli/types/basic', 'gcli/argument'], function(require, exports, module) {
var createEvent = require('gcli/util').createEvent;
var util = require('gcli/util');
var canon = require('gcli/canon');
var Promise = require('gcli/promise').Promise;
@ -3676,7 +3619,7 @@ exports.shutdown = function() {
function Assignment(param, paramIndex) {
this.param = param;
this.paramIndex = paramIndex;
this.assignmentChange = createEvent('Assignment.assignmentChange');
this.assignmentChange = util.createEvent('Assignment.assignmentChange');
this.setDefault();
}
@ -4023,7 +3966,7 @@ function CommandAssignment() {
description: 'The command to execute'
});
this.paramIndex = -1;
this.assignmentChange = createEvent('CommandAssignment.assignmentChange');
this.assignmentChange = util.createEvent('CommandAssignment.assignmentChange');
this.setDefault();
}
@ -4048,7 +3991,7 @@ function UnassignedAssignment() {
type: 'string'
});
this.paramIndex = -1;
this.assignmentChange = createEvent('UnassignedAssignment.assignmentChange');
this.assignmentChange = util.createEvent('UnassignedAssignment.assignmentChange');
this.setDefault();
}
@ -4133,9 +4076,9 @@ function Requisition(environment, document) {
this.commandOutputManager = canon.commandOutputManager;
this.assignmentChange = createEvent('Requisition.assignmentChange');
this.commandChange = createEvent('Requisition.commandChange');
this.inputChange = createEvent('Requisition.inputChange');
this.assignmentChange = util.createEvent('Requisition.assignmentChange');
this.commandChange = util.createEvent('Requisition.commandChange');
this.inputChange = util.createEvent('Requisition.inputChange');
}
/**
@ -5108,9 +5051,8 @@ define('gcli/ui/inputter', ['require', 'exports', 'module' , 'gcli/util', 'gcli/
var cliView = exports;
var event = require('gcli/util').event;
var KeyEvent = require('gcli/util').event.KeyEvent;
var dom = require('gcli/util').dom;
var KeyEvent = event.KeyEvent;
var Status = require('gcli/types').Status;
var History = require('gcli/history').History;
@ -5154,8 +5096,8 @@ function Inputter(options) {
// Ensure that TAB/UP/DOWN isn't handled by the browser
this.onKeyDown = this.onKeyDown.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
event.addListener(this.element, 'keydown', this.onKeyDown);
event.addListener(this.element, 'keyup', this.onKeyUp);
this.element.addEventListener('keydown', this.onKeyDown, false);
this.element.addEventListener('keyup', this.onKeyUp, false);
if (options.completer == null) {
options.completer = new Completer(options);
@ -5174,7 +5116,7 @@ function Inputter(options) {
this.onMouseUp = function(ev) {
this.completer.update(this.getInputState());
}.bind(this);
event.addListener(this.element, 'mouseup', this.onMouseUp);
this.element.addEventListener('mouseup', this.onMouseUp, false);
this.focusManager = options.focusManager;
if (this.focusManager) {
@ -5193,8 +5135,8 @@ Inputter.prototype.destroy = function() {
this.focusManager.removeMonitoredElement(this.element, 'input');
}
event.removeListener(this.element, 'keydown', this.onKeyDown);
event.removeListener(this.element, 'keyup', this.onKeyUp);
this.element.removeEventListener('keydown', this.onKeyDown, false);
this.element.removeEventListener('keyup', this.onKeyUp, false);
delete this.onKeyDown;
delete this.onKeyUp;
@ -5349,8 +5291,8 @@ Inputter.prototype._processCaretChange = function(input, forceUpdate) {
this.completer.update(newInput);
}
dom.setSelectionStart(this.element, newInput.cursor.start);
dom.setSelectionEnd(this.element, newInput.cursor.end);
this.element.selectionStart = newInput.cursor.start;
this.element.selectionEnd = newInput.cursor.end;
this._caretChange = null;
return newInput;
@ -5383,12 +5325,12 @@ Inputter.prototype.focus = function() {
*/
Inputter.prototype.onKeyDown = function(ev) {
if (ev.keyCode === KeyEvent.DOM_VK_UP || ev.keyCode === KeyEvent.DOM_VK_DOWN) {
event.stopEvent(ev);
ev.preventDefault();
}
if (ev.keyCode === KeyEvent.DOM_VK_TAB) {
this.lastTabDownAt = 0;
if (!ev.shiftKey) {
event.stopEvent(ev);
ev.preventDefault();
// Record the timestamp of this TAB down so onKeyUp can distinguish
// focus from TAB in the CLI.
this.lastTabDownAt = ev.timeStamp;
@ -5474,7 +5416,7 @@ Inputter.prototype.onKeyUp = function(ev) {
* i.e Requisition.getAssignmentAt(cursorPos);
*/
Inputter.prototype.getCurrentAssignment = function() {
var start = dom.getSelectionStart(this.element);
var start = this.element.selectionStart;
return this.requisition.getAssignmentAt(start);
};
@ -5494,15 +5436,15 @@ Inputter.prototype.getInputState = function() {
var input = {
typed: this.element.value,
cursor: {
start: dom.getSelectionStart(this.element),
end: dom.getSelectionEnd(this.element)
start: this.element.selectionStart,
end: this.element.selectionEnd
}
};
// Workaround for potential XUL bug 676520 where textbox gives incorrect
// values for its content
if (input.typed == null) {
input.typed = '';
input = { typed: '', cursor: { start: 0, end: 0 } };
console.log('fixing input.typed=""', input);
}
@ -5564,7 +5506,7 @@ Completer.prototype.destroy = function() {
delete this.backgroundElement;
if (this.elementCreated) {
event.removeListener(this.document.defaultView, 'resize', this.resizer);
this.document.defaultView.removeEventListener('resize', this.resizer, false);
}
delete this.inputter;
@ -5590,8 +5532,9 @@ Completer.prototype.decorate = function(inputter) {
if (this.elementCreated) {
this.inputter.appendAfter(this.element);
var styles = this.document.defaultView.getComputedStyle(input, null);
Completer.copyStyles.forEach(function(style) {
this.element.style[style] = dom.computedStyle(input, style);
this.element.style[style] = styles[style];
}, this);
// The completer text is by default invisible so we make it the same color
@ -5611,7 +5554,7 @@ Completer.prototype.decorate = function(inputter) {
input.style.paddingLeft = '20px';
this.resizer = this.resizer.bind(this);
event.addListener(this.document.defaultView, 'resize', this.resizer);
this.document.defaultView.addEventListener('resize', this.resizer, false);
this.resizer();
}
};
@ -6455,9 +6398,7 @@ JavascriptField.prototype.setConversion = function(conversion) {
}, this);
this.menu.show(items);
if (conversion.getStatus() === Status.ERROR) {
this.setMessage(conversion.message);
}
this.setMessage(conversion.message);
};
JavascriptField.prototype.onItemClick = function(ev) {
@ -6840,11 +6781,10 @@ CommandMenu.prototype.onItemClick = function(ev) {
CommandMenu.prototype.onCommandChange = function(ev) {
var command = this.requisition.commandAssignment.getValue();
if (!command || !command.exec) {
var error;
var error = this.requisition.commandAssignment.getMessage();
var predictions = this.requisition.commandAssignment.getPredictions();
if (predictions.length === 0) {
error = this.requisition.commandAssignment.getMessage();
var commandType = this.requisition.commandAssignment.param.type;
var conversion = commandType.parse(new Argument());
predictions = conversion.getPredictions();

View File

@ -54,18 +54,22 @@ var Node = Components.interfaces.nsIDOMNode;
* http://opensource.org/licenses/BSD-3-Clause
*/
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testHistory', 'gclitest/testRequire'], function(require, exports, module) {
define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testTokenize', 'gclitest/testSplit', 'gclitest/testCli', 'gclitest/testHistory', 'gclitest/testRequire', 'gclitest/testJs'], function(require, exports, module) {
// We need to make sure GCLI is initialized before we begin testing it
require('gcli/index');
var examiner = require('test/examiner');
// It's tempting to want to unify these strings and make addSuite() do the
// call to require(), however that breaks the build system which looks for
// the strings passed to require
examiner.addSuite('gclitest/testTokenize', require('gclitest/testTokenize'));
examiner.addSuite('gclitest/testSplit', require('gclitest/testSplit'));
examiner.addSuite('gclitest/testCli', require('gclitest/testCli'));
examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory'));
examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire'));
examiner.addSuite('gclitest/testJs', require('gclitest/testJs'));
examiner.run();
@ -295,7 +299,9 @@ Test.prototype.run = function() {
this.status = stati.fail;
this.messages.push('' + ex);
console.error(ex);
console.trace();
if (console.trace) {
console.trace();
}
}
if (this.status === stati.executing) {
@ -930,19 +936,19 @@ function verifyPredictionsContains(name, predictions) {
exports.testBlank = function() {
update({ typed: '', cursor: { start: 0, end: 0 } });
test.is( '', statuses);
test.is( '', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.is(null, requ.commandAssignment.getValue());
update({ typed: ' ', cursor: { start: 1, end: 1 } });
test.is( 'V', statuses);
test.is( 'V', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.is(null, requ.commandAssignment.getValue());
update({ typed: ' ', cursor: { start: 0, end: 0 } });
test.is( 'V', statuses);
test.is( 'V', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.is(null, requ.commandAssignment.getValue());
@ -950,7 +956,7 @@ exports.testBlank = function() {
exports.testIncompleteMultiMatch = function() {
update({ typed: 't', cursor: { start: 1, end: 1 } });
test.is( 'I', statuses);
test.is( 'I', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.ok(assignC.getPredictions().length > 0);
@ -962,7 +968,7 @@ exports.testIncompleteMultiMatch = function() {
exports.testIncompleteSingleMatch = function() {
update({ typed: 'tselar', cursor: { start: 6, end: 6 } });
test.is( 'IIIIII', statuses);
test.is( 'IIIIII', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.is(1, assignC.getPredictions().length);
@ -972,25 +978,25 @@ exports.testIncompleteSingleMatch = function() {
exports.testTsv = function() {
update({ typed: 'tsv', cursor: { start: 3, end: 3 } });
test.is( 'VVV', statuses);
test.is( 'VVV', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.is('tsv', requ.commandAssignment.getValue().name);
update({ typed: 'tsv ', cursor: { start: 4, end: 4 } });
test.is( 'VVVV', statuses);
test.is( 'VVVV', statuses);
test.is(Status.ERROR, status);
test.is(0, assignC.paramIndex);
test.is('tsv', requ.commandAssignment.getValue().name);
update({ typed: 'tsv ', cursor: { start: 2, end: 2 } });
test.is( 'VVVV', statuses);
test.is( 'VVVV', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.is('tsv', requ.commandAssignment.getValue().name);
update({ typed: 'tsv o', cursor: { start: 5, end: 5 } });
test.is( 'VVVVI', statuses);
test.is( 'VVVVI', statuses);
test.is(Status.ERROR, status);
test.is(0, assignC.paramIndex);
test.is(2, assignC.getPredictions().length);
@ -1001,7 +1007,7 @@ exports.testTsv = function() {
test.is(null, assign1.getValue());
update({ typed: 'tsv option', cursor: { start: 10, end: 10 } });
test.is( 'VVVVIIIIII', statuses);
test.is( 'VVVVIIIIII', statuses);
test.is(Status.ERROR, status);
test.is(0, assignC.paramIndex);
test.is(2, assignC.getPredictions().length);
@ -1012,7 +1018,7 @@ exports.testTsv = function() {
test.is(null, assign1.getValue());
update({ typed: 'tsv option', cursor: { start: 1, end: 1 } });
test.is( 'VVVVEEEEEE', statuses);
test.is( 'VVVVEEEEEE', statuses);
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.is('tsv', requ.commandAssignment.getValue().name);
@ -1020,7 +1026,7 @@ exports.testTsv = function() {
test.is(null, assign1.getValue());
update({ typed: 'tsv option ', cursor: { start: 11, end: 11 } });
test.is( 'VVVVEEEEEEV', statuses);
test.is( 'VVVVEEEEEEV', statuses);
test.is(Status.ERROR, status);
test.is(1, assignC.paramIndex);
test.is(0, assignC.getPredictions().length);
@ -1029,7 +1035,7 @@ exports.testTsv = function() {
test.is(null, assign1.getValue());
update({ typed: 'tsv option1', cursor: { start: 11, end: 11 } });
test.is( 'VVVVVVVVVVV', statuses);
test.is( 'VVVVVVVVVVV', statuses);
test.is(Status.ERROR, status);
test.is('tsv', requ.commandAssignment.getValue().name);
test.is('option1', assign1.getArg().text);
@ -1037,7 +1043,7 @@ exports.testTsv = function() {
test.is(0, assignC.paramIndex);
update({ typed: 'tsv option1 ', cursor: { start: 12, end: 12 } });
test.is( 'VVVVVVVVVVVV', statuses);
test.is( 'VVVVVVVVVVVV', statuses);
test.is(Status.ERROR, status);
test.is('tsv', requ.commandAssignment.getValue().name);
test.is('option1', assign1.getArg().text);
@ -1045,7 +1051,7 @@ exports.testTsv = function() {
test.is(1, assignC.paramIndex);
update({ typed: 'tsv option1 6', cursor: { start: 13, end: 13 } });
test.is( 'VVVVVVVVVVVVV', statuses);
test.is( 'VVVVVVVVVVVVV', statuses);
test.is(Status.VALID, status);
test.is('tsv', requ.commandAssignment.getValue().name);
test.is('option1', assign1.getArg().text);
@ -1056,7 +1062,7 @@ exports.testTsv = function() {
test.is(1, assignC.paramIndex);
update({ typed: 'tsv option2 6', cursor: { start: 13, end: 13 } });
test.is( 'VVVVVVVVVVVVE', statuses);
test.is( 'VVVVVVVVVVVVE', statuses);
test.is(Status.ERROR, status);
test.is('tsv', requ.commandAssignment.getValue().name);
test.is('option2', assign1.getArg().text);
@ -1068,26 +1074,26 @@ exports.testTsv = function() {
exports.testInvalid = function() {
update({ typed: 'fred', cursor: { start: 4, end: 4 } });
test.is( 'EEEE', statuses);
test.is( 'EEEE', statuses);
test.is('fred', requ.commandAssignment.getArg().text);
test.is('', requ._unassigned.getArg().text);
test.is(-1, assignC.paramIndex);
update({ typed: 'fred ', cursor: { start: 5, end: 5 } });
test.is( 'EEEEV', statuses);
test.is( 'EEEEV', statuses);
test.is('fred', requ.commandAssignment.getArg().text);
test.is('', requ._unassigned.getArg().text);
test.is(-1, assignC.paramIndex);
update({ typed: 'fred one', cursor: { start: 8, end: 8 } });
test.is( 'EEEEVEEE', statuses);
test.is( 'EEEEVEEE', statuses);
test.is('fred', requ.commandAssignment.getArg().text);
test.is('one', requ._unassigned.getArg().text);
};
exports.testSingleString = function() {
update({ typed: 'tsr', cursor: { start: 3, end: 3 } });
test.is( 'VVV', statuses);
test.is( 'VVV', statuses);
test.is(Status.ERROR, status);
test.is('tsr', requ.commandAssignment.getValue().name);
//test.is(undefined, assign1.getArg());
@ -1095,7 +1101,7 @@ exports.testSingleString = function() {
test.is(undefined, assign2);
update({ typed: 'tsr ', cursor: { start: 4, end: 4 } });
test.is( 'VVVV', statuses);
test.is( 'VVVV', statuses);
test.is(Status.ERROR, status);
test.is('tsr', requ.commandAssignment.getValue().name);
//test.is(undefined, assign1.getArg());
@ -1103,21 +1109,21 @@ exports.testSingleString = function() {
test.is(undefined, assign2);
update({ typed: 'tsr h', cursor: { start: 5, end: 5 } });
test.is( 'VVVVV', statuses);
test.is( 'VVVVV', statuses);
test.is(Status.VALID, status);
test.is('tsr', requ.commandAssignment.getValue().name);
test.is('h', assign1.getArg().text);
test.is('h', assign1.getValue());
update({ typed: 'tsr "h h"', cursor: { start: 9, end: 9 } });
test.is( 'VVVVVVVVV', statuses);
test.is( 'VVVVVVVVV', statuses);
test.is(Status.VALID, status);
test.is('tsr', requ.commandAssignment.getValue().name);
test.is('h h', assign1.getArg().text);
test.is('h h', assign1.getValue());
update({ typed: 'tsr h h h', cursor: { start: 9, end: 9 } });
test.is( 'VVVVVVVVV', statuses);
test.is( 'VVVVVVVVV', statuses);
test.is('tsr', requ.commandAssignment.getValue().name);
test.is('h h h', assign1.getArg().text);
test.is('h h h', assign1.getValue());
@ -1127,21 +1133,21 @@ exports.testSingleString = function() {
exports.testSingleNumber = function() {
update({ typed: 'tsu', cursor: { start: 3, end: 3 } });
test.is( 'VVV', statuses);
test.is( 'VVV', statuses);
test.is(Status.ERROR, status);
test.is('tsu', requ.commandAssignment.getValue().name);
//test.is(undefined, assign1.getArg());
test.is(null, assign1.getValue());
update({ typed: 'tsu ', cursor: { start: 4, end: 4 } });
test.is( 'VVVV', statuses);
test.is( 'VVVV', statuses);
test.is(Status.ERROR, status);
test.is('tsu', requ.commandAssignment.getValue().name);
//test.is(undefined, assign1.getArg());
test.is(null, assign1.getValue());
update({ typed: 'tsu 1', cursor: { start: 5, end: 5 } });
test.is( 'VVVVV', statuses);
test.is( 'VVVVV', statuses);
test.is(Status.VALID, status);
test.is('tsu', requ.commandAssignment.getValue().name);
test.is('1', assign1.getArg().text);
@ -1149,7 +1155,7 @@ exports.testSingleNumber = function() {
test.is('number', typeof assign1.getValue());
update({ typed: 'tsu x', cursor: { start: 5, end: 5 } });
test.is( 'VVVVE', statuses);
test.is( 'VVVVE', statuses);
test.is(Status.ERROR, status);
test.is('tsu', requ.commandAssignment.getValue().name);
test.is('x', assign1.getArg().text);
@ -1158,46 +1164,46 @@ exports.testSingleNumber = function() {
exports.testNestedCommand = function() {
update({ typed: 'tsn', cursor: { start: 3, end: 3 } });
test.is( 'III', statuses);
test.is( 'III', statuses);
test.is(Status.ERROR, status);
test.is('tsn', requ.commandAssignment.getValue().name);
test.is(undefined, assign1);
update({ typed: 'tsn ', cursor: { start: 4, end: 4 } });
test.is( 'IIIV', statuses);
test.is( 'IIIV', statuses);
test.is(Status.ERROR, status);
test.is('tsn', requ.commandAssignment.getValue().name);
test.is(undefined, assign1);
update({ typed: 'tsn x', cursor: { start: 5, end: 5 } });
test.is( 'EEEVE', statuses);
test.is( 'EEEVE', statuses);
test.is(Status.ERROR, status);
test.is('tsn x', requ.commandAssignment.getArg().text);
test.is(undefined, assign1);
update({ typed: 'tsn dif', cursor: { start: 7, end: 7 } });
test.is( 'VVVVVVV', statuses);
test.is( 'VVVVVVV', statuses);
test.is(Status.ERROR, status);
test.is('tsn dif', requ.commandAssignment.getValue().name);
//test.is(undefined, assign1.getArg());
//test.is(undefined, assign1.getValue());
update({ typed: 'tsn dif ', cursor: { start: 8, end: 8 } });
test.is( 'VVVVVVVV', statuses);
test.is( 'VVVVVVVV', statuses);
test.is(Status.ERROR, status);
test.is('tsn dif', requ.commandAssignment.getValue().name);
//test.is(undefined, assign1.getArg());
//test.is(undefined, assign1.getValue());
update({ typed: 'tsn dif x', cursor: { start: 9, end: 9 } });
test.is( 'VVVVVVVVV', statuses);
test.is( 'VVVVVVVVV', statuses);
test.is(Status.VALID, status);
test.is('tsn dif', requ.commandAssignment.getValue().name);
test.is('x', assign1.getArg().text);
test.is('x', assign1.getValue());
update({ typed: 'tsn ext', cursor: { start: 7, end: 7 } });
test.is( 'VVVVVVV', statuses);
test.is( 'VVVVVVV', statuses);
test.is(Status.ERROR, status);
test.is('tsn ext', requ.commandAssignment.getValue().name);
//test.is(undefined, assign1.getArg());
@ -1369,6 +1375,165 @@ define('gclitest/requirable', ['require', 'exports', 'module' ], function(requir
exports.setStatus = function(aStatus) { status = aStatus; };
exports.getStatus = function() { return status; };
});
/*
* Copyright 2009-2011 Mozilla Foundation and contributors
* Licensed under the New BSD license. See LICENSE.txt or:
* http://opensource.org/licenses/BSD-3-Clause
*/
define('gclitest/testJs', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/types', 'gcli/types/javascript', 'test/assert'], function(require, exports, module) {
var Requisition = require('gcli/cli').Requisition;
var Status = require('gcli/types').Status;
var javascript = require('gcli/types/javascript');
var test = require('test/assert');
var debug = false;
var requ;
var assign;
var status;
var statuses;
var globalObject;
exports.setup = function() {
globalObject = javascript.getGlobalObject();
Object.defineProperty(globalObject, 'donteval', {
get: function() {
test.ok(false, 'donteval should not be used');
return { cant: '', touch: '', 'this': '' };
},
enumerable: true,
configurable : true
});
};
exports.shutdown = function() {
delete globalObject.donteval;
globalObject = undefined;
};
function input(typed) {
if (!requ) {
requ = new Requisition();
}
var cursor = { start: typed.length, end: typed.length };
var input = { typed: typed, cursor: cursor };
requ.update(input);
if (debug) {
console.log('####### TEST: typed="' + typed +
'" cur=' + cursor.start +
' cli=', requ);
}
status = requ.getStatus();
statuses = requ.getInputStatusMarkup().map(function(s) {
return s.toString()[0];
}).join('');
if (requ.commandAssignment.getValue()) {
assign = requ.getAssignment(0);
}
else {
assign = undefined;
}
}
function predictionsHas(name) {
return assign.getPredictions().some(function(prediction) {
return name === prediction.name;
}, this);
}
function check(expStatuses, expStatus, expAssign, expPredict) {
test.is('{', requ.commandAssignment.getValue().name, 'is exec');
test.is(expStatuses, statuses, 'unexpected status markup');
test.is(expStatus.toString(), status.toString(), 'unexpected status');
test.is(expAssign, assign.getValue(), 'unexpected assignment');
if (expPredict != null) {
var contains;
if (Array.isArray(expPredict)) {
expPredict.forEach(function(p) {
contains = predictionsHas(p);
test.ok(contains, 'missing prediction ' + p);
});
}
else if (typeof expPredict === 'number') {
contains = true;
test.is(assign.getPredictions().length, expPredict, 'prediction count');
}
else {
contains = predictionsHas(expPredict);
test.ok(contains, 'missing prediction ' + expPredict);
}
if (!contains) {
console.log('Predictions: ' + assign.getPredictions().map(function(p) {
return p.name;
}).join(', '));
}
}
}
exports.testBasic = function() {
input('{');
check('V', Status.ERROR, '');
input('{ ');
check('VV', Status.ERROR, '');
input('{ w');
check('VVI', Status.ERROR, 'w', 'window');
input('{ windo');
check('VVIIIII', Status.ERROR, 'windo', 'window');
input('{ window');
check('VVVVVVVV', Status.VALID, 'window', 0);
input('{ window.d');
check('VVIIIIIIII', Status.ERROR, 'window.d', 'window.document');
input('{ window.document.title');
check('VVVVVVVVVVVVVVVVVVVVVVV', Status.VALID, 'window.document.title', 0);
input('{ d');
check('VVI', Status.ERROR, 'd', 'document');
input('{ document.title');
check('VVVVVVVVVVVVVVVV', Status.VALID, 'document.title', 0);
test.ok('donteval' in globalObject, 'donteval exists');
input('{ don');
check('VVIII', Status.ERROR, 'don', 'donteval');
input('{ donteval');
check('VVVVVVVVVV', Status.VALID, 'donteval', 0);
/*
// This is a controversial test - technically we can tell that it's an error
// because 'donteval.' is a syntax error, however donteval is unsafe so we
// are playing safe by bailing out early. It's enough of a corner case that
// I don't think it warrants fixing
input('{ donteval.');
check('VVIIIIIIIII', Status.ERROR, 'donteval.', 0);
*/
input('{ donteval.cant');
check('VVVVVVVVVVVVVVV', Status.VALID, 'donteval.cant', 0);
input('{ donteval.xxx');
check('VVVVVVVVVVVVVV', Status.VALID, 'donteval.xxx', 0);
};
});
function undefine() {
@ -1382,6 +1547,7 @@ function undefine() {
delete define.modules['gclitest/testHistory'];
delete define.modules['gclitest/testRequire'];
delete define.modules['gclitest/requirable'];
delete define.modules['gclitest/testJs'];
delete define.globalDomain.modules['gclitest/suite'];
delete define.globalDomain.modules['test/examiner'];
@ -1393,6 +1559,7 @@ function undefine() {
delete define.globalDomain.modules['gclitest/testHistory'];
delete define.globalDomain.modules['gclitest/testRequire'];
delete define.globalDomain.modules['gclitest/requirable'];
delete define.globalDomain.modules['gclitest/testJs'];
}
registerCleanupFunction(function() {

View File

@ -217,6 +217,8 @@ can reach it easily. -->
<!ENTITY inspectButton.label "Inspect">
<!ENTITY inspectButton.accesskey "I">
<!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
<!ENTITY inspectStyleButton.label "Style">
<!ENTITY inspectStyleButton.accesskey "S">
<!ENTITY getMoreDevtoolsCmd.label "Get More Tools">
<!ENTITY getMoreDevtoolsCmd.accesskey "M">

View File

@ -55,6 +55,10 @@ jstypeBeginSyntax=Syntax error
# error message is displayed.
jstypeBeginUnterm=Unterminated string literal
# LOCALIZATION NOTE (jstypeParseError): If the system for providing JavaScript
# completions encounters and error it displays this.
jstypeParseError=Error
# LOCALIZATION NOTE (typesNumberNan): When the command line is passed a
# number, however the input string is not a valid number, this error message
# is displayed.

View File

@ -30,7 +30,7 @@ group.Lists=Lists
group.Effects_and_Other=Effects and Other
# LOCALIZATION NOTE (style.highlighter.button): These strings are used inside
# html tree of the highlighter for the style inspector button
style.highlighter.button.label=Style
style.highlighter.accesskey=S
# sidebar of the Highlighter for the style inspector button
style.highlighter.button.label1=Properties
style.highlighter.accesskey1=P
style.highlighter.button.tooltip=Inspect element styles

View File

@ -29,6 +29,7 @@
* Dão Gottwald (dao@mozilla.com)
* Drew Willcoxon (adw@mozilla.com)
* Paul Rouget (paul@mozilla.com)
* Rob Campbell (rcampbell@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
@ -1989,8 +1990,27 @@ panel[dimmed="true"] {
-moz-padding-end: 0;
}
#devtools-sidebar-toolbar {
-moz-appearance: none;
padding: 4px 3px;
box-shadow: 0 1px 0 0 hsla(210, 16%, 76%, .2) inset;
background-image: -moz-linear-gradient(top, hsl(210,11%,36%), hsl(210,11%,18%));
}
#devtools-side-splitter {
-moz-appearance: none;
border: 0;
-moz-border-start: 1px solid #242b33;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-end: -3px;
position: relative;
}
#inspector-inspect-toolbutton,
#inspector-tools > toolbarbutton {
#inspector-tools > toolbarbutton,
#devtools-sidebar-toolbar > toolbarbutton {
-moz-appearance: none;
min-width: 78px;
min-height: 22px;
@ -2003,14 +2023,16 @@ panel[dimmed="true"] {
}
#inspector-inspect-toolbutton:not([checked]):hover:active,
#inspector-tools > toolbarbutton:not([checked]):hover:active {
#inspector-tools > toolbarbutton:not([checked]):hover:active,
#devtools-sidebar-toolbar > toolbarbutton:not([checked]):hover:active {
border-color: hsla(210,8%,5%,.6);
background: -moz-linear-gradient(hsla(220,6%,10%,.3), hsla(212,7%,57%,.15) 65%, hsla(212,7%,57%,.3));
box-shadow: 0 0 3px hsla(210,8%,5%,.25) inset, 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 0 hsla(210,16%,76%,.15);
}
#inspector-inspect-toolbutton[checked],
#inspector-tools > toolbarbutton[checked] {
#inspector-tools > toolbarbutton[checked],
#devtools-sidebar-toolbar > toolbarbutton[checked] {
color: hsl(208,100%,60%) !important;
border-color: hsla(210,8%,5%,.6) !important;
background: -moz-linear-gradient(hsla(220,6%,10%,.6), hsla(210,11%,18%,.45) 75%, hsla(210,11%,30%,.4));
@ -2018,12 +2040,14 @@ panel[dimmed="true"] {
}
#inspector-inspect-toolbutton[checked]:hover,
#inspector-tools > toolbarbutton[checked]:hover {
#inspector-tools > toolbarbutton[checked]:hover,
#devtools-sidebar-toolbar > toolbarbutton[checked]:hover {
background-color: transparent !important;
}
#inspector-inspect-toolbutton[checked]:hover:active,
#inspector-tools > toolbarbutton[checked]:hover:active {
#inspector-tools > toolbarbutton[checked]:hover:active,
#devtools-sidebar-toolbar > toolbarbutton[checked]:hover:active {
background-color: hsla(210,8%,5%,.2) !important;
}

View File

@ -28,6 +28,7 @@
* Stephen Horlander (stephen@noved.org)
* Drew Willcoxon (adw@mozilla.com)
* Paul Rouget (paul@mozilla.com)
* Rob Campbell (rcampbell@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
@ -2567,8 +2568,27 @@ panel[dimmed="true"] {
padding: 0 0 4px;
}
#devtools-sidebar-toolbar {
-moz-appearance: none;
padding: 4px 3px;
box-shadow: 0 1px 0 0 hsla(210, 16%, 76%, .2) inset;
background-image: -moz-linear-gradient(top, hsl(210,11%,36%), hsl(210,11%,18%));
}
#devtools-side-splitter {
background-image: none !important;
border: 0;
-moz-border-start: 1px solid #242b33;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-end: -3px;
position: relative;
}
#inspector-inspect-toolbutton,
#inspector-tools > toolbarbutton {
#inspector-tools > toolbarbutton,
#devtools-sidebar-toolbar > toolbarbutton {
-moz-appearance: none;
min-width: 78px;
min-height: 22px;
@ -2581,19 +2601,22 @@ panel[dimmed="true"] {
}
#inspector-inspect-toolbutton > .toolbarbutton-text ,
#inspector-tools > toolbarbutton > .toolbarbutton-text {
#inspector-tools > toolbarbutton > .toolbarbutton-text,
#devtools-sidebar-toolbar > toolbarbutton > .toolbarbutton-text {
margin: 1px 6px;
}
#inspector-inspect-toolbutton:not([checked]):hover:active,
#inspector-tools > toolbarbutton:not([checked]):hover:active {
#inspector-tools > toolbarbutton:not([checked]):hover:active,
#devtools-sidebar-toolbar > toolbarbutton:not([checked]):hover:active {
border-color: hsla(210,8%,5%,.6);
background: -moz-linear-gradient(hsla(220,6%,10%,.3), hsla(212,7%,57%,.15) 65%, hsla(212,7%,57%,.3));
box-shadow: 0 0 3px hsla(210,8%,5%,.25) inset, 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 0 hsla(210,16%,76%,.15);
}
#inspector-inspect-toolbutton[checked],
#inspector-tools > toolbarbutton[checked] {
#inspector-tools > toolbarbutton[checked],
#devtools-sidebar-toolbar > toolbarbutton[checked] {
color: hsl(208,100%,60%) !important;
border-color: hsla(210,8%,5%,.6);
background: -moz-linear-gradient(hsla(220,6%,10%,.6), hsla(210,11%,18%,.45) 75%, hsla(210,11%,30%,.4));
@ -2601,7 +2624,8 @@ panel[dimmed="true"] {
}
#inspector-inspect-toolbutton[checked]:hover:active,
#inspector-tools > toolbarbutton[checked]:hover:active {
#inspector-tools > toolbarbutton[checked]:hover:active,
#devtools-sidebar-toolbar > toolbarbutton[checked]:hover:active {
background-color: hsla(210,8%,5%,.2);
}

View File

@ -29,6 +29,7 @@
* Jim Mathies (jmathies@mozilla.com)
* Drew Willcoxon (adw@mozilla.com)
* Paul Rouget (paul@mozilla.com)
* Rob Campbell (rcampbell@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
@ -2661,8 +2662,26 @@ panel[dimmed="true"] {
-moz-padding-end: 0;
}
#devtools-sidebar-toolbar {
-moz-appearance: none;
padding: 4px 3px;
box-shadow: 0 1px 0 hsla(209,29%,72%,.25) inset;
background-image: -moz-linear-gradient(top, hsl(209,18%,34%), hsl(210,24%,16%));
}
#devtools-side-splitter {
border: 0;
-moz-border-start: 1px solid #242b33;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-end: -3px;
position: relative;
}
#inspector-inspect-toolbutton,
#inspector-tools > toolbarbutton {
#inspector-tools > toolbarbutton,
#devtools-sidebar-toolbar > toolbarbutton {
-moz-appearance: none;
min-width: 78px;
min-height: 22px;
@ -2675,19 +2694,22 @@ panel[dimmed="true"] {
}
#inspector-inspect-toolbutton > .toolbarbutton-icon,
#inspector-tools > toolbarbutton > .toolbarbutton-icon {
#inspector-tools > toolbarbutton > .toolbarbutton-icon,
#devtools-sidebar-toolbar > toolbarbutton > .toolbarbutton-icon {
margin: 0;
}
#inspector-inspect-toolbutton:not([checked]):hover:active,
#inspector-tools > toolbarbutton:not([checked]):hover:active {
#inspector-tools > toolbarbutton:not([checked]):hover:active,
#devtools-sidebar-toolbar > toolbarbutton:not([checked]):hover:active {
background-color: hsla(210,18%,9%,.1);
background-image: -moz-linear-gradient(hsla(209,13%,54%,.35), hsla(209,13%,54%,.1) 85%, hsla(209,13%,54%,.2));
box-shadow: 0 1px 3px hsla(211,68%,6%,.5) inset, 0 0 0 1px hsla(209,29%,72%,.1), 0 1px 0 hsla(210,16%,76%,.1);
}
#inspector-inspect-toolbutton[checked],
#inspector-tools > toolbarbutton[checked] {
#inspector-tools > toolbarbutton[checked],
#devtools-sidebar-toolbar > toolbarbutton[checked] {
border-color: hsla(211,68%,6%,.6);
background: -moz-linear-gradient(hsla(211,68%,6%,.1), hsla(211,68%,6%,.2));
box-shadow: 0 1px 3px hsla(211,68%,6%,.5) inset, 0 0 0 1px hsla(209,29%,72%,.1), 0 1px 0 hsla(210,16%,76%,.1);
@ -2695,7 +2717,8 @@ panel[dimmed="true"] {
}
#inspector-inspect-toolbutton[checked]:hover:active,
#inspector-tools > toolbarbutton[checked]:hover:active {
#inspector-tools > toolbarbutton[checked]:hover:active,
#devtools-sidebar-toolbar > toolbarbutton[checked]:hover:active {
background-color: hsla(211,68%,6%,.2);
}