Merge mozilla-central to mozilla-inbound

This commit is contained in:
Graeme McCutcheon 2012-09-19 15:20:22 +01:00
commit a0fb07fcc1
9 changed files with 503 additions and 44 deletions

View File

@ -105,6 +105,7 @@ MOCHITEST_BROWSER_FILES = \
browser_webconsole_bug_664131_console_group.js \
browser_webconsole_bug_704295.js \
browser_webconsole_bug_658368_time_methods.js \
browser_webconsole_bug_764572_output_open_url.js \
browser_webconsole_bug_622303_persistent_filters.js \
browser_webconsole_window_zombie.js \
browser_cached_messages.js \

View File

@ -0,0 +1,226 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// This is a test for the Open URL context menu item
// that is shown for network requests
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html"
const COMMAND_NAME = "consoleCmd_openURL";
const CONTEXT_MENU_ID = "#menu_openURL";
let HUD = null, outputNode = null, contextMenu = null;
function test() {
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, consoleOpened);
}, true);
}
function consoleOpened(aHud) {
HUD = aHud;
outputNode = aHud.outputNode;
contextMenu = HUD.iframeWindow.document.getElementById("output-contextmenu");
executeSoon(testOnNotNetActivity);
}
function testOnNotNetActivity() {
HUD.jsterm.clearOutput();
outputNode = HUD.outputNode;
let console = content.wrappedJSObject.console;
console.log("bug 764572");
testOnNotNetActivity_command();
}
function testOnNotNetActivity_command () {
waitForSuccess({
name: "show no net activity in console",
validatorFn: function () {
return outputNode.textContent.indexOf("bug 764572") > -1;
},
successFn: function () {
outputNode.focus();
outputNode.selectedItem = outputNode.querySelector(".webconsole-msg-log");
// check whether the command is disable
goUpdateCommand(COMMAND_NAME);
let controller = top.document.commandDispatcher.
getControllerForCommand(COMMAND_NAME);
let isDisabled = !controller || !controller.isCommandEnabled("consoleCmd_openURL");
ok(isDisabled, COMMAND_NAME + " should be disabled.");
executeSoon(testOnNotNetActivity_contextmenu);
},
failureFn: testOnNotNetActivity_contextmenu,
});
}
function testOnNotNetActivity_contextmenu() {
let target = outputNode.querySelector(".webconsole-msg-log");
outputNode.focus();
outputNode.selectedItem = target;
waitForOpenContextMenu(contextMenu, {
target: target,
successFn: function () {
let isHidden = contextMenu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isHidden, CONTEXT_MENU_ID + "should be hidden.");
closeContextMenu(contextMenu);
executeSoon(testOnNetActivity);
},
failureFn: function(){
closeContextMenu(contextMenu);
executeSoon(testOnNetActivity);
},
});
}
function testOnNetActivity() {
HUD.jsterm.clearOutput();
// reload the url to show net activity in console.
content.location.reload();
testOnNetActivity_command();
}
function testOnNetActivity_command() {
waitForSuccess({
name: "show TEST_URI's net activity in console",
validatorFn: function () {
outputNode.focus();
outputNode.selectedItem = outputNode.querySelector(".webconsole-msg-network");
let item = outputNode.selectedItem;
return item && item.url;
},
successFn: function () {
outputNode.focus();
// set up the event handler for TabOpen
gBrowser.tabContainer.addEventListener("TabOpen", function onOpen(aEvent) {
gBrowser.tabContainer.removeEventListener("TabOpen", onOpen, true);
let tab = aEvent.target;
onTabOpen(tab);
}, true);
// check whether the command is enable
goUpdateCommand(COMMAND_NAME);
let controller = top.document.commandDispatcher.
getControllerForCommand(COMMAND_NAME);
ok(controller.isCommandEnabled("consoleCmd_openURL"), COMMAND_NAME + " should be enabled.");
// try to open url.
goDoCommand(COMMAND_NAME);
},
failureFn: testOnNetActivity_contextmenu,
});
}
// check TabOpen event
function onTabOpen(aTab) {
waitForSuccess({
name: "complete to initialize the opening tab",
validatorFn: function()
{
// wait to complete initializing the opend tab.
let url = aTab.linkedBrowser.currentURI.spec;
return url === TEST_URI;
},
successFn: function()
{
gBrowser.removeTab(aTab);
executeSoon(testOnNetActivity_contextmenu);
},
failureFn: testOnNetActivity_contextmenu,
});
}
function testOnNetActivity_contextmenu() {
let target = outputNode.querySelector(".webconsole-msg-network");
outputNode.focus();
outputNode.selectedItem = target;
waitForOpenContextMenu(contextMenu, {
target: target,
successFn: function () {
let isShown = !contextMenu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isShown, CONTEXT_MENU_ID + "should be shown.");
closeContextMenu(contextMenu);
executeSoon(finalizeTest);
},
failureFn: function(){
closeContextMenu(contextMenu);
executeSoon(finalizeTest);
},
});
}
function finalizeTest() {
HUD = null;
outputNode = null;
contextMenu = null
finishTest();
}
/**
* Polls a given function waiting for opening context menu.
*
* @Param {nsIDOMElement} aContextMenu
* @param object aOptions
* Options object with the following properties:
* - successFn
* A function called if opening the given context menu - success to return.
* - failureFn
* A function called if not opening the given context menu - fails to return.
* - target
* The target element for showing a context menu.
* - timeout
* Timeout for popup shown, in milliseconds. Default is 5000.
*/
function waitForOpenContextMenu(aContextMenu, aOptions) {
let start = Date.now();
let timeout = aOptions.timeout || 5000;
let targetElement = aOptions.target;
if (!aContextMenu) {
ok(false, "Can't get a context menu.");
aOptions.failureFn();
return;
}
if (!targetElement) {
ok(false, "Can't get a target element.");
aOptions.failureFn();
return;
}
function onPopupShown() {
aContextMenu.removeEventListener("popupshown", onPopupShown);
clearTimeout(onTimeout);
aOptions.successFn();
}
aContextMenu.addEventListener("popupshown", onPopupShown);
let onTimeout = setTimeout(function(){
aContextMenu.removeEventListener("popupshown", onPopupShown);
aOptions.failureFn();
}, timeout);
// open a context menu.
let eventDetails = { type : "contextmenu", button : 2};
EventUtils.synthesizeMouse(targetElement, 2, 2,
eventDetails, targetElement.ownerDocument.defaultView);
}
function closeContextMenu (aContextMenu) {
aContextMenu.hidePopup();
}

View File

@ -1306,6 +1306,7 @@ WebConsoleFrame.prototype = {
msgNode, null, null, clipboardText);
messageNode._connectionId = entry.connection;
messageNode.url = request.url;
this.makeOutputMessageLink(messageNode, function WCF_net_message_link() {
if (!messageNode._panelOpen) {
@ -2306,6 +2307,20 @@ WebConsoleFrame.prototype = {
clipboardHelper.copyString(strings.join("\n"), this.document);
},
/**
* Open the selected item's URL in a new tab.
*/
openSelectedItemInTab: function WCF_openSelectedItemInTab()
{
let item = this.outputNode.selectedItem;
if (!item || !item.url) {
return;
}
this.owner.openLink(item.url);
},
/**
* Destroy the HUD object. Call this method to avoid memory leaks when the Web
* Console is closed.
@ -3441,6 +3456,14 @@ CommandController.prototype = {
this.owner.outputNode.selectAll();
},
/**
* Open the URL of the selected message in a new tab.
*/
openURL: function CommandController_openURL()
{
this.owner.openSelectedItemInTab();
},
supportsCommand: function CommandController_supportsCommand(aCommand)
{
return this.isCommandEnabled(aCommand);
@ -3452,6 +3475,11 @@ CommandController.prototype = {
case "cmd_copy":
// Only enable "copy" if nodes are selected.
return this.owner.outputNode.selectedCount > 0;
case "consoleCmd_openURL": {
// Only enable "open url" if node is Net Activity.
let selectedItem = this.owner.outputNode.selectedItem;
return selectedItem && selectedItem.url;
}
case "cmd_fontSizeEnlarge":
case "cmd_fontSizeReduce":
case "cmd_fontSizeReset":
@ -3466,6 +3494,9 @@ CommandController.prototype = {
case "cmd_copy":
this.copy();
break;
case "consoleCmd_openURL":
this.openURL();
break;
case "cmd_selectAll":
this.selectAll();
break;
@ -3488,3 +3519,114 @@ function gSequenceId()
}
gSequenceId.n = 0;
function goUpdateConsoleCommands() {
goUpdateCommand("consoleCmd_openURL");
}
///////////////////////////////////////////////////////////////////////////////
// Context Menu
///////////////////////////////////////////////////////////////////////////////
const CONTEXTMENU_ID = "output-contextmenu";
/*
* ConsoleContextMenu: This handle to show/hide a context menu item.
*/
let ConsoleContextMenu = {
/*
* Handle to show/hide context menu item.
*
* @param nsIDOMEvent aEvent
*/
build: function CCM_build(aEvent)
{
let popup = aEvent.target;
if (popup.id !== CONTEXTMENU_ID) {
return;
}
let view = document.querySelector(".hud-output-node");
let metadata = this.getSelectionMetadata(view);
for (let i = 0, l = popup.childNodes.length; i < l; ++i) {
let element = popup.childNodes[i];
element.hidden = this.shouldHideMenuItem(element, metadata);
}
},
/*
* Get selection information from the view.
*
* @param nsIDOMElement aView
* This should be <xul:richlistbox>.
*
* @return object
* Selection metadata.
*/
getSelectionMetadata: function CCM_getSelectionMetadata(aView)
{
let metadata = {
selectionType: "",
selection: new Set(),
};
let selectedItems = aView.selectedItems;
metadata.selectionType = (selectedItems > 1) ? "multiple" : "single";
let selection = metadata.selection;
for (let item of selectedItems) {
switch (item.category) {
case CATEGORY_NETWORK:
selection.add("network");
break;
case CATEGORY_CSS:
selection.add("css");
break;
case CATEGORY_JS:
selection.add("js");
break;
case CATEGORY_WEBDEV:
selection.add("webdev");
break;
}
}
return metadata;
},
/*
* Determine if an item should be hidden.
*
* @param nsIDOMElement aMenuItem
* @param object aMetadata
* @return boolean
* Whether the given item should be hidden or not.
*/
shouldHideMenuItem: function CCM_shouldHideMenuItem(aMenuItem, aMetadata)
{
let selectionType = aMenuItem.getAttribute("selectiontype");
if (selectionType && !aMetadata.selectionType == selectionType) {
return true;
}
let selection = aMenuItem.getAttribute("selection");
if (!selection) {
return false;
}
let shouldHide = true;
let itemData = selection.split("|");
for (let type of aMetadata.selection) {
// check whether this menu item should show or not.
if (itemData.indexOf(type) !== -1) {
shouldHide = false;
break;
}
}
return shouldHide;
},
};

View File

@ -21,7 +21,12 @@
<commandset id="editMenuCommands"/>
<commandset>
<commandset id="consoleCommands"
commandupdater="true"
events="richlistbox-select"
oncommandupdate="goUpdateConsoleCommands();">
<command id="consoleCmd_openURL"
oncommand="goDoCommand('consoleCmd_openURL');"/>
<command id="cmd_fullZoomEnlarge" oncommand="goDoCommand('cmd_fontSizeEnlarge');"/>
<command id="cmd_fullZoomReduce" oncommand="goDoCommand('cmd_fontSizeReduce');"/>
<command id="cmd_fullZoomReset" oncommand="goDoCommand('cmd_fontSizeReset');"/>
@ -38,9 +43,13 @@
<keyset id="editMenuKeys"/>
<popupset id="mainPopupSet">
<menupopup id="output-contextmenu">
<menupopup id="output-contextmenu"
onpopupshowing="ConsoleContextMenu.build(event);">
<menuitem id="saveBodiesContextMenu" type="checkbox" label="&saveBodies.label;"
accesskey="&saveBodies.accesskey;"/>
<menuitem id="menu_openURL" label="&openURL.label;"
accesskey="&openURL.accesskey;" command="consoleCmd_openURL"
selection="network" selectionType="single"/>
<menuitem id="menu_copy"/>
<menuitem id="menu_selectAll"/>
</menupopup>

View File

@ -32,6 +32,11 @@
<!ENTITY saveBodies.label "Log Request and Response Bodies">
<!ENTITY saveBodies.accesskey "L">
<!-- LOCALIZATION NOTE (openURL.label): You can see this string in the Web
- Console context menu. -->
<!ENTITY openURL.label "Open URL in New Tab">
<!ENTITY openURL.accesskey "T">
<!-- LOCALIZATION NOTE (btnPageNet.label): This string is used for the menu
- button that allows users to toggle the network logging output.
- This string and the following strings toggle various kinds of output

View File

@ -427,8 +427,9 @@ TestRunner.testFinished = function(tests) {
if (TestRunner.currentTestURL != TestRunner.getLoadedTestURL()) {
TestRunner.error("TEST-UNEXPECTED-FAIL | " +
TestRunner.currentTestURL +
" | finished in a non-clean fashion (in " +
TestRunner.getLoadedTestURL() + ")");
" | " + TestRunner.getLoadedTestURL() +
" finished in a non-clean fashion, probably" +
" because it didn't call SimpleTest.finish()");
tests.push({ result: false });
}

View File

@ -1932,14 +1932,26 @@ var AddonManagerInternal = {
},
get addonTypes() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return this.typesProxy;
},
get autoUpdateDefault() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return gAutoUpdateDefault;
},
set autoUpdateDefault(aValue) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
aValue = !!aValue;
if (aValue != gAutoUpdateDefault)
Services.prefs.setBoolPref(PREF_EM_AUTOUPDATE_DEFAULT, aValue);
@ -1947,10 +1959,18 @@ var AddonManagerInternal = {
},
get checkCompatibility() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return gCheckCompatibility;
},
set checkCompatibility(aValue) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
aValue = !!aValue;
if (aValue != gCheckCompatibility) {
if (!aValue)
@ -1962,10 +1982,18 @@ var AddonManagerInternal = {
},
get strictCompatibility() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return gStrictCompatibility;
},
set strictCompatibility(aValue) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
aValue = !!aValue;
if (aValue != gStrictCompatibility)
Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, aValue);
@ -1973,14 +2001,26 @@ var AddonManagerInternal = {
},
get checkUpdateSecurityDefault() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return gCheckUpdateSecurityDefault;
},
get checkUpdateSecurity() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return gCheckUpdateSecurity;
},
set checkUpdateSecurity(aValue) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
aValue = !!aValue;
if (aValue != gCheckUpdateSecurity) {
if (aValue != gCheckUpdateSecurityDefault)
@ -1992,10 +2032,18 @@ var AddonManagerInternal = {
},
get updateEnabled() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return gUpdateEnabled;
},
set updateEnabled(aValue) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
aValue = !!aValue;
if (aValue != gUpdateEnabled)
Services.prefs.setBoolPref(PREF_EM_UPDATE_ENABLED, aValue);
@ -2003,6 +2051,10 @@ var AddonManagerInternal = {
},
get hotfixID() {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
return gHotfixID;
},
};
@ -2340,6 +2392,10 @@ var AddonManager = {
* @return true if the addon should auto-update, false otherwise.
*/
shouldAutoUpdate: function AM_shouldAutoUpdate(aAddon) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
if (!aAddon || typeof aAddon != "object")
throw Components.Exception("aAddon must be specified",
Cr.NS_ERROR_INVALID_ARG);

View File

@ -4,57 +4,75 @@
// Verify that API functions fail if the Add-ons Manager isn't initialised.
const IGNORE = ["escapeAddonURI", "shouldAutoUpdate", "getStartupChanges",
"addTypeListener", "removeTypeListener",
"addAddonListener", "removeAddonListener",
"addInstallListener", "removeInstallListener",
"addManagerListener", "removeManagerListener"];
const IGNORE = {
funcs: ["escapeAddonURI", "getStartupChanges", "addTypeListener",
"removeTypeListener", "addAddonListener", "removeAddonListener",
"addInstallListener", "removeInstallListener", "addManagerListener",
"removeManagerListener"],
getters: ["__AddonManagerInternal__"],
setters: []
};
const IGNORE_PRIVATE = ["AddonAuthor", "AddonCompatibilityOverride",
"AddonScreenshot", "AddonType", "startup", "shutdown",
"registerProvider", "unregisterProvider",
"addStartupChange", "removeStartupChange"];
const IGNORE_PRIVATE = {
funcs: ["AddonAuthor", "AddonCompatibilityOverride", "AddonScreenshot",
"AddonType", "startup", "shutdown", "registerProvider",
"unregisterProvider", "addStartupChange", "removeStartupChange"],
getters: [],
setters: []
};
function test_functions() {
for (let prop in AddonManager) {
if (typeof AddonManager[prop] != "function")
continue;
if (IGNORE.indexOf(prop) != -1)
continue;
try {
do_print("AddonManager." + prop);
AddonManager[prop]();
do_throw(prop + " did not throw an exception");
}
catch (e) {
if (e.result != Components.results.NS_ERROR_NOT_INITIALIZED)
do_throw(prop + " threw an unexpected exception: " + e);
}
}
function test_functions(aObjName, aIgnore) {
let obj = this[aObjName];
for (let prop in obj) {
let desc = Object.getOwnPropertyDescriptor(obj, prop);
for (let prop in AddonManagerPrivate) {
if (typeof AddonManagerPrivate[prop] != "function")
continue;
if (IGNORE_PRIVATE.indexOf(prop) != -1)
continue;
if (typeof desc.value == "function") {
if (aIgnore.funcs.indexOf(prop) != -1)
continue;
try {
do_print("AddonManagerPrivate." + prop);
AddonManagerPrivate[prop]();
do_throw(prop + " did not throw an exception");
}
catch (e) {
if (e.result != Components.results.NS_ERROR_NOT_INITIALIZED)
do_throw(prop + " threw an unexpected exception: " + e);
try {
do_print(aObjName + "." + prop + "()");
obj[prop]();
do_throw(prop + " did not throw an exception");
}
catch (e) {
if (e.result != Components.results.NS_ERROR_NOT_INITIALIZED)
do_throw(prop + " threw an unexpected exception: " + e);
}
} else {
if (typeof desc.get == "function" && aIgnore.getters.indexOf(prop) == -1) {
do_print(aObjName + "." + prop + " getter");
try {
let temp = obj[prop];
do_throw(prop + " did not throw an exception");
}
catch (e) {
if (e.result != Components.results.NS_ERROR_NOT_INITIALIZED)
do_throw(prop + " threw an unexpected exception: " + e);
}
}
if (typeof desc.set == "function" && aIgnore.setters.indexOf(prop) == -1) {
do_print(aObjName + "." + prop + " setter");
try {
obj[prop] = "i am the walrus";
do_throw(prop + " did not throw an exception");
}
catch (e) {
if (e.result != Components.results.NS_ERROR_NOT_INITIALIZED)
do_throw(prop + " threw an unexpected exception: " + e);
}
}
}
}
}
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
test_functions();
test_functions("AddonManager", IGNORE);
test_functions("AddonManagerPrivate", IGNORE_PRIVATE);
startupManager();
shutdownManager();
test_functions();
test_functions("AddonManager", IGNORE);
test_functions("AddonManagerPrivate", IGNORE_PRIVATE);
}

View File

@ -18,6 +18,7 @@ function run_test() {
testserver.start(4444);
do_test_pending();
startupManager();
run_test_1();
}