зеркало из https://github.com/mozilla/pjs.git
Merge mozilla-central and mozilla-inbound
This commit is contained in:
Коммит
43b5aad4fe
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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) { }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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';",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче