merge m-c to fx-team

This commit is contained in:
Tim Taubert 2012-09-22 09:32:24 +02:00
commit 8676d23ae0
19 changed files with 345 additions and 158 deletions

View File

@ -11,7 +11,6 @@ let TabView = {
_closedLastVisibleTabBeforeFrameInitialized: false,
_isFrameLoading: false,
_initFrameCallbacks: [],
_lastSessionGroupName: null,
PREF_BRANCH: "browser.panorama.",
PREF_FIRST_RUN: "browser.panorama.experienced_first_run",
PREF_STARTUP_PAGE: "browser.startup.page",

View File

@ -155,7 +155,7 @@ XPCOMUtils.defineLazyGetter(this, "SafeBrowsing", function() {
#endif
XPCOMUtils.defineLazyModuleGetter(this, "gBrowserNewTabPreloader",
"resource://gre/modules/BrowserNewTabPreloader.jsm", "BrowserNewTabPreloader");
"resource:///modules/BrowserNewTabPreloader.jsm", "BrowserNewTabPreloader");
let gInitialPages = [
"about:blank",

View File

@ -34,7 +34,6 @@ function GroupItem(listOfEls, options) {
this._inited = false;
this._uninited = false;
this._children = []; // an array of Items
this.defaultSize = new Point(TabItems.tabWidth * 1.5, TabItems.tabHeight * 1.5);
this.isAGroupItem = true;
this.id = options.id || GroupItems.getNextID();
this._isStacked = false;
@ -2111,18 +2110,6 @@ let GroupItems = {
return result;
},
// ----------
// Function: getStorageData
// Returns an object for saving GroupItems state to persistent storage.
getStorageData: function GroupItems_getStorageData() {
var data = {nextID: this.nextID, groupItems: []};
this.groupItems.forEach(function(groupItem) {
data.groupItems.push(groupItem.getStorageData());
});
return data;
},
// ----------
// Function: saveAll
// Saves GroupItems state, as well as the state of all of the groupItems.

View File

@ -17,9 +17,6 @@
//
// Subclasses of Item must also provide the <Subscribable> interface.
//
// ... and this property:
// defaultSize - a Point
//
// Make sure to call _init() from your subclass's constructor.
function Item() {
// Variable: isAnItem
@ -102,7 +99,6 @@ Item.prototype = {
Utils.assert(typeof this.setZ == 'function', 'Subclass must provide setZ');
Utils.assert(typeof this.close == 'function', 'Subclass must provide close');
Utils.assert(typeof this.save == 'function', 'Subclass must provide save');
Utils.assert(Utils.isPoint(this.defaultSize), 'Subclass must provide defaultSize');
Utils.assert(Utils.isRect(this.bounds), 'Subclass must provide bounds');
this.container = container;

View File

@ -36,29 +36,6 @@ let Storage = {
this._sessionStore = null;
},
// ----------
// Function: wipe
// Cleans out all the stored data, leaving empty objects.
wipe: function Storage_wipe() {
try {
var self = this;
// ___ Tabs
AllTabs.tabs.forEach(function(tab) {
self.saveTab(tab, null);
});
// ___ Other
this.saveGroupItemsData(gWindow, {});
this.saveUIData(gWindow, {});
this._sessionStore.setWindowValue(gWindow, this.GROUP_DATA_IDENTIFIER,
JSON.stringify({}));
} catch (e) {
Utils.log("Error in wipe: "+e);
}
},
// ----------
// Function: saveTab
// Saves the data for a single tab.

View File

@ -41,7 +41,6 @@ function TabItem(tab, options) {
this.tabCanvas = new TabCanvas(this.tab, this.$canvas[0]);
this.defaultSize = new Point(TabItems.tabWidth, TabItems.tabHeight);
this._hidden = false;
this.isATabItem = true;
this.keepProportional = true;

View File

@ -1,37 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let stateStartup = {windows:[
{tabs:[{entries:[{url:"about:home"}]}], extData:{"tabview-last-session-group-name":"title"}}
]};
function test() {
let assertWindowTitle = function (win, title) {
let browser = win.gBrowser.tabs[0].linkedBrowser;
let winTitle = win.gBrowser.getWindowTitleForBrowser(browser);
info('window title is: "' + winTitle + '"');
is(winTitle.indexOf(title), 0, "title starts with '" + title + "'");
};
let testGroupNameChange = function (win) {
showTabView(function () {
let cw = win.TabView.getContentWindow();
let groupItem = cw.GroupItems.groupItems[0];
groupItem.setTitle("new-title");
hideTabView(function () {
assertWindowTitle(win, "new-title");
finish();
}, win);
}, win);
};
waitForExplicitFinish();
newWindowWithState(stateStartup, function (win) {
registerCleanupFunction(function () win.close());
assertWindowTitle(win, "title");
testGroupNameChange(win);
});
}

View File

@ -22,7 +22,39 @@ function test()
"testTabActor's actorPrefix should be used.");
gClient.request({ to: globalActor, type: "ping" }, function(aResponse) {
is(aResponse.pong, "pong", "Actor should respond to requests.");
finish_test();
// Send another ping to see if the same actor is used.
gClient.request({ to: globalActor, type: "ping" }, function(aResponse) {
is(aResponse.pong, "pong", "Actor should respond to requests.");
// Make sure that lazily-created actors are created only once.
let connections = Object.keys(DebuggerServer._connections);
is(connections.length, 1, "Only one connection is established.");
let connPrefix = connections[0];
ok(DebuggerServer._connections[connPrefix],
connPrefix + " is the only connection.");
// First we look for the pool of global actors.
let extraPools = DebuggerServer._connections[connPrefix]._extraPools;
let globalPool;
for (let pool of extraPools) {
if (Object.keys(pool._actors).some(function(elem) {
// Tab actors are in the global pool.
let re = new RegExp(connPrefix + "tab", "g");
return elem.match(re) !== null;
})) {
globalPool = pool;
break;
}
}
// Then we look if the global pool contains only one test actor.
let actorPrefix = connPrefix + "testone";
let actors = Object.keys(globalPool._actors).join();
info("Global actors: " + actors);
isnot(actors.indexOf(actorPrefix), -1, "The test actor exists in the pool.");
is(actors.indexOf(actorPrefix), actors.lastIndexOf(actorPrefix),
"Only one actor exists in the pool.");
finish_test();
});
});
});
});

View File

@ -115,6 +115,7 @@ MOCHITEST_BROWSER_FILES = \
browser_webconsole_bug_737873_mixedcontent.js \
browser_output_breaks_after_console_dir_uninspectable.js \
browser_console_log_inspectable_object.js \
browser_bug_638949_copy_link_location.js \
head.js \
$(NULL)

View File

@ -0,0 +1,153 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/" +
"test/test-console.html?_date=" + Date.now();
const COMMAND_NAME = "consoleCmd_copyURL";
const CONTEXT_MENU_ID = "#menu_copyURL";
let HUD = null;
let output = null;
let menu = null;
function test() {
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole(null, function (aHud) {
HUD = aHud;
output = aHud.outputNode;
menu = HUD.iframeWindow.document.getElementById("output-contextmenu");
executeSoon(testWithoutNetActivity);
});
}, true);
}
// Return whether "Copy Link Location" command is enabled or not.
function isEnabled() {
let controller = top.document.commandDispatcher.
getControllerForCommand(COMMAND_NAME);
return controller && controller.isCommandEnabled(COMMAND_NAME);
}
function select(query) {
let target = output.querySelector(query);
output.focus();
output.selectedItem = target;
return target;
}
function testWithoutNetActivity() {
HUD.jsterm.clearOutput();
output = HUD.outputNode;
content.wrappedJSObject.console.log("bug 638949");
// Test that "Copy Link Location" command is disabled if there
// were no network-related messages.
waitForSuccess({
name: "no net activity in console",
validatorFn: function () {
return output.textContent.indexOf("bug 638949") > -1;
},
successFn: function () {
select(".webconsole-msg-log");
goUpdateCommand(COMMAND_NAME);
ok(!isEnabled(), COMMAND_NAME + "is disabled");
executeSoon(testMenuWithoutNetActivity);
}
});
}
function testMenuWithoutNetActivity() {
// Test that "Copy Link Location" menu item is hidden if there
// were no network-related messages.
let target = select(".webconsole-msg-log");
function next() {
menu.hidePopup();
executeSoon(testWithNetActivity);
}
waitForOpenContextMenu(menu, {
target: target,
successFn: function () {
let isHidden = menu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isHidden, CONTEXT_MENU_ID + " is hidden");
next();
},
failureFn: next
});
}
function testWithNetActivity() {
HUD.jsterm.clearOutput();
content.location.reload(); // Reloading will produce network logging
// Test that "Copy Link Location" command is enabled and works
// as expected if there were any network-related messages.
//
// This command should copy only the URL without timestamp and other
// stuff.
waitForSuccess({
name: "net activity in console",
validatorFn: function () {
let item = select(".webconsole-msg-network");
return item && item.url;
},
successFn: function () {
output.focus();
goUpdateCommand(COMMAND_NAME);
ok(isEnabled(), COMMAND_NAME + " is enabled");
waitForClipboard(output.selectedItem.url, function clipboardSetup() {
goDoCommand(COMMAND_NAME);
}, testMenuWithNetActivity, testMenuWithNetActivity);
},
failureFn: testMenuWithNetActivity
});
}
function testMenuWithNetActivity() {
// Test that "Copy Link Location" menu item is visible if there
// were any network-related messages.
let target = select(".webconsole-msg-network");
function next() {
menu.hidePopup();
executeSoon(finalize);
}
waitForOpenContextMenu(menu, {
target: target,
successFn: function () {
let isVisible = !menu.querySelector(CONTEXT_MENU_ID).hidden;
ok(isVisible, CONTEXT_MENU_ID + " is visible");
next();
},
failureFn: next
});
}
function finalize() {
HUD = null;
output = null;
menu = null;
finishTest();
}

