Merge m-c to inbound

This commit is contained in:
Wes Kocher 2013-12-20 19:00:45 -08:00
commit 207a21dbe8
240 changed files with 9351 additions and 1302 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 878935 landed without a UUID change (and was since backed out)
Bug 910189 requires a clobber due to Proguard inner class errors from bug 946083.

View File

@ -280,6 +280,7 @@ pref("layers.offmainthreadcomposition.async-animations", true);
pref("layers.async-video.enabled", true);
pref("layers.async-pan-zoom.enabled", true);
pref("gfx.content.azure.backends", "cairo");
pref("layers.composer2d.enabled", true);
#endif
// Web Notifications
@ -863,6 +864,9 @@ pref("media.webspeech.synth.enabled", true);
pref("dom.mozDownloads.enabled", true);
pref("dom.downloads.max_retention_days", 7);
// Downloads API
pref("dom.mozDownloads.enabled", true);
// Inactivity time in milliseconds after which we shut down the OS.File worker.
pref("osfile.reset_worker_delay", 5000);

View File

@ -527,6 +527,9 @@ SettingsListener.observe("debug.paint-flashing.enabled", false, function(value)
SettingsListener.observe("layers.draw-borders", false, function(value) {
Services.prefs.setBoolPref("layers.draw-borders", value);
});
SettingsListener.observe("layers.composer2d.enabled", true, function(value) {
Services.prefs.setBoolPref("layers.composer2d.enabled", value);
});
// ================ Accessibility ============
SettingsListener.observe("accessibility.screenreader", false, function(value) {

View File

@ -1,4 +1,4 @@
{
"revision": "6c2b33c8f522e2fa419011bc2de456c11e76b29f",
"revision": "f7a78194ae8eddcc20af610abed89bac359067d2",
"repo_path": "/integration/gaia-central"
}

View File

@ -1313,7 +1313,6 @@ pref("security.csp.speccompliant", true);
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);
// Override the Gecko-default value of false for Firefox.
pref("plain_text.wrap_long_lines", true);
@ -1331,5 +1330,9 @@ pref("network.disable.ipc.security", true);
// CustomizableUI debug logging.
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/flow?moar_native=true");
// The URL of the Firefox Accounts auth server backend
pref("identity.fxaccounts.auth.uri", "https://api-accounts.dev.lcip.org/v1");

View File

@ -0,0 +1,21 @@
* {
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
#content {
width: 100%;
height: 100%;
border: 0;
display: flex;
}
#remote {
width: 100%;
height: 100%;
border: 0;
}

View File

@ -0,0 +1,133 @@
/* 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";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FxAccounts.jsm");
function log(msg) {
//dump("FXA: " + msg + "\n");
};
function error(msg) {
console.log("Firefox Account Error: " + msg + "\n");
};
let wrapper = {
iframe: null,
init: function () {
let iframe = document.getElementById("remote");
this.iframe = iframe;
iframe.addEventListener("load", this);
try {
iframe.src = fxAccounts.getAccountsURI();
} catch (e) {
error("Couldn't init Firefox Account wrapper: " + e.message);
}
},
handleEvent: function (evt) {
switch (evt.type) {
case "load":
this.iframe.contentWindow.addEventListener("FirefoxAccountsCommand", this);
this.iframe.removeEventListener("load", this);
break;
case "FirefoxAccountsCommand":
this.handleRemoteCommand(evt);
break;
}
},
/**
* onLogin handler receives user credentials from the jelly after a
* sucessful login and stores it in the fxaccounts service
*
* @param accountData the user's account data and credentials
*/
onLogin: function (accountData) {
log("Received: 'login'. Data:" + JSON.stringify(accountData));
fxAccounts.setSignedInUser(accountData).then(
() => {
this.injectData("message", { status: "login" });
// until we sort out a better UX, just leave the jelly page in place.
// If the account email is not yet verified, it will tell the user to
// go check their email, but then it will *not* change state after
// the verification completes (the browser will begin syncing, but
// won't notify the user). If the email has already been verified,
// the jelly will say "Welcome! You are successfully signed in as
// EMAIL", but it won't then say "syncing started".
},
(err) => this.injectData("message", { status: "error", error: err })
);
},
/**
* onSessionStatus sends the currently signed in user's credentials
* to the jelly.
*/
onSessionStatus: function () {
log("Received: 'session_status'.");
fxAccounts.getSignedInUser().then(
(accountData) => this.injectData("message", { status: "session_status", data: accountData }),
(err) => this.injectData("message", { status: "error", error: err })
);
},
/**
* onSignOut handler erases the current user's session from the fxaccounts service
*/
onSignOut: function () {
log("Received: 'sign_out'.");
fxAccounts.signOut().then(
() => this.injectData("message", { status: "sign_out" }),
(err) => this.injectData("message", { status: "error", error: err })
);
},
handleRemoteCommand: function (evt) {
log('command: ' + evt.detail.command);
let data = evt.detail.data;
switch (evt.detail.command) {
case "login":
this.onLogin(data);
break;
case "session_status":
this.onSessionStatus(data);
break;
case "sign_out":
this.onSignOut(data);
break;
default:
log("Unexpected remote command received: " + evt.detail.command + ". Ignoring command.");
break;
}
},
injectData: function (type, content) {
let authUrl;
try {
authUrl = fxAccounts.getAccountsURI();
} catch (e) {
error("Couldn't inject data: " + e.message);
return;
}
let data = {
type: type,
content: content
};
this.iframe.contentWindow.postMessage(data, authUrl);
},
};
wrapper.init();

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % aboutAccountsDTD SYSTEM "chrome://browser/locale/aboutAccounts.dtd">
%aboutAccountsDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&aboutAccounts.pageTitle;</title>
<link rel="icon" type="image/png" id="favicon"
href="chrome://branding/content/icon32.png"/>
<link rel="stylesheet"
href="chrome://browser/content/aboutaccounts/aboutaccounts.css"
type="text/css" />
</head>
<body>
<iframe mozframetype="content" id="remote" />
<script type="text/javascript;version=1.8"
src="chrome://browser/content/aboutaccounts/aboutaccounts.js" />
</body>
</html>

View File

@ -279,13 +279,20 @@ let gSyncUI = {
*/
openSetup: function SUI_openSetup(wizardType) {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win)
win.focus();
else {
window.openDialog("chrome://browser/content/sync/setup.xul",
"weaveSetup", "centerscreen,chrome,resizable=no",
wizardType);
let xps = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
if (xps.fxAccountsEnabled) {
switchToTabHavingURI("about:accounts", true);
} else {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win)
win.focus();
else {
window.openDialog("chrome://browser/content/sync/setup.xul",
"weaveSetup", "centerscreen,chrome,resizable=no",
wizardType);
}
}
},

View File

@ -472,6 +472,13 @@ var gSyncSetup = {
Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
this._handleNoScript(false);
Weave.Svc.Prefs.set("firstSync", "newAccount");
#ifdef XP_WIN
#ifdef MOZ_METRO
if (document.getElementById("metroSetupCheckbox").checked) {
Services.metro.storeSyncInfo(email, password, Weave.Service.identity.syncKey);
}
#endif
#endif
this.wizardFinish();
return false;
}

View File

@ -172,6 +172,20 @@
<label class="status" value=" "/>
</hbox>
</row>
#ifdef XP_WIN
#ifdef MOZ_METRO
<row id="metroRow" align="center">
<spacer/>
<hbox align="center">
<checkbox label="&setup.setupMetro.label;"
accesskey="&setup.setupMetro.accesskey;"
control="weavePasswordConfirm"
id="metroSetupCheckbox"
checked="true"/>
</hbox>
</row>
#endif
#endif
<row id="TOSRow" align="center">
<spacer/>
<hbox align="center">

View File

@ -0,0 +1,66 @@
# 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/.
# test_contextmenu.html and test_contextmenu_input are disabled on Linux due to bug 513558
ifndef MOZ_WIDGET_GTK
MOCHITEST_FILES += \
audio.ogg \
privateBrowsingMode.js \
subtst_contextmenu.html \
contextmenu_common.js \
test_contextmenu.html \
test_contextmenu_input.html \
$(NULL)
endif
# The following tests are disabled because they are unreliable:
# browser_bug423833.js is bug 428712
# browser_sanitize-download-history.js is bug 432425
#
# browser_sanitizeDialog_treeView.js is disabled until the tree view is added
# back to the clear recent history dialog (sanitize.xul), if it ever is (bug
# 480169)
# browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
# browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
# Disable tests on Windows due to frequent failures (bugs 825739, 841341)
ifneq (windows,$(MOZ_WIDGET_TOOLKIT))
MOCHITEST_BROWSER_FILES += \
browser_bookmark_titles.js \
browser_popupNotification.js \
$(NULL)
endif
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT))
MOCHITEST_BROWSER_FILES += \
browser_bug462289.js \
$(NULL)
else
MOCHITEST_BROWSER_FILES += \
browser_bug565667.js \
$(NULL)
endif
ifdef MOZ_DATA_REPORTING
MOCHITEST_BROWSER_FILES += \
browser_datareporting_notification.js \
$(NULL)
endif
ifdef MOZ_CRASHREPORTER
MOCHITEST_BROWSER_FILES += \
browser_pluginCrashCommentAndURL.js \
pluginCrashCommentAndURL.html \
browser_CTP_crashreporting.js \
$(NULL)
endif
# browser_CTP_context_menu.js fails intermittently on Linux (bug 909342)
ifndef MOZ_WIDGET_GTK
MOCHITEST_BROWSER_FILES += \
browser_CTP_context_menu.js \
$(NULL)
endif

View File

@ -0,0 +1,81 @@
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript;version=1.8">
function init() {
window.addEventListener("message", function process(e) {doTest(e)}, false);
// unless we relinquish the eventloop,
// tests will run before the chrome event handlers are ready
setTimeout(doTest, 0);
}
function checkStatusValue(payload, expectedValue) {
return payload.status == expectedValue;
}
let tests = [
{
info: "Check account log in",
event: "login",
data: {
email: "foo@example.com",
uid: "1234@lcip.org",
assertion: "foobar",
sessionToken: "dead",
kA: "beef",
kB: "cafe",
isVerified: true
},
payloadType: "message",
validateResponse: function(payload) {
return checkStatusValue(payload, "login");
},
},
];
let currentTest = -1;
function doTest(evt) {
if (evt) {
if (currentTest < 0 || !evt.data.content)
return; // not yet testing
let test = tests[currentTest];
if (evt.data.type != test.payloadType)
return; // skip unrequested events
let error = JSON.stringify(evt.data.content);
let pass = false;
try {
pass = test.validateResponse(evt.data.content)
} catch (e) {}
reportResult(test.info, pass, error);
}
// start the next test if there are any left
if (tests[++currentTest])
sendToBrowser(tests[currentTest].event, tests[currentTest].data);
else
reportFinished();
}
function reportResult(info, pass, error) {
let data = {type: "testResult", info: info, pass: pass, error: error};
window.parent.postMessage(data, "*");
}
function reportFinished(cmd) {
let data = {type: "testsComplete", count: tests.length};
window.parent.postMessage(data, "*");
}
function sendToBrowser(type, data) {
let event = new CustomEvent("FirefoxAccountsCommand", {detail: {command: type, data: data}, bubbles: true});
document.dispatchEvent(event);
}
</script>
</head>
<body onload="init()">
</body>
</html>

View File

@ -1,6 +1,7 @@
[DEFAULT]
support-files =
POSTSearchEngine.xml
accounts_testRemoteCommands.html
alltabslistener.html
app_bug575561.html
app_subframe_bug575561.html
@ -111,6 +112,7 @@ run-if = crashreporter
[browser_CTP_nonplugins.js]
[browser_CTP_resize.js]
[browser_URLBarSetURI.js]
[browser_aboutAccounts.js]
[browser_aboutHealthReport.js]
skip-if = os == "linux" # Bug 924307
[browser_aboutHome.js]

View File

@ -0,0 +1,89 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
registerCleanupFunction(function() {
// Ensure we don't pollute prefs for next tests.
Services.prefs.clearUserPref("firefox.accounts.remoteUrl");
});
let gTests = [
{
desc: "Test the remote commands",
setup: function ()
{
Services.prefs.setCharPref("firefox.accounts.remoteUrl",
"https://example.com/browser/browser/base/content/test/general/accounts_testRemoteCommands.html");
},
run: function ()
{
let deferred = Promise.defer();
let results = 0;
try {
let win = gBrowser.contentWindow;
win.addEventListener("message", function testLoad(e) {
if (e.data.type == "testResult") {
ok(e.data.pass, e.data.info);
results++;
}
else if (e.data.type == "testsComplete") {
is(results, e.data.count, "Checking number of results received matches the number of tests that should have run");
win.removeEventListener("message", testLoad, false, true);
deferred.resolve();
}
}, false, true);
} catch(e) {
ok(false, "Failed to get all commands");
deferred.reject();
}
return deferred.promise;
}
},
]; // gTests
function test()
{
waitForExplicitFinish();
Task.spawn(function () {
for (let test of gTests) {
info(test.desc);
test.setup();
yield promiseNewTabLoadEvent("about:accounts");
yield test.run();
gBrowser.removeCurrentTab();
}
finish();
});
}
function promiseNewTabLoadEvent(aUrl, aEventType="load")
{
let deferred = Promise.defer();
let tab = gBrowser.selectedTab = gBrowser.addTab(aUrl);
tab.linkedBrowser.addEventListener(aEventType, function load(event) {
tab.linkedBrowser.removeEventListener(aEventType, load, true);
let iframe = tab.linkedBrowser.contentDocument.getElementById("remote");
iframe.addEventListener("load", function frameLoad(e) {
iframe.removeEventListener("load", frameLoad, false);
deferred.resolve();
}, false);
}, true);
return deferred.promise;
}

View File

@ -50,6 +50,9 @@ browser.jar:
content/browser/abouthealthreport/abouthealth.js (content/abouthealthreport/abouthealth.js)
content/browser/abouthealthreport/abouthealth.css (content/abouthealthreport/abouthealth.css)
#endif
content/browser/aboutaccounts/aboutaccounts.xhtml (content/aboutaccounts/aboutaccounts.xhtml)
content/browser/aboutaccounts/aboutaccounts.js (content/aboutaccounts/aboutaccounts.js)
content/browser/aboutaccounts/aboutaccounts.css (content/aboutaccounts/aboutaccounts.css)
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
content/browser/aboutSocialError.xhtml (content/aboutSocialError.xhtml)
@ -77,10 +80,10 @@ browser.jar:
content/browser/sync/aboutSyncTabs.js (content/sync/aboutSyncTabs.js)
content/browser/sync/aboutSyncTabs.css (content/sync/aboutSyncTabs.css)
content/browser/sync/aboutSyncTabs-bindings.xml (content/sync/aboutSyncTabs-bindings.xml)
content/browser/sync/setup.xul (content/sync/setup.xul)
* content/browser/sync/setup.xul (content/sync/setup.xul)
content/browser/sync/addDevice.js (content/sync/addDevice.js)
content/browser/sync/addDevice.xul (content/sync/addDevice.xul)
content/browser/sync/setup.js (content/sync/setup.js)
* content/browser/sync/setup.js (content/sync/setup.js)
content/browser/sync/genericChange.xul (content/sync/genericChange.xul)
content/browser/sync/genericChange.js (content/sync/genericChange.js)
content/browser/sync/key.xhtml (content/sync/key.xhtml)

View File

