Merge fx-team to m-c.

This commit is contained in:
Ryan VanderMeulen 2014-01-23 15:56:13 -05:00
commit 2e91c12958
73 changed files with 876 additions and 595 deletions

View File

@ -1103,6 +1103,8 @@ let RemoteDebugger = {
DebuggerServer.registerModule("devtools/server/actors/inspector");
DebuggerServer.registerModule("devtools/server/actors/styleeditor");
DebuggerServer.registerModule("devtools/server/actors/stylesheets");
DebuggerServer.registerModule("devtools/server/actors/tracer");
DebuggerServer.registerModule("devtools/server/actors/webgl");
}
DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/webapps.js");

View File

@ -525,8 +525,6 @@
@BINPATH@/components/CaptivePortalDetectComponents.manifest
@BINPATH@/components/captivedetect.js
#endif
@BINPATH@/components/TelemetryPing.js
@BINPATH@/components/TelemetryPing.manifest
@BINPATH@/components/TelemetryStartup.js
@BINPATH@/components/TelemetryStartup.manifest
@BINPATH@/components/Webapps.js

View File

@ -1337,7 +1337,7 @@ pref("browser.uiCustomization.debug", false);
// The URL where remote content that composes the UI for Firefox Accounts should
// be fetched. Must use HTTPS.
pref("firefox.accounts.remoteUrl", "https://accounts.dev.lcip.org/?service=sync");
pref("identity.fxaccounts.remote.uri", "https://accounts.dev.lcip.org/?service=sync");
// The URL of the Firefox Accounts auth server backend
pref("identity.fxaccounts.auth.uri", "https://api-accounts.dev.lcip.org/v1");

View File

@ -46,14 +46,16 @@ var FeedHandler = {
var item = document.createElement(itemNodeType);
var baseTitle = feedInfo.title || feedInfo.href;
var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
item.setAttribute("class", "feed-" + itemNodeType);
item.setAttribute("label", labelStr);
item.setAttribute("feed", feedInfo.href);
item.setAttribute("tooltiptext", feedInfo.href);
item.setAttribute("crop", "center");
let className = "feed-" + itemNodeType;
if (isSubview) {
item.setAttribute("tabindex", "0");
className += " subviewbutton";
}
item.setAttribute("class", className);
container.appendChild(item);
}
return true;

View File

@ -9,7 +9,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
registerCleanupFunction(function() {
// Ensure we don't pollute prefs for next tests.
Services.prefs.clearUserPref("firefox.accounts.remoteUrl");
Services.prefs.clearUserPref("identity.fxaccounts.remote.uri");
});
let gTests = [
@ -18,7 +18,7 @@ let gTests = [
desc: "Test the remote commands",
setup: function ()
{
Services.prefs.setCharPref("firefox.accounts.remoteUrl",
Services.prefs.setCharPref("identity.fxaccounts.remote.uri",
"https://example.com/browser/browser/base/content/test/general/accounts_testRemoteCommands.html");
},
run: function ()

View File

@ -982,7 +982,7 @@ var tests = [
},
onHidden: function() { }
},
{ // Test #31 - Moving a tab to a new window should remove non-swappable
{ // Test #34 - Moving a tab to a new window should remove non-swappable
// notifications.
run: function() {
gBrowser.selectedTab = gBrowser.addTab("about:blank");
@ -1002,7 +1002,7 @@ var tests = [
});
}
},
{ // Test #32 - Moving a tab to a new window should preserve swappable notifications.
{ // Test #35 - Moving a tab to a new window should preserve swappable notifications.
run: function() {
gBrowser.selectedTab = gBrowser.addTab("about:blank");
let notifyObj = new basicNotification();
@ -1024,6 +1024,50 @@ var tests = [
goNext();
});
}
},
{ // Test #36 - the hideNotNow option
run: function () {
this.notifyObj = new basicNotification();
this.notifyObj.options.hideNotNow = true;
this.notifyObj.mainAction.dismiss = true;
showNotification(this.notifyObj);
},
onShown: function (popup) {
// checkPopup verifies that the Not Now item is hidden, and that no separator is added.
checkPopup(popup, this.notifyObj);
triggerMainCommand(popup);
},
onHidden: function (popup) { }
},
{ // Test #37 - the main action callback can keep the notification.
run: function () {
this.notifyObj = new basicNotification();
this.notifyObj.mainAction.dismiss = true;
showNotification(this.notifyObj);
},
onShown: function (popup) {
checkPopup(popup, this.notifyObj);
triggerMainCommand(popup);
},
onHidden: function (popup) {
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered");
ok(!this.notifyObj.removedCallbackTriggered, "removed callback wasn't triggered");
}
},
{ // Test #38 - a secondary action callback can keep the notification.
run: function () {
this.notifyObj = new basicNotification();
this.notifyObj.secondaryActions[0].dismiss = true;
showNotification(this.notifyObj);
},
onShown: function (popup) {
checkPopup(popup, this.notifyObj);
triggerSecondaryCommand(popup, 0);
},
onHidden: function (popup) {
ok(this.notifyObj.dismissalCallbackTriggered, "dismissal callback was triggered");
ok(!this.notifyObj.removedCallbackTriggered, "removed callback wasn't triggered");
}
}
];
@ -1063,7 +1107,12 @@ function checkPopup(popup, notificationObj) {
function (child) child.nodeName == "menuitem");
let secondaryActions = notificationObj.secondaryActions || [];
let actualSecondaryActionsCount = actualSecondaryActions.length;
if (secondaryActions.length) {
if (notificationObj.options.hideNotNow) {
is(notification.getAttribute("hidenotnow"), "true", "Not Now item hidden");
if (secondaryActions.length)
is(notification.lastChild.tagName, "menuitem", "no menuseparator");
}
else if (secondaryActions.length) {
is(notification.lastChild.tagName, "menuseparator", "menuseparator exists");
}
is(actualSecondaryActionsCount, secondaryActions.length, actualSecondaryActions.length + " secondary actions");

View File

@ -38,25 +38,28 @@
</panelview>
<panelview id="PanelUI-history" flex="1">
<label value="&appMenuHistory.label;"/>
<label value="&appMenuHistory.label;" class="panel-subview-header"/>
<toolbarbutton id="appMenuViewHistorySidebar" tabindex="0"
label="&appMenuHistory.viewSidebar.label;"
type="checkbox"
class="subviewbutton"
oncommand="toggleSidebar('viewHistorySidebar'); PanelUI.hide();">
<observes element="viewHistorySidebar" attribute="checked"/>
</toolbarbutton>
<toolbarbutton id="appMenuClearRecentHistory" tabindex="0"
label="&appMenuHistory.clearRecent.label;"
class="subviewbutton"
command="Tools:Sanitize"/>
#ifdef MOZ_SERVICES_SYNC
<toolbarbutton id="sync-tabs-menuitem2"
class="syncTabsMenuItem"
class="syncTabsMenuItem subviewbutton"
label="&syncTabsMenu2.label;"
oncommand="BrowserOpenSyncTabs();"
disabled="true"/>
#endif
<toolbarbutton id="appMenuRestoreLastSession" tabindex="0"
label="&appMenuHistory.restoreSession.label;"
class="subviewbutton"
command="Browser:RestoreLastSession"/>
<menuseparator id="PanelUI-recentlyClosedTabs-separator"/>
<vbox id="PanelUI-recentlyClosedTabs" tooltip="bhTooltip"/>
@ -64,24 +67,28 @@
<vbox id="PanelUI-recentlyClosedWindows" tooltip="bhTooltip"/>
<menuseparator id="PanelUI-historyItems-separator"/>
<vbox id="PanelUI-historyItems" tooltip="bhTooltip"/>
<label value="&appMenuHistory.showAll.label;"
id="PanelUI-historyMore"
class="text-link"
onclick="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/>
<toolbarbutton id="PanelUI-historyMore" tabindex="0"
class="panel-subview-footer subviewbutton"
label="&appMenuHistory.showAll.label;"
oncommand="PlacesCommandHook.showPlacesOrganizer('History'); CustomizableUI.hidePanelForNode(this);"/>
</panelview>
<panelview id="PanelUI-bookmarks" flex="1">
<panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView">
<label value="&bookmarksMenu.label;" class="panel-subview-header"/>
<toolbarbutton id="panelMenuBookmarkThisPage"
label="&bookmarkThisPageCmd.label;"
class="subviewbutton"
command="Browser:AddBookmarkAs"
onclick="PanelUI.hide();"/>
<toolbarseparator/>
<toolbarbutton id="panelMenu_showAllBookmarks"
label="&showAllBookmarks2.label;"
class="subviewbutton"
command="Browser:ShowAllBookmarks"
onclick="PanelUI.hide();"/>
<toolbarbutton id="panelMenu_viewBookmarksSidebar"
label="&viewBookmarksSidebar2.label;"
class="subviewbutton"
oncommand="toggleSidebar('viewBookmarksSidebar'); PanelUI.hide();">
<observes element="viewBookmarksSidebar" attribute="checked"/>
</toolbarbutton>
@ -89,13 +96,16 @@
label="&viewBookmarksToolbar.label;"
type="checkbox"
toolbarId="PersonalToolbar"
class="subviewbutton"
oncommand="onViewToolbarCommand(event); PanelUI.hide();"/>
<toolbarseparator/>
<toolbarbutton id="panelMenu_bookmarksToolbar"
label="&personalbarCmd.label;"
class="subviewbutton"
oncommand="PlacesCommandHook.showPlacesOrganizer('BookmarksToolbar'); PanelUI.hide();"/>
<toolbarbutton id="panelMenu_unsortedBookmarks"
label="&unsortedBookmarksCmd.label;"
class="subviewbutton"
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); PanelUI.hide();"/>
<toolbarseparator/>
<toolbaritem id="panelMenu_bookmarksMenu"
@ -116,17 +126,17 @@
<panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);"></panelview>
<panelview id="PanelUI-helpView" flex="1">
<label value="&helpMenu.label;"/>
<label value="&helpMenu.label;" class="panel-subview-header"/>
<vbox id="PanelUI-helpItems"/>
</panelview>
<panelview id="PanelUI-developer" flex="1">
<label value="&webDeveloperMenu.label;"/>
<label value="&webDeveloperMenu.label;" class="panel-subview-header"/>
<vbox id="PanelUI-developerItems"/>
</panelview>
<panelview id="PanelUI-characterEncodingView" flex="1">
<label value="&charsetMenu.label;"/>
<label value="&charsetMenu.label;" class="panel-subview-header"/>
<vbox id="PanelUI-characterEncodingView-customlist"
class="PanelUI-characterEncodingView-list"/>

