Bug 753311 - Prevent the Debugger from opening on more than one tab; r=past

This commit is contained in:
Victor Porof 2012-05-31 13:01:13 +03:00
parent c3d47be20e
commit cdd95256a0
34 changed files with 357 additions and 55 deletions

View File

@ -160,7 +160,7 @@ gcli.addCommand({
returnType: "html",
exec: function(args, context) {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
@ -206,7 +206,7 @@ gcli.addCommand({
name: "selection",
data: function() {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
let files = [];
if (dbg) {
let scriptsView = dbg.contentWindow.DebuggerView.Scripts;
@ -229,7 +229,7 @@ gcli.addCommand({
exec: function(args, context) {
args.type = "line";
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
@ -261,7 +261,7 @@ gcli.addCommand({
min: 0,
max: function() {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
@ -274,7 +274,7 @@ gcli.addCommand({
returnType: "html",
exec: function(args, context) {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}

View File

@ -12,6 +12,7 @@ const Cu = Components.utils;
const DBG_XUL = "chrome://browser/content/debugger.xul";
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
const REMOTE_PROFILE_NAME = "_remote-debug";
const TAB_SWITCH_NOTIFICATION = "debugger-tab-switch";
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -31,6 +32,7 @@ function DebuggerUI(aWindow) {
}
DebuggerUI.prototype = {
/**
* Called by the DebuggerPane to update the Debugger toggle switches with the
* debugger state.
@ -39,7 +41,7 @@ DebuggerUI.prototype = {
let selectedTab = this.chromeWindow.getBrowser().selectedTab;
let command = this.chromeWindow.document.getElementById("Tools:Debugger");
if (this.getDebugger(selectedTab) != null) {
if (this.getDebugger()) {
command.setAttribute("checked", "true");
} else {
command.removeAttribute("checked");
@ -51,13 +53,18 @@ DebuggerUI.prototype = {
* @return DebuggerPane if the debugger is started, null if it's stopped.
*/
toggleDebugger: function DUI_toggleDebugger() {
let tab = this.chromeWindow.gBrowser.selectedTab;
let scriptDebugger = this.getDebugger();
let selectedTab = this.chromeWindow.gBrowser.selectedTab;
if (tab._scriptDebugger) {
tab._scriptDebugger.close();
if (scriptDebugger) {
if (scriptDebugger.ownerTab !== selectedTab) {
this.showTabSwitchNotification();
return scriptDebugger;
}
scriptDebugger.close();
return null;
}
return new DebuggerPane(this, tab);
return new DebuggerPane(this, selectedTab);
},
/**
@ -65,10 +72,10 @@ DebuggerUI.prototype = {
* @return RemoteDebuggerWindow if the debugger is started, null if stopped.
*/
toggleRemoteDebugger: function DUI_toggleRemoteDebugger() {
let win = this.chromeWindow;
let remoteDebugger = this.getRemoteDebugger();
if (win._remoteDebugger) {
win._remoteDebugger.close();
if (remoteDebugger) {
remoteDebugger.close();
return null;
}
return new RemoteDebuggerWindow(this);
@ -79,21 +86,22 @@ DebuggerUI.prototype = {
* @return ChromeDebuggerProcess if the debugger is started, null if stopped.
*/
toggleChromeDebugger: function DUI_toggleChromeDebugger(aOnClose, aOnRun) {
let win = this.chromeWindow;
let chromeDebugger = this.getChromeDebugger();
if (win._chromeDebugger) {
win._chromeDebugger.close();
if (chromeDebugger) {
chromeDebugger.close();
return null;
}
return new ChromeDebuggerProcess(win, aOnClose, aOnRun, true);
return new ChromeDebuggerProcess(this.chromeWindow, aOnClose, aOnRun, true);
},
/**
* Get the debugger for a specified tab.
* Get the current script debugger.
* @return DebuggerPane if a debugger exists for the tab, null otherwise.
*/
getDebugger: function DUI_getDebugger(aTab) {
return '_scriptDebugger' in aTab ? aTab._scriptDebugger : null;
getDebugger: function DUI_getDebugger() {
let win = this.chromeWindow;
return '_scriptDebugger' in win ? win._scriptDebugger : null;
},
/**
@ -120,6 +128,52 @@ DebuggerUI.prototype = {
*/
get preferences() {
return DebuggerPreferences;
},
/**
* Currently, there can only be one debugger per tab.
* Show an asynchronous notification which asks the user to switch the
* script debugger to the current tab if it's already open in another one.
*/
showTabSwitchNotification: function DUI_showTabSwitchNotification()
{
let gBrowser = this.chromeWindow.gBrowser;
let selectedBrowser = gBrowser.selectedBrowser;
let nbox = gBrowser.getNotificationBox(selectedBrowser);
let notification = nbox.getNotificationWithValue(TAB_SWITCH_NOTIFICATION);
if (notification) {
nbox.removeNotification(notification);
return;
}
let buttons = [{
id: "debugger.confirmTabSwitch.buttonSwitch",
label: L10N.getStr("confirmTabSwitch.buttonSwitch"),
accessKey: L10N.getStr("confirmTabSwitch.buttonSwitch.accessKey"),
callback: function DUI_notificationButtonSwitch() {
gBrowser.selectedTab = this.getDebugger().ownerTab;
}.bind(this)
}, {
id: "debugger.confirmTabSwitch.buttonOpen",
label: L10N.getStr("confirmTabSwitch.buttonOpen"),
accessKey: L10N.getStr("confirmTabSwitch.buttonOpen.accessKey"),
callback: function DUI_notificationButtonOpen() {
this.getDebugger().close();
this.toggleDebugger();
}.bind(this)
}];
let message = L10N.getStr("confirmTabSwitch.message");
let imageURL = "chrome://browser/skin/Info.png";
notification = nbox.appendNotification(
message, TAB_SWITCH_NOTIFICATION,
imageURL, nbox.PRIORITY_WARNING_HIGH, buttons, null);
// Make sure this is not a transient notification, to avoid the automatic
// transient notification removal.
notification.persistence = -1;
}
};
@ -133,6 +187,7 @@ DebuggerUI.prototype = {
*/
function DebuggerPane(aDebuggerUI, aTab) {
this._globalUI = aDebuggerUI;
this._win = aDebuggerUI.chromeWindow;
this._tab = aTab;
this._initServer();
@ -155,9 +210,9 @@ DebuggerPane.prototype = {
* Creates and initializes the widgets containing the debugger UI.
*/
_create: function DP__create() {
this._tab._scriptDebugger = this;
this._win._scriptDebugger = this;
let gBrowser = this._tab.linkedBrowser.getTabBrowser();
let gBrowser = this._win.gBrowser;
let ownerDocument = gBrowser.parentNode.ownerDocument;
this._splitter = ownerDocument.createElement("splitter");
@ -193,10 +248,11 @@ DebuggerPane.prototype = {
* Closes the debugger, removing child nodes and event listeners.
*/
close: function DP_close() {
if (!this._tab) {
if (!this._win) {
return;
}
delete this._tab._scriptDebugger;
delete this._win._scriptDebugger;
this._win = null;
this._tab = null;
DebuggerPreferences.height = this._frame.height;
@ -213,6 +269,14 @@ DebuggerPane.prototype = {
this._globalUI.refreshCommand();
},
/**
* Gets the tab owning this debugger instance.
* @return XULElement
*/
get ownerTab() {
return this._tab;
},
/**
* Gets the debugger content window.
* @return nsIDOMWindow if a debugger window exists, null otherwise

View File

@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_dbg_createRemote.js \
browser_dbg_createChrome.js \
browser_dbg_debugger-tab-switch.js \
browser_dbg_debuggerstatement.js \
browser_dbg_listtabs.js \
browser_dbg_tabactor-01.js \

View File

@ -27,7 +27,7 @@ function testCleanExit() {
is(gDebugger.DebuggerController.activeThread.paused, true,
"Should be paused after the debugger statement.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
});

View File

@ -37,7 +37,7 @@ function test() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: function() {
closeDebuggerAndFinish(gTab, true);
closeDebuggerAndFinish(true);
}}, 0);
});

View File

@ -0,0 +1,228 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let gTab1, gTab2, gTab3, gTab4;
let gPane1, gPane2;
let gNbox;
function test() {
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
testTab1(function() {
testTab2(function() {
testTab3(function() {
testTab4(function() {
lastTest(function() {
cleanup(function() {
finish();
});
});
});
});
});
});
}
function testTab1(callback) {
gTab1 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab1;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
ok(!DebuggerUI.getDebugger(),
"Shouldn't have a debugger pane for this tab yet.");
info("Toggling a debugger (1).");
gPane1 = DebuggerUI.toggleDebugger();
ok(gPane1, "toggleDebugger() should return a pane.");
is(gPane1.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as toggleDebugger().");
gPane1._frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
gPane1._frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
info("First debugger has finished loading correctly.");
executeSoon(function() {
callback();
});
}, true);
});
}
function testTab2(callback) {
gTab2 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab2;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification yet.");
ok(DebuggerUI.getDebugger(),
"Should already have a debugger pane for another tab.");
gNbox.addEventListener("AlertActive", function active() {
gNbox.removeEventListener("AlertActive", active, true);
executeSoon(function() {
ok(gPane2, "toggleDebugger() should always return a pane.");
is(gPane2.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as the first call to toggleDebugger().");
is(DebuggerUI.getDebugger(), gPane2,
"getDebugger() should return the same pane as the second call to toggleDebugger().");
info("Second debugger has not loaded.");
let notification = gNbox.getNotificationWithValue("debugger-tab-switch");
ok(gNbox.currentNotification, "Should have a tab switch notification.");
is(gNbox.currentNotification, notification, "Incorrect current notification.");
info("Notification will be simply closed.");
notification.close();
executeSoon(function() {
callback();
});
});
}, true);
info("Toggling a debugger (2).");
gPane2 = DebuggerUI.toggleDebugger();
});
}
function testTab3(callback) {
gTab3 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab3;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
ok(DebuggerUI.getDebugger(),
"Should already have a debugger pane for another tab.");
gNbox.addEventListener("AlertActive", function active() {
gNbox.removeEventListener("AlertActive", active, true);
executeSoon(function() {
ok(gPane2, "toggleDebugger() should always return a pane.");
is(gPane2.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as the first call to toggleDebugger().");
is(DebuggerUI.getDebugger(), gPane2,
"getDebugger() should return the same pane as the second call to toggleDebugger().");
info("Second debugger has not loaded.");
let notification = gNbox.getNotificationWithValue("debugger-tab-switch");
ok(gNbox.currentNotification, "Should have a tab switch notification.");
is(gNbox.currentNotification, notification, "Incorrect current notification.");
gBrowser.tabContainer.addEventListener("TabSelect", function tabSelect() {
gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect, true);
executeSoon(function() {
callback();
});
}, true);
let buttonSwitch = notification.querySelectorAll("button")[0];
buttonSwitch.focus();
EventUtils.sendKey("SPACE");
info("The switch button on the notification was pressed.");
});
}, true);
info("Toggling a debugger (3).");
gPane2 = DebuggerUI.toggleDebugger();
});
}
function testTab4(callback) {
is(gBrowser.selectedTab, gTab1,
"Should've switched to the first debugged tab.");
gTab4 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab4;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
ok(DebuggerUI.getDebugger(),
"Should already have a debugger pane for another tab.");
gNbox.addEventListener("AlertActive", function active() {
gNbox.removeEventListener("AlertActive", active, true);
executeSoon(function() {
ok(gPane2, "toggleDebugger() should always return a pane.");
is(gPane2.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as the first call to toggleDebugger().");
is(DebuggerUI.getDebugger(), gPane2,
"getDebugger() should return the same pane as the second call to toggleDebugger().");
info("Second debugger has not loaded.");
let notification = gNbox.getNotificationWithValue("debugger-tab-switch");
ok(gNbox.currentNotification, "Should have a tab switch notification.");
is(gNbox.currentNotification, notification, "Incorrect current notification.");
let buttonOpen = notification.querySelectorAll("button")[1];
buttonOpen.focus();
EventUtils.sendKey("SPACE");
info("The open button on the notification was pressed.");
executeSoon(function() {
callback();
});
});
}, true);
info("Toggling a debugger (4).");
gPane2 = DebuggerUI.toggleDebugger();
});
}
function lastTest(callback) {
isnot(gBrowser.selectedTab, gTab1,
"Shouldn't have switched to the first debugged tab.");
is(gBrowser.selectedTab, gTab4,
"Should currently be in the fourth tab.");
is(DebuggerUI.getDebugger().ownerTab, gTab4,
"The debugger should be open for the fourth tab.");
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
info("Second debugger has loaded.");
executeSoon(function() {
callback();
});
}
function cleanup(callback) {
removeTab(gTab1);
removeTab(gTab2);
removeTab(gTab3);
removeTab(gTab4);
gTab1 = null;
gTab2 = null;
gTab3 = null;
gTab4 = null;
gPane1 = null;
gPane2 = null;
gNbox = null;
callback();
}

View File

@ -36,7 +36,7 @@ function test() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
});

View File

@ -55,7 +55,7 @@ function testLocationChange()
gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
ok(true, "Successfully reattached to the tab again.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
content.location = TAB1_URL;

View File

@ -8,7 +8,7 @@ function test() {
var tab1 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = tab1;
ok(!DebuggerUI.getDebugger(gBrowser.selectedTab),
ok(!DebuggerUI.getDebugger(),
"Shouldn't have a debugger pane for this tab yet.");
let pane = DebuggerUI.toggleDebugger();
@ -16,7 +16,7 @@ function test() {
ok(pane, "toggleDebugger() should return a pane.");
is(DebuggerUI.getDebugger(gBrowser.selectedTab), pane,
is(DebuggerUI.getDebugger(), pane,
"getDebugger() should return the same pane as toggleDebugger().");
ok(DebuggerUI.preferences.height,

View File

@ -61,7 +61,7 @@ function testResume() {
is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("pauseTooltip"),
"Button tooltip should be pause when running.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
});

View File

@ -89,7 +89,7 @@ function testScriptLabelShortening() {
is(vs._scripts.itemCount, 9,
"Didn't get the correct number of scripts in the list.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
}

View File

@ -117,7 +117,7 @@ function testSimpleCall() {
"Clicking again the testScope tilte should collapse it.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -189,7 +189,7 @@ function testSimpleCall() {
"The scope should have been removed from the parent container tree.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -74,7 +74,7 @@ function testSimpleCall() {
"The var should have been removed from the parent container tree.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -82,7 +82,7 @@ function testSimpleCall() {
"The var should have been removed from the parent container tree.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -129,7 +129,7 @@ function testSimpleCall() {
"The grip information for the localVar5 wasn't set correctly.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -105,7 +105,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}, true);
gDebugger.DebuggerController.activeThread.resume();

View File

@ -127,7 +127,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}, true);
gDebugger.DebuggerController.activeThread.resume();

View File

@ -79,7 +79,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
}, true);

View File

@ -90,7 +90,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
}, true);

View File

@ -97,7 +97,7 @@ function testModification(aVar, aCallback, aNewValue, aNewResult) {
function resumeAndFinish() {
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -136,7 +136,7 @@ function testSwitchRunning()
is(gDebugger.editor.getDebugLocation(), -1,
"editor debugger location is still -1.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}
registerCleanupFunction(function() {

View File

@ -157,7 +157,7 @@ function testScriptSearching() {
is(gScripts.visibleItemsCount, 1,
"Not all the scripts are shown after the search. (20)");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -116,7 +116,7 @@ function finalCheck() {
is(gScripts.visibleItemsCount, 2,
"Not all the scripts are shown after the search. (3)");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}
function clear() {

View File

@ -35,7 +35,7 @@ function resumeAndFinish() {
addScriptsAndCheckOrder(1, function() {
addScriptsAndCheckOrder(2, function() {
addScriptsAndCheckOrder(3, function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
});

View File

@ -68,7 +68,7 @@ function testSelectLine() {
"The correct line is selected.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
});

View File

@ -37,7 +37,7 @@ function testSimpleCall() {
"All children should be frames.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -68,7 +68,7 @@ function testEvalCall() {
"Second frame should not be selected after click inside the first frame.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -48,7 +48,7 @@ function testRecurse() {
"Should have reached the recurse limit.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});

View File

@ -49,7 +49,7 @@ function testEvalCallResume() {
is(frames.querySelectorAll(".empty").length, 1,
"Should have the empty list explanation.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}, true);
gDebugger.DebuggerController.activeThread.resume();

View File

@ -98,7 +98,7 @@ function testRecurse()
gDebugger.DebuggerController.activeThread.resume(function() {
is(gDebugger.editor.getDebugLocation(), -1,
"editor debugger location is correct after resume.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -97,7 +97,7 @@ function testSwitchPaused()
"Found the expected editor mode.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -49,13 +49,13 @@ function removeTab(aTab) {
gBrowser.removeTab(aTab);
}
function closeDebuggerAndFinish(aTab, aRemoteFlag) {
function closeDebuggerAndFinish(aRemoteFlag) {
DebuggerUI.chromeWindow.addEventListener("Debugger:Shutdown", function cleanup() {
DebuggerUI.chromeWindow.removeEventListener("Debugger:Shutdown", cleanup, false);
finish();
}, false);
if (!aRemoteFlag) {
DebuggerUI.getDebugger(aTab).close();
DebuggerUI.getDebugger().close();
} else {
DebuggerUI.getRemoteDebugger().close();
}

View File

@ -10,6 +10,15 @@
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (confirmTabSwitch): The messages displayed for all the
# title and buttons on the notification shown when a user attempts to open a
# debugger in a new tab while a different tab is already being debugged.
confirmTabSwitch.message=Debugger is already open in another tab. Continuing will close the other instance.
confirmTabSwitch.buttonSwitch=Switch to debugged tab
confirmTabSwitch.buttonSwitch.accessKey=S
confirmTabSwitch.buttonOpen=Open anyway
confirmTabSwitch.buttonOpen.accessKey=O
# LOCALIZATION NOTE (remoteDebuggerWindowTitle): The title displayed for the
# remote debugger window.
remoteDebuggerWindowTitle=Remote Debugger