View File

@ -170,57 +170,6 @@ function finalizeTest() {
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

@ -179,6 +179,57 @@ function closeConsole(aTab, aCallback)
HUDService.deactivateHUDForContext(aTab || tab);
}
/**
* 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 finishTest()
{
browser = hudId = hud = filterBox = outputNode = cs = null;

View File

@ -2271,9 +2271,16 @@ WebConsoleFrame.prototype = {
/**
* Copies the selected items to the system clipboard.
*
* @param object aOptions
* - linkOnly:
* An optional flag to copy only URL without timestamp and
* other meta-information. Default is false.
*/
copySelectedItems: function WCF_copySelectedItems()
copySelectedItems: function WCF_copySelectedItems(aOptions)
{
aOptions = aOptions || { linkOnly: false };
// Gather up the selected items and concatenate their clipboard text.
let strings = [];
let newGroup = false;
@ -2300,7 +2307,13 @@ WebConsoleFrame.prototype = {
strings.push("--");
newGroup = false;
}
strings.push("[" + timestampString + "] " + item.clipboardText);
if (aOptions.linkOnly) {
strings.push(item.url);
}
else {
strings.push("[" + timestampString + "] " + item.clipboardText);
}
}
}
@ -3464,6 +3477,11 @@ CommandController.prototype = {
this.owner.openSelectedItemInTab();
},
copyURL: function CommandController_copyURL()
{
this.owner.copySelectedItems({ linkOnly: true });
},
supportsCommand: function CommandController_supportsCommand(aCommand)
{
return this.isCommandEnabled(aCommand);
@ -3475,8 +3493,9 @@ 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.
case "consoleCmd_openURL":
case "consoleCmd_copyURL": {
// Only enable URL-related actions if node is Net Activity.
let selectedItem = this.owner.outputNode.selectedItem;
return selectedItem && selectedItem.url;
}
@ -3497,6 +3516,9 @@ CommandController.prototype = {
case "consoleCmd_openURL":
this.openURL();
break;
case "consoleCmd_copyURL":
this.copyURL();
break;
case "cmd_selectAll":
this.selectAll();
break;
@ -3522,6 +3544,7 @@ gSequenceId.n = 0;
function goUpdateConsoleCommands() {
goUpdateCommand("consoleCmd_openURL");
goUpdateCommand("consoleCmd_copyURL");
}

View File

@ -27,6 +27,8 @@
oncommandupdate="goUpdateConsoleCommands();">
<command id="consoleCmd_openURL"
oncommand="goDoCommand('consoleCmd_openURL');"/>
<command id="consoleCmd_copyURL"
oncommand="goDoCommand('consoleCmd_copyURL');"/>
<command id="cmd_fullZoomEnlarge" oncommand="goDoCommand('cmd_fontSizeEnlarge');"/>
<command id="cmd_fullZoomReduce" oncommand="goDoCommand('cmd_fontSizeReduce');"/>
<command id="cmd_fullZoomReset" oncommand="goDoCommand('cmd_fontSizeReset');"/>
@ -50,6 +52,9 @@
<menuitem id="menu_openURL" label="&openURL.label;"
accesskey="&openURL.accesskey;" command="consoleCmd_openURL"
selection="network" selectionType="single"/>
<menuitem id="menu_copyURL" label="&copyURLCmd.label;"
accesskey="&copyURLCmd.accesskey;" command="consoleCmd_copyURL"
selection="network" selectionType="single"/>
<menuitem id="menu_copy"/>
<menuitem id="menu_selectAll"/>
</menupopup>

View File

@ -93,3 +93,6 @@
<!ENTITY fullZoomResetCmd.commandkey "0">
<!ENTITY fullZoomResetCmd.commandkey2 "">
<!ENTITY copyURLCmd.label "Copy Link Location">
<!ENTITY copyURLCmd.accesskey "a">

View File

@ -15,17 +15,16 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const PREF_BRANCH = "browser.newtab.";
const TOPIC_DELAYED_STARTUP = "browser-delayed-startup-finished";
const PRELOADER_INIT_DELAY_MS = 5000;
let BrowserNewTabPreloader = {
let BrowserNewTabPreloader = {
init: function Preloader_init() {
Preferences.init();
if (Preferences.enabled) {
HiddenBrowser.create();
}
Initializer.start();
},
uninit: function Preloader_uninit() {
Initializer.stop();
HostFrame.destroy();
Preferences.uninit();
HiddenBrowser.destroy();
@ -38,6 +37,51 @@ let BrowserNewTabPreloader = {
Object.freeze(BrowserNewTabPreloader);
let Initializer = {
_timer: null,
_observing: false,
start: function Initializer_start() {
Services.obs.addObserver(this, TOPIC_DELAYED_STARTUP, false);
this._observing = true;
},
stop: function Initializer_stop() {
if (this._timer) {
this._timer.cancel();
this._timer = null;
}
if (this._observing) {
Services.obs.removeObserver(this, TOPIC_DELAYED_STARTUP);
this._observing = false;
}
},
observe: function Initializer_observe(aSubject, aTopic, aData) {
if (aTopic == TOPIC_DELAYED_STARTUP) {
Services.obs.removeObserver(this, TOPIC_DELAYED_STARTUP);
this._observing = false;
this._startTimer();
} else if (aTopic == "timer-callback") {
this._timer = null;
this._startPreloader();
}
},
_startTimer: function Initializer_startTimer() {
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this._timer.init(this, PRELOADER_INIT_DELAY_MS, Ci.nsITimer.TYPE_ONE_SHOT);
},
_startPreloader: function Initializer_startPreloader() {
Preferences.init();
if (Preferences.enabled) {
HiddenBrowser.create();
}
}
};
let Preferences = {
_enabled: null,
_branch: null,

View File

@ -106,7 +106,7 @@ static PRLogModuleInfo* gLogModule = PR_LOG_DEFINE("nsSHistory");
nsCOMPtr<nsISHistoryListener> listener = \
do_QueryReferent(iter.GetNext()); \
if (listener) { \
body; \
body \
} \
} \
} \

View File

@ -40,8 +40,6 @@ ThreadActor.prototype = {
get state() { return this._state; },
get dbg() { return this._dbg; },
get _breakpointStore() { return ThreadActor._breakpointStore; },
get threadLifetimePool() {
@ -53,10 +51,10 @@ ThreadActor.prototype = {
},
clearDebuggees: function TA_clearDebuggees() {
if (this._dbg) {
let debuggees = this._dbg.getDebuggees();
if (this.dbg) {
let debuggees = this.dbg.getDebuggees();
for (let debuggee of debuggees) {
this._dbg.removeDebuggee(debuggee);
this.dbg.removeDebuggee(debuggee);
}
}
this.conn.removeActorPool(this._threadLifetimePool || undefined);
@ -79,11 +77,11 @@ ThreadActor.prototype = {
// medium- to long-term, and will be managed by the engine
// instead.
if (!this._dbg) {
this._dbg = new Debugger();
this._dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
this._dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
this._dbg.onNewScript = this.onNewScript.bind(this);
if (!this.dbg) {
this.dbg = new Debugger();
this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
this.dbg.onNewScript = this.onNewScript.bind(this);
// Keep the debugger disabled until a client attaches.
this.dbg.enabled = this._state != "detached";
}
@ -115,11 +113,11 @@ ThreadActor.prototype = {
this.clearDebuggees();
if (!this._dbg) {
if (!this.dbg) {
return;
}
this._dbg.enabled = false;
this._dbg = null;
this.dbg.enabled = false;
this.dbg = null;
},
/**
@ -1126,7 +1124,11 @@ PauseScopedActor.prototype = {
*/
function update(aTarget, aNewAttrs) {
for (let key in aNewAttrs) {
aTarget[key] = aNewAttrs[key];
let desc = Object.getOwnPropertyDescriptor(aNewAttrs, key);
if (desc) {
Object.defineProperty(aTarget, key, desc);
}
}
}

View File

@ -529,8 +529,11 @@ DebuggerServerConnection.prototype = {
"': " + safeErrorString(e))
});
}
// We want the newly-constructed actor to completely replace the factory
// actor. Reusing the existing actor ID will make sure ActorPool.addActor
// does the right thing.
instance.actorID = actor.actorID;
actor.registeredPool.addActor(instance);
actor.registeredPool.removeActor(actor);
actor = instance;
}