@ -90,6 +90,8 @@ static RedirEntry kRedirMap[] = {
{ "healthreport", "chrome://browser/content/abouthealthreport/abouthealth.xhtml",
nsIAboutModule::ALLOW_SCRIPT },
#endif
{ "accounts", "chrome://browser/content/aboutaccounts/aboutaccounts.xhtml",
nsIAboutModule::ALLOW_SCRIPT },
{ "app-manager", "chrome://browser/content/devtools/app-manager/index.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "customizing", "chrome://browser/content/customizableui/aboutCustomizing.xhtml",

View File

@ -106,6 +106,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "accounts", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#ifdef MOZ_SERVICES_HEALTHREPORT
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#endif

View File

@ -1695,7 +1695,10 @@ let CustomizableUIInternal = {
// If the widget doesn't have an existing placement, and it hasn't been
// seen before, then add it to its default area so it can be used.
if (autoAdd && !widget.currentArea && !gSeenWidgets.has(widget.id)) {
// If the widget is not removable, we *have* to add it to its default
// area here.
let canBeAutoAdded = autoAdd && !gSeenWidgets.has(widget.id);
if (!widget.currentArea && (!widget.removable || canBeAutoAdded)) {
this.beginBatchUpdate();
try {
gSeenWidgets.add(widget.id);

View File

@ -48,4 +48,5 @@ skip-if = os == "mac"
[browser_944887_destroyWidget_should_destroy_in_palette.js]
[browser_945739_showInPrivateBrowsing_customize_mode.js]
[browser_947987_removable_default.js]
[browser_948985_non_removable_defaultArea.js]
[browser_panel_toggle.js]

View File

@ -0,0 +1,32 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const kWidgetId = "test-destroy-non-removable-defaultArea";
add_task(function() {
let spec = {id: kWidgetId, label: "Test non-removable defaultArea re-adding.",
removable: false, defaultArea: CustomizableUI.AREA_NAVBAR};
CustomizableUI.createWidget(spec);
let placement = CustomizableUI.getPlacementOfWidget(kWidgetId);
ok(placement, "Should have placed the widget.");
is(placement && placement.area, CustomizableUI.AREA_NAVBAR, "Widget should be in navbar");
CustomizableUI.destroyWidget(kWidgetId);
CustomizableUI.removeWidgetFromArea(kWidgetId);
CustomizableUI.createWidget(spec);
ok(placement, "Should have placed the widget.");
is(placement && placement.area, CustomizableUI.AREA_NAVBAR, "Widget should be in navbar");
CustomizableUI.destroyWidget(kWidgetId);
CustomizableUI.removeWidgetFromArea(kWidgetId);
const kPrefCustomizationAutoAdd = "browser.uiCustomization.autoAdd";
Services.prefs.setBoolPref(kPrefCustomizationAutoAdd, false);
CustomizableUI.createWidget(spec);
ok(placement, "Should have placed the widget.");
is(placement && placement.area, CustomizableUI.AREA_NAVBAR, "Widget should be in navbar");
CustomizableUI.destroyWidget(kWidgetId);
CustomizableUI.removeWidgetFromArea(kWidgetId);
Services.prefs.clearUserPref(kPrefCustomizationAutoAdd);
});

View File

@ -583,6 +583,25 @@ nsBrowserContentHandler.prototype = {
overridePage = overridePage.replace("%OLD_VERSION%", old_mstone);
break;
// Temporary case for Australis whatsnew
case OVERRIDE_NEW_BUILD_ID:
let locale = "en-US";
try {
locale = Services.prefs.getCharPref("general.useragent.locale");
} catch (e) {}
let showedAustralisWhatsNew = false;
try {
showedAustralisWhatsNew = Services.prefs.getBoolPref("browser.showedAustralisWhatsNew");
} catch(e) {}
// Show the Australis whatsnew page for en-US if we haven't yet shown it
if (!showedAustralisWhatsNew && locale == "en-US") {
Services.prefs.setBoolPref("browser.showedAustralisWhatsNew", true);
overridePage = "https://www.mozilla.org/en-US/firefox/29.0a1/whatsnew/";
}
break;
}
}
} catch (ex) {}

View File

@ -91,6 +91,13 @@ let gSyncPane = {
if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED ||
Weave.Svc.Prefs.get("firstSync", "") == "notReady") {
this.page = PAGE_NO_ACCOUNT;
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
// no concept of "pair" in an fxAccounts world.
if (service.fxAccountsEnabled) {
document.getElementById("pairDevice").hidden = true;
}
} else if (Weave.Status.login == Weave.LOGIN_FAILED_INVALID_PASSPHRASE ||
Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) {
this.needsUpdate();
@ -148,13 +155,22 @@ let gSyncPane = {
* "reset" -- reset sync
*/
openSetup: function (wizardType) {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win)
win.focus();
else {
window.openDialog("chrome://browser/content/sync/setup.xul",
"weaveSetup", "centerscreen,chrome,resizable=no",
wizardType);
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
if (service.fxAccountsEnabled) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
win.switchToTabHavingURI("about:accounts", true);
} else {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win)
win.focus();
else {
window.openDialog("chrome://browser/content/sync/setup.xul",
"weaveSetup", "centerscreen,chrome,resizable=no",
wizardType);
}
}
},

View File

@ -38,10 +38,12 @@
<label class="text-link"
onclick="event.stopPropagation(); gSyncPane.openSetup(null);"
value="&setupButton.label;"/>
<separator/>
<label class="text-link"
onclick="event.stopPropagation(); gSyncPane.openSetup('pair');"
value="&pairDevice.label;"/>
<vbox id="pairDevice">
<separator/>
<label class="text-link"
onclick="event.stopPropagation(); gSyncPane.openSetup('pair');"
value="&pairDevice.label;"/>
</vbox>
<spacer flex="3"/>
</vbox>

View File

@ -91,6 +91,13 @@ let gSyncPane = {
if (Weave.Status.service == Weave.CLIENT_NOT_CONFIGURED ||
Weave.Svc.Prefs.get("firstSync", "") == "notReady") {
this.page = PAGE_NO_ACCOUNT;
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
// no concept of "pair" in an fxAccounts world.
if (service.fxAccountsEnabled) {
document.getElementById("pairDevice").hidden = true;
}
} else if (Weave.Status.login == Weave.LOGIN_FAILED_INVALID_PASSPHRASE ||
Weave.Status.login == Weave.LOGIN_FAILED_LOGIN_REJECTED) {
this.needsUpdate();
@ -151,13 +158,24 @@ let gSyncPane = {
* "reset" -- reset sync
*/
openSetup: function (wizardType) {
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win) {
win.focus();
let service = Components.classes["@mozilla.org/weave/service;1"]
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
if (service.fxAccountsEnabled) {
let win = Services.wm.getMostRecentWindow("navigator:browser");
win.switchToTabHavingURI("about:accounts", true);
// seeing as we are doing this in a tab we close the prefs dialog.
window.close();
} else {
window.openDialog("chrome://browser/content/sync/setup.xul",
"weaveSetup", "centerscreen,chrome,resizable=no",
wizardType);
let win = Services.wm.getMostRecentWindow("Weave:AccountSetup");
if (win) {
win.focus();
} else {
window.openDialog("chrome://browser/content/sync/setup.xul",
"weaveSetup", "centerscreen,chrome,resizable=no",
wizardType);
}
}
},

View File

@ -47,10 +47,12 @@
<label class="text-link"
onclick="event.stopPropagation(); gSyncPane.openSetup(null);"
value="&setupButton.label;"/>
<separator/>
<label class="text-link"
onclick="event.stopPropagation(); gSyncPane.openSetup('pair');"
value="&pairDevice.label;"/>
<vbox id="pairDevice">
<separator/>
<label class="text-link"
onclick="event.stopPropagation(); gSyncPane.openSetup('pair');"
value="&pairDevice.label;"/>
</vbox>
<spacer flex="3"/>
</vbox>

View File

@ -182,9 +182,6 @@ let TabStateInternal = {
tabData.index = history.index;
}
// Copy data from the persistent cache.
this._copyFromPersistentCache(tab, tabData);
// If we're still the latest async collection for the given tab and
// the cache hasn't been filled by collect() in the meantime, let's
// fill the cache with the data we received.
@ -193,6 +190,16 @@ let TabStateInternal = {
this._pendingCollections.delete(browser);
}
// Copy data from the persistent cache. We need to create an explicit
// copy of the |tabData| object so that the properties injected by
// |_copyFromPersistentCache| don't end up in the non-persistent cache.
// The persistent cache does not store "null" values, so any values that
// have been cleared by the frame script would not be overriden by
// |_copyFromPersistentCache|. These two caches are only an interim
// solution and the non-persistent one will go away soon.
tabData = Utils.copy(tabData);
this._copyFromPersistentCache(tab, tabData);
throw new Task.Result(tabData);
}.bind(this));
@ -219,7 +226,16 @@ let TabStateInternal = {
throw new TypeError("Expecting a tab");
}
if (TabStateCache.has(tab)) {
return TabStateCache.get(tab);
// Copy data from the persistent cache. We need to create an explicit
// copy of the |tabData| object so that the properties injected by
// |_copyFromPersistentCache| don't end up in the non-persistent cache.
// The persistent cache does not store "null" values, so any values that
// have been cleared by the frame script would not be overriden by
// |_copyFromPersistentCache|. These two caches are only an interim
// solution and the non-persistent one will go away soon.
let tabData = Utils.copy(TabStateCache.get(tab));
this._copyFromPersistentCache(tab, tabData);
return tabData;
}
let tabData = this._collectSyncUncached(tab);
@ -228,6 +244,16 @@ let TabStateInternal = {
TabStateCache.set(tab, tabData);
}
// Copy data from the persistent cache. We need to create an explicit
// copy of the |tabData| object so that the properties injected by
// |_copyFromPersistentCache| don't end up in the non-persistent cache.
// The persistent cache does not store "null" values, so any values that
// have been cleared by the frame script would not be overriden by
// |_copyFromPersistentCache|. These two caches are only an interim
// solution and the non-persistent one will go away soon.
tabData = Utils.copy(tabData);
this._copyFromPersistentCache(tab, tabData);
// Prevent all running asynchronous collections from filling the cache.
// Every asynchronous data collection started before a collectSync() call
// can't expect to retrieve different data than the sync call. That's why
@ -262,7 +288,13 @@ let TabStateInternal = {
* up-to-date.
*/
clone: function (tab) {
return this._collectSyncUncached(tab, {includePrivateData: true});
let options = {includePrivateData: true};
let tabData = this._collectSyncUncached(tab, options);
// Copy data from the persistent cache.
this._copyFromPersistentCache(tab, tabData, options);
return tabData;
},
/**
@ -305,9 +337,6 @@ let TabStateInternal = {
tabData.index = history.index;
}
// Copy data from the persistent cache.
this._copyFromPersistentCache(tab, tabData, options);
return tabData;
},

View File

@ -64,5 +64,16 @@ this.Utils = Object.freeze({
map.set(otherKey, value);
map.delete(key);
}
},
// Copies all properties of a given object to a new one and returns it.
copy: function (from) {
let to = {};
for (let key of Object.keys(from)) {
to[key] = from[key];
}
return to;
}
});

View File

@ -1928,7 +1928,10 @@ Breakpoints.prototype = {
let disabledPromise = this._disabled.get(identifier);
if (disabledPromise) {
disabledPromise.then(({ conditionalExpression: previousValue }) => {
aBreakpointClient.conditionalExpression = previousValue;
// Setting a falsy conditional expression is redundant.
if (previousValue) {
aBreakpointClient.conditionalExpression = previousValue;
}
});
this._disabled.delete(identifier);
}

View File

@ -100,6 +100,7 @@ support-files =
[browser_dbg_conditional-breakpoints-01.js]
[browser_dbg_conditional-breakpoints-02.js]
[browser_dbg_conditional-breakpoints-03.js]
[browser_dbg_conditional-breakpoints-04.js]
[browser_dbg_controller-evaluate-01.js]
[browser_dbg_controller-evaluate-02.js]
[browser_dbg_debugger-statement.js]

View File

@ -77,13 +77,13 @@ function test() {
.getAttribute("value"), "getName",
"Should have the right property name for 'getName' in person.");
is(personNode.get("getName").target.querySelector(".value")
.getAttribute("value"), "Function",
.getAttribute("value"), "_pfactory/<.getName()",
"'getName' in person should have the right value.");
is(personNode.get("getFoo").target.querySelector(".name")
.getAttribute("value"), "getFoo",
"Should have the right property name for 'getFoo' in person.");
is(personNode.get("getFoo").target.querySelector(".value")
.getAttribute("value"), "Function",
.getAttribute("value"), "_pfactory/<.getFoo()",
"'getFoo' in person should have the right value.");
// Expand the function nodes. This causes their properties to be

View File

@ -0,0 +1,84 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that conditional breakpoints with undefined expressions
* are stored as plain breakpoints when re-enabling them.
*/
const TAB_URL = EXAMPLE_URL + "doc_conditional-breakpoints.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gSources, gBreakpoints, gLocation;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
gLocation = { url: gSources.selectedValue, line: 18 };
waitForSourceAndCaretAndScopes(gPanel, ".html", 17)
.then(addBreakpoint)
.then(setDummyConditional)
.then(() => {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.BREAKPOINT_REMOVED);
toggleBreakpoint();
return finished;
})
.then(() => {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.BREAKPOINT_ADDED);
toggleBreakpoint();
return finished;
})
.then(testConditionalExpressionOnClient)
.then(() => {
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.CONDITIONAL_BREAKPOINT_POPUP_SHOWING);
openConditionalPopup();
finished.then(() => ok(false, "The popup shouldn't have opened."));
return waitForTime(1000);
})
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
gDebuggee.ermahgerd();
});
function addBreakpoint() {
return gPanel.addBreakpoint(gLocation);
}
function setDummyConditional(aClient) {
// This happens when a conditional expression input popup is shown
// but the user doesn't type anything into it.
aClient.conditionalExpression = "";
}
function toggleBreakpoint() {
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint-checkbox"),
gDebugger);
}
function openConditionalPopup() {
EventUtils.sendMouseEvent({ type: "click" },
gDebugger.document.querySelector(".dbg-breakpoint"),
gDebugger);
}
function testConditionalExpressionOnClient() {
return gBreakpoints._getAdded(gLocation).then(aClient => {
if ("conditionalExpression" in aClient) {
ok(false, "A conditional expression shouldn't have been set.");
} else {
ok(true, "The conditional expression wasn't set, as expected.");
}
});
}
}

View File

@ -30,13 +30,15 @@ function testPause() {
gDebugger.gThreadClient.addOneTimeListener("paused", () => {
gToolbox.selectTool("webconsole").then(() => {
ok(gToolboxTab.classList.contains("highlighted"),
ok(gToolboxTab.hasAttribute("highlighted") &&
gToolboxTab.getAttribute("highlighted") == "true",
"The highlighted class is present");
ok(!gToolboxTab.hasAttribute("selected") ||
gToolboxTab.getAttribute("selected") != "true",
"The tab is not selected");
}).then(() => gToolbox.selectTool("jsdebugger")).then(() => {
ok(gToolboxTab.classList.contains("highlighted"),
ok(gToolboxTab.hasAttribute("highlighted") &&
gToolboxTab.getAttribute("highlighted") == "true",
"The highlighted class is present");
ok(gToolboxTab.hasAttribute("selected") &&
gToolboxTab.getAttribute("selected") == "true",

View File

@ -78,13 +78,15 @@ function testPause() {
"Debugger's tab got selected.");
}
gToolbox.selectTool("webconsole").then(() => {
ok(gToolboxTab.classList.contains("highlighted"),
ok(gToolboxTab.hasAttribute("highlighted") &&
gToolboxTab.getAttribute("highlighted") == "true",
"The highlighted class is present");
ok(!gToolboxTab.hasAttribute("selected") ||
gToolboxTab.getAttribute("selected") != "true",
"The tab is not selected");
}).then(() => gToolbox.selectTool("jsdebugger")).then(() => {
ok(gToolboxTab.classList.contains("highlighted"),
ok(gToolboxTab.hasAttribute("highlighted") &&
gToolboxTab.getAttribute("highlighted") == "true",
"The highlighted class is present");
ok(gToolboxTab.hasAttribute("selected") &&
gToolboxTab.getAttribute("selected") == "true",
@ -100,7 +102,8 @@ function testPause() {
function testResume() {
gDebugger.gThreadClient.addOneTimeListener("resumed", () => {
gToolbox.selectTool("webconsole").then(() => {
ok(!gToolboxTab.classList.contains("highlighted"),
ok(!gToolboxTab.hasAttribute("highlighted") ||
gToolboxTab.getAttribute("highlighted") != "true",
"The highlighted class is not present now after the resume");
ok(!gToolboxTab.hasAttribute("selected") ||
gToolboxTab.getAttribute("selected") != "true",

View File

@ -58,7 +58,7 @@ function testPauseOnExceptionsDisabled() {
is(innerNodes[0].querySelector(".name").getAttribute("value"), "this",
"Should have the right property name for 'this'.");
is(innerNodes[0].querySelector(".value").getAttribute("value"), "HTMLButtonElement",
is(innerNodes[0].querySelector(".value").getAttribute("value"), "<button>",
"Should have the right property value for 'this'.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {
@ -124,7 +124,7 @@ function testPauseOnExceptionsEnabled() {
is(innerNodes[0].querySelector(".name").getAttribute("value"), "this",
"Should have the right property name for 'this'.");
is(innerNodes[0].querySelector(".value").getAttribute("value"), "HTMLButtonElement",
is(innerNodes[0].querySelector(".value").getAttribute("value"), "<button>",
"Should have the right property value for 'this'.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {

View File

@ -79,7 +79,7 @@ function testPauseOnExceptionsAfterReload() {
is(innerNodes[0].querySelector(".name").getAttribute("value"), "this",
"Should have the right property name for 'this'.");
is(innerNodes[0].querySelector(".value").getAttribute("value"), "HTMLButtonElement",
is(innerNodes[0].querySelector(".value").getAttribute("value"), "<button>",
"Should have the right property value for 'this'.");
let finished = waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => {

View File

@ -22,16 +22,16 @@ function test() {
.then(() => initialChecks())
.then(() => testModification("a", "1"))
.then(() => testModification("{ a: 1 }", "Object"))
.then(() => testModification("[a]", "Array"))
.then(() => testModification("[a]", "Array[1]"))
.then(() => testModification("b", "Object"))
.then(() => testModification("b.a", "1"))
.then(() => testModification("c.a", "1"))
.then(() => testModification("Infinity", "Infinity"))
.then(() => testModification("NaN", "NaN"))
.then(() => testModification("new Function", "Function"))
.then(() => testModification("new Function", "anonymous()"))
.then(() => testModification("+0", "0"))
.then(() => testModification("-0", "-0"))
.then(() => testModification("Object.keys({})", "Array"))
.then(() => testModification("Object.keys({})", "Array[0]"))
.then(() => testModification("document.title", '"Debugger test page"'))
.then(() => resumeDebuggerThenCloseAndFinish(gPanel))
.then(null, aError => {

View File

@ -89,14 +89,16 @@ function testExpandVariables() {
waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_PROPERTIES, 3).then(() => {
is(thisVar.get("window").target.querySelector(".name").getAttribute("value"), "window",
"Should have the right property name for 'window'.");
is(thisVar.get("window").target.querySelector(".value").getAttribute("value"), "Window",
is(thisVar.get("window").target.querySelector(".value").getAttribute("value"),
"Window \u2192 doc_frame-parameters.html",
"Should have the right property value for 'window'.");
ok(thisVar.get("window").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'window'.");
is(thisVar.get("document").target.querySelector(".name").getAttribute("value"), "document",
"Should have the right property name for 'document'.");
is(thisVar.get("document").target.querySelector(".value").getAttribute("value"), "HTMLDocument",
is(thisVar.get("document").target.querySelector(".value").getAttribute("value"),
"HTMLDocument \u2192 doc_frame-parameters.html",
"Should have the right property value for 'document'.");
ok(thisVar.get("document").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'document'.");

View File

@ -56,7 +56,8 @@ function testScopeVariables() {
is(localEnums[0].querySelector(".name").getAttribute("value"), "this",
"Should have the right property name for 'this'.");
is(localEnums[0].querySelector(".value").getAttribute("value"), "Window",
is(localEnums[0].querySelector(".value").getAttribute("value"),
"Window \u2192 doc_frame-parameters.html",
"Should have the right property value for 'this'.");
ok(localEnums[0].querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'this'.");
@ -192,7 +193,8 @@ function testArgumentsProperties() {
is(argsNonEnums[0].querySelector(".name").getAttribute("value"), "callee",
"Should have the right property name for 'callee'.");
is(argsNonEnums[0].querySelector(".value").getAttribute("value"), "Function",
is(argsNonEnums[0].querySelector(".value").getAttribute("value"),
"test(aArg,bArg,cArg,dArg,eArg,fArg)",
"Should have the right property name for 'callee'.");
ok(argsNonEnums[0].querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'callee'.");
@ -518,14 +520,16 @@ function testGetterSetterObject() {
is(propNonEnums[0].querySelector(".name").getAttribute("value"), "get",
"Should have the right property name for 'get'.");
is(propNonEnums[0].querySelector(".value").getAttribute("value"), "Function",
is(propNonEnums[0].querySelector(".value").getAttribute("value"),
"test/myVar.prop()",
"Should have the right property value for 'get'.");
ok(propNonEnums[0].querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'get'.");
is(propNonEnums[1].querySelector(".name").getAttribute("value"), "set",
"Should have the right property name for 'set'.");
is(propNonEnums[1].querySelector(".value").getAttribute("value"), "Function",
is(propNonEnums[1].querySelector(".value").getAttribute("value"),
"test/myVar.prop(val)",
"Should have the right property value for 'set'.");
ok(propNonEnums[1].querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'set'.");

View File

@ -71,12 +71,14 @@ function testGlobalScope() {
is(globalScope.get("window").target.querySelector(".name").getAttribute("value"), "window",
"Should have the right property name for 'window'.");
is(globalScope.get("window").target.querySelector(".value").getAttribute("value"), "Window",
is(globalScope.get("window").target.querySelector(".value").getAttribute("value"),
"Window \u2192 doc_frame-parameters.html",
"Should have the right property value for 'window'.");
is(globalScope.get("document").target.querySelector(".name").getAttribute("value"), "document",
"Should have the right property name for 'document'.");
is(globalScope.get("document").target.querySelector(".value").getAttribute("value"), "HTMLDocument",
is(globalScope.get("document").target.querySelector(".value").getAttribute("value"),
"HTMLDocument \u2192 doc_frame-parameters.html",
"Should have the right property value for 'document'.");
is(globalScope.get("undefined").target.querySelector(".name").getAttribute("value"), "undefined",
@ -123,12 +125,14 @@ function testWindowVariable() {
is(windowVar.get("window").target.querySelector(".name").getAttribute("value"), "window",
"Should have the right property name for 'window'.");
is(windowVar.get("window").target.querySelector(".value").getAttribute("value"), "Window",
is(windowVar.get("window").target.querySelector(".value").getAttribute("value"),
"Window \u2192 doc_frame-parameters.html",
"Should have the right property value for 'window'.");
is(windowVar.get("document").target.querySelector(".name").getAttribute("value"), "document",
"Should have the right property name for 'document'.");
is(windowVar.get("document").target.querySelector(".value").getAttribute("value"), "HTMLDocument",
is(windowVar.get("document").target.querySelector(".value").getAttribute("value"),
"HTMLDocument \u2192 doc_frame-parameters.html",
"Should have the right property value for 'document'.");
is(windowVar.get("undefined").target.querySelector(".name").getAttribute("value"), "undefined",

View File

@ -57,7 +57,8 @@ function testFirstWithScope() {
is(withEnums[0].querySelector(".name").getAttribute("value"), "this",
"Should have the right property name for 'this'.");
is(withEnums[0].querySelector(".value").getAttribute("value"), "Window",
is(withEnums[0].querySelector(".value").getAttribute("value"),
"Window \u2192 doc_with-frame.html",
"Should have the right property value for 'this'.");
ok(withEnums[0].querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'this'.");
@ -131,7 +132,7 @@ function testSecondWithScope() {
is(secondWithScope.get("random").target.querySelector(".name").getAttribute("value"), "random",
"Should have the right property name for 'random'.");
is(secondWithScope.get("random").target.querySelector(".value").getAttribute("value"), "Function",
is(secondWithScope.get("random").target.querySelector(".value").getAttribute("value"), "random()",
"Should have the right property value for 'random'.");
ok(secondWithScope.get("random").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'random'.");

View File

@ -54,7 +54,7 @@ function initialChecks() {
is(arrayVar.target.querySelector(".name").getAttribute("value"), "largeArray",
"Should have the right property name for 'largeArray'.");
is(arrayVar.target.querySelector(".value").getAttribute("value"), "Int8Array",
is(arrayVar.target.querySelector(".value").getAttribute("value"), "Int8Array[10000]",
"Should have the right property value for 'largeArray'.");
ok(arrayVar.target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'largeArray'.");

View File

@ -62,7 +62,7 @@ function performTest() {
is(buttonVar.target.querySelector(".name").getAttribute("value"), "button",
"Should have the right property name for 'button'.");
is(buttonVar.target.querySelector(".value").getAttribute("value"), "HTMLButtonElement",
is(buttonVar.target.querySelector(".value").getAttribute("value"), "<button>",
"Should have the right property value for 'button'.");
ok(buttonVar.target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'button'.");
@ -76,7 +76,8 @@ function performTest() {
is(documentVar.target.querySelector(".name").getAttribute("value"), "document",
"Should have the right property name for 'document'.");
is(documentVar.target.querySelector(".value").getAttribute("value"), "HTMLDocument",
is(documentVar.target.querySelector(".value").getAttribute("value"),
"HTMLDocument \u2192 doc_frame-parameters.html",
"Should have the right property value for 'document'.");
ok(documentVar.target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'document'.");
@ -98,14 +99,14 @@ function performTest() {
is(buttonVar.get("childNodes").target.querySelector(".name").getAttribute("value"), "childNodes",
"Should have the right property name for 'childNodes'.");
is(buttonVar.get("childNodes").target.querySelector(".value").getAttribute("value"), "NodeList",
is(buttonVar.get("childNodes").target.querySelector(".value").getAttribute("value"), "NodeList[1]",
"Should have the right property value for 'childNodes'.");
ok(buttonVar.get("childNodes").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'childNodes'.");
is(buttonVar.get("onclick").target.querySelector(".name").getAttribute("value"), "onclick",
"Should have the right property name for 'onclick'.");
is(buttonVar.get("onclick").target.querySelector(".value").getAttribute("value"), "Function",
is(buttonVar.get("onclick").target.querySelector(".value").getAttribute("value"), "onclick(event)",
"Should have the right property value for 'onclick'.");
ok(buttonVar.get("onclick").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'onclick'.");
@ -119,7 +120,7 @@ function performTest() {
is(documentVar.get("childNodes").target.querySelector(".name").getAttribute("value"), "childNodes",
"Should have the right property name for 'childNodes'.");
is(documentVar.get("childNodes").target.querySelector(".value").getAttribute("value"), "NodeList",
is(documentVar.get("childNodes").target.querySelector(".value").getAttribute("value"), "NodeList[3]",
"Should have the right property value for 'childNodes'.");
ok(documentVar.get("childNodes").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'childNodes'.");
@ -144,7 +145,7 @@ function performTest() {
is(buttonAsProtoProtoVar.target.querySelector(".name").getAttribute("value"), "__proto__",
"Should have the right property name for '__proto__'.");
is(buttonAsProtoProtoVar.target.querySelector(".value").getAttribute("value"), "HTMLButtonElement",
is(buttonAsProtoProtoVar.target.querySelector(".value").getAttribute("value"), "<button>",
"Should have the right property value for '__proto__'.");
ok(buttonAsProtoProtoVar.target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for '__proto__'.");
@ -173,14 +174,14 @@ function performTest() {
is(buttonAsProtoProtoVar.get("childNodes").target.querySelector(".name").getAttribute("value"), "childNodes",
"Should have the right property name for 'childNodes'.");
is(buttonAsProtoProtoVar.get("childNodes").target.querySelector(".value").getAttribute("value"), "NodeList",
is(buttonAsProtoProtoVar.get("childNodes").target.querySelector(".value").getAttribute("value"), "NodeList[1]",
"Should have the right property value for 'childNodes'.");
ok(buttonAsProtoProtoVar.get("childNodes").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'childNodes'.");
is(buttonAsProtoProtoVar.get("onclick").target.querySelector(".name").getAttribute("value"), "onclick",
"Should have the right property name for 'onclick'.");
is(buttonAsProtoProtoVar.get("onclick").target.querySelector(".value").getAttribute("value"), "Function",
is(buttonAsProtoProtoVar.get("onclick").target.querySelector(".value").getAttribute("value"), "onclick(event)",
"Should have the right property value for 'onclick'.");
ok(buttonAsProtoProtoVar.get("onclick").target.querySelector(".value").className.contains("token-other"),
"Should have the right token class for 'onclick'.");

View File

@ -65,20 +65,20 @@ function unhighlightTab(toolId) {
function checkHighlighted(toolId) {
let tab = toolbox.doc.getElementById("toolbox-tab-" + toolId);
ok(tab.classList.contains("highlighted"), "The highlighted class is present");
ok(tab.hasAttribute("highlighted"), "The highlighted attribute is present");
ok(!tab.hasAttribute("selected") || tab.getAttribute("selected") != "true",
"The tab is not selected");
}
function checkNoHighlightWhenSelected(toolId) {
let tab = toolbox.doc.getElementById("toolbox-tab-" + toolId);
ok(tab.classList.contains("highlighted"), "The highlighted class is present");
ok(tab.hasAttribute("highlighted"), "The highlighted attribute is present");
ok(tab.hasAttribute("selected") && tab.getAttribute("selected") == "true",
"and the tab is selected, so the orange glow will not be present.");
}
function checkNoHighlight(toolId) {
let tab = toolbox.doc.getElementById("toolbox-tab-" + toolId);
ok(!tab.classList.contains("highlighted"),
"The highlighted class is not present");
ok(!tab.hasAttribute("highlighted"),
"The highlighted attribute is not present");
}

View File

@ -796,7 +796,7 @@ Toolbox.prototype = {
*/
highlightTool: function(id) {
let tab = this.doc.getElementById("toolbox-tab-" + id);
tab && tab.classList.add("highlighted");
tab && tab.setAttribute("highlighted", "true");
},
/**
@ -807,7 +807,7 @@ Toolbox.prototype = {
*/
unhighlightTool: function(id) {
let tab = this.doc.getElementById("toolbox-tab-" + id);
tab && tab.classList.remove("highlighted");
tab && tab.removeAttribute("highlighted");
},
/**

View File

@ -27,6 +27,9 @@ Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "devtools",
"resource://gre/modules/devtools/Loader.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
@ -2346,7 +2349,10 @@ Variable.prototype = Heritage.extend(Scope.prototype, {
this._valueLabel.classList.remove(VariablesView.getClass(prevGrip));
}
this._valueGrip = aGrip;
this._valueString = VariablesView.getString(aGrip, true);
this._valueString = VariablesView.getString(aGrip, {
concise: true,
noEllipsis: true,
});
this._valueClassName = VariablesView.getClass(aGrip);
this._valueLabel.classList.add(this._valueClassName);
@ -3118,12 +3124,16 @@ VariablesView.getGrip = function(aValue) {
*
* @param any aGrip
* @see Variable.setGrip
* @param boolean aConciseFlag
* Return a concisely formatted property string.
* @param object aOptions
* Options:
* - concise: boolean that tells you want a concisely formatted string.
* - noStringQuotes: boolean that tells to not quote strings.
* - noEllipsis: boolean that tells to not add an ellipsis after the
* initial text of a longString.
* @return string
* The formatted property string.
*/
VariablesView.getString = function(aGrip, aConciseFlag) {
VariablesView.getString = function(aGrip, aOptions = {}) {
if (aGrip && typeof aGrip == "object") {
switch (aGrip.type) {
case "undefined":
@ -3133,18 +3143,30 @@ VariablesView.getString = function(aGrip, aConciseFlag) {
case "-Infinity":
case "-0":
return aGrip.type;
case "longString":
return "\"" + aGrip.initial + "\"";
default:
if (!aConciseFlag) {
return "[" + aGrip.type + " " + aGrip.class + "]";
let stringifier = VariablesView.stringifiers.byType[aGrip.type];
if (stringifier) {
let result = stringifier(aGrip, aOptions);
if (result != null) {
return result;
}
}
return aGrip.class;
if (aGrip.displayString) {
return VariablesView.getString(aGrip.displayString, aOptions);
}
if (aGrip.type == "object" && aOptions.concise) {
return aGrip.class;
}
return "[" + aGrip.type + " " + aGrip.class + "]";
}
}
switch (typeof aGrip) {
case "string":
return "\"" + aGrip + "\"";
return VariablesView.stringifiers.byType.string(aGrip, aOptions);
case "boolean":
return aGrip ? "true" : "false";
case "number":
@ -3156,6 +3178,367 @@ VariablesView.getString = function(aGrip, aConciseFlag) {
}
};
/**
* The VariablesView stringifiers are used by VariablesView.getString(). These
* are organized by object type, object class and by object actor preview kind.
* Some objects share identical ways for previews, for example Arrays, Sets and
* NodeLists.
*
* Any stringifier function must return a string. If null is returned, * then
* the default stringifier will be used. When invoked, the stringifier is
* given the same two arguments as those given to VariablesView.getString().
*/
VariablesView.stringifiers = {};
VariablesView.stringifiers.byType = {
string: function(aGrip, {noStringQuotes}) {
if (noStringQuotes) {
return aGrip;
}
return uneval(aGrip);
},
longString: function({initial}, {noStringQuotes, noEllipsis}) {
let ellipsis = noEllipsis ? "" : Scope.ellipsis;
if (noStringQuotes) {
return initial + ellipsis;
}
let result = uneval(initial);
if (!ellipsis) {
return result;
}
return result.substr(0, result.length - 1) + ellipsis + '"';
},
object: function(aGrip, aOptions) {
let {preview} = aGrip;
let stringifier;
if (preview && preview.kind) {
stringifier = VariablesView.stringifiers.byObjectKind[preview.kind];
}
if (!stringifier && aGrip.class) {
stringifier = VariablesView.stringifiers.byObjectClass[aGrip.class];
}
if (stringifier) {
return stringifier(aGrip, aOptions);
}
return null;
},
}; // VariablesView.stringifiers.byType
VariablesView.stringifiers.byObjectClass = {
Function: function(aGrip, {concise}) {
// TODO: Bug 948484 - support arrow functions and ES6 generators
let name = aGrip.userDisplayName || aGrip.displayName || aGrip.name || "";
name = VariablesView.getString(name, { noStringQuotes: true });
// TODO: Bug 948489 - Support functions with destructured parameters and
// rest parameters
let params = aGrip.parameterNames || "";
if (!concise) {
return "function " + name + "(" + params + ")";
}
return (name || "function ") + "(" + params + ")";
},
RegExp: function({displayString}) {
return VariablesView.getString(displayString, { noStringQuotes: true });
},
Date: function({preview}) {
if (!preview || !("timestamp" in preview)) {
return null;
}
if (typeof preview.timestamp != "number") {
return new Date(preview.timestamp).toString(); // invalid date
}
return "Date " + new Date(preview.timestamp).toISOString();
},
}; // VariablesView.stringifiers.byObjectClass
VariablesView.stringifiers.byObjectKind = {
ArrayLike: function(aGrip, {concise}) {
let {preview} = aGrip;
if (concise) {
return aGrip.class + "[" + preview.length + "]";
}
if (!preview.items) {
return null;
}
let shown = 0, result = [], lastHole = null;
for (let item of preview.items) {
if (item === null) {
if (lastHole !== null) {
result[lastHole] += ",";
} else {
result.push("");
}
lastHole = result.length - 1;
} else {
lastHole = null;
result.push(VariablesView.getString(item, { concise: true }));
}
shown++;
}
if (shown < preview.length) {
let n = preview.length - shown;
result.push(VariablesView.stringifiers._getNMoreString(n));
} else if (lastHole !== null) {
// make sure we have the right number of commas...
result[lastHole] += ",";
}
let prefix = aGrip.class == "Array" ? "" : aGrip.class + " ";
return prefix + "[" + result.join(", ") + "]";
},
MapLike: function(aGrip, {concise}) {
let {preview} = aGrip;
if (concise || !preview.entries) {
let size = typeof preview.size == "number" ?
"[" + preview.size + "]" : "";
return aGrip.class + size;
}
let entries = [];
for (let [key, value] of preview.entries) {
let keyString = VariablesView.getString(key, {
concise: true,
noStringQuotes: true,
});
let valueString = VariablesView.getString(value, { concise: true });
entries.push(keyString + ": " + valueString);
}
if (typeof preview.size == "number" && preview.size > entries.length) {
let n = preview.size - entries.length;
entries.push(VariablesView.stringifiers._getNMoreString(n));
}
return aGrip.class + " {" + entries.join(", ") + "}";
},
ObjectWithText: function(aGrip, {concise}) {
if (concise) {
return aGrip.class;
}
return aGrip.class + " " + VariablesView.getString(aGrip.preview.text);
},
ObjectWithURL: function(aGrip, {concise}) {
let result = aGrip.class;
let url = aGrip.preview.url;
if (!VariablesView.isFalsy({ value: url })) {
result += " \u2192 " + WebConsoleUtils.abbreviateSourceURL(url,
{ onlyCropQuery: !concise });
}
return result;
},
// Stringifier for any kind of object.
Object: function(aGrip, {concise}) {
if (concise) {
return aGrip.class;
}
let {preview} = aGrip;
let props = [];
for (let key of Object.keys(preview.ownProperties || {})) {
let value = preview.ownProperties[key];
let valueString = "";
if (value.get) {
valueString = "Getter";
} else if (value.set) {
valueString = "Setter";
} else {
valueString = VariablesView.getString(value.value, { concise: true });
}
props.push(key + ": " + valueString);
}
for (let key of Object.keys(preview.safeGetterValues || {})) {
let value = preview.safeGetterValues[key];
let valueString = VariablesView.getString(value.getterValue,
{ concise: true });
props.push(key + ": " + valueString);
}
if (!props.length) {
return null;
}
if (preview.ownPropertiesLength) {
let previewLength = Object.keys(preview.ownProperties).length;
let diff = preview.ownPropertiesLength - previewLength;
if (diff > 0) {
props.push(VariablesView.stringifiers._getNMoreString(diff));
}
}
let prefix = aGrip.class != "Object" ? aGrip.class + " " : "";
return prefix + "{" + props.join(", ") + "}";
}, // Object
Error: function(aGrip, {concise}) {
let {preview} = aGrip;
let name = VariablesView.getString(preview.name, { noStringQuotes: true });
if (concise) {
return name || aGrip.class;
}
let msg = name + ": " +
VariablesView.getString(preview.message, { noStringQuotes: true });
if (!VariablesView.isFalsy({ value: preview.stack })) {
msg += "\n" + STR.GetStringFromName("variablesViewErrorStacktrace") +
"\n" + preview.stack;
}
return msg;
},
DOMException: function(aGrip, {concise}) {
let {preview} = aGrip;
if (concise) {
return preview.name || aGrip.class;
}
let msg = aGrip.class + " [" + preview.name + ": " +
VariablesView.getString(preview.message) + "\n" +
"code: " + preview.code + "\n" +
"nsresult: 0x" + (+preview.result).toString(16);
if (preview.filename) {
msg += "\nlocation: " + preview.filename;
if (preview.lineNumber) {
msg += ":" + preview.lineNumber;
}
}
return msg + "]";
},
DOMEvent: function(aGrip, {concise}) {
let {preview} = aGrip;
if (!preview.type) {
return null;
}
if (concise) {
return aGrip.class + " " + preview.type;
}
let result = preview.type;
if (preview.eventKind == "key" && preview.modifiers &&
preview.modifiers.length) {
result += " " + preview.modifiers.join("-");
}
let props = [];
if (preview.target) {
let target = VariablesView.getString(preview.target, { concise: true });
props.push("target: " + target);
}
for (let prop in preview.properties) {
let value = preview.properties[prop];
props.push(prop + ": " + VariablesView.getString(value, { concise: true }));
}
return result + " {" + props.join(", ") + "}";
}, // DOMEvent
DOMNode: function(aGrip, {concise}) {
let {preview} = aGrip;
switch (preview.nodeType) {
case Ci.nsIDOMNode.DOCUMENT_NODE: {
let location = WebConsoleUtils.abbreviateSourceURL(preview.location,
{ onlyCropQuery: !concise });
return aGrip.class + " \u2192 " + location;
}
case Ci.nsIDOMNode.ATTRIBUTE_NODE: {
let value = VariablesView.getString(preview.value, { noStringQuotes: true });
return preview.nodeName + '="' + escapeHTML(value) + '"';
}
case Ci.nsIDOMNode.TEXT_NODE:
return preview.nodeName + " " +
VariablesView.getString(preview.textContent);
case Ci.nsIDOMNode.COMMENT_NODE: {
let comment = VariablesView.getString(preview.textContent,
{ noStringQuotes: true });
return "<!--" + comment + "-->";
}
case Ci.nsIDOMNode.DOCUMENT_FRAGMENT_NODE: {
if (concise || !preview.childNodes) {
return aGrip.class + "[" + preview.childNodesLength + "]";
}
let nodes = [];
for (let node of preview.childNodes) {
nodes.push(VariablesView.getString(node));
}
if (nodes.length < preview.childNodesLength) {
let n = preview.childNodesLength - nodes.length;
nodes.push(VariablesView.stringifiers._getNMoreString(n));
}
return aGrip.class + " [" + nodes.join(", ") + "]";
}
case Ci.nsIDOMNode.ELEMENT_NODE: {
let attrs = preview.attributes;
if (!concise) {
let n = 0, result = "<" + preview.nodeName;
for (let name in attrs) {
let value = VariablesView.getString(attrs[name],
{ noStringQuotes: true });
result += " " + name + '="' + escapeHTML(value) + '"';
n++;
}
if (preview.attributesLength > n) {
result += " " + Scope.ellipsis;
}
return result + ">";
}
let result = "<" + preview.nodeName;
if (attrs.id) {
result += "#" + attrs.id;
}
return result + ">";
}
default:
return null;
}
}, // DOMNode
}; // VariablesView.stringifiers.byObjectKind
/**
* Get the "N more…" formatted string, given an N. This is used for displaying
* how many elements are not displayed in an object preview (eg. an array).
*
* @private
* @param number aNumber
* @return string
*/
VariablesView.stringifiers._getNMoreString = function(aNumber) {
let str = STR.GetStringFromName("variablesViewMoreObjects");
return PluralForm.get(aNumber, str).replace("#1", aNumber);
};
/**
* Returns a custom class style for a grip.
*
@ -3208,6 +3591,22 @@ let generateId = (function() {
};
})();
/**
* Escape some HTML special characters. We do not need full HTML serialization
* here, we just want to make strings safe to display in HTML attributes, for
* the stringifiers.
*
* @param string aString
* @return string
*/
function escapeHTML(aString) {
return aString.replace(/&/g, "&amp;")
.replace(/"/g, "&quot;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
}
/**
* An Editable encapsulates the UI of an edit box that overlays a label,
* allowing the user to edit the value.

View File

@ -997,10 +997,12 @@ Messages.Extended.prototype = Heritage.extend(Messages.Simple.prototype,
}
let result = this.document.createDocumentFragment();
if (!isPrimitive || (!this._quoteStrings && typeof piece == "string")) {
result.textContent = piece;
if (isPrimitive) {
result.textContent = VariablesView.getString(piece, {
noStringQuotes: !this._quoteStrings,
});
} else {
result.textContent = VariablesView.getString(piece);
result.textContent = piece;
}
return result;
@ -1219,7 +1221,7 @@ Widgets.JSObject.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
_onClick: function()
{
this.output.openVariablesView({
label: this.element.textContent,
label: VariablesView.getString(this.objectActor, { concise: true }),
objectActor: this.objectActor,
autofocus: true,
});
@ -1273,11 +1275,10 @@ Widgets.LongString.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
*/
_renderString: function(str)
{
if (this.message._quoteStrings) {
this.element.textContent = VariablesView.getString(str);
} else {
this.element.textContent = str;
}
this.element.textContent = VariablesView.getString(str, {
noStringQuotes: !this.message._quoteStrings,
noEllipsis: true,
});
},
/**

View File

@ -64,6 +64,10 @@ support-files =
test-console-extras.html
test-console-replaced-api.html
test-console.html
test-console-output-02.html
test-console-output-03.html
test-console-output-04.html
test-console-output-events.html
test-consoleiframes.html
test-data.json
test-data.json^headers^
@ -167,7 +171,6 @@ support-files =
[browser_webconsole_bug_597136_network_requests_from_chrome.js]
[browser_webconsole_bug_597460_filter_scroll.js]
[browser_webconsole_bug_597756_reopen_closed_tab.js]
[browser_webconsole_bug_598357_jsterm_output.js]
[browser_webconsole_bug_599725_response_headers.js]
[browser_webconsole_bug_600183_charset.js]
[browser_webconsole_bug_601177_log_levels.js]
@ -248,3 +251,8 @@ run-if = os == "mac"
[browser_webconsole_expandable_timestamps.js]
[browser_webconsole_autocomplete_in_debugger_stackframe.js]
[browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
[browser_webconsole_output_01.js]
[browser_webconsole_output_02.js]
[browser_webconsole_output_03.js]
[browser_webconsole_output_04.js]
[browser_webconsole_output_events.js]

View File

@ -36,7 +36,8 @@ function onExecuteFooObj(msg)
let anchor = msg.querySelector("a");
ok(anchor, "object anchor");
isnot(anchor.textContent.indexOf("[object Object]"), -1, "message text check");
isnot(anchor.textContent.indexOf('testProp: "testValue"'), -1,
"message text check");
gJSTerm.once("variablesview-fetched", onFooObjFetch);
EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow)
@ -76,7 +77,8 @@ function onExecuteWindow(msg)
ok(msg, "output message found");
let anchor = msg.querySelector("a");
ok(anchor, "object anchor");
isnot(anchor.textContent.indexOf("[object Window]"), -1, "message text check");
isnot(anchor.textContent.indexOf("Window \u2192 http://example.com/browser/"), -1,
"message text check");
gJSTerm.once("variablesview-fetched", onWindowFetch);
EventUtils.synthesizeMouse(anchor, 2, 2, {}, gWebConsole.iframeWindow)

View File

@ -46,7 +46,7 @@ function onConsoleMessage(aResults)
{
let clickable = aResults[0].clickableElements[0];
ok(clickable, "clickable object found");
isnot(clickable.textContent.indexOf("[object Object]"), -1,
isnot(clickable.textContent.indexOf('{hello: "world!",'), -1,
"message text check");
gJSTerm.once("variablesview-fetched", onObjFetch);

View File

@ -71,7 +71,7 @@ function test()
},
{
name: "console.error output",
text: /\bbug851231-error\b.+\[object Object\]/,
text: /\bbug851231-error\b.+\{bug851231prop:\s"bug851231value"\}/,
category: CATEGORY_WEBDEV,
severity: SEVERITY_ERROR,
objects: true,
@ -91,7 +91,7 @@ function test()
},
{
name: "console.dir output",
consoleDir: "[object XULDocument]",
consoleDir: "XULDocument {",
},
{
name: "console.time output",

View File

@ -34,7 +34,7 @@ function performTest(hud)
}).then(([result]) => {
let clickable = result.clickableElements[0];
ok(clickable, "the console.log() object anchor was found");
isnot(clickable.textContent.indexOf("Object"), -1,
isnot(clickable.textContent.indexOf('{abba: "omgBug676722"}'), -1,
"clickable node content is correct");
hud.jsterm.once("variablesview-fetched",

View File

@ -30,7 +30,7 @@ function consoleOpened(hud)
waitForMessages({
webconsole: hud,
messages: [{
text: "[object HTMLDocument]",
text: "HTMLDocument \u2192 data:text/html;charset=utf8",
category: CATEGORY_OUTPUT,
objects: true,
}],
@ -90,7 +90,7 @@ function testParagraphs()
waitForMessages({
webconsole: gWebConsole,
messages: [{
text: "[object NodeList]",
text: "NodeList [",
category: CATEGORY_OUTPUT,
objects: true,
}],

View File

@ -28,7 +28,8 @@ function consoleOpened(hud)
function onExecuteFooObj(msg)
{
ok(msg, "output message found");
isnot(msg.textContent.indexOf("[object Object]"), -1, "message text check");
isnot(msg.textContent.indexOf('{testProp: "testValue"}'), -1,
"message text check");
let anchor = msg.querySelector("a");
ok(anchor, "object link found");

View File

@ -62,7 +62,8 @@ function onFramesAdded()
function onExecuteFooObj(msg)
{
ok(msg, "output message found");
isnot(msg.textContent.indexOf("[object Object]"), -1, "message text check");
isnot(msg.textContent.indexOf('{testProp2: "testValue2"}'), -1,
"message text check");
let anchor = msg.querySelector("a");
ok(anchor, "object link found");

View File

@ -57,7 +57,8 @@ function onFramesAdded()
function onExecuteFooObj(msg)
{
ok(msg, "output message found");
isnot(msg.textContent.indexOf("[object Object]"), -1, "message text check");
isnot(msg.textContent.indexOf('{testProp2: "testValue2"}'), -1,
"message text check");
let anchor = msg.querySelector("a");
ok(anchor, "object link found");

View File

@ -29,7 +29,7 @@ function test()
findVariableViewProperties(aVar, [
{ name: "testProp", value: "testValue" },
{ name: "document", value: "HTMLDocument" },
{ name: "document", value: /HTMLDocument \u2192 data:/ },
], { webconsole: hud }).then(finishTest);
}
}

View File

@ -28,10 +28,10 @@ function performTest(hud)
ok(!hud.outputNode.querySelector("#foobar"), "no #foobar element found");
ok(msg, "eval output node found");
is(msg.textContent.indexOf("HTMLDivElement"), -1,
"HTMLDivElement string is not displayed");
isnot(msg.textContent.indexOf("HTMLParagraphElement"), -1,
"HTMLParagraphElement string is displayed");
is(msg.textContent.indexOf("<div>"), -1,
"<div> string is not displayed");
isnot(msg.textContent.indexOf("<p>"), -1,
"<p> string is displayed");
EventUtils.synthesizeMouseAtCenter(msg, {type: "mousemove"});
ok(!gBrowser._bug772506, "no content variable");

View File

@ -80,9 +80,8 @@ function tab2Loaded(aEvent) {
function testEnd() {
ok(noErrors, "there were no errors");
Array.forEach(win1.gBrowser.tabs, function(aTab) {
win1.gBrowser.removeTab(aTab);
});
win1.gBrowser.removeTab(tab1);
Array.forEach(win2.gBrowser.tabs, function(aTab) {
win2.gBrowser.removeTab(aTab);
});

View File

@ -1,267 +0,0 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* ***** BEGIN LICENSE BLOCK *****
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Contributor(s):
* Mihai Șucan <mihai.sucan@gmail.com>
*
* ***** END LICENSE BLOCK ***** */
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
let testEnded = false;
let pos = -1;
let dateNow = Date.now();
let tempScope = {};
Cu.import("resource://gre/modules/devtools/dbg-server.jsm", tempScope);
let longString = (new Array(tempScope.DebuggerServer.LONG_STRING_LENGTH + 4)).join("a");
let initialString = longString.substring(0,
tempScope.DebuggerServer.LONG_STRING_INITIAL_LENGTH);
let inputValues = [
// [showsVariablesView?, input value, expected output format,
// print() output, console API output, optional console API test]
// 0
[false, "'hello \\nfrom \\rthe \\\"string world!'",
'"hello \nfrom \rthe "string world!"',
"hello \nfrom \rthe \"string world!"],
// 1
[false, "'\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165'",
"\"\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165\"",
"\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165"],
// 2
[false, "window.location.href", '"' + TEST_URI + '"', TEST_URI],
// 3
[false, "0", "0"],
// 4
[false, "'0'", '"0"', "0"],
// 5
[false, "42", "42"],
// 6
[false, "'42'", '"42"', "42"],
// 7
[true, "/foobar/", "[object RegExp]", '"/foobar/"', "[object RegExp]"],
// 8
[false, "null", "null"],
// 9
[false, "undefined", "undefined"],
// 10
[false, "true", "true"],
// 11
[true, "document.getElementById", "[object Function]",
"function getElementById() {\n [native code]\n}",
"[object Function]"],
// 12
[true, "(function() { return 42; })", "[object Function]",
"function () { return 42; }", "[object Function]"],
// 13
[true, "new Date(" + dateNow + ")", "[object Date]", (new Date(dateNow)).toString(), "[object Date]"],
// 14
[true, "document.body", "[object HTMLBodyElement]"],
// 15
[true, "window.location", "[object Location]", TEST_URI, "[object Location]"],
// 16
[true, "[1,2,3,'a','b','c','4','5']", '[object Array]',
'1,2,3,a,b,c,4,5',
"[object Array]"],
// 17
[true, "({a:'b', c:'d', e:1, f:'2'})", "[object Object]"],
// 18
[false, "'" + longString + "'",
'"' + initialString + "\"[\u2026]", initialString],
];
longString = null;
initialString = null;
tempScope = null;
let eventHandlers = [];
let popupShown = [];
let HUD;
let testDriver;
function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, tabLoad, true);
waitForFocus(function () {
openConsole(null, function(aHud) {
HUD = aHud;
testNext();
});
}, content);
}
function subtestNext() {
testDriver.next();
}
function testNext() {
pos++;
if (pos == inputValues.length) {
testEnd();
return;
}
testDriver = testGen();
testDriver.next();
}
function testGen() {
let cpos = pos;
let showsVariablesView = inputValues[cpos][0];
let inputValue = inputValues[cpos][1];
let expectedOutput = inputValues[cpos][2];
let printOutput = inputValues[cpos].length >= 4 ?
inputValues[cpos][3] : expectedOutput;
let consoleOutput = inputValues[cpos].length >= 5 ?
inputValues[cpos][4] : printOutput;
let consoleTest = inputValues[cpos][5] || inputValue;
HUD.jsterm.clearOutput();
// Test the console.log() output.
let outputItem;
function onExecute(msg) {
outputItem = msg;
subtestNext();
}
HUD.jsterm.execute("console.log(" + consoleTest + ")");
waitForMessages({
webconsole: HUD,
messages: [{
name: "console API output is correct for inputValues[" + cpos + "]",
text: consoleOutput,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
}).then(subtestNext);
yield undefined;
HUD.jsterm.clearOutput();
// Test jsterm print() output.
HUD.jsterm.setInputValue("print(" + inputValue + ")");
HUD.jsterm.execute(null, onExecute);
yield undefined;
ok(outputItem,
"found the jsterm print() output line for inputValues[" + cpos + "]");
ok(outputItem.textContent.indexOf(printOutput) > -1,
"jsterm print() output is correct for inputValues[" + cpos + "]");
// Test jsterm execution output.
HUD.jsterm.clearOutput();
HUD.jsterm.setInputValue(inputValue);
HUD.jsterm.execute(null, onExecute);
yield undefined;
ok(outputItem, "found the jsterm output line for inputValues[" + cpos + "]");
ok(outputItem.textContent.indexOf(expectedOutput) > -1,
"jsterm output is correct for inputValues[" + cpos + "]");
let messageBody = outputItem.querySelector(".body a") ||
outputItem.querySelector(".body");
ok(messageBody, "we have the message body for inputValues[" + cpos + "]");
// Test click on output.
let eventHandlerID = eventHandlers.length + 1;
let variablesViewShown = function(aEvent, aView, aOptions) {
if (aOptions.label.indexOf(expectedOutput) == -1) {
return;
}
HUD.jsterm.off("variablesview-open", variablesViewShown);
eventHandlers[eventHandlerID] = null;
ok(showsVariablesView,
"the variables view shown for inputValues[" + cpos + "]");
popupShown[cpos] = true;
if (showsVariablesView) {
executeSoon(subtestNext);
}
};
HUD.jsterm.on("variablesview-open", variablesViewShown);
eventHandlers.push(variablesViewShown);
EventUtils.synthesizeMouse(messageBody, 2, 2, {}, HUD.iframeWindow);
if (showsVariablesView) {
info("messageBody tagName '" + messageBody.tagName + "' className '" + messageBody.className + "'");
yield undefined; // wait for the panel to open if we need to.
}
testNext();
yield undefined;
}
function testEnd() {
if (testEnded) {
return;
}
testEnded = true;
for (let i = 0; i < eventHandlers.length; i++) {
if (eventHandlers[i]) {
HUD.jsterm.off("variablesview-open", eventHandlers[i]);
}
}
for (let i = 0; i < inputValues.length; i++) {
if (inputValues[i][0] && !popupShown[i]) {
ok(false, "the variables view failed to show for inputValues[" + i + "]");
}
}
HUD = inputValues = testDriver = null;
executeSoon(finishTest);
}
function test() {
requestLongerTimeout(2);
addTab(TEST_URI);
browser.addEventListener("load", tabLoad, true);
}

View File

@ -57,20 +57,16 @@ function autocompletePopupHidden()
popup._panel.removeEventListener("popuphidden", autocompletePopupHidden, false);
ok(!popup.isOpen, "popup is not open");
jsterm.once("autocomplete-updated", function() {
is(completeNode.value, testStr + "dy", "autocomplete shows document.body");
testPropertyPanel();
});
let inputStr = "document.b";
jsterm.setInputValue(inputStr);
EventUtils.synthesizeKey("o", {});
let testStr = inputStr.replace(/./g, " ") + " ";
waitForSuccess({
name: "autocomplete shows document.body",
validatorFn: function()
{
return completeNode.value == testStr + "dy";
},
successFn: testPropertyPanel,
failureFn: finishTest,
});
}
function testPropertyPanel()
@ -87,7 +83,6 @@ function testPropertyPanel()
function onVariablesViewReady(aEvent, aView)
{
findVariableViewProperties(aView, [
{ name: "body", value: "HTMLBodyElement" },
{ name: "body", value: "<body>" },
], { webconsole: gHUD }).then(finishTest);
}

View File

@ -88,8 +88,7 @@ function performWebConsoleTests(hud)
function onNodeOutput(node)
{
isnot(node.textContent.indexOf("[object HTMLHeadingElement"), -1,
"correct output for $0");
isnot(node.textContent.indexOf("<h1>"), -1, "correct output for $0");
jsterm.clearOutput();
jsterm.execute("$0.textContent = 'bug653531'", onNodeUpdate);

View File

@ -22,8 +22,8 @@ function consoleOpened(hud) {
function testConsoleDir(hud, ev, view) {
findVariableViewProperties(view, [
{ name: "__proto__.__proto__.querySelectorAll", value: "Function" },
{ name: "location", value: "Location" },
{ name: "__proto__.write", value: "Function" },
{ name: "__proto__.__proto__.querySelectorAll", value: "querySelectorAll()" },
{ name: "location", value: /Location \u2192 data:Web/ },
{ name: "__proto__.write", value: "write()" },
], { webconsole: hud }).then(finishTest);
}

View File

@ -54,7 +54,7 @@ function consoleOpened(hud)
waitForMessages({
webconsole: gWebConsole,
messages: [{
text: "[object Function]",
text: "function _pfactory/<.getName()",
category: CATEGORY_OUTPUT,
objects: true,
}],

View File

@ -118,7 +118,7 @@ function testJSTerm(hud)
jsterm.clearOutput();
jsterm.execute("pprint({b:2, a:1})");
checkResult('" b: 2\n a: 1"', "pprint()");
checkResult("\" b: 2\\n a: 1\"", "pprint()");
yield undefined;
// check instanceof correctness, bug 599940
@ -154,7 +154,7 @@ function testJSTerm(hud)
// bug 614561
jsterm.clearOutput();
jsterm.execute("pprint('hi')");
checkResult('" 0: "h"\n 1: "i""', "pprint('hi')");
checkResult("\" 0: \\\"h\\\"\\n 1: \\\"i\\\"\"", "pprint('hi')");
yield undefined;
// check that pprint(function) shows function source, bug 618344

View File

@ -0,0 +1,146 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test the webconsole output for various types of objects.
const TEST_URI = "data:text/html;charset=utf8,test for console output - 01";
let dateNow = Date.now();
let {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
let LONG_STRING_LENGTH = DebuggerServer.LONG_STRING_LENGTH;
let LONG_STRING_INITIAL_LENGTH = DebuggerServer.LONG_STRING_INITIAL_LENGTH;
DebuggerServer.LONG_STRING_LENGTH = 100;
DebuggerServer.LONG_STRING_INITIAL_LENGTH = 50;
let longString = (new Array(DebuggerServer.LONG_STRING_LENGTH + 4)).join("a");
let initialString = longString.substring(0, DebuggerServer.LONG_STRING_INITIAL_LENGTH);
let inputTests = [
// 0
{
input: "'hello \\nfrom \\rthe \\\"string world!'",
output: "\"hello \\nfrom \\rthe \\\"string world!\"",
},
// 1
{
// unicode test
input: "'\xFA\u1E47\u0129\xE7\xF6d\xEA \u021B\u0115\u0219\u0165'",
output: "\"\\xFA\\u1E47\\u0129\\xE7\\xF6d\\xEA \\u021B\\u0115\\u0219\\u0165\"",
},
// 2
{
input: "'" + longString + "'",
output: '"' + initialString + "\"[\u2026]",
printOutput: initialString,
},
// 3
{
input: "''",
output: '""',
printOutput: '""',
},
// 4
{
input: "0",
output: "0",
},
// 5
{
input: "'0'",
output: '"0"',
},
// 6
{
input: "42",
output: "42",
},
// 7
{
input: "'42'",
output: '"42"',
},
// 8
{
input: "/foobar/",
output: "/foobar/",
inspectable: true,
},
// 9
{
input: "/foo?b*\\s\"ar/igym",
output: "/foo?b*\\s\"ar/gimy",
printOutput: "/foo?b*\\\\s\\\"ar/gimy",
inspectable: true,
},
// 10
{
input: "null",
output: "null",
},
// 11
{
input: "undefined",
output: "undefined",
},
// 12
{
input: "true",
output: "true",
},
// 13
{
input: "false",
output: "false",
},
// 14
{
input: "new Date(" + dateNow + ")",
output: "Date " + (new Date(dateNow)).toISOString(),
printOutput: (new Date(dateNow)).toString(),
inspectable: true,
},
// 15
{
input: "new Date('test')",
output: "Invalid Date",
printOutput: "Invalid Date",
inspectable: true,
variablesViewLabel: "Invalid Date",
},
];
longString = initialString = null;
function test() {
registerCleanupFunction(() => {
DebuggerServer.LONG_STRING_LENGTH = LONG_STRING_LENGTH;
DebuggerServer.LONG_STRING_INITIAL_LENGTH = LONG_STRING_INITIAL_LENGTH;
});
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole().then((hud) => {
return checkOutputForInputs(hud, inputTests);
}).then(finishTest);
}, true);
}

View File

@ -0,0 +1,161 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test the webconsole output for various types of objects.
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-02.html";
let inputTests = [
// 0 - native named function
{
input: "document.getElementById",
output: "function getElementById()",
printOutput: "function getElementById() {\\n [native code]\\n}",
inspectable: true,
variablesViewLabel: "getElementById()",
},
// 1 - anonymous function
{
input: "(function() { return 42; })",
output: "function ()",
printOutput: "function () { return 42; }",
inspectable: true,
},
// 2 - named function
{
input: "window.testfn1",
output: "function testfn1()",
printOutput: "function testfn1() { return 42; }",
inspectable: true,
variablesViewLabel: "testfn1()",
},
// 3 - anonymous function, but spidermonkey gives us an inferred name.
{
input: "testobj1.testfn2",
output: "function testobj1.testfn2()",
printOutput: "function () { return 42; }",
inspectable: true,
variablesViewLabel: "testobj1.testfn2()",
},
// 4 - named function with custom display name
{
input: "window.testfn3",
output: "function testfn3DisplayName()",
printOutput: "function testfn3() { return 42; }",
inspectable: true,
variablesViewLabel: "testfn3DisplayName()",
},
// 5 - basic array
{
input: "window.array1",
output: '[1, 2, 3, "a", "b", "c", "4", "5"]',
printOutput: "1,2,3,a,b,c,4,5",
inspectable: true,
variablesViewLabel: "Array[8]",
},
// 6 - array with objects
{
input: "window.array2",
output: '["a", HTMLDocument \u2192 test-console-output-02.html, <body>, ' +
"DOMStringMap[0], DOMTokenList[0]]",
printOutput: '"a,[object HTMLDocument],[object HTMLBodyElement],' +
'[object DOMStringMap],"',
inspectable: true,
variablesViewLabel: "Array[5]",
},
// 7 - array with more than 10 elements
{
input: "window.array3",
output: '[1, Window \u2192 test-console-output-02.html, null, "a", "b", ' +
'undefined, false, "", -Infinity, testfn3DisplayName(), 3 more\u2026]',
printOutput: '"1,[object Window],,a,b,,false,,-Infinity,' +
'function testfn3() { return 42; },[object Object],foo,bar"',
inspectable: true,
variablesViewLabel: "Array[13]",
},
// 8 - array with holes and a cyclic reference
{
input: "window.array4",
output: '[,,,,, "test", Array[7]]',
printOutput: '",,,,,test,"',
inspectable: true,
variablesViewLabel: "Array[7]",
},
// 9
{
input: "window.typedarray1",
output: 'Int32Array [1, 287, 8651, 40983, 8754]',
printOutput: "[object Int32Array]",
inspectable: true,
variablesViewLabel: "Int32Array[5]",
},
// 10 - Set with cyclic reference
{
input: "window.set1",
output: 'Set [1, 2, null, Array[13], "a", "b", undefined, <head>, Set[9]]',
printOutput: "[object Set]",
inspectable: true,
variablesViewLabel: "Set[9]",
},
// 11 - Object with cyclic reference and a getter
{
input: "window.testobj2",
output: '{a: "b", c: "d", e: 1, f: "2", foo: Object, bar: Object, ' +
"getterTest: Getter}",
printOutput: "[object Object]",
inspectable: true,
variablesViewLabel: "Object",
},
// 12 - Object with more than 10 properties
{
input: "window.testobj3",
output: '{a: "b", c: "d", e: 1, f: "2", g: true, h: null, i: undefined, ' +
'j: "", k: StyleSheetList[0], l: NodeList[5], 2 more\u2026}',
printOutput: "[object Object]",
inspectable: true,
variablesViewLabel: "Object",
},
// 13 - Object with a non-enumerable property that we do not show
{
input: "window.testobj4",
output: '{a: "b", c: "d", 1 more\u2026}',
printOutput: "[object Object]",
inspectable: true,
variablesViewLabel: "Object",
},
// 14 - Map with cyclic references
{
input: "window.map1",
output: 'Map {a: "b", HTMLCollection[2]: Object, Map[3]: Set[9]}',
printOutput: "[object Map]",
inspectable: true,
variablesViewLabel: "Map[3]",
},
];
function test() {
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole().then((hud) => {
return checkOutputForInputs(hud, inputTests);
}).then(finishTest);
}, true);
}

View File

@ -0,0 +1,164 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test the webconsole output for various types of objects.
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-03.html";
let inputTests = [
// 0
{
input: "document",
output: "HTMLDocument \u2192 " + TEST_URI,
printOutput: "[object HTMLDocument]",
inspectable: true,
noClick: true,
},
// 1
{
input: "window",
output: "Window \u2192 " + TEST_URI,
printOutput: "[object Window",
inspectable: true,
noClick: true,
},
// 2
{
input: "document.body",
output: "<body>",
printOutput: "[object HTMLBodyElement]",
inspectable: true,
noClick: true,
},
// 3
{
input: "document.body.dataset",
output: "DOMStringMap {}",
printOutput: "[object DOMStringMap]",
inspectable: true,
variablesViewLabel: "DOMStringMap[0]",
},
// 4
{
input: "document.body.classList",
output: "DOMTokenList []",
printOutput: '""',
inspectable: true,
variablesViewLabel: "DOMTokenList[0]",
},
// 5
{
input: "window.location.href",
output: '"' + TEST_URI + '"',
},
// 6
{
input: "window.location",
output: "Location \u2192 " + TEST_URI,
printOutput: TEST_URI,
inspectable: true,
variablesViewLabel: "Location \u2192 test-console-output-03.html",
},
// 7
{
input: "document.body.attributes",
output: "MozNamedAttrMap []",
printOutput: "[object MozNamedAttrMap]",
inspectable: true,
variablesViewLabel: "MozNamedAttrMap[0]",
},
// 8
{
input: "document.styleSheets",
output: "StyleSheetList []",
printOutput: "[object StyleSheetList",
inspectable: true,
variablesViewLabel: "StyleSheetList[0]",
},
// 9
{
input: "testBodyClassName()",
output: '<body class="test1 tezt2">',
printOutput: "[object HTMLBodyElement]",
inspectable: true,
noClick: true,
},
// 10
{
input: "testBodyID()",
output: '<body class="test1 tezt2" id="foobarid">',
printOutput: "[object HTMLBodyElement]",
inspectable: true,
noClick: true,
},
// 11
{
input: "document.body.classList",
output: 'DOMTokenList ["test1", "tezt2"]',
printOutput: '"test1 tezt2"',
inspectable: true,
variablesViewLabel: "DOMTokenList[2]",
},
// 12
{
input: "testBodyDataset()",
output: '<body class="test1 tezt2" id="foobarid"' +
' data-preview="zuzu&quot;&lt;a&gt;foo">',
printOutput: "[object HTMLBodyElement]",
inspectable: true,
noClick: true,
},
// 13
{
input: "document.body.dataset",
output: 'DOMStringMap {preview: "zuzu\\"<a>foo"}',
printOutput: "[object DOMStringMap]",
inspectable: true,
variablesViewLabel: "DOMStringMap[1]",
},
// 14
{
input: "document.body.attributes",
output: 'MozNamedAttrMap [class="test1 tezt2", id="foobarid", ' +
'data-preview="zuzu&quot;&lt;a&gt;foo"]',
printOutput: "[object MozNamedAttrMap]",
inspectable: true,
variablesViewLabel: "MozNamedAttrMap[3]",
},
// 15
{
input: "document.body.attributes[0]",
output: 'class="test1 tezt2"',
printOutput: "[object Attr]",
inspectable: true,
variablesViewLabel: 'class="test1 tezt2"',
},
];
function test() {
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole().then((hud) => {
return checkOutputForInputs(hud, inputTests);
}).then(finishTest);
}, true);
}

View File

@ -0,0 +1,120 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test the webconsole output for various types of objects.
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-04.html";
let inputTests = [
// 0
{
input: "testTextNode()",
output: '#text "hello world!"',
printOutput: "[object Text]",
inspectable: true,
noClick: true,
},
// 1
{
input: "testCommentNode()",
output: "<!--\n - Any copyright ",
printOutput: "[object Comment]",
inspectable: true,
noClick: true,
},
// 2
{
input: "testDocumentFragment()",
output: 'DocumentFragment [<div id="foo1" class="bar">, <div id="foo3">]',
printOutput: "[object DocumentFragment]",
inspectable: true,
variablesViewLabel: "DocumentFragment[2]",
},
// 3
{
input: "testError()",
output: "TypeError: window.foobar is not a function\n" +
"Stack trace:\n" +
"testError@" + TEST_URI + ":44",
printOutput: '"TypeError: window.foobar is not a function"',
inspectable: true,
variablesViewLabel: "TypeError",
},
// 4
{
input: "testDOMException()",
output: 'DOMException [SyntaxError: "An invalid or illegal string was specified"',
printOutput: '[Exception... \\"An invalid or illegal string was specified\\"',
inspectable: true,
variablesViewLabel: "SyntaxError",
},
// 5
{
input: "testCSSStyleDeclaration()",
output: 'CSS2Properties {color: "green", font-size: "2em"}',
printOutput: "[object CSS2Properties]",
inspectable: true,
noClick: true,
},
// 6
{
input: "testStyleSheetList()",
output: "StyleSheetList [CSSStyleSheet]",
printOutput: "[object StyleSheetList",
inspectable: true,
variablesViewLabel: "StyleSheetList[1]",
},
// 7
{
input: "document.styleSheets[0]",
output: "CSSStyleSheet",
printOutput: "[object CSSStyleSheet]",
inspectable: true,
},
// 8
{
input: "document.styleSheets[0].cssRules",
output: "CSSRuleList [CSSStyleRule, CSSMediaRule]",
printOutput: "[object CSSRuleList",
inspectable: true,
variablesViewLabel: "CSSRuleList[2]",
},
// 9
{
input: "document.styleSheets[0].cssRules[0]",
output: 'CSSStyleRule "p, div"',
printOutput: "[object CSSStyleRule",
inspectable: true,
variablesViewLabel: "CSSStyleRule",
},
// 10
{
input: "document.styleSheets[0].cssRules[1]",
output: 'CSSMediaRule "print"',
printOutput: "[object CSSMediaRule",
inspectable: true,
variablesViewLabel: "CSSMediaRule",
},
];
function test() {
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
openConsole().then((hud) => {
return checkOutputForInputs(hud, inputTests);
}).then(finishTest);
}, true);
}

View File

@ -0,0 +1,60 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test the webconsole output for DOM events.
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-events.html";
function test() {
addTab(TEST_URI);
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
Task.spawn(runner);
}, true);
function* runner()
{
let hud = yield openConsole();
hud.jsterm.clearOutput();
hud.jsterm.execute("testDOMEvents()");
yield waitForMessages({
webconsole: hud,
messages: [{
name: "testDOMEvents() output",
text: "undefined",
category: CATEGORY_OUTPUT,
}],
});
EventUtils.synthesizeMouse(content.document.body, 2, 2, {type: "mousemove"}, content);
yield waitForMessages({
webconsole: hud,
messages: [{
name: "console.log() output for mousemove",
text: /"eventLogger" mousemove {target: .+, buttons: 1, clientX: \d+, clientY: \d+, layerX: \d+, layerY: \d+}/,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
content.focus();
EventUtils.synthesizeKey("a", {shiftKey: true}, content);
yield waitForMessages({
webconsole: hud,
messages: [{
name: "console.log() output for keypress",
text: /"eventLogger" keypress Shift {target: .+, key: .+, charCode: \d+, keyCode: \d+}/,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
finishTest();
}
}

View File

@ -3,18 +3,18 @@
* 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/. */
let WebConsoleUtils, gDevTools, TargetFactory, console, promise, require;
let WebConsoleUtils, TargetFactory, require;
let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
let {Promise: promise} = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
let {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
(() => {
gDevTools = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}).gDevTools;
console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
let tools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
let utils = tools.require("devtools/toolkit/webconsole/utils");
TargetFactory = tools.TargetFactory;
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let utils = devtools.require("devtools/toolkit/webconsole/utils");
TargetFactory = devtools.TargetFactory;
WebConsoleUtils = utils.Utils;
require = tools.require;
require = devtools.require;
})();
// promise._reportErrors = true; // please never leave me.
@ -152,15 +152,20 @@ function findLogEntry(aString)
* @param function [aCallback]
* Optional function to invoke after the Web Console completes
* initialization (web-console-created).
* @return object
* A promise that is resolved once the web console is open.
*/
function openConsole(aTab, aCallback = function() { })
{
let deferred = promise.defer();
let target = TargetFactory.forTab(aTab || tab);
gDevTools.showToolbox(target, "webconsole").then(function(toolbox) {
let hud = toolbox.getCurrentPanel().hud;
hud.jsterm._lazyVariablesView = false;
aCallback(hud);
deferred.resolve(hud);
});
return deferred.promise;
}
/**
@ -1259,3 +1264,153 @@ function whenDelayedStartupFinished(aWindow, aCallback)
}
}, "browser-delayed-startup-finished", false);
}
/**
* Check the web console output for the given inputs. Each input is checked for
* the expected JS eval result, the result of calling print(), the result of
* console.log(). The JS eval result is also checked if it opens the variables
* view on click.
*
* @param object hud
* The web console instance to work with.
* @param array inputTests
* An array of input tests. An input test element is an object. Each
* object has the following properties:
* - input: string, JS input value to execute.
*
* - output: string|RegExp, expected JS eval result.
*
* - inspectable: boolean, when true, the test runner expects the JS eval
* result is an object that can be clicked for inspection.
*
* - noClick: boolean, when true, the test runner does not click the JS
* eval result. Some objects, like |window|, have a lot of properties and
* opening vview for them is very slow (they can cause timeouts in debug
* builds).
*
* - printOutput: string|RegExp, optional, expected output for
* |print(input)|. If this is not provided, printOutput = output.
*
* - variablesViewLabel: string|RegExp, optional, the expected variables
* view label when the object is inspected. If this is not provided, then
* |output| is used.
*/
function checkOutputForInputs(hud, inputTests)
{
let eventHandlers = new Set();
function* runner()
{
for (let [i, entry] of inputTests.entries()) {
info("checkInput(" + i + "): " + entry.input);
yield checkInput(entry);
}
for (let fn of eventHandlers) {
hud.jsterm.off("variablesview-open", fn);
}
}
function* checkInput(entry)
{
yield checkConsoleLog(entry);
yield checkPrintOutput(entry);
yield checkJSEval(entry);
}
function checkConsoleLog(entry)
{
hud.jsterm.clearOutput();
hud.jsterm.execute("console.log(" + entry.input + ")");
return waitForMessages({
webconsole: hud,
messages: [{
name: "console.log() output: " + entry.output,
text: entry.output,
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
}
function checkPrintOutput(entry)
{
hud.jsterm.clearOutput();
hud.jsterm.execute("print(" + entry.input + ")");
let printOutput = entry.printOutput || entry.output;
return waitForMessages({
webconsole: hud,
messages: [{
name: "print() output: " + printOutput,
text: printOutput,
category: CATEGORY_OUTPUT,
}],
});
}
function* checkJSEval(entry)
{
hud.jsterm.clearOutput();
hud.jsterm.execute(entry.input);
let [result] = yield waitForMessages({
webconsole: hud,
messages: [{
name: "JS eval output: " + entry.output,
text: entry.output,
category: CATEGORY_OUTPUT,
}],
});
if (!entry.noClick) {
let msg = [...result.matched][0];
yield checkObjectClick(entry, msg);
}
}
function checkObjectClick(entry, msg)
{
let body = msg.querySelector(".body a") || msg.querySelector(".body");
ok(body, "the message body");
let deferred = promise.defer();
entry._onVariablesViewOpen = onVariablesViewOpen.bind(null, entry, deferred);
hud.jsterm.on("variablesview-open", entry._onVariablesViewOpen);
eventHandlers.add(entry._onVariablesViewOpen);
body.scrollIntoView();
EventUtils.synthesizeMouse(body, 2, 2, {}, hud.iframeWindow);
if (entry.inspectable) {
info("message body tagName '" + body.tagName + "' className '" + body.className + "'");
return deferred.promise; // wait for the panel to open if we need to.
}
return promise.resolve(null);
}
function onVariablesViewOpen(entry, deferred, event, view, options)
{
let label = entry.variablesViewLabel || entry.output;
if (typeof label == "string" && options.label != label) {
return;
}
if (label instanceof RegExp && !label.test(options.label)) {
return;
}
hud.jsterm.off("variablesview-open", entry._onVariablesViewOpen);
eventHandlers.delete(entry._onVariablesViewOpen);
entry._onVariablesViewOpen = null;
ok(entry.inspectable, "variables view was shown");
deferred.resolve(null);
}
return Task.spawn(runner);
}

View File

@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8">
<title>Test the web console output - 02</title>
<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-->
</head>
<body>
<p>hello world!</p>
<script type="text/javascript">
function testfn1() { return 42; }
var testobj1 = {
testfn2: function() { return 42; },
};
function testfn3() { return 42; }
testfn3.displayName = "testfn3DisplayName";
var array1 = [1, 2, 3, "a", "b", "c", "4", "5"];
var array2 = ["a", document, document.body, document.body.dataset,
document.body.classList];
var array3 = [1, window, null, "a", "b", undefined, false, "", -Infinity, testfn3, testobj1, "foo", "bar"];
var array4 = new Array(5);
array4.push("test");
array4.push(array4);
var typedarray1 = new Int32Array([1, 287, 8651, 40983, 8754]);
var set1 = new Set([1, 2, null, array3, "a", "b", undefined, document.head]);
set1.add(set1);
var testobj2 = {a: "b", c: "d", e: 1, f: "2"};
testobj2.foo = testobj1;
testobj2.bar = testobj2;
Object.defineProperty(testobj2, "getterTest", {
enumerable: true,
get: function() {
return 42;
},
});
var testobj3 = {a: "b", c: "d", e: 1, f: "2", g: true, h: null, i: undefined,
j: "", k: document.styleSheets, l: document.body.childNodes,
o: new Array(125), m: document.head};
var testobj4 = {a: "b", c: "d"};
Object.defineProperty(testobj4, "nonEnumerable", { value: "hello world" });
var map1 = new Map([["a", "b"], [document.body.children, testobj2]]);
map1.set(map1, set1);
</script>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8">
<title>Test the web console output - 03</title>
<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-->
</head>
<body>
<p>hello world!</p>
<script type="text/javascript">
function testBodyClassName() {
document.body.className = "test1 tezt2";
return document.body;
}
function testBodyID() {
document.body.id = 'foobarid';
return document.body;
}
function testBodyDataset() {
document.body.dataset.preview = 'zuzu"<a>foo';
return document.body;
}
</script>
</body>
</html>

View File

@ -0,0 +1,77 @@
<!DOCTYPE HTML>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8">
<title>Test the web console output - 04</title>
<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-->
</head>
<body>
<p>hello world!</p>
<script type="text/javascript">
function testTextNode() {
return document.querySelector("p").childNodes[0];
}
function testCommentNode() {
return document.head.childNodes[5];
}
function testDocumentFragment() {
var frag = document.createDocumentFragment();
var div = document.createElement("div");
div.id = "foo1";
div.className = "bar";
frag.appendChild(div);
var span = document.createElement("span");
span.id = "foo2";
span.textContent = "hello world";
div.appendChild(span);
var div2 = document.createElement("div");
div2.id = "foo3";
frag.appendChild(div2);
return frag;
}
function testError() {
try {
window.foobar("a");
} catch (ex) {
return ex;
}
return null;
}
function testDOMException() {
try {
var foo = document.querySelector("foo;()bar!");
} catch (ex) {
return ex;
}
return null;
}
function testCSSStyleDeclaration() {
document.body.style = 'color: green; font-size: 2em';
return document.body.style;
}
function testStyleSheetList() {
var style = document.querySelector("style");
if (!style) {
style = document.createElement("style");
style.textContent = "p, div { color: blue; font-weight: bold }\n" +
"@media print { p { background-color: yellow } }";
document.head.appendChild(style);
}
return document.styleSheets;
}
</script>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8">
<title>Test the web console output for DOM events</title>
<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-->
</head>
<body>
<p>hello world!</p>
<script type="text/javascript">
function testDOMEvents() {
function eventLogger(ev) {
console.log("eventLogger", ev);
}
document.addEventListener("mousemove", eventLogger);
document.addEventListener("keypress", eventLogger);
}
</script>
</body>
</html>

View File

@ -1183,10 +1183,6 @@ WebConsoleFrame.prototype = {
let clipboardArray = [];
args.forEach((aValue) => {
clipboardArray.push(VariablesView.getString(aValue));
if (aValue && typeof aValue == "object" &&
aValue.type == "longString") {
clipboardArray.push(l10n.getStr("longStringEllipsis"));
}
});
clipboardText = clipboardArray.join(" ");
break;
@ -3103,7 +3099,7 @@ JSTerm.prototype = {
aAfterMessage._objectActors.add(helperResult.object.actor);
}
this.openVariablesView({
label: VariablesView.getString(helperResult.object),
label: VariablesView.getString(helperResult.object, { concise: true }),
objectActor: helperResult.object,
});
break;
@ -4265,6 +4261,7 @@ JSTerm.prototype = {
popup.selectNextItem();
}
this.emit("autocomplete-updated");
aCallback && aCallback(this);
},

View File

@ -0,0 +1,5 @@
<!-- 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/. -->
<!ENTITY aboutAccounts.pageTitle "&brandShortName; Accounts">

View File

@ -202,8 +202,8 @@ loadingText=Loading\u2026
# viewer when there is an error loading a file
errorLoadingText=Error loading source:\n
# LOCALIZATION NOTE (emptyStackText): The text that is displayed in the watch
# expressions list to add a new item.
# LOCALIZATION NOTE (addWatchExpressionText): The text that is displayed in the
# watch expressions list to add a new item.
addWatchExpressionText=Add watch expression
# LOCALIZATION NOTE (emptyVariablesText): The text that is displayed in the
@ -225,6 +225,19 @@ watchExpressionsScopeLabel=Watch expressions
# the global scope.
globalScopeLabel=Global
# LOCALIZATION NOTE (variablesViewErrorStacktrace): This is the text that is
# shown before the stack trace in an error.
variablesViewErrorStacktrace=Stack trace:
# LOCALIZATION NOTE (variablesViewMoreObjects): the text that is displayed
# when you have an object preview that does not show all of the elements. At the end of the list
# you see "N more..." in the web console output.
# This is a semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #1 number of remaining items in the object
# example: 3 more…
variablesViewMoreObjects=#1 more…;#1 more…
# LOCALIZATION NOTE (variablesEditableNameTooltip): The text that is displayed
# in the variables list on an item with an editable name.
variablesEditableNameTooltip=Double click to edit

View File

@ -33,6 +33,8 @@
<!ENTITY setup.choosePassword.accesskey "P">
<!ENTITY setup.confirmPassword.label "Confirm Password">
<!ENTITY setup.confirmPassword.accesskey "m">
<!ENTITY setup.setupMetro.label "Sync with Windows 8 style &brandShortName;">
<!ENTITY setup.setupMetro.accesskey "S">
<!-- LOCALIZATION NOTE: tosAgree1, tosLink, tosAgree2, ppLink, tosAgree3 are
joined with implicit white space, so spaces in the strings aren't necessary -->

View File

@ -6,6 +6,7 @@
@AB_CD@.jar:
% locale browser @AB_CD@ %locale/browser/
locale/browser/aboutAccounts.dtd (%chrome/browser/aboutAccounts.dtd)
locale/browser/aboutCertError.dtd (%chrome/browser/aboutCertError.dtd)
locale/browser/aboutDialog.dtd (%chrome/browser/aboutDialog.dtd)
locale/browser/aboutPrivateBrowsing.dtd (%chrome/browser/aboutPrivateBrowsing.dtd)

View File

@ -100,11 +100,26 @@ XPCOMUtils.defineLazyGetter(this, "DEFAULT_ITEMS", function() {
return result;
});
const ALL_BUILTIN_ITEMS = [
"fullscreen-button",
"switch-to-metro-button",
"bookmarks-menu-button",
];
XPCOMUtils.defineLazyGetter(this, "ALL_BUILTIN_ITEMS", function() {
// These special cases are for click events on built-in items that are
// contained within customizable items (like the navigation widget).
const SPECIAL_CASES = [
"back-button",
"forward-button",
"urlbar-stop-button",
"urlbar-go-button",
"urlbar-reload-button",
"searchbar",
"cut-button",
"copy-button",
"paste-button",
"zoom-out-button",
"zoom-reset-button",
"zoom-in-button",
]
return DEFAULT_ITEMS.concat(PALETTE_ITEMS)
.concat(SPECIAL_CASES);
});
const OTHER_MOUSEUP_MONITORED_ITEMS = [
"PlacesChevron",
@ -318,6 +333,14 @@ this.BrowserUITelemetry = {
// Base case - we clicked directly on one of our built-in items,
// and we can go ahead and register that click.
this._countMouseUpEvent("click-builtin-item", item.id, aEvent.button);
return;
}
// If not, we need to check if one of the ancestors of the clicked
// item is in our list of built-in items to check.
let candidate = getIDBasedOnFirstIDedAncestor(item);
if (ALL_BUILTIN_ITEMS.indexOf(candidate) != -1) {
this._countMouseUpEvent("click-builtin-item", candidate, aEvent.button);
}
},
@ -396,4 +419,4 @@ function getIDBasedOnFirstIDedAncestor(aNode) {
}
return aNode.id;
}
}

View File

@ -51,7 +51,7 @@
display: none;
}
.devtools-toolbarbutton:not([checked=true]):hover:active {
.devtools-toolbarbutton:not([checked]):hover:active {
border-color: hsla(210,8%,5%,.6);
background: linear-gradient(hsla(220,6%,10%,.3), hsla(212,7%,57%,.15) 65%, hsla(212,7%,57%,.3));
box-shadow: 0 0 3px hsla(210,8%,5%,.25) inset, 0 1px 3px hsla(210,8%,5%,.25) inset, 0 1px 0 hsla(210,16%,76%,.15);
@ -282,28 +282,28 @@
background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @smallSeparator@;
}
.devtools-sidebar-tabs > tabs > tab[selected=true] + tab {
.devtools-sidebar-tabs > tabs > tab[selected] + tab {
background-image: linear-gradient(transparent, transparent), @solidSeparator@;
}
.devtools-sidebar-tabs > tabs > tab[selected=true] + tab:hover {
.devtools-sidebar-tabs > tabs > tab[selected] + tab:hover {
background-image: linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.2)), @solidSeparator@;
}
.devtools-sidebar-tabs > tabs > tab[selected=true] + tab:hover:active {
.devtools-sidebar-tabs > tabs > tab[selected] + tab:hover:active {
background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @solidSeparator@;
}
.devtools-sidebar-tabs > tabs > tab[selected=true] {
.devtools-sidebar-tabs > tabs > tab[selected] {
color: #f5f7fa;
background-image: linear-gradient(#1d4f73, #1d4f73), @solidSeparator@;
}
.devtools-sidebar-tabs > tabs > tab[selected=true]:hover {
.devtools-sidebar-tabs > tabs > tab[selected]:hover {
background-image: linear-gradient(#274f64, #274f64), @solidSeparator@;
}
.devtools-sidebar-tabs > tabs > tab[selected=true]:hover:active {
.devtools-sidebar-tabs > tabs > tab[selected]:hover:active {
background-image: linear-gradient(#1f3e4f, #1f3e4f), @solidSeparator@;
}
@ -520,7 +520,7 @@
}
.devtools-tab:active > image,
.devtools-tab[selected=true] > image {
.devtools-tab[selected] > image {
opacity: 1;
}
@ -534,7 +534,7 @@
color: #f5f7fa;
}
#toolbox-tabs .devtools-tab[selected=true] {
#toolbox-tabs .devtools-tab[selected] {
color: #f5f7fa;
background-color: #1a4666;
box-shadow: 0 2px 0 #d7f1ff inset,
@ -542,32 +542,32 @@
0 -2px 0 rgba(0,0,0,.2) inset;
}
.devtools-tab[selected=true]:not(:first-child),
.devtools-tab.highlighted:not(:first-child) {
.devtools-tab[selected]:not(:first-child),
.devtools-tab[highlighted]:not(:first-child) {
border-width: 0;
-moz-padding-start: 1px;
}
.devtools-tab[selected=true]:last-child,
.devtools-tab.highlighted:last-child {
.devtools-tab[selected]:last-child,
.devtools-tab[highlighted]:last-child {
-moz-padding-end: 1px;
}
.devtools-tab[selected=true] + .devtools-tab,
.devtools-tab.highlighted + .devtools-tab {
.devtools-tab[selected] + .devtools-tab,
.devtools-tab[highlighted] + .devtools-tab {
-moz-border-start-width: 0;
-moz-padding-start: 1px;
}
.devtools-tab:not([selected=true]).highlighted {
.devtools-tab:not([selected])[highlighted] {
color: #f5f7fa;
background-color: hsla(99,100%,14%,.2);
box-shadow: 0 2px 0 #7bc107 inset;
}
.devtools-tab:not(.highlighted) > .highlighted-icon,
.devtools-tab[selected=true] > .highlighted-icon,
.devtools-tab:not([selected=true]).highlighted > .default-icon {
.devtools-tab:not([highlighted]) > .highlighted-icon,
.devtools-tab[selected] > .highlighted-icon,
.devtools-tab:not([selected])[highlighted] > .default-icon {
visibility: collapse;
}

View File

@ -686,7 +686,6 @@ GK_ATOM(ondisabled, "ondisabled")
GK_ATOM(ondischargingtimechange, "ondischargingtimechange")
GK_ATOM(ondisconnected, "ondisconnected")
GK_ATOM(ondisconnecting, "ondisconnecting")
GK_ATOM(ondiscoverystatechanged, "ondiscoverystatechanged")
GK_ATOM(ondownloading, "ondownloading")
GK_ATOM(onDOMActivate, "onDOMActivate")
GK_ATOM(onDOMAttrModified, "onDOMAttrModified")

View File

@ -48,10 +48,6 @@ const kEventConstructors = {
return new BluetoothDeviceEvent(aName, aProps);
},
},
BluetoothDiscoveryStateChangedEvent: { create: function (aName, aProps) {
return new BluetoothDiscoveryStateChangedEvent(aName, aProps);
},
},
BluetoothStatusChangedEvent: { create: function (aName, aProps) {
return new BluetoothStatusChangedEvent(aName, aProps);
},

View File

@ -23,7 +23,7 @@ interface nsIMarkupDocumentViewer;
[ref] native nsIMarkupDocumentViewerTArray(nsTArray<nsCOMPtr<nsIMarkupDocumentViewer> >);
[scriptable, uuid(3528324f-f5d3-4724-bd8d-9233a7114112)]
[scriptable, uuid(7aea9561-5346-401c-b40e-418688da2d0d)]
interface nsIMarkupDocumentViewer : nsISupports
{
@ -82,6 +82,18 @@ interface nsIMarkupDocumentViewer : nsISupports
*/
void changeMaxLineBoxWidth(in int32_t maxLineBoxWidth);
/**
* Instruct the refresh driver to discontinue painting until further
* notice.
*/
void pausePainting();
/**
* Instruct the refresh driver to resume painting after a previous call to
* pausePainting().
*/
void resumePainting();
/*
* Render the document as if being viewed on a device with the specified
* media type. This will cause a reflow.

View File

@ -9,7 +9,6 @@
#include "nsCxPusher.h"
#include "nsDOMClassInfo.h"
#include "nsIDOMBluetoothDeviceEvent.h"
#include "nsIDOMBluetoothDiscoveryStateChangedEvent.h"
#include "nsIDOMBluetoothStatusChangedEvent.h"
#include "nsTArrayHelpers.h"
#include "DOMRequest.h"
@ -322,19 +321,6 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) {
SetPropertyByValue(arr[i]);
}
} else if (aData.name().EqualsLiteral(DISCOVERY_STATE_CHANGED_ID)) {
MOZ_ASSERT(v.type() == BluetoothValue::Tbool);
bool isDiscovering = v.get_bool();
nsCOMPtr<nsIDOMEvent> event;
NS_NewDOMBluetoothDiscoveryStateChangedEvent(
getter_AddRefs(event), this, nullptr, nullptr);
nsCOMPtr<nsIDOMBluetoothDiscoveryStateChangedEvent> e =
do_QueryInterface(event);
e->InitBluetoothDiscoveryStateChangedEvent(aData.name(), false, false,
isDiscovering);
DispatchTrustedEvent(event);
} else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) ||
aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) ||

View File

@ -147,7 +147,6 @@ public:
SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv);
IMPL_EVENT_HANDLER(devicefound);
IMPL_EVENT_HANDLER(discoverystatechanged);
IMPL_EVENT_HANDLER(a2dpstatuschanged);
IMPL_EVENT_HANDLER(hfpstatuschanged);
IMPL_EVENT_HANDLER(pairedstatuschanged);

View File

@ -92,11 +92,6 @@ extern bool gBluetoothDebugFlag;
*/
#define PAIRED_STATUS_CHANGED_ID "pairedstatuschanged"
/**
* This event would be fired when discovery procedure starts or stops.
*/
#define DISCOVERY_STATE_CHANGED_ID "discoverystatechanged"
/**
* When receiving a query about current play status from remote device, we'll
* dispatch an event.

View File

@ -50,6 +50,7 @@ static InfallibleTArray<nsString> sAdapterBondedAddressArray;
static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
@ -510,16 +511,12 @@ DiscoveryStateChangedCallback(bt_discovery_state_t aState)
{
MOZ_ASSERT(!NS_IsMainThread());
bool isDiscovering = (aState == BT_DISCOVERY_STARTED);
if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
BluetoothValue values(true);
DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
values, EmptyString());
BluetoothSignal signal(NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID),
NS_LITERAL_STRING(KEY_ADAPTER),
isDiscovering);
nsRefPtr<DistributeBluetoothSignalTask>
t = new DistributeBluetoothSignalTask(signal);
if (NS_FAILED(NS_DispatchToMainThread(t))) {
BT_WARNING("Failed to dispatch to main thread!");
sChangeDiscoveryRunnableArray.RemoveElementAt(0);
}
}
@ -936,17 +933,17 @@ BluetoothServiceBluedroid::StartDiscoveryInternal(
if (!IsReady()) {
NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
return NS_OK;
}
int ret = sBtInterface->start_discovery();
if (ret != BT_STATUS_SUCCESS) {
ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery"));
return NS_ERROR_FAILURE;
return NS_OK;
}
DispatchBluetoothReply(aRunnable, true, EmptyString());
sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
return NS_OK;
}
@ -965,10 +962,10 @@ BluetoothServiceBluedroid::StopDiscoveryInternal(
int ret = sBtInterface->cancel_discovery();
if (ret != BT_STATUS_SUCCESS) {
ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery"));
return NS_ERROR_FAILURE;
return NS_OK;
}
DispatchBluetoothReply(aRunnable, true, EmptyString());
sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
return NS_OK;
}

View File

@ -1560,20 +1560,6 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
errorStr,
sAdapterProperties,
ArrayLength(sAdapterProperties));
BluetoothNamedValue& property = v.get_ArrayOfBluetoothNamedValue()[0];
if (property.name().EqualsLiteral("Discovering")) {
bool isDiscovering = property.value();
BluetoothSignal signal(NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID),
NS_LITERAL_STRING(KEY_ADAPTER),
isDiscovering);
nsRefPtr<DistributeBluetoothSignalTask>
t = new DistributeBluetoothSignalTask(signal);
if (NS_FAILED(NS_DispatchToMainThread(t))) {
BT_WARNING("Failed to dispatch to main thread!");
}
}
} else if (dbus_message_is_signal(aMsg, DBUS_DEVICE_IFACE,
"PropertyChanged")) {
ParsePropertyChange(aMsg,

View File

@ -8,7 +8,6 @@ if CONFIG['MOZ_B2G_BT']:
XPIDL_SOURCES += [
'nsIDOMBluetoothDevice.idl',
'nsIDOMBluetoothDeviceEvent.idl',
'nsIDOMBluetoothDiscoveryStateChangedEvent.idl',
'nsIDOMBluetoothStatusChangedEvent.idl',
]
XPIDL_MODULE = 'dom_bluetooth'

View File

@ -1,22 +0,0 @@
/* 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 "nsIDOMEvent.idl"
[scriptable, builtinclass, uuid(9de639cb-71c4-4144-8462-09763ec87c20)]
interface nsIDOMBluetoothDiscoveryStateChangedEvent : nsIDOMEvent
{
readonly attribute boolean discovering;
[noscript]
void initBluetoothDiscoveryStateChangedEvent(in DOMString aType,
in boolean aCanBubble,
in boolean aCancelable,
in boolean aDiscovering);
};
dictionary BluetoothDiscoveryStateChangedEventInit : EventInit
{
bool discovering;
};

View File

@ -60,7 +60,7 @@ let CERTIFICATE_ERROR_PAGE_PREF = 'security.alternate_certificate_error_page';
let NS_ERROR_MODULE_BASE_OFFSET = 0x45;
let NS_ERROR_MODULE_SECURITY= 21;
function NS_ERROR_GET_MODULE(err) {
return ((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff)
return ((((err) >> 16) - NS_ERROR_MODULE_BASE_OFFSET) & 0x1fff);
}
function NS_ERROR_GET_CODE(err) {
@ -82,7 +82,7 @@ let SSL_ERROR_BAD_CERT_DOMAIN = (SSL_ERROR_BASE + 12);
function getErrorClass(errorCode) {
let NSPRCode = -1 * NS_ERROR_GET_CODE(errorCode);
switch (NSPRCode) {
case SEC_ERROR_UNKNOWN_ISSUER:
case SEC_ERROR_CA_CERT_INVALID:
@ -129,6 +129,9 @@ function BrowserElementChild() {
this._nextPaintHandler = null;
this._isContentWindowCreated = false;
this._pendingSetInputMethodActive = [];
this._init();
};
@ -566,6 +569,11 @@ BrowserElementChild.prototype = {
this._addMozAfterPaintHandler(function () {
sendAsyncMsg('documentfirstpaint');
});
this._isContentWindowCreated = true;
// Handle pending SetInputMethodActive request.
while (this._pendingSetInputMethodActive.length > 0) {
this._recvSetInputMethodActive(this._pendingSetInputMethodActive.shift());
}
}
},
@ -904,6 +912,17 @@ BrowserElementChild.prototype = {
_recvSetInputMethodActive: function(data) {
let msgData = { id: data.json.id };
if (!this._isContentWindowCreated) {
if (data.json.args.isActive) {
// To activate the input method, we should wait before the content
// window is ready.
this._pendingSetInputMethodActive.push(data);
return;
}
sendAsyncMsg('got-set-input-method-active', msgData);
msgData.successRv = null;
return;
}
// Unwrap to access webpage content.
let nav = XPCNativeWrapper.unwrap(content.document.defaultView.navigator);
if (nav.mozInputMethod) {
@ -977,7 +996,7 @@ BrowserElementChild.prototype = {
return;
}
if (NS_ERROR_GET_MODULE(status) == NS_ERROR_MODULE_SECURITY &&
if (NS_ERROR_GET_MODULE(status) == NS_ERROR_MODULE_SECURITY &&
getErrorClass(status) == Ci.nsINSSErrorsService.ERROR_CLASS_BAD_CERT) {
// XXX Is there a point firing the event if the error page is not

View File

@ -198,7 +198,6 @@ function createDOMDownloadObject(aWindow, aDownload) {
function DOMDownloadImpl() {
debug("DOMDownloadImpl constructor ");
this.wrappedJSObject = this;
this.totalBytes = 0;
this.currentBytes = 0;
@ -206,10 +205,8 @@ function DOMDownloadImpl() {
this.path = null;
this.state = "stopped";
this.contentType = null;
/* fields that require getters/setters */
this._error = null;
this._startTime = new Date();
this.startTime = Date.now();
this.error = null;
/* private fields */
this.id = null;
@ -247,27 +244,6 @@ DOMDownloadImpl.prototype = {
return this.__DOM_IMPL__.getEventHandler("onstatechange");
},
get error() {
return this._error;
},
set error(aError) {
this._error = aError;
},
get startTime() {
return this._startTime;
},
set startTime(aStartTime) {
if (aStartTime instanceof Date) {
this._startTime = aStartTime;
}
else {
this._startTime = new Date(aStartTime);
}
},
_init: function(aWindow, aDownload) {
this._window = aWindow;
this.id = aDownload.id;

View File

@ -24,10 +24,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=938023
SimpleTest.waitForExplicitFinish();
var index = -1;
var todayDate = new Date();
var baseServeURL = "http://mochi.test:8888/tests/dom/downloads/tests/";
var baseDownloadPath = "/mnt/sdcard/downloads/";
var lastKnownCurrentBytes = 0;
function next() {
index += 1;
@ -42,54 +38,16 @@ function next() {
}
}
function checkConsistentDownloadAttributes(download) {
var href = document.getElementById("download1").getAttribute("href");
var expectedServeURL = baseServeURL + href;
var expectedDownloadPath = baseDownloadPath + "test.bin";
// bug 945323: Download path isn't honoring download attribute
todo(download.path === expectedDownloadPath,
"Download path = " + expectedDownloadPath);
ok(download.startTime >= todayDate,
"Download start time should be greater than or equal to today");
is(download.error, null, "Download does not have an error");
is(download.url, expectedServeURL,
"Download URL = " + expectedServeURL);
ok(download.id !== null, "Download id is defined");
is(download.contentType, "application/octet-stream",
"Download content type is application/octet-stream");
}
function downloadChange(evt) {
var download = evt.download;
checkConsistentDownloadAttributes(download);
is(download.totalBytes, 1024, "Download total size is 1024 bytes");
if (download.state === "succeeded") {
is(download.currentBytes, 1024, "Download current size is 1024 bytes");
if (download.state == "succeeded") {
ok(download.totalBytes == 1024, "Download size is 1024 bytes.");
ok(download.contentType == "application/octet-stream",
"contentType is application/octet-stream.");
SimpleTest.finish();
} else if (download.state === "downloading") {
ok(download.currentBytes > lastKnownCurrentBytes,
"Download current size is larger than last download change event");
lastKnownCurrentBytes = download.currentBytes;
} else {
ok(false, "Unexpected download state = " + download.state);
}
}
function downloadStart(evt) {
var download = evt.download;
checkConsistentDownloadAttributes(download);
is(download.currentBytes, 0, "Download current size is zero");
is(download.state, "downloading", "Download state is downloading");
download.onstatechange = downloadChange;
}
var steps = [
// Start by setting the pref to true.
function() {
@ -103,7 +61,11 @@ var steps = [
SpecialPowers.pushPermissions([
{type: "downloads", allow: true, context: document}
], function() {
navigator.mozDownloadManager.ondownloadstart = downloadStart;
navigator.mozDownloadManager.ondownloadstart =
function(evt) {
ok(true, "Download started");
evt.download.addEventListener("statechange", downloadChange);
}
next();
});
},
@ -120,4 +82,3 @@ next();
</pre>
</body>
</html>

View File

@ -0,0 +1,18 @@
<html>
<body>
<script>
var im = navigator.mozInputMethod;
if (im) {
// Automatically append location hash to current input field.
im.oninputcontextchange = function() {
var ctx = im.inputcontext;
if (ctx) {
intervalId = setTimeout(function() {
ctx.replaceSurroundingText(location.hash);
}, 0);
}
};
}
</script>
</body>
</html>

View File

@ -2,6 +2,8 @@
support-files =
inputmethod_common.js
file_test_app.html
file_inputmethod.html
[test_basic.html]
[test_bug944397.html]

View File

@ -0,0 +1,89 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=944397
-->
<head>
<title>Basic test for InputMethod API.</title>
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=944397">Mozilla Bug 944397</a>
<input type="text" />
<p id="display"></p>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
inputmethod_setup(function() {
runTest();
});
// The frame script running in file_test_app.html.
function appFrameScript() {
let input = content.document.getElementById('test-input');
input.oninput = function() {
sendAsyncMessage('test:InputMethod:oninput', {});
};
}
function runTest() {
var timeoutId = null;
// Create an app frame to recieve keyboard inputs.
let app = document.createElement('iframe');
app.src = 'file_test_app.html';
app.setAttribute('mozbrowser', true);
document.body.appendChild(app);
app.addEventListener('mozbrowserloadend', function() {
let mm = SpecialPowers.getBrowserFrameMessageManager(app);
mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false);
mm.addMessageListener("test:InputMethod:oninput", function() {
ok(true, 'Keyboard input was received.');
clearTimeout(timeoutId);
inputmethod_cleanup();
});
});
// Create a browser frame to load the input method app.
let keyboard = document.createElement('iframe');
keyboard.setAttribute('mozbrowser', true);
document.body.appendChild(keyboard);
let path = location.pathname;
let imeUrl = location.protocol + '//' + location.host +
path.substring(0, path.lastIndexOf('/')) +
'/file_inputmethod.html#data';
SpecialPowers.pushPermissions([{
type: 'input',
allow: true,
context: imeUrl
}], function() {
let req = keyboard.setInputMethodActive(true);
req.onsuccess = function() {
ok(true, 'setInputMethodActive succeeded.');
timeoutId = setTimeout(function() {
inputmethod_cleanup();
ok(false, 'Failed to generate keyboard input.');
}, 60000);
};
req.onerror = function() {
ok(false, 'setInputMethodActive failed: ' + this.error.name);
inputmethod_cleanup();
};
// Loads the input method app to the browser frame after a delay.
setTimeout(function() {
keyboard.src = imeUrl;
}, 100);
});
}
</script>
</pre>
</body>
</html>

View File

@ -42,6 +42,10 @@ function debug(s) {
dump("-*- RadioInterfaceLayer: " + s + "\n");
}
// Ril quirk to attach data registration on demand.
let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND =
libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true";
const RADIOINTERFACELAYER_CID =
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
const RADIOINTERFACE_CID =
@ -690,6 +694,18 @@ function RadioInterfaceLayer() {
options.clientId = clientId;
this.radioInterfaces.push(new RadioInterface(options));
}
// TODO: Move 'ril.data.*' settings handler to DataConnectionManager,
// see bug 905568.
let lock = gSettingsService.createLock();
// Read the data enabled setting from DB.
lock.get("ril.data.enabled", this);
// Read the default client id for data call.
lock.get("ril.data.defaultServiceId", this);
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
Services.obs.addObserver(this, kNetworkInterfaceStateChangedTopic, false);
}
RadioInterfaceLayer.prototype = {
@ -701,12 +717,171 @@ RadioInterfaceLayer.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer,
Ci.nsIObserver]),
// Flag to determine the data state to start with when we boot up. It
// corresponds to the 'ril.data.enabled' setting from the UI.
_dataEnabled: null,
// Flag to record the default client id for data call. It
// corresponds to the 'ril.data.defaultServiceId' setting from the UI.
_dataDefaultClientId: -1,
// Flag to record the current default client id for data call.
// It differs from _dataDefaultClientId in that it is set only when
// the switch of client id process is done.
_currentDataClientId: -1,
// Pending function to execute when we are notified that another data call has
// been disconnected.
_pendingDataCallRequest: null,
/**
* nsIObserver interface methods.
*/
observe: function observe(subject, topic, data) {
// Nothing to do now. Just for profile-after-change.
switch (topic) {
case kMozSettingsChangedObserverTopic:
let setting = JSON.parse(data);
this.handle(setting.key, setting.value);
break;
case kNetworkInterfaceStateChangedTopic:
let network = subject.QueryInterface(Ci.nsINetworkInterface);
// DSDS: setup pending data connection when switching the default id
// for data call. We can not use network.type to tell if it's
// NETWORK_TYPE_MOBILE, since the type is removed from
// RILNetworkInterface.connectedTypes on disconnect().
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN) {
let oldRadioInterface =
this.radioInterfaces[this._currentDataClientId];
if (!oldRadioInterface.anyDataConnected() &&
typeof this._pendingDataCallRequest === "function") {
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
oldRadioInterface.setDataRegistration(false);
}
if (DEBUG) debug("All data calls disconnected, setup pending data call.");
this._pendingDataCallRequest();
this._pendingDataCallRequest = null;
}
}
break;
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN);
Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic);
Services.obs.removeObserver(this, kNetworkInterfaceStateChangedTopic);
break;
}
},
// nsISettingsServiceCallback
handle: function handle(name, result) {
switch(name) {
// TODO: Move 'ril.data.*' settings handler to DataConnectionManager,
// see bug 905568.
case "ril.data.enabled":
if (DEBUG) debug("'ril.data.enabled' is now " + result);
if (this._dataEnabled == result) {
break;
}
this._dataEnabled = result;
if (DEBUG) debug("Default id for data call: " + this._dataDefaultClientId);
if (this._dataDefaultClientId == -1) {
// We haven't got the default id for data from db.
break;
}
let radioInterface = this.radioInterfaces[this._dataDefaultClientId];
radioInterface.dataCallSettings.oldEnabled = radioInterface.dataCallSettings.enabled;
radioInterface.dataCallSettings.enabled = result;
radioInterface.updateRILNetworkInterface();
break;
case "ril.data.defaultServiceId":
result = result ? result : 0;
if (DEBUG) debug("'ril.data.defaultServiceId' is now " + result);
if (this._dataDefaultClientId == result) {
break;
}
this._dataDefaultClientId = result;
this.handleDataClientIdChange();
break;
}
},
handleError: function handleError(errorMessage) {
if (DEBUG) {
debug("There was an error while reading RIL settings: " + errorMessage);
}
},
handleDataClientIdChange: function handleDataClientIdChange() {
if (this._currentDataClientId == -1) {
// This is to handle boot up stage.
this._currentDataClientId = this._dataDefaultClientId;
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
let radioInterface = this.radioInterfaces[this._currentDataClientId];
radioInterface.setDataRegistration(true);
}
if (this._dataEnabled) {
let radioInterface = this.radioInterfaces[this._currentDataClientId];
radioInterface.dataCallSettings.oldEnabled =
radioInterface.dataCallSettings.enabled;
radioInterface.dataCallSettings.enabled = true;
radioInterface.updateRILNetworkInterface();
}
return;
}
if (!this._dataEnabled) {
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
let oldRadioInterface = this.radioInterfaces[this._currentDataClientId];
let newRadioInterface = this.radioInterfaces[this._dataDefaultClientId];
oldRadioInterface.setDataRegistration(false);
newRadioInterface.setDataRegistration(true);
}
this._currentDataClientId = this._dataDefaultClientId;
return;
}
let oldRadioInterface = this.radioInterfaces[this._currentDataClientId];
oldRadioInterface.dataCallSettings.oldEnabled =
oldRadioInterface.dataCallSettings.enabled;
oldRadioInterface.dataCallSettings.enabled = false;
if (oldRadioInterface.anyDataConnected()) {
this._pendingDataCallRequest = function () {
if (DEBUG) debug("Executing pending data call request.");
let newRadioInterface = this.radioInterfaces[this._dataDefaultClientId];
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
newRadioInterface.setDataRegistration(true);
}
newRadioInterface.dataCallSettings.oldEnabled =
newRadioInterface.dataCallSettings.enabled;
newRadioInterface.dataCallSettings.enabled = this._dataEnabled;
this._currentDataClientId = this._dataDefaultClientId;
newRadioInterface.updateRILNetworkInterface();
};
if (DEBUG) {
debug("handleDataClientIdChange: existing data call(s) active,"
+ " wait for them to get disconnected.");
}
oldRadioInterface.deactivateDataCalls();
return;
}
let newRadioInterface = this.radioInterfaces[this._dataDefaultClientId];
newRadioInterface.dataCallSettings.oldEnabled =
newRadioInterface.dataCallSettings.enabled;
newRadioInterface.dataCallSettings.enabled = true;
this._currentDataClientId = this._dataDefaultClientId;
if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
oldRadioInterface.setDataRegistration(false);
newRadioInterface.setDataRegistration(true);
}
newRadioInterface.updateRILNetworkInterface();
},
/**
@ -942,12 +1117,8 @@ function RadioInterface(options) {
// Read the APN data from the settings DB.
lock.get("ril.data.roaming_enabled", this);
lock.get("ril.data.enabled", this);
lock.get("ril.data.apnSettings", this);
// Read the default client id for data call.
lock.get("ril.data.defaultServiceId", this);
// Read the "time.clock.automatic-update.enabled" setting to see if
// we need to adjust the system clock time by NITZ or SNTP.
lock.get(kSettingsClockAutoUpdateEnabled, this);
@ -1801,6 +1972,18 @@ RadioInterface.prototype = {
}
},
anyDataConnected: function anyDataConnected() {
for each (let apnSetting in this.apnSettings.byApn) {
for each (let type in apnSetting.types) {
if (this.getDataCallStateByType(type) ==
RIL.GECKO_NETWORK_STATE_CONNECTED) {
return true;
}
}
}
return false;
},
/**
* Check if we get all necessary APN data.
*/
@ -1811,32 +1994,8 @@ RadioInterface.prototype = {
apnSetting.types.length);
},
handleDataClientIdChange: function handleDataClientIdChange() {
// Default data has been switched to the current RadioInterface.
// If there is an active default data call, wait for it to get
// disconnected, otherwise connect directly.
if (this.clientId == this._dataDefaultClientId &&
this._dataEnabled) {
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
this.dataCallSettings.enabled = true;
if (gNetworkManager.active &&
gNetworkManager.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
if (DEBUG) this.debug("Default data active, wait for it to get disconnected.");
this._dataCallSetupPending = true;
return;
}
this.updateRILNetworkInterface();
return;
}
// Default data has been switched from this current RadioInterface,
// disconnet data call if it is enabled.
if (this.clientId != this._dataDefaultClientId &&
this.dataCallSettings.enabled) {
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
this.dataCallSettings.enabled = false;
this.updateRILNetworkInterface();
}
setDataRegistration: function setDataRegistration(attach) {
this.workerMessenger.send("setDataRegistration", {attach: attach});
},
updateRILNetworkInterface: function updateRILNetworkInterface() {
@ -2471,18 +2630,6 @@ RadioInterface.prototype = {
this._sntp.request();
}
}
// DSDS: setup pending data connection when switching the default id
// for data call.
// We can not use network.type to tell if it's NETWORK_TYPE_MOBILE,
// since the type is removed from RILNetworkInterface.connectedTypes
// on disconnect().
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN &&
this._dataCallSetupPending) {
if (DEBUG) this.debug("Default data disconnected, setup pending data call.");
this._dataCallSetupPending = false;
this.updateRILNetworkInterface();
}
break;
case kScreenStateChangedTopic:
this.workerMessenger.send("setScreenState", { on: (data === "on") });
@ -2495,17 +2642,6 @@ RadioInterface.prototype = {
apnSettings: null,
// Flag to determine the data state to start with when we boot up. It
// corresponds to the 'ril.data.enabled' setting from the UI.
_dataEnabled: null,
// Flag to record the default client id for data call.
_dataDefaultClientId: null,
// Flag to determine if we need to setup data call when we are notified
// that another data call has been disconnected.
_dataCallSetupPending: false,
// Flag to determine whether to update system clock automatically. It
// corresponds to the "time.clock.automatic-update.enabled" setting.
_clockAutoUpdateEnabled: null,
@ -2565,19 +2701,6 @@ RadioInterface.prototype = {
if (DEBUG) this.debug("'ril.radio.preferredNetworkType' is now " + aResult);
this.setPreferredNetworkTypeBySetting(aResult);
break;
case "ril.data.enabled":
if (DEBUG) this.debug("'ril.data.enabled' is now " + aResult);
if (this._dataEnabled == aResult) {
break;
}
this._dataEnabled = aResult;
if (this.clientId != this._dataDefaultClientId) {
break;
}
this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled;
this.dataCallSettings.enabled = aResult;
this.updateRILNetworkInterface();
break;
case "ril.data.roaming_enabled":
if (DEBUG) this.debug("'ril.data.roaming_enabled' is now " + aResult);
this.dataCallSettings.roamingEnabled = aResult;
@ -2590,15 +2713,6 @@ RadioInterface.prototype = {
this.updateRILNetworkInterface();
}
break;
case "ril.data.defaultServiceId":
aResult = aResult ? aResult : 0;
if (DEBUG) this.debug("'ril.data.defaultServiceId' is now " + aResult);
if (this._dataDefaultClientId == aResult) {
break;
}
this._dataDefaultClientId = aResult;
this.handleDataClientIdChange();
break;
case kSettingsClockAutoUpdateEnabled:
this._clockAutoUpdateEnabled = aResult;
if (!this._clockAutoUpdateEnabled) {

View File

@ -152,6 +152,10 @@ this.REQUEST_MODIFY_QOS = 118;
this.REQUEST_SUSPEND_QOS = 119;
this.REQUEST_RESUME_QOS = 120;
// Fugu specific parcel types.
this.RIL_REQUEST_GPRS_ATTACH = 5018;
this.RIL_REQUEST_GPRS_DETACH = 5019;
// UICC Secure Access
this.REQUEST_SIM_OPEN_CHANNEL = 121;
this.REQUEST_SIM_CLOSE_CHANNEL = 122;

Some files were not shown because too many files have changed in this diff Show More