View File

@ -409,6 +409,7 @@ const PanelUI = {
continue;
button.setAttribute(attrName, node.getAttribute(attrName));
}
button.setAttribute("class", "subviewbutton");
fragment.appendChild(button);
}
items.appendChild(fragment);

View File

@ -102,6 +102,7 @@ const CustomizableWidgets = [{
item.setAttribute("label", title || uri);
item.setAttribute("tabindex", "0");
item.setAttribute("targetURI", uri);
item.setAttribute("class", "subviewbutton");
item.addEventListener("command", function (aEvent) {
onHistoryVisit(uri, aEvent, item);
});
@ -152,12 +153,24 @@ const CustomizableWidgets = [{
let tabsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getTabsFragment(doc.defaultView, "toolbarbutton");
let separator = doc.getElementById("PanelUI-recentlyClosedTabs-separator");
separator.hidden = !tabsFragment.childElementCount;
let elementCount = tabsFragment.childElementCount;
separator.hidden = !elementCount;
while (--elementCount >= 0) {
if (tabsFragment.children[elementCount].localName != "toolbarbutton")
continue;
tabsFragment.children[elementCount].setAttribute("class", "subviewbutton");
}
recentlyClosedTabs.appendChild(tabsFragment);
let windowsFragment = RecentlyClosedTabsAndWindowsMenuUtils.getWindowsFragment(doc.defaultView, "toolbarbutton");
separator = doc.getElementById("PanelUI-recentlyClosedWindows-separator");
separator.hidden = !windowsFragment.childElementCount;
elementCount = windowsFragment.childElementCount;
separator.hidden = !elementCount;
while (--elementCount >= 0) {
if (windowsFragment.children[elementCount].localName != "toolbarbutton")
continue;
windowsFragment.children[elementCount].setAttribute("class", "subviewbutton");
}
recentlyClosedWindows.appendChild(windowsFragment);
},
onViewHiding: function(aEvent) {
@ -244,6 +257,7 @@ const CustomizableWidgets = [{
} else if (node.localName == "menuitem") {
item = doc.createElementNS(kNSXUL, "toolbarbutton");
item.setAttribute("tabindex", "0");
item.setAttribute("class", "subviewbutton");
} else {
continue;
}
@ -715,6 +729,7 @@ const CustomizableWidgets = [{
elem.setAttribute("current", "true");
if (disabled)
elem.setAttribute("disabled", "true");
elem.setAttribute("class", "subviewbutton");
containerElem.appendChild(elem);
}
},

View File

@ -1780,7 +1780,7 @@ PlacesPanelMenuView.prototype = {
}
else {
button = document.createElement("toolbarbutton");
button.className = "bookmark-item";
button.className = "bookmark-item subviewbutton";
button.setAttribute("label", aChild.title);
let icon = aChild.icon;
if (icon)

View File

@ -60,7 +60,9 @@ let SessionCookiesInternal = {
// Collect all hosts for the current window.
let hosts = this.getHostsForWindow(window, true);
for (let [host, isPinned] in Iterator(hosts)) {
for (let host of Object.keys(hosts)) {
let isPinned = hosts[host];
for (let cookie of CookieStore.getCookiesForHost(host)) {
// _getCookiesForHost() will only return hosts with the right privacy
// rules, so there is no need to do anything special with this call
@ -302,7 +304,7 @@ let CookieStore = {
let cookies = [];
for (let pathToNamesMap of this._hosts.get(host).values()) {
cookies = cookies.concat([cookie for (cookie of pathToNamesMap.values())]);
cookies.push(...pathToNamesMap.values());
}
return cookies;

View File

@ -113,9 +113,9 @@ let SessionStorageInternal = {
// of missing documentURI will be solved in a followup bug to bug 600307.
let storage = storageManager.createStorage(principal, "", aDocShell.usePrivateBrowsing);
for (let [key, value] in Iterator(data)) {
for (let key of Object.keys(data)) {
try {
storage.setItem(key, value);
storage.setItem(key, data[key]);
} catch (e) {
// throws e.g. for URIs that can't have sessionStorage
console.error(e);

View File

@ -288,7 +288,8 @@ function test_setBrowserState() {
waitForBrowserState(lameMultiWindowState, function() {
let checkedWindows = 0;
for each (let [id, winEvents] in Iterator(windowEvents)) {
for (let id of Object.keys(windowEvents)) {
let winEvents = windowEvents[id];
is(winEvents.busyEventCount, 1,
"[test_setBrowserState] window" + id + " busy event count correct");
is(winEvents.readyEventCount, 1,

View File

@ -235,7 +235,7 @@ let DebuggerController = {
if (target.chrome) {
this._startChromeDebugging(chromeDebugger, startedDebugging.resolve);
} else {
this._startDebuggingTab(threadActor, startedDebugging.resolve);
this._startDebuggingTab(startedDebugging.resolve);
const startedTracing = promise.defer();
this._startTracingTab(traceActor, startedTracing.resolve);
@ -339,13 +339,13 @@ let DebuggerController = {
/**
* Sets up a debugging session.
*
* @param string aThreadActor
* The remote protocol grip of the tab.
* @param function aCallback
* A function to invoke once the client attaches to the active thread.
*/
_startDebuggingTab: function(aThreadActor, aCallback) {
this.client.attachThread(aThreadActor, (aResponse, aThreadClient) => {
_startDebuggingTab: function(aCallback) {
this._target.activeTab.attachThread({
useSourceMaps: Prefs.sourceMapsEnabled
}, (aResponse, aThreadClient) => {
if (!aThreadClient) {
Cu.reportError("Couldn't attach to thread: " + aResponse.error);
return;
@ -355,12 +355,14 @@ let DebuggerController = {
this.ThreadState.connect();
this.StackFrames.connect();
this.SourceScripts.connect();
if (aThreadClient.paused) {
aThreadClient.resume(this._ensureResumptionOrder);
}
if (aCallback) {
aCallback();
}
}, { useSourceMaps: Prefs.sourceMapsEnabled });
});
},
/**
@ -382,7 +384,9 @@ let DebuggerController = {
this.ThreadState.connect();
this.StackFrames.connect();
this.SourceScripts.connect();
if (aThreadClient.paused) {
aThreadClient.resume(this._ensureResumptionOrder);
}
if (aCallback) {
aCallback();
@ -419,7 +423,7 @@ let DebuggerController = {
* away old sources and get them again.
*/
reconfigureThread: function(aUseSourceMaps) {
this.client.reconfigureThread({ useSourceMaps: aUseSourceMaps }, aResponse => {
this.activeThread.reconfigure({ useSourceMaps: aUseSourceMaps }, aResponse => {
if (aResponse.error) {
let msg = "Couldn't reconfigure thread: " + aResponse.message;
Cu.reportError(msg);
@ -432,8 +436,10 @@ let DebuggerController = {
this.SourceScripts.handleTabNavigation();
// Update the stack frame list.
if (this.activeThread.paused) {
this.activeThread._clearFrames();
this.activeThread.fillFrames(CALL_STACK_PAGE_SIZE);
}
});
},

View File

@ -1068,7 +1068,24 @@ FilterView.prototype = {
_doSearch: function(aOperator = "", aText = "") {
this._searchbox.focus();
this._searchbox.value = ""; // Need to clear value beforehand. Bug 779738.
this._searchbox.value = aOperator + (aText || DebuggerView.editor.getSelection());
if (aText) {
this._searchbox.value = aOperator + aText;
}
else if (DebuggerView.editor.somethingSelected()) {
this._searchbox.value = aOperator + DebuggerView.editor.getSelection();
}
else {
let cursor = DebuggerView.editor.getCursor();
let content = DebuggerView.editor.getText();
let location = DebuggerView.Sources.selectedValue;
let source = DebuggerController.Parser.get(content, location);
let identifier = source.getIdentifierAt({ line: cursor.line+1, column: cursor.ch });
if (identifier && identifier.name) {
this._searchbox.value = aOperator + identifier.name;
}
}
},
/**

View File

@ -247,6 +247,7 @@ support-files =
[browser_dbg_variables-view-webidl.js]
[browser_dbg_watch-expressions-01.js]
[browser_dbg_watch-expressions-02.js]
[browser_dbg_search-function.js]
[browser_dbg_chrome-create.js]
skip-if = os == "linux" # Bug 847558
[browser_dbg_on-pause-raise.js]

View File

@ -32,7 +32,7 @@ function test() {
is(gEvents.itemCount, 0, "There should be no events before reloading.");
let reloaded = waitForSourcesAfterReload();
gDebugger.gClient.activeTab.reload();
gDebugger.DebuggerController._target.activeTab.reload();
is(gEvents.itemCount, 0, "There should be no events while reloading.");
yield reloaded;

View File

@ -47,7 +47,7 @@ function test() {
let reloading = once(gDebugger.gTarget, "will-navigate");
let reloaded = waitForSourcesAfterReload();
gDebugger.gClient.activeTab.reload();
gDebugger.DebuggerController._target.activeTab.reload();
yield reloading;
@ -89,7 +89,7 @@ function test() {
let reloading = once(gDebugger.gTarget, "will-navigate");
let reloaded = waitForSourcesAfterReload();
gDebugger.gClient.activeTab.reload();
gDebugger.DebuggerController._target.activeTab.reload();
yield reloading;

View File

@ -68,7 +68,7 @@ function testBreakOnAll() {
// Test calling pauseOnDOMEvents from a paused state.
gThreadClient.pauseOnDOMEvents("*", (aPacket) => {
is(aPacket, undefined,
is(aPacket.error, undefined,
"The pause-on-any-event request completed successfully.");
gClient.addOneTimeListener("paused", (aEvent, aPacket) => {

View File

@ -0,0 +1,28 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that Debugger Search uses the identifier under cursor
* if nothing is selected or manually passed
*/
"use strict";
function test() {
const TAB_URL = EXAMPLE_URL + "doc_function-search.html";
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
let Source = 'code_function-search-01.js';
let Debugger = aPanel.panelWin;
let Editor = Debugger.DebuggerView.editor;
let Filtering = Debugger.DebuggerView.Filtering;
waitForSourceShown(aPanel, Source).then(() => {
Editor.setCursor({ line: 7, ch: 0});
Filtering._doSearch("@");
is(Filtering._searchbox.value, "@test", "Searchbox value should be set to the identifier under cursor if no aText or selection provided");
closeDebuggerAndFinish(aPanel);
});
});
};

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_binary_search.html";
const JS_URL = EXAMPLE_URL + "code_binary_search.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources, gFrames, gPrefs, gOptions;
let gDebuggee, gPanel, gDebugger, gEditor;
let gSources, gFrames, gPrefs, gOptions;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -26,7 +25,6 @@ function test() {
waitForSourceShown(gPanel, ".coffee")
.then(testToggleGeneratedSource)
.then(testSetBreakpoint)
.then(testHitBreakpoint)
.then(testToggleOnPause)
.then(testResume)
.then(() => closeDebuggerAndFinish(gPanel))
@ -68,19 +66,7 @@ function testSetBreakpoint() {
ok(!aResponse.error,
"Should be able to set a breakpoint in a js file.");
deferred.resolve();
});
return deferred.promise;
}
function testHitBreakpoint() {
let deferred = promise.defer();
gDebugger.gThreadClient.resume(aResponse => {
ok(!aResponse.error, "Shouldn't get an error resuming.");
is(aResponse.type, "resumed", "Type should be 'resumed'.");
gDebugger.gClient.addOneTimeListener("resumed", () => {
waitForCaretAndScopes(gPanel, 7).then(() => {
// Make sure that we have JavaScript stack frames.
is(gFrames.itemCount, 1,
@ -97,6 +83,7 @@ function testHitBreakpoint() {
// paused state.
gDebuggee.binary_search([0, 2, 3, 5, 7, 10], 5);
});
});
return deferred.promise;
}
@ -148,7 +135,6 @@ function testResume() {
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_minified.html";
const JS_URL = EXAMPLE_URL + "code_math.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gDebuggee, gPanel, gDebugger;
let gEditor, gSources, gFrames;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -24,7 +23,6 @@ function test() {
waitForSourceShown(gPanel, JS_URL)
.then(checkInitialSource)
.then(testSetBreakpoint)
.then(testHitBreakpoint)
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
@ -45,27 +43,13 @@ function checkInitialSource() {
function testSetBreakpoint() {
let deferred = promise.defer();
gDebugger.gThreadClient.interrupt(aResponse => {
gDebugger.gThreadClient.setBreakpoint({ url: JS_URL, line: 30, column: 21 }, aResponse => {
ok(!aResponse.error,
"Should be able to set a breakpoint in a js file.");
ok(!aResponse.actualLocation,
"Should be able to set a breakpoint on line 30 and column 10.");
deferred.resolve();
});
});
return deferred.promise;
}
function testHitBreakpoint() {
let deferred = promise.defer();
gDebugger.gThreadClient.resume(aResponse => {
ok(!aResponse.error, "Shouldn't get an error resuming.");
is(aResponse.type, "resumed", "Type should be 'resumed'.");
gDebugger.gClient.addOneTimeListener("resumed", () => {
waitForCaretAndScopes(gPanel, 30).then(() => {
// Make sure that we have the right stack frames.
is(gFrames.itemCount, 9,
@ -82,13 +66,12 @@ function testHitBreakpoint() {
// paused state.
gDebuggee.arithmetic();
});
});
return deferred.promise;
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;

View File

@ -101,7 +101,7 @@ function testSetBreakpoint() {
function reloadPage() {
let loaded = waitForSourceAndCaret(gPanel, ".js", 3);
gDebugger.gClient.activeTab.reload();
gDebugger.DebuggerController._target.activeTab.reload();
return loaded.then(() => ok(true, "Page was reloaded and execution resumed."));
}

View File

@ -410,7 +410,7 @@ function ensureThreadClientState(aPanel, aState) {
function navigateActiveTabTo(aPanel, aUrl, aWaitForEventName, aEventRepeat) {
let finished = waitForDebuggerEvents(aPanel, aWaitForEventName, aEventRepeat);
let activeTab = aPanel.panelWin.gClient.activeTab;
let activeTab = aPanel.panelWin.DebuggerController._target.activeTab;
aUrl ? activeTab.navigateTo(aUrl) : activeTab.reload();
return finished;
}

View File

@ -194,17 +194,16 @@ FontInspector.prototype = {
!this.inspector.selection.isElementNode()) {
return;
}
let node = this.inspector.selection.nodeFront;
let contentDocument = node.ownerDocument;
let root = contentDocument.documentElement;
if (contentDocument.body) {
root = contentDocument.body;
}
this.inspector.selection.setNode(root, "fontinspector");
// Select the body node to show all fonts
let walker = this.inspector.walker;
walker.getRootNode().then(root => walker.querySelector(root, "body")).then(body => {
this.inspector.selection.setNodeFront(body, "fontinspector");
});
},
}
window.setPanel = function(panel) {
window.fontInspector = new FontInspector(panel, window);
}

View File

@ -12,8 +12,8 @@ function test() {
waitForExplicitFinish();
let doc;
let node;
let view;
let viewDoc;
let inspector;
gBrowser.selectedTab = gBrowser.addTab();
@ -43,25 +43,23 @@ function test() {
}
function openFontInspector(aInspector) {
inspector = aInspector;
info("Inspector open");
inspector = aInspector;
inspector.selection.setNode(doc.body);
inspector.sidebar.select("fontinspector");
inspector.sidebar.once("fontinspector-ready", viewReady);
inspector.sidebar.once("fontinspector-ready", testBodyFonts);
}
function viewReady() {
function testBodyFonts() {
info("Font Inspector ready");
view = inspector.sidebar.getWindowForTab("fontinspector");
viewDoc = view.document;
ok(!!view.fontInspector, "Font inspector document is alive.");
let d = view.document;
let s = d.querySelectorAll("#all-fonts > section");
let s = viewDoc.querySelectorAll("#all-fonts > section");
is(s.length, 2, "Found 2 fonts");
is(s[0].querySelector(".font-name").textContent,
@ -76,7 +74,6 @@ function test() {
is(s[0].querySelector(".font-css-name").textContent,
"bar", "font 0: right css name");
let font1Name = s[1].querySelector(".font-name").textContent;
let font1CssName = s[1].querySelector(".font-css-name").textContent;
@ -89,14 +86,40 @@ function test() {
ok((font1CssName == "Arial") || (font1CssName == "Liberation Sans"),
"Arial", "font 1: right css name");
executeSoon(function() {
gDevTools.once("toolbox-destroyed", finishUp);
inspector._toolbox.destroy();
testDivFonts();
}
function testDivFonts() {
inspector.selection.setNode(doc.querySelector("div"));
inspector.once("inspector-updated", () => {
let s = viewDoc.querySelectorAll("#all-fonts > section");
is(s.length, 1, "Found 1 font on DIV");
is(s[0].querySelector(".font-name").textContent, "DeLarge Bold",
"The DIV font has the right name");
testShowAllFonts();
});
}
function testShowAllFonts() {
viewDoc.querySelector("#showall").click();
inspector.once("inspector-updated", () => {
is(inspector.selection.node, doc.body, "Show all fonts selected the body node");
let s = viewDoc.querySelectorAll("#all-fonts > section");
is(s.length, 2, "And font-inspector still shows 2 fonts for body");
finishUp();
});
}
function finishUp() {
executeSoon(function() {
gDevTools.once("toolbox-destroyed", () => {
doc = view = viewDoc = inspector = null;
gBrowser.removeCurrentTab();
finish();
});
inspector._toolbox.destroy();
});
}
}

View File

@ -284,6 +284,7 @@ TabTarget.prototype = {
this._remote.reject("Unable to attach to the tab");
return;
}
this.activeTab = aTabClient;
this.threadActor = aResponse.threadActor;
this._remote.resolve(null);
});
@ -444,11 +445,14 @@ TabTarget.prototype = {
this._teardownListeners();
}
let cleanupAndResolve = () => {
this._cleanup();
this._destroyer.resolve(null);
};
// If this target was not remoted, the promise will be resolved before the
// function returns.
if (this._tab && !this._client) {
this._cleanup();
this._destroyer.resolve(null);
cleanupAndResolve();
} else if (this._client) {
// If, on the other hand, this target was remoted, the promise will be
// resolved after the remote connection is closed.
@ -457,15 +461,15 @@ TabTarget.prototype = {
if (this.isLocalTab) {
// We started with a local tab and created the client ourselves, so we
// should close it.
this._client.close(() => {
this._cleanup();
this._destroyer.resolve(null);
});
this._client.close(cleanupAndResolve);
} else {
// The client was handed to us, so we are not responsible for closing
// it.
this._cleanup();
this._destroyer.resolve(null);
// it. We just need to detach from the tab, if already attached.
if (this.activeTab) {
this.activeTab.detach(cleanupAndResolve);
} else {
cleanupAndResolve();
}
}
}
@ -481,6 +485,7 @@ TabTarget.prototype = {
} else {
promiseTargets.delete(this._form);
}
this.activeTab = null;
this._client = null;
this._tab = null;
this._form = null;

View File

@ -212,7 +212,7 @@ OptionsPanel.prototype = {
}.bind(menulist));
}
this.target.client.attachTab(this.target.client.activeTab._actor, (response) => {
this.target.client.attachTab(this.target.activeTab._actor, (response) => {
this._origJavascriptEnabled = response.javascriptEnabled;
this._origCacheEnabled = response.cacheEnabled;
@ -248,7 +248,7 @@ OptionsPanel.prototype = {
"javascriptEnabled": !checked
};
this.target.client.reconfigureTab(options);
this.target.activeTab.reconfigure(options);
},
/**
@ -264,7 +264,7 @@ OptionsPanel.prototype = {
"cacheEnabled": !checked
};
this.target.client.reconfigureTab(options);
this.target.activeTab.reconfigure(options);
},
destroy: function() {
@ -291,7 +291,7 @@ OptionsPanel.prototype = {
"cacheEnabled": this._origCacheEnabled,
"javascriptEnabled": this._origJavascriptEnabled
};
this.target.client.reconfigureTab(options, () => {
this.target.activeTab.reconfigure(options, () => {
this.toolbox = null;
deferred.resolve();
}, true);

View File

@ -1217,7 +1217,7 @@ Toolbox.prototype = {
outstanding.push(panel.destroy());
} catch (e) {
// We don't want to stop here if any panel fail to close.
console.error(e);
console.error("Panel " + id + ":", e);
}
}

View File

@ -229,12 +229,12 @@ function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate"
}
function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.client.activeTab.navigateTo(aUrl));
executeSoon(() => aTarget.activeTab.navigateTo(aUrl));
return once(aTarget, aWaitForTargetEvent);
}
function reload(aTarget, aWaitForTargetEvent = "navigate") {
executeSoon(() => aTarget.client.activeTab.reload());
executeSoon(() => aTarget.activeTab.reload());
return once(aTarget, aWaitForTargetEvent);
}

View File

@ -9,6 +9,7 @@ const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this,
"Reflect", "resource://gre/modules/reflect.jsm");
@ -65,7 +66,7 @@ Parser.prototype = {
syntaxTrees.push(new SyntaxTree(nodes, aUrl, length));
} catch (e) {
this.errors.push(e);
log(aUrl, e);
DevToolsUtils.reportException(aUrl, e);
}
}
// Generate the AST nodes for each script.
@ -79,7 +80,7 @@ Parser.prototype = {
syntaxTrees.push(new SyntaxTree(nodes, aUrl, length, offset));
} catch (e) {
this.errors.push(e);
log(aUrl, e);
DevToolsUtils.reportException(aUrl, e);
}
}
}
@ -225,7 +226,7 @@ SyntaxTreesPool.prototype = {
// Can't guarantee that the tree traversal logic is forever perfect :)
// Language features may be added, in which case the recursive methods
// need to be updated. If an exception is thrown here, file a bug.
log("syntax tree", e);
DevToolsUtils.reportException("syntax tree", e);
}
}
this._cache.set(requestId, results);
@ -2341,26 +2342,4 @@ let SyntaxTreeVisitor = {
}
};
/**
* Logs a warning.
*
* @param string aStr
* The message to be displayed.
* @param Exception aEx
* The thrown exception.
*/
function log(aStr, aEx) {
let msg = "Warning: " + aStr + ", " + aEx.message;
if ("lineNumber" in aEx && "columnNumber" in aEx) {
msg += ", line: " + aEx.lineNumber + ", column: " + aEx.columnNumber;
}
if ("stack" in aEx) {
msg += "\n" + aEx.stack;
}
Cu.reportError(msg);
dump(msg + "\n");
};
XPCOMUtils.defineLazyGetter(Parser, "reflectionAPI", () => Reflect);

View File

@ -167,7 +167,9 @@ BreadcrumbsWidget.prototype = {
// Repeated calls to ensureElementIsVisible would interfere with each other
// and may sometimes result in incorrect scroll positions.
setNamedTimeout("breadcrumb-select", ENSURE_SELECTION_VISIBLE_DELAY, () => {
if (this._list.ensureElementIsVisible) {
this._list.ensureElementIsVisible(aElement);
}
});
},

View File

@ -510,8 +510,6 @@
#endif
@BINPATH@/components/servicesComponents.manifest
@BINPATH@/components/cryptoComponents.manifest
@BINPATH@/components/TelemetryPing.js
@BINPATH@/components/TelemetryPing.manifest
@BINPATH@/components/TelemetryStartup.js
@BINPATH@/components/TelemetryStartup.manifest
@BINPATH@/components/messageWakeupService.js

View File

@ -477,6 +477,10 @@ getUserMedia.denyRequest.accesskey = D
getUserMedia.sharingCamera.message2 = You are currently sharing your camera with this page.
getUserMedia.sharingMicrophone.message2 = You are currently sharing your microphone with this page.
getUserMedia.sharingCameraAndMicrophone.message2 = You are currently sharing your camera and microphone with this page.
getUserMedia.continueSharing.label = Continue Sharing
getUserMedia.continueSharing.accesskey = C
getUserMedia.stopSharing.label = Stop Sharing
getUserMedia.stopSharing.accesskey = S
# Mixed Content Blocker Doorhanger Notification
# LOCALIZATION NOTE - %S is brandShortName

View File

@ -643,9 +643,6 @@ Desktop browser's sync prefs.
#endif
<flyoutpanel id="prefs-flyoutpanel" class="flyout-narrow" headertext="&optionsHeader.title;">
<settings id="prefs-charencoding" label="&optionsHeader.char.title;">
<setting pref="browser.menu.showCharacterEncoding" title="&optionsHeader.char.options.label;" type="bool"/>
</settings>
<settings id="prefs-privdata" label="&clearPrivateData.title;">
<description>&clearPrivateData.label;</description>

View File

@ -121,7 +121,7 @@ HelperAppLauncherDialog.prototype = {
className: "download-filename-text"
},
{
text: aLauncher.suggestedFileName,
text: aLauncher.downloadSize,
className: "download-size-text"
},
{

View File

@ -251,9 +251,26 @@ function showBrowserSpecificIndicator(aBrowser) {
let stringBundle = chromeWin.gNavigatorBundle;
let message = stringBundle.getString("getUserMedia.sharing" + captureState + ".message2");
let mainAction = null;
let secondaryActions = null;
let windowId = aBrowser.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.currentInnerWindowID;
let mainAction = {
label: stringBundle.getString("getUserMedia.continueSharing.label"),
accessKey: stringBundle.getString("getUserMedia.continueSharing.accesskey"),
callback: function () {},
dismiss: true
};
let secondaryActions = [{
label: stringBundle.getString("getUserMedia.stopSharing.label"),
accessKey: stringBundle.getString("getUserMedia.stopSharing.accesskey"),
callback: function () {
Services.obs.notifyObservers(null, "getUserMedia:revoke", windowId);
}
}];
let options = {
hideNotNow: true,
dismissed: true,
eventCallback: function(aTopic) aTopic == "swapping"
};

View File

@ -159,7 +159,7 @@ toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
/* ----- BOOKMARK BUTTONS ----- */
toolbarbutton.bookmark-item,
toolbarbutton.bookmark-item:not(.subviewbutton),
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder {
font-weight: bold;
color: #222;
@ -199,8 +199,8 @@ toolbarbutton.bookmark-item[open="true"] {
background-color: rgba(0, 0, 0, .205);
}
toolbarbutton.bookmark-item:hover,
toolbarbutton.bookmark-item[open="true"] {
+toolbarbutton.bookmark-item:hover:not(.subviewbutton),
+toolbarbutton.bookmark-item[open="true"]:not(.subviewbutton) {
color: #FFF !important;
text-shadow: 0 1px rgba(0, 0, 0, .4) !important;
}

View File

@ -4,10 +4,6 @@
%include ../../shared/customizableui/panelUIOverlay.inc.css
.panel-subviews {
background-color: #f5f5f5;
}
@media (min-resolution: 2dppx) {
#customization-palette toolbarbutton > .toolbarbutton-icon,
#PanelUI-contents toolbarbutton > .toolbarbutton-icon {

View File

@ -6,22 +6,23 @@
%define menuPanelWidth 22.35em
%define exitSubviewGutterWidth 38px
%define buttonStateHover :not(:-moz-any([disabled],[checked="true"],[open],:active)):hover
%define buttonStateActive :not([disabled]):-moz-any([open],[checked="true"],:hover:active)
%define buttonStateHover :not(:-moz-any([disabled],[open],[checked="true"],[_moz-menuactive="true"],:active)):hover
%define buttonStateActive :not([disabled]):-moz-any([open],[checked="true"],[_moz-menuactive="true"],:hover:active)
%include ../browser.inc
.panel-subviews {
background-image: linear-gradient(to bottom, white 1px, rgba(255, 255, 255, 0) 15px);
background-color: -moz-dialog;
box-shadow: -1px 0px 0px rgba(0, 0, 0, 0.2), -1px 0px 2px rgba(0, 0, 0, 0.1), 1px 0px 0px rgba(255, 255, 255, 0.2) inset;
padding: 4px;
background-color: hsla(0,0%,100%,.97);
background-clip: padding-box;
border-right: 1px solid hsla(210,4%,10%,.2);
border-left: 1px solid hsla(210,4%,10%,.2);
box-shadow: 0 3px 5px hsla(210,4%,10%,.1),
0 0 7px hsla(210,4%,10%,.1);
color: #222426;
-moz-margin-start: @exitSubviewGutterWidth@;
}
.panel-subviews:-moz-locale-dir(rtl) {
box-shadow: 1px 0px 0px rgba(0, 0, 0, 0.2), 1px 0px 2px rgba(0, 0, 0, 0.1), -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
}
.panel-viewstack[viewtype="main"] > .panel-subviews {
transform: translateX(@menuPanelWidth@);
}
@ -34,6 +35,23 @@
-moz-box-flex: 1;
}
.panel-subview-header,
.subviewbutton.panel-subview-footer {
padding: 12px;
background-color: hsla(210,4%,10%,.04);
}
.panel-subview-header {
margin: -4px -4px 4px;
box-shadow: 0 -1px 0 hsla(210,4%,10%,.08) inset;
color: #797c80;
}
.subviewbutton.panel-subview-footer {
margin: 4px -4px -4px;
box-shadow: 0 1px 0 hsla(210,4%,10%,.08) inset;
}
#PanelUI-mainView {
display: flex;
flex-direction: column;
@ -317,8 +335,9 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
display: none;
}
panelview toolbarbutton,
#widget-overflow-list > toolbarbutton,
panelview .toolbarbutton-1,
panelview .subviewbutton,
.widget-overflow-list .toolbarbutton-1,
.customizationmode-button,
#edit-controls@inAnyPanel@ > toolbarbutton,
#zoom-controls@inAnyPanel@ > toolbarbutton,
@ -334,13 +353,43 @@ panelview toolbarbutton,
transition-duration: 150ms;
}
.PanelUI-subView .subviewbutton.panel-subview-footer {
border-radius: 0;
border: none;
}
.PanelUI-subView .subviewbutton.panel-subview-footer > .toolbarbutton-text {
-moz-padding-start: 0;
text-align: center;
}
.PanelUI-subView .subviewbutton:not(.panel-subview-footer) {
margin: 2px 0;
}
.PanelUI-subView .subviewbutton:not(.panel-subview-footer) > .toolbarbutton-text {
font-size: 1.1em;
}
.PanelUI-subView .subviewbutton.bookmark-item {
font-weight: normal;
color: inherit;
}
.PanelUI-subView menuseparator,
.PanelUI-subView toolbarseparator {
-moz-margin-start: -5px;
-moz-margin-end: -4px;
}
panelview .toolbarbutton-1,
#widget-overflow-list > toolbarbutton {
.widget-overflow-list .toolbarbutton-1 {
margin-top: 6px;
}
panelview toolbarbutton@buttonStateHover@,
#widget-overflow-list > toolbarbutton@buttonStateHover@,
panelview .toolbarbutton-1@buttonStateHover@,
panelview .subviewbutton@buttonStateHover@,
.widget-overflow-list .toolbarbutton-1@buttonStateHover@,
.customizationmode-button,
#edit-controls@inAnyPanel@ > toolbarbutton@buttonStateHover@,
#zoom-controls@inAnyPanel@ > toolbarbutton@buttonStateHover@,
@ -356,9 +405,10 @@ panelview toolbarbutton@buttonStateHover@,
border-color: hsla(210,4%,10%,.1);
}
panelview toolbarbutton@buttonStateActive@,
panelview .toolbarbutton-1@buttonStateActive@,
panelview .subviewbutton@buttonStateActive@,
.customizationmode-button@buttonStateActive@,
#widget-overflow-list > toolbarbutton@buttonStateActive@,
.widget-overflow-list .toolbarbutton-1@buttonStateActive@,
#edit-controls@inAnyPanel@ > toolbarbutton@buttonStateActive@,
#zoom-controls@inAnyPanel@ > toolbarbutton@buttonStateActive@,
#BMB_bookmarksPopup > menu@buttonStateActive@,

View File

@ -801,7 +801,7 @@ pref("browser.ui.linkify.phone", false);
pref("snav.enabled", true);
// URL to fetch about:accounts web content from.
pref("firefox.accounts.remoteUrl", "https://accounts.dev.lcip.org/mobile");
pref("identity.fxaccounts.remote.uri", "https://accounts.dev.lcip.org/mobile");
// This url, if changed, MUST continue to point to an https url. Pulling arbitrary content to inject into
// this page over http opens us up to a man-in-the-middle attack that we'd rather not face. If you are a downstream

View File

@ -102,9 +102,6 @@ public final class HomeConfig {
private static final String JSON_KEY_DEFAULT = "default";
private static final String JSON_KEY_DISABLED = "disabled";
private static final int IS_DEFAULT = 1;
private static final int IS_DISABLED = 1;
public enum Flags {
DEFAULT_PANEL,
DISABLED_PANEL
@ -138,13 +135,11 @@ public final class HomeConfig {
mFlags = EnumSet.noneOf(Flags.class);
final boolean isDefault = (json.optInt(JSON_KEY_DEFAULT, -1) == IS_DEFAULT);
if (isDefault) {
if (json.optBoolean(JSON_KEY_DEFAULT, false)) {
mFlags.add(Flags.DEFAULT_PANEL);
}
final boolean isDisabled = (json.optInt(JSON_KEY_DISABLED, -1) == IS_DISABLED);
if (isDisabled) {
if (json.optBoolean(JSON_KEY_DISABLED, false)) {
mFlags.add(Flags.DISABLED_PANEL);
}
@ -300,11 +295,11 @@ public final class HomeConfig {
}
if (mFlags.contains(Flags.DEFAULT_PANEL)) {
json.put(JSON_KEY_DEFAULT, IS_DEFAULT);
json.put(JSON_KEY_DEFAULT, true);
}
if (mFlags.contains(Flags.DISABLED_PANEL)) {
json.put(JSON_KEY_DISABLED, IS_DISABLED);
json.put(JSON_KEY_DISABLED, true);
}
return json;

View File

@ -221,7 +221,12 @@ public class TopSitesPanel extends HomeFragment {
@Override
public void onDestroyView() {
super.onDestroyView();
// Discard any additional item clicks on the list
// as the panel is getting destroyed (see bug 930160).
mList.setOnItemClickListener(null);
mList = null;
mGrid = null;
mListAdapter = null;
mGridAdapter = null;

View File

@ -270,7 +270,7 @@ var PluginHelper = {
// "Learn More..." link in the missing plugin error message.
let learnMoreLink = doc.getAnonymousElementByAttribute(plugin, "class", "unsupportedLearnMoreLink");
let learnMoreUrl = Services.urlFormatter.formatURLPref("app.support.baseURL");
learnMoreUrl += "why-cant-firefox-mobile-play-flash-on-my-device";
learnMoreUrl += "mobile-flash-unsupported";
learnMoreLink.href = learnMoreUrl;
overlay.classList.add("visible");
break;

View File

@ -93,7 +93,7 @@ let wrapper = {
get accountsURI() {
delete this.accountsURI;
return this.accountsURI = Services.urlFormatter.formatURLPref("firefox.accounts.remoteUrl");
return this.accountsURI = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.uri");
},
handleRemoteCommand: function (evt) {

View File

@ -384,8 +384,6 @@
@BINPATH@/components/nsINIProcessor.js
@BINPATH@/components/nsPrompter.manifest
@BINPATH@/components/nsPrompter.js
@BINPATH@/components/TelemetryPing.js
@BINPATH@/components/TelemetryPing.manifest
@BINPATH@/components/TelemetryStartup.js
@BINPATH@/components/TelemetryStartup.manifest
@BINPATH@/components/Webapps.js

View File

@ -582,7 +582,7 @@ this.FxAccounts.prototype = Object.freeze({
// Return the URI of the remote UI flows.
getAccountsURI: function() {
let url = Services.urlFormatter.formatURLPref("firefox.accounts.remoteUrl");
let url = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.uri");
if (!/^https:/.test(url)) { // Comment to un-break emacs js-mode highlighting
throw new Error("Firefox Accounts server must use HTTPS");
}

View File

@ -116,13 +116,13 @@ MockFxAccounts.prototype = {
add_test(function test_non_https_remote_server_uri() {
Services.prefs.setCharPref(
"firefox.accounts.remoteUrl",
"identity.fxaccounts.remote.uri",
"http://example.com/browser/browser/base/content/test/general/accounts_testRemoteCommands.html");
do_check_throws_message(function () {
fxAccounts.getAccountsURI();
}, "Firefox Accounts server must use HTTPS");
Services.prefs.clearUserPref("firefox.accounts.remoteUrl");
Services.prefs.clearUserPref("identity.fxaccounts.remote.uri");
run_next_test();
});

View File

@ -66,11 +66,35 @@ WeaveService.prototype = {
},
get fxAccountsEnabled() {
let fxAccountsEnabled = false;
// first check if Firefox accounts is available at all. This is so we can
// get this landed without forcing Fxa to be used (and require nightly
// testers to manually set this pref)
// Once we decide we want Fxa to be available, we just remove this block.
let fxAccountsAvailable;
try {
fxAccountsEnabled = Services.prefs.getBoolPref("identity.fxaccounts.enabled");
fxAccountsAvailable = Services.prefs.getBoolPref("identity.fxaccounts.enabled");
} catch (_) {
}
if (!fxAccountsAvailable) {
// Currently we don't support toggling this pref after initialization, so
// inject the pref value as a regular boolean.
delete this.fxAccountsEnabled;
this.fxAccountsEnabled = false;
return false;
}
// work out what identity manager to use. This is stored in a preference;
// if the preference exists, we trust it.
let fxAccountsEnabled;
try {
fxAccountsEnabled = Services.prefs.getBoolPref("services.sync.fxaccounts.enabled");
} catch (_) {
// That pref doesn't exist - so let's assume this is a first-run.
// If sync already appears configured, we assume it's for the legacy
// provider.
let prefs = Services.prefs.getBranch(SYNC_PREFS_BRANCH);
fxAccountsEnabled = !prefs.prefHasUserValue("username");
Services.prefs.setBoolPref("services.sync.fxaccounts.enabled", fxAccountsEnabled);
}
// Currently we don't support toggling this pref after initialization, so
// inject the pref value as a regular boolean.
delete this.fxAccountsEnabled;

View File

@ -65,7 +65,7 @@ const TEST_STORE_FILE_NAME = "test-downloads.json";
const TEST_REFERRER_URL = "http://www.example.com/referrer.html";
const TEST_DATA_SHORT = "This test string is downloaded.";
// Generate using gzipCompressString in TelemetryPing.js.
// Generate using gzipCompressString in TelemetryPing.jsm.
const TEST_DATA_SHORT_GZIP_ENCODED_FIRST = [
31,139,8,0,0,0,0,0,0,3,11,201,200,44,86,40,73,45,46,81,40,46,41,202,204
];

View File

@ -4866,6 +4866,34 @@
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took to display a selected source to the user."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETAB_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure tab' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETAB_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure tab' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_LOCAL_RECONFIGURETHREAD_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure thread' request to go round trip."
},
"DEVTOOLS_DEBUGGER_RDP_REMOTE_RECONFIGURETHREAD_MS": {
"expires_in_version": "never",
"kind": "exponential",
"high": "10000",
"n_buckets": "1000",
"description": "The time (in milliseconds) that it took a 'reconfigure thread' request to go round trip."
},
"WEBRTC_ICE_SUCCESS_RATE": {
"expires_in_version": "never",
"kind": "boolean",

View File

@ -1,23 +0,0 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* 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/. */
"use strict";
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm")
Components.utils.import("resource://gre/modules/Deprecated.jsm");
let JSM = {};
Components.utils.import("resource://gre/modules/TelemetryPing.jsm", JSM);
function TelemetryPing() {
Deprecated.warning("nsITelemetryPing is deprecated. Please use TelemetryPing.jsm instead",
"https://bugzilla.mozilla.org/show_bug.cgi?id=913070");
}
TelemetryPing.prototype = Object.create(JSM.TelemetryPing);
TelemetryPing.prototype.classID = Components.ID("{55d6a5fa-130e-4ee6-a158-0133af3b86ba}");
TelemetryPing.prototype.QueryInterface = XPCOMUtils.generateQI([Components.interfaces.nsITelemetryPing]);
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TelemetryPing]);

View File

@ -1,2 +0,0 @@
component {55d6a5fa-130e-4ee6-a158-0133af3b86ba} TelemetryPing.js
contract @mozilla.org/base/telemetry-ping;1 {55d6a5fa-130e-4ee6-a158-0133af3b86ba}

View File

@ -8,7 +8,6 @@ TEST_DIRS += ['tests']
XPIDL_SOURCES += [
'nsITelemetry.idl',
'nsITelemetryPing.idl',
]
XPIDL_MODULE = 'telemetry'
@ -24,8 +23,6 @@ SOURCES += [
]
EXTRA_COMPONENTS += [
'TelemetryPing.js',
'TelemetryPing.manifest',
'TelemetryStartup.js',
'TelemetryStartup.manifest'
]

View File

@ -1,66 +0,0 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
/* 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/. */
#include "nsIObserver.idl"
interface nsIFile;
[scriptable, uuid(32fbb784-a20c-49aa-9db9-9a0da1c2f7d8)]
interface nsITelemetryPing : nsIObserver {
/**
* Return the current telemetry payload.
*/
jsval getPayload();
/**
* Save histograms to a file.
*
* @param aFile - File to load from.
* @param aSync - Use sync writes.
*/
void saveHistograms(in nsIFile aFile, in boolean aSync);
/**
* Collect and store information about startup.
*/
void gatherStartup();
/**
* Notify observers when loads and saves finish. Used only for testing.
*/
void enableLoadSaveNotifications();
/**
* Cache the profile directory for later use.
*/
void cacheProfileDirectory();
/**
* Inform the ping which AddOns are installed.
*
* @param aAddOns - The AddOns.
*/
void setAddOns(in AString aAddOns);
/**
* Send a ping to a test server. Used only for testing.
*
* @param aServer - The server.
*/
void testPing(in AString aServer);
/**
* Load histograms from a file.
*
* @param aFile - File to load from.
* @param aSync - Use sync reads.
*/
void testLoadHistograms(in nsIFile aFile, in boolean aSync);
/**
* Return the path component of the current submission URL.
*/
AString submissionPath();
};

View File

@ -468,7 +468,7 @@
<children/>
<xul:menuitem class="menuitem-iconic popup-notification-closeitem close-icon"
label="&closeNotificationItem.label;"
xbl:inherits="oncommand=closeitemcommand"/>
xbl:inherits="oncommand=closeitemcommand,hidden=hidenotnow"/>
</xul:menupopup>
</xul:button>
</xul:hbox>

View File

@ -16,18 +16,22 @@ let { Services } = Components.utils.import("resource://gre/modules/Services.jsm"
this.safeErrorString = function safeErrorString(aError) {
try {
let errorString = aError.toString();
if (typeof errorString === "string") {
if (typeof errorString == "string") {
// Attempt to attach a stack to |errorString|. If it throws an error, or
// isn't a string, don't use it.
try {
if (aError.stack) {
let stack = aError.stack.toString();
if (typeof stack === "string") {
if (typeof stack == "string") {
errorString += "\nStack: " + stack;
}
}
} catch (ee) { }
if (typeof aError.lineNumber == "number" && typeof aError.columnNumber == "number") {
errorString += ", line: " + aError.lineNumber + ", column: " + aError.columnNumber;
}
return errorString;
}
} catch (ee) { }

View File

@ -234,9 +234,12 @@ this.DebuggerClient = function (aTransport)
{
this._transport = aTransport;
this._transport.hooks = this;
this._threadClients = {};
this._tabClients = {};
this._consoleClients = {};
// Map actor ID to client instance for each actor type.
this._threadClients = new Map;
this._tabClients = new Map;
this._tracerClients = new Map;
this._consoleClients = new Map;
this._pendingRequests = [];
this._activeRequests = new Map;
@ -281,7 +284,7 @@ this.DebuggerClient = function (aTransport)
*/
DebuggerClient.requester = function (aPacketSkeleton,
{ telemetry, before, after }) {
return function (...args) {
return DevToolsUtils.makeInfallible(function (...args) {
let histogram, startTime;
if (telemetry) {
let transportType = this._transport.onOutputStreamReady === undefined
@ -311,7 +314,7 @@ DebuggerClient.requester = function (aPacketSkeleton,
outgoingPacket = before.call(this, outgoingPacket);
}
this.request(outgoingPacket, function (aResponse) {
this.request(outgoingPacket, DevToolsUtils.makeInfallible(function (aResponse) {
if (after) {
let { from } = aResponse;
aResponse = after.call(this, aResponse);
@ -323,19 +326,15 @@ DebuggerClient.requester = function (aPacketSkeleton,
// The callback is always the last parameter.
let thisCallback = args[maxPosition + 1];
if (thisCallback) {
try {
thisCallback(aResponse);
} catch (e) {
DevToolsUtils.reportException("DebuggerClient.requester callback", e);
}
}
if (histogram) {
histogram.add(+new Date - startTime);
}
}.bind(this));
}.bind(this), "DebuggerClient.requester request callback"));
};
}, "DebuggerClient.requester");
};
function args(aPos) {
@ -390,43 +389,35 @@ DebuggerClient.prototype = {
});
}
// In this function, we're using the hoisting behavior of nested
// function definitions to write the code in the order it will actually
// execute. So converting to arrow functions to get rid of 'self' would
// be unhelpful here.
let self = this;
const detachClients = (clientMap, next) => {
const clients = clientMap.values();
const total = clientMap.size;
let numFinished = 0;
let continuation = function () {
self._consoleClients = {};
detachThread();
if (total == 0) {
next();
return;
}
for each (let client in this._consoleClients) {
continuation = client.close.bind(client, continuation);
for (let client of clients) {
let method = client instanceof WebConsoleClient ? "close" : "detach";
client[method](() => {
if (++numFinished === total) {
clientMap.clear();
next();
}
});
}
};
continuation();
function detachThread() {
if (self.activeThread) {
self.activeThread.detach(detachTab);
} else {
detachTab();
}
}
function detachTab() {
if (self.activeTab) {
self.activeTab.detach(closeTransport);
} else {
closeTransport();
}
}
function closeTransport() {
self._transport.close();
self._transport = null;
}
detachClients(this._consoleClients, () => {
detachClients(this._threadClients, () => {
detachClients(this._tabClients, () => {
this._transport.close();
this._transport = null;
});
});
});
},
/*
@ -451,6 +442,16 @@ DebuggerClient.prototype = {
* (which will be undefined on error).
*/
attachTab: function (aTabActor, aOnResponse) {
if (this._tabClients.has(aTabActor)) {
let cachedTab = this._tabClients.get(aTabActor);
let cachedResponse = {
cacheEnabled: cachedTab.cacheEnabled,
javascriptEnabled: cachedTab.javascriptEnabled
};
setTimeout(() => aOnResponse(cachedResponse, cachedTab), 0);
return;
}
let packet = {
to: aTabActor,
type: "attach"
@ -458,9 +459,8 @@ DebuggerClient.prototype = {
this.request(packet, (aResponse) => {
let tabClient;
if (!aResponse.error) {
tabClient = new TabClient(this, aTabActor);
this._tabClients[aTabActor] = tabClient;
this.activeTab = tabClient;
tabClient = new TabClient(this, aResponse);
this._tabClients.set(aTabActor, tabClient);
}
aOnResponse(aResponse, tabClient);
});
@ -479,6 +479,11 @@ DebuggerClient.prototype = {
*/
attachConsole:
function (aConsoleActor, aListeners, aOnResponse) {
if (this._consoleClients.has(aConsoleActor)) {
setTimeout(() => aOnResponse({}, this._consoleClients.get(aConsoleActor)), 0);
return;
}
let packet = {
to: aConsoleActor,
type: "startListeners",
@ -489,14 +494,14 @@ DebuggerClient.prototype = {
let consoleClient;
if (!aResponse.error) {
consoleClient = new WebConsoleClient(this, aConsoleActor);
this._consoleClients[aConsoleActor] = consoleClient;
this._consoleClients.set(aConsoleActor, consoleClient);
}
aOnResponse(aResponse, consoleClient);
});
},
/**
* Attach to a thread actor.
* Attach to a global-scoped thread actor for chrome debugging.
*
* @param string aThreadActor
* The actor ID for the thread to attach.
@ -508,6 +513,11 @@ DebuggerClient.prototype = {
* - useSourceMaps: whether to use source maps or not.
*/
attachThread: function (aThreadActor, aOnResponse, aOptions={}) {
if (this._threadClients.has(aThreadActor)) {
setTimeout(() => aOnResponse({}, this._threadClients.get(aThreadActor)), 0);
return;
}
let packet = {
to: aThreadActor,
type: "attach",
@ -516,8 +526,7 @@ DebuggerClient.prototype = {
this.request(packet, (aResponse) => {
if (!aResponse.error) {
var threadClient = new ThreadClient(this, aThreadActor);
this._threadClients[aThreadActor] = threadClient;
this.activeThread = threadClient;
this._threadClients.set(aThreadActor, threadClient);
}
aOnResponse(aResponse, threadClient);
});
@ -533,52 +542,24 @@ DebuggerClient.prototype = {
* (which will be undefined on error).
*/
attachTracer: function (aTraceActor, aOnResponse) {
if (this._tracerClients.has(aTraceActor)) {
setTimeout(() => aOnResponse({}, this._tracerClients.get(aTraceActor)), 0);
return;
}
let packet = {
to: aTraceActor,
type: "attach"
};
this.request(packet, (aResponse) => {
if (!aResponse.error) {
let traceClient = new TraceClient(this, aTraceActor);
aOnResponse(aResponse, traceClient);
var traceClient = new TraceClient(this, aTraceActor);
this._tracerClients.set(aTraceActor, traceClient);
}
aOnResponse(aResponse, traceClient);
});
},
/**
* Reconfigure a thread actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the thread actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigureThread: function (aOptions, aOnResponse) {
let packet = {
to: this.activeThread._actor,
type: "reconfigure",
options: aOptions
};
this.request(packet, aOnResponse);
},
/**
* Reconfigure a tab actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the tab actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigureTab: function (aOptions, aOnResponse) {
let packet = {
to: this.activeTab._actor,
type: "reconfigure",
options: aOptions
};
this.request(packet, aOnResponse);
},
/**
* Release an object actor.
*
@ -697,17 +678,18 @@ DebuggerClient.prototype = {
// Packets that indicate thread state changes get special treatment.
if (aPacket.type in ThreadStateTypes &&
aPacket.from in this._threadClients) {
this._threadClients[aPacket.from]._onThreadState(aPacket);
this._threadClients.has(aPacket.from)) {
this._threadClients.get(aPacket.from)._onThreadState(aPacket);
}
// On navigation the server resumes, so the client must resume as well.
// We achieve that by generating a fake resumption packet that triggers
// the client's thread state change listeners.
if (this.activeThread &&
aPacket.type == UnsolicitedNotifications.tabNavigated &&
aPacket.from in this._tabClients) {
let resumption = { from: this.activeThread._actor, type: "resumed" };
this.activeThread._onThreadState(resumption);
if (aPacket.type == UnsolicitedNotifications.tabNavigated &&
this._tabClients.has(aPacket.from) &&
this._tabClients.get(aPacket.from).thread) {
let thread = this._tabClients.get(aPacket.from).thread;
let resumption = { from: thread._actor, type: "resumed" };
thread._onThreadState(resumption);
}
// Only try to notify listeners on events, not responses to requests
// that lack a packet type.
@ -959,18 +941,52 @@ SSProto.translatePacket = function (aPacket, aReplacePacket, aExtraPacket,
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aActor string
* The actor ID for this tab.
* @param aForm object
* The protocol form for this tab.
*/
function TabClient(aClient, aActor) {
this._client = aClient;
this._actor = aActor;
this.request = this._client.request;
function TabClient(aClient, aForm) {
this.client = aClient;
this._actor = aForm.from;
this._threadActor = aForm.threadActor;
this.javascriptEnabled = aForm.javascriptEnabled;
this.cacheEnabled = aForm.cacheEnabled;
this.thread = null;
this.request = this.client.request;
}
TabClient.prototype = {
get actor() { return this._actor },
get _transport() { return this._client._transport; },
get _transport() { return this.client._transport; },
/**
* Attach to a thread actor.
*
* @param object aOptions
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
* @param function aOnResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
*/
attachThread: function(aOptions={}, aOnResponse) {
if (this.thread) {
setTimeout(() => aOnResponse({}, this.thread), 0);
return;
}
let packet = {
to: this._threadActor,
type: "attach",
options: aOptions
};
this.request(packet, (aResponse) => {
if (!aResponse.error) {
this.thread = new ThreadClient(this, this._threadActor);
this.client._threadClients.set(this._threadActor, this.thread);
}
aOnResponse(aResponse, this.thread);
});
},
/**
* Detach the client from the tab actor.
@ -981,11 +997,14 @@ TabClient.prototype = {
detach: DebuggerClient.requester({
type: "detach"
}, {
after: function (aResponse) {
if (this.activeTab === this._client._tabClients[this.actor]) {
this.activeTab = undefined;
before: function (aPacket) {
if (this.thread) {
this.thread.detach();
}
delete this._client._tabClients[this.actor];
return aPacket;
},
after: function (aResponse) {
this.client._tabClients.delete(this.actor);
return aResponse;
},
telemetry: "TABDETACH"
@ -1012,6 +1031,21 @@ TabClient.prototype = {
}, {
telemetry: "NAVIGATETO"
}),
/**
* Reconfigure the tab actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the tab actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: args(0)
}, {
telemetry: "RECONFIGURETAB"
}),
};
eventSource(TabClient.prototype);
@ -1077,19 +1111,21 @@ RootClient.prototype = {
* is a front to the thread actor created in the server side, hiding the
* protocol details in a traditional JavaScript API.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aClient DebuggerClient|TabClient
* The parent of the thread (tab for tab-scoped debuggers, DebuggerClient
* for chrome debuggers).
* @param aActor string
* The actor ID for this thread.
*/
function ThreadClient(aClient, aActor) {
this._client = aClient;
this._parent = aClient;
this.client = aClient instanceof DebuggerClient ? aClient : aClient.client;
this._actor = aActor;
this._frameCache = [];
this._scriptCache = {};
this._pauseGrips = {};
this._threadGrips = {};
this.request = this._client.request;
this.request = this.client.request;
}
ThreadClient.prototype = {
@ -1104,12 +1140,12 @@ ThreadClient.prototype = {
_actor: null,
get actor() { return this._actor; },
get compat() { return this._client.compat; },
get _transport() { return this._client._transport; },
get compat() { return this.client.compat; },
get _transport() { return this.client._transport; },
_assertPaused: function (aCommand) {
if (!this.paused) {
throw Error(aCommand + " command sent while not paused.");
throw Error(aCommand + " command sent while not paused. Currently " + this._state);
}
},
@ -1156,6 +1192,21 @@ ThreadClient.prototype = {
telemetry: "RESUME"
}),
/**
* Reconfigure the thread actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the thread actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: args(0)
}, {
telemetry: "RECONFIGURETHREAD"
}),
/**
* Resume a paused thread.
*/
@ -1222,7 +1273,7 @@ ThreadClient.prototype = {
// If the debuggee is paused, we have to send the flag via a reconfigure
// request.
if (this.paused) {
this._client.reconfigureThread({
this.reconfigure({
pauseOnExceptions: aPauseOnExceptions,
ignoreCaughtExceptions: aIgnoreCaughtExceptions
}, aOnResponse);
@ -1256,12 +1307,16 @@ ThreadClient.prototype = {
// If the debuggee is paused, the value of the array will be communicated in
// the next resumption. Otherwise we have to force a pause in order to send
// the array.
if (this.paused)
return void setTimeout(onResponse, 0);
if (this.paused) {
setTimeout(() => onResponse({}), 0);
return;
}
this.interrupt(response => {
// Can't continue if pausing failed.
if (response.error)
return void onResponse(response);
if (response.error) {
onResponse(response);
return;
}
this.resume(onResponse);
});
},
@ -1310,10 +1365,8 @@ ThreadClient.prototype = {
type: "detach"
}, {
after: function (aResponse) {
if (this.activeThread === this._client._threadClients[this.actor]) {
this.activeThread = null;
}
delete this._client._threadClients[this.actor];
this.client._threadClients.delete(this.actor);
this._parent.thread = null;
return aResponse;
},
telemetry: "THREADDETACH"
@ -1332,11 +1385,11 @@ ThreadClient.prototype = {
let doSetBreakpoint = function (aCallback) {
let packet = { to: this._actor, type: "setBreakpoint",
location: aLocation };
this._client.request(packet, function (aResponse) {
this.client.request(packet, function (aResponse) {
// Ignoring errors, since the user may be setting a breakpoint in a
// dead script that will reappear on a page reload.
if (aOnResponse) {
let bpClient = new BreakpointClient(this._client, aResponse.actor,
let bpClient = new BreakpointClient(this.client, aResponse.actor,
aLocation);
if (aCallback) {
aCallback(aOnResponse(aResponse, bpClient));
@ -1570,7 +1623,7 @@ ThreadClient.prototype = {
return this._pauseGrips[aGrip.actor];
}
let client = new ObjectClient(this._client, aGrip);
let client = new ObjectClient(this.client, aGrip);
this._pauseGrips[aGrip.actor] = client;
return client;
},
@ -1590,7 +1643,7 @@ ThreadClient.prototype = {
return this[aGripCacheName][aGrip.actor];
}
let client = new LongStringClient(this._client, aGrip);
let client = new LongStringClient(this.client, aGrip);
this[aGripCacheName][aGrip.actor] = client;
return client;
},
@ -1655,14 +1708,14 @@ ThreadClient.prototype = {
this._clearFrames();
this._clearPauseGrips();
aPacket.type === ThreadStateTypes.detached && this._clearThreadGrips();
this._client._eventsEnabled && this.notify(aPacket.type, aPacket);
this.client._eventsEnabled && this.notify(aPacket.type, aPacket);
},
/**
* Return an EnvironmentClient instance for the given environment actor form.
*/
environment: function (aForm) {
return new EnvironmentClient(this._client, aForm);
return new EnvironmentClient(this.client, aForm);
},
/**
@ -1673,8 +1726,7 @@ ThreadClient.prototype = {
return this._threadGrips[aForm.actor];
}
return this._threadGrips[aForm.actor] = new SourceClient(this._client,
aForm);
return this._threadGrips[aForm.actor] = new SourceClient(this, aForm);
},
/**
@ -1724,8 +1776,15 @@ TraceClient.prototype = {
/**
* Detach from the trace actor.
*/
detach: DebuggerClient.requester({ type: "detach" },
{ telemetry: "TRACERDETACH" }),
detach: DebuggerClient.requester({
type: "detach"
}, {
after: function (aResponse) {
this._client._tracerClients.delete(this.actor);
return aResponse;
},
telemetry: "TRACERDETACH"
}),
/**
* Start a new trace.
@ -1964,8 +2023,8 @@ LongStringClient.prototype = {
/**
* A SourceClient provides a way to access the source text of a script.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aClient ThreadClient
* The thread client parent.
* @param aForm Object
* The form sent across the remote debugging protocol.
*/
@ -1973,12 +2032,12 @@ function SourceClient(aClient, aForm) {
this._form = aForm;
this._isBlackBoxed = aForm.isBlackBoxed;
this._isPrettyPrinted = aForm.isPrettyPrinted;
this._client = aClient;
this._activeThread = aClient;
this._client = aClient.client;
}
SourceClient.prototype = {
get _transport() this._client._transport,
get _activeThread() this._client.activeThread,
get isBlackBoxed() this._isBlackBoxed,
get isPrettyPrinted() this._isPrettyPrinted,
get actor() this._form.actor,
@ -2089,8 +2148,7 @@ SourceClient.prototype = {
}
let { contentType, source } = aResponse;
let longString = this._client.activeThread.threadLongString(
source);
let longString = this._activeThread.threadLongString(source);
longString.substring(0, longString.length, function (aResponse) {
if (aResponse.error) {
aCallback(aResponse);

View File

@ -655,8 +655,6 @@ ThreadActor.prototype = {
this.onResume();
}
this._state = "exited";
this.clearDebuggees();
this.conn.removeActorPool(this._threadLifetimePool);
this._threadLifetimePool = null;
@ -682,6 +680,7 @@ ThreadActor.prototype = {
*/
exit: function () {
this.disconnect();
this._state = "exited";
},
// Request handlers
@ -691,7 +690,8 @@ ThreadActor.prototype = {
}
if (this.state !== "detached") {
return { error: "wrongState" };
return { error: "wrongState",
message: "Current state is " + this.state };
}
this._state = "attached";
@ -741,6 +741,8 @@ ThreadActor.prototype = {
onDetach: function (aRequest) {
this.disconnect();
this._state = "detached";
dumpn("ThreadActor.prototype.onDetach: returning 'detached' packet");
return {
type: "detached"

View File

@ -677,7 +677,7 @@ WebappsActor.prototype = {
} catch(e) {
deferred.resolve({
error: "noIcon",
message: "The icon file '" + iconURL + "' doesn't exists"
message: "The icon file '" + iconURL + "' doesn't exist"
});
return;
}

View File

@ -890,27 +890,25 @@ BrowserTabActor.prototype = {
*/
onWindowCreated:
makeInfallible(function BTA_onWindowCreated(evt) {
if (evt.target === this.browser.contentDocument) {
// pageshow events for non-persisted pages have already been handled by a
// prior DOMWindowCreated event.
if (evt.type == "pageshow" && !evt.persisted) {
if (!this._attached || (evt.type == "pageshow" && !evt.persisted)) {
return;
}
if (this._attached) {
if (evt.target === this.browser.contentDocument ) {
this.threadActor.clearDebuggees();
if (this.threadActor.dbg) {
this.threadActor.dbg.enabled = true;
this.threadActor.global = evt.target.defaultView.wrappedJSObject;
this.threadActor.maybePauseOnExceptions();
}
}
}
if (this._attached) {
this.threadActor.global = evt.target.defaultView.wrappedJSObject;
// Refresh the debuggee list when a new window object appears (top window or
// iframe).
if (this.threadActor.attached) {
this.threadActor.findGlobals();
}
}
}, "BrowserTabActor.prototype.onWindowCreated"),
/**

View File

@ -376,6 +376,7 @@ var DebuggerServer = {
this.registerModule("devtools/server/actors/webgl");
this.registerModule("devtools/server/actors/stylesheets");
this.registerModule("devtools/server/actors/styleeditor");
this.registerModule("devtools/server/actors/tracer");
}
if (!("ContentAppActor" in DebuggerServer)) {
this.addActors("resource://gre/modules/devtools/server/actors/childtab.js");

View File

@ -154,9 +154,10 @@ function attachTestTab(aClient, aTitle, aCallback) {
// thread.
function attachTestThread(aClient, aTitle, aCallback) {
attachTestTab(aClient, aTitle, function (aResponse, aTabClient) {
aClient.attachThread(aResponse.threadActor, function (aResponse, aThreadClient) {
function onAttach(aResponse, aThreadClient) {
aCallback(aResponse, aTabClient, aThreadClient);
}, { useSourceMaps: true });
}
aTabClient.attachThread({ useSourceMaps: true }, onAttach);
});
}

View File

@ -14,15 +14,15 @@ function run_test()
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
attachTestTab(gClient, "test-1", function(aReply, aTabClient) {
test_attach(aReply.threadActor);
test_attach(aTabClient);
});
});
do_test_pending();
}
function test_attach(aThreadActorID)
function test_attach(aTabClient)
{
gClient.attachThread(aThreadActorID, function(aResponse, aThreadClient) {
aTabClient.attachThread({}, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused");
aThreadClient.resume(cleanup);
});

View File

@ -43,12 +43,12 @@ function setUpCode() {
}
function setBreakpoint() {
gClient.addOneTimeListener("resumed", runCode);
gThreadClient.setBreakpoint({
url: URL,
line: 1
}, ({ error }) => {
do_check_true(!error);
gThreadClient.resume(runCode);
});
}

View File

@ -5,6 +5,7 @@ Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
var gClient;
var gTabClient;
var gDebuggee;
function run_test()
@ -17,6 +18,7 @@ function run_test()
gClient = new DebuggerClient(transport);
gClient.connect(function(aType, aTraits) {
attachTestTab(gClient, "test-1", function(aReply, aTabClient) {
gTabClient = aTabClient;
test_threadAttach(aReply.threadActor);
});
});
@ -26,7 +28,7 @@ function run_test()
function test_threadAttach(aThreadActorID)
{
do_print("Trying to attach to thread " + aThreadActorID);
gClient.attachThread(aThreadActorID, function(aResponse, aThreadClient) {
gTabClient.attachThread({}, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.state, "paused");
do_check_eq(aThreadClient.actor, aThreadActorID);
aThreadClient.resume(function() {

View File

@ -20,21 +20,21 @@ function run_test()
function test_attach(aResponse, aTabClient)
{
gClient.attachThread(aResponse.threadActor, function(aResponse, aThreadClient) {
aTabClient.attachThread({}, function(aResponse, aThreadClient) {
do_check_eq(aThreadClient.paused, true);
aThreadClient.resume(function() {
test_interrupt();
test_interrupt(aThreadClient);
});
});
}
function test_interrupt()
function test_interrupt(aThreadClient)
{
do_check_eq(gClient.activeThread.paused, false);
gClient.activeThread.interrupt(function(aResponse) {
do_check_eq(gClient.activeThread.paused, true);
gClient.activeThread.resume(function() {
do_check_eq(gClient.activeThread.paused, false);
do_check_eq(aThreadClient.paused, false);
aThreadClient.interrupt(function(aResponse) {
do_check_eq(aThreadClient.paused, true);
aThreadClient.resume(function() {
do_check_eq(aThreadClient.paused, false);
cleanup();
});
});

View File

@ -5,7 +5,7 @@
// Test that we can detect nested event loops in tabs with the same URL.
const { defer } = devtools.require("sdk/core/promise");
var gClient1, gClient2;
var gClient1, gClient2, gThreadClient1, gThreadClient2;
function run_test() {
initTestDebuggerServer();
@ -15,6 +15,7 @@ function run_test() {
gClient1 = new DebuggerClient(DebuggerServer.connectPipe());
gClient1.connect(function () {
attachTestThread(gClient1, "test-nesting1", function (aResponse, aTabClient, aThreadClient) {
gThreadClient1 = aThreadClient;
start_second_connection();
});
});
@ -25,6 +26,7 @@ function start_second_connection() {
gClient2 = new DebuggerClient(DebuggerServer.connectPipe());
gClient2.connect(function () {
attachTestThread(gClient2, "test-nesting1", function (aResponse, aTabClient, aThreadClient) {
gThreadClient2 = aThreadClient;
test_nesting();
});
});
@ -33,15 +35,15 @@ function start_second_connection() {
function test_nesting() {
const { resolve, reject, promise } = defer();
gClient1.activeThread.resume(aResponse => {
gThreadClient1.resume(aResponse => {
do_check_eq(aResponse.error, "wrongOrder");
gClient2.activeThread.resume(aResponse => {
gThreadClient2.resume(aResponse => {
do_check_true(!aResponse.error);
do_check_eq(aResponse.from, gClient2.activeThread.actor);
do_check_eq(aResponse.from, gThreadClient2.actor);
gClient1.activeThread.resume(aResponse => {
gThreadClient1.resume(aResponse => {
do_check_true(!aResponse.error);
do_check_eq(aResponse.from, gClient1.activeThread.actor);
do_check_eq(aResponse.from, gThreadClient1.actor);
gClient1.close(() => finishClient(gClient2));
});

View File

@ -59,7 +59,7 @@ function test_definition_site(func, obj) {
function test_bad_definition_site(obj) {
try {
obj.getDefinitionSite(() => do_check_true(false));
obj._client.request("definitionSite", () => do_check_true(false));
} catch (e) {
gThreadClient.resume(() => finishClient(gClient));
}

View File

@ -0,0 +1,58 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that reattaching to a previously detached thread works.
*/
var gClient, gDebuggee, gThreadClient, gTabClient;
function run_test()
{
initTestDebuggerServer();
gDebuggee = testGlobal("test-reattach");
DebuggerServer.addTestGlobal(gDebuggee);
let transport = DebuggerServer.connectPipe();
gClient = new DebuggerClient(transport);
gClient.connect(() => {
attachTestTab(gClient, "test-reattach", (aReply, aTabClient) => {
gTabClient = aTabClient;
test_attach();
});
});
do_test_pending();
}
function test_attach()
{
gTabClient.attachThread({}, (aResponse, aThreadClient) => {
do_check_eq(aThreadClient.state, "paused");
gThreadClient = aThreadClient;
aThreadClient.resume(test_detach);
});
}
function test_detach()
{
gThreadClient.detach(() => {
do_check_eq(gThreadClient.state, "detached");
do_check_eq(gTabClient.thread, null);
test_reattach();
});
}
function test_reattach()
{
gTabClient.attachThread({}, (aResponse, aThreadClient) => {
do_check_neq(gThreadClient, aThreadClient);
do_check_eq(aThreadClient.state, "paused");
do_check_eq(gTabClient.thread, aThreadClient);
aThreadClient.resume(cleanup);
});
}
function cleanup()
{
gClient.close(do_test_finished);
}

View File

@ -30,6 +30,7 @@ reason = bug 821285
[test_dbgglobal.js]
[test_dbgclient_debuggerstatement.js]
[test_attach.js]
[test_reattach-thread.js]
[test_blackboxing-01.js]
[test_blackboxing-02.js]
[test_blackboxing-03.js]

View File

@ -19,6 +19,9 @@ function test_with_error() {
// Got the stack.
do_check_true(s.contains("test_with_error"))
do_check_true(s.contains("test_safeErrorString.js"));
// Got the lineNumber and columnNumber.
do_check_true(s.contains("line"));
do_check_true(s.contains("column"));
}
function test_with_tricky_error() {

View File

@ -196,6 +196,8 @@ PopupNotifications.prototype = {
* - accessKey (string): the button's accessKey.
* - callback (function): a callback to be invoked when the button is
* pressed.
* - [optional] dismiss (boolean): If this is true, the notification
* will be dismissed instead of removed after running the callback.
* If null, the notification will not have a button, and
* secondaryActions will be ignored.
* @param secondaryActions
@ -249,6 +251,11 @@ PopupNotifications.prototype = {
* removed when they would have otherwise been dismissed
* (i.e. any time the popup is closed due to user
* interaction).
* hideNotNow: If true, indicates that the 'Not Now' menuitem should
* not be shown. If 'Not Now' is hidden, it needs to be
* replaced by another 'do nothing' item, so providing at
* least one secondary action is required; and one of the
* actions needs to have the 'dismiss' property set to true.
* popupIconURL:
* A string. URL of the image to be displayed in the popup.
* Normally specified in CSS using list-style-image and the
@ -269,6 +276,10 @@ PopupNotifications.prototype = {
throw "PopupNotifications_show: invalid mainAction";
if (secondaryActions && secondaryActions.some(isInvalidAction))
throw "PopupNotifications_show: invalid secondaryActions";
if (options && options.hideNotNow &&
(!secondaryActions || !secondaryActions.length ||
!secondaryActions.concat(mainAction).some(action => action.dismiss)))
throw "PopupNotifications_show: 'Not Now' item hidden without replacement";
let notification = new Notification(id, message, anchorID, mainAction,
secondaryActions, browser, this, options);
@ -549,7 +560,10 @@ PopupNotifications.prototype = {
popupnotification.appendChild(item);
}, this);
if (n.secondaryActions.length) {
if (n.options.hideNotNow) {
popupnotification.setAttribute("hidenotnow", "true");
}
else if (n.secondaryActions.length) {
let closeItemSeparator = doc.createElementNS(XUL_NS, "menuseparator");
popupnotification.appendChild(closeItemSeparator);
}
@ -894,6 +908,11 @@ PopupNotifications.prototype = {
Cu.reportError(error);
}
if (notification.mainAction.dismiss) {
this._dismiss();
return;
}
this._remove(notification);
this._update();
},
@ -910,6 +929,11 @@ PopupNotifications.prototype = {
Cu.reportError(error);
}
if (target.action.dismiss) {
this._dismiss();
return;
}
this._remove(target.notification);
this._update();
},