Merge m-c to inbound on a CLOSED TREE.
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"branch": "",
|
||||
"revision": ""
|
||||
},
|
||||
"revision": "c5bd933fe99317a7e99822f2d9345ae67a3043df",
|
||||
"revision": "93de9c5bcb90ae32bd3599b185f4bbf67e4529ff",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
|
||||
|
|
|
@ -9,9 +9,17 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
||||
|
||||
let fxAccountsCommon = {};
|
||||
Cu.import("resource://gre/modules/FxAccountsCommon.js", fxAccountsCommon);
|
||||
|
||||
const PREF_LAST_FXA_USER = "identity.fxaccounts.lastSignedInUserHash";
|
||||
const PREF_SYNC_SHOW_CUSTOMIZATION = "services.sync.ui.showCustomizationDialog";
|
||||
|
||||
const OBSERVER_TOPICS = [
|
||||
fxAccountsCommon.ONVERIFIED_NOTIFICATION,
|
||||
fxAccountsCommon.ONLOGOUT_NOTIFICATION,
|
||||
];
|
||||
|
||||
function log(msg) {
|
||||
//dump("FXA: " + msg + "\n");
|
||||
};
|
||||
|
@ -150,6 +158,11 @@ let wrapper = {
|
|||
xps.whenLoaded().then(() => {
|
||||
return fxAccounts.setSignedInUser(accountData);
|
||||
}).then(() => {
|
||||
// If the user data is verified, we want it to immediately look like
|
||||
// they are signed in without waiting for messages to bounce around.
|
||||
if (accountData.verified) {
|
||||
showManage();
|
||||
}
|
||||
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
|
||||
|
@ -249,23 +262,36 @@ function openPrefs() {
|
|||
}
|
||||
|
||||
function init() {
|
||||
if (window.location.href.contains("action=signin")) {
|
||||
show("remote");
|
||||
wrapper.init(fxAccounts.getAccountsSignInURI());
|
||||
} else if (window.location.href.contains("action=signup")) {
|
||||
show("remote");
|
||||
wrapper.init();
|
||||
} else if (window.location.href.contains("action=reauth")) {
|
||||
fxAccounts.promiseAccountsForceSigninURI().then(url => {
|
||||
show("remote");
|
||||
wrapper.init(url);
|
||||
});
|
||||
} else {
|
||||
// Check if we have a local account
|
||||
fxAccounts.getSignedInUser().then(user => {
|
||||
fxAccounts.getSignedInUser().then(user => {
|
||||
if (window.location.href.contains("action=signin")) {
|
||||
if (user) {
|
||||
show("stage");
|
||||
show("manage");
|
||||
// asking to sign-in when already signed in just shows manage.
|
||||
showManage();
|
||||
} else {
|
||||
show("remote");
|
||||
wrapper.init(fxAccounts.getAccountsSignInURI());
|
||||
}
|
||||
} else if (window.location.href.contains("action=signup")) {
|
||||
if (user) {
|
||||
// asking to sign-up when already signed in just shows manage.
|
||||
showManage();
|
||||
} else {
|
||||
show("remote");
|
||||
wrapper.init();
|
||||
}
|
||||
} else if (window.location.href.contains("action=reauth")) {
|
||||
// ideally we would only show this when we know the user is in a
|
||||
// "must reauthenticate" state - but we don't.
|
||||
// As the email address will be included in the URL returned from
|
||||
// promiseAccountsForceSigninURI, just always show it.
|
||||
fxAccounts.promiseAccountsForceSigninURI().then(url => {
|
||||
show("remote");
|
||||
wrapper.init(url);
|
||||
});
|
||||
} else {
|
||||
// No action specified
|
||||
if (user) {
|
||||
showManage();
|
||||
let sb = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
|
||||
document.title = sb.GetStringFromName("manage.pageTitle");
|
||||
} else {
|
||||
|
@ -274,8 +300,8 @@ function init() {
|
|||
// load the remote frame in the background
|
||||
wrapper.init();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function show(id) {
|
||||
|
@ -285,7 +311,38 @@ function hide(id) {
|
|||
document.getElementById(id).style.display = 'none';
|
||||
}
|
||||
|
||||
function showManage() {
|
||||
show("stage");
|
||||
show("manage");
|
||||
hide("remote");
|
||||
hide("intro");
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function onload() {
|
||||
document.removeEventListener("DOMContentLoaded", onload, true);
|
||||
init();
|
||||
}, true);
|
||||
|
||||
function initObservers() {
|
||||
function observe(subject, topic, data) {
|
||||
log("about:accounts observed " + topic);
|
||||
if (topic == fxAccountsCommon.ONLOGOUT_NOTIFICATION) {
|
||||
// All about:account windows get changed to action=signin on logout.
|
||||
window.location = "about:accounts?action=signin";
|
||||
return;
|
||||
}
|
||||
// must be onverified - just about:accounts is loaded.
|
||||
window.location = "about:accounts";
|
||||
}
|
||||
|
||||
for (let topic of OBSERVER_TOPICS) {
|
||||
Services.obs.addObserver(observe, topic, false);
|
||||
}
|
||||
window.addEventListener("unload", function(event) {
|
||||
log("about:accounts unloading")
|
||||
for (let topic of OBSERVER_TOPICS) {
|
||||
Services.obs.removeObserver(observe, topic);
|
||||
}
|
||||
});
|
||||
}
|
||||
initObservers();
|
||||
|
|
|
@ -24,6 +24,7 @@ let gFxAccounts = {
|
|||
// Do all this dance to lazy-load FxAccountsCommon.
|
||||
delete this.topics;
|
||||
return this.topics = [
|
||||
"weave:service:ready",
|
||||
"weave:service:sync:start",
|
||||
"weave:service:login:error",
|
||||
FxAccountsCommon.ONLOGIN_NOTIFICATION,
|
||||
|
|
|
@ -901,7 +901,7 @@ SocialSidebar = {
|
|||
let popup = event.target;
|
||||
let providerMenuSeps = popup.getElementsByClassName("social-provider-menu");
|
||||
if (providerMenuSeps[0].previousSibling.nodeName == "menuseparator")
|
||||
SocialSidebar._populateProviderMenu(providerMenuSeps[0]);
|
||||
SocialSidebar.populateProviderMenu(providerMenuSeps[0]);
|
||||
},
|
||||
|
||||
clearProviderMenus: function() {
|
||||
|
@ -916,7 +916,7 @@ SocialSidebar = {
|
|||
}
|
||||
},
|
||||
|
||||
_populateProviderMenu: function(providerMenuSep) {
|
||||
populateProviderMenu: function(providerMenuSep) {
|
||||
let menu = providerMenuSep.parentNode;
|
||||
// selectable providers are inserted before the provider-menu seperator,
|
||||
// remove any menuitems in that area
|
||||
|
|
|
@ -768,10 +768,6 @@ toolbarbutton[type="badged"] {
|
|||
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#toolbarbutton-badged");
|
||||
}
|
||||
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[type="badged"] > .toolbarbutton-badge-container {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
toolbarbutton[type="socialmark"] {
|
||||
-moz-binding: url("chrome://browser/content/socialmarks.xml#toolbarbutton-marks");
|
||||
}
|
||||
|
@ -779,11 +775,9 @@ toolbarbutton[type="socialmark"] {
|
|||
toolbarbutton[type="badged"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
|
||||
toolbarbutton[type="socialmark"] > .toolbarbutton-icon {
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
}
|
||||
toolbarpaletteitem[place="palette"] > toolbarbutton[type="badged"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
max-width: 32px;
|
||||
max-height: 32px;
|
||||
}
|
||||
|
||||
panelview > .social-panel-frame {
|
||||
|
|
|
@ -1166,7 +1166,7 @@
|
|||
|
||||
#ifndef XP_UNIX
|
||||
<svg:clipPath id="windows-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
|
||||
<svg:path d="M 0,0 C 0.16,0.11 0.28,0.29 0.28,0.5 0.28,0.71 0.16,0.89 0,1 L 1,1 1,0 0,0 z"/>
|
||||
<svg:path d="m 0,0 c .3,.25 .3,.75, 0,1 l 1,0 0,-1 z"/>
|
||||
</svg:clipPath>
|
||||
<svg:clipPath id="windows-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
|
||||
<svg:path d="m 0,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/>
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
<xul:panel anonid="panel" hidden="true" type="arrow" class="social-panel"/>
|
||||
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
|
||||
<xul:label class="toolbarbutton-text" crop="right" flex="1"
|
||||
xbl:inherits="value=label,accesskey,crop"/>
|
||||
xbl:inherits="value=label,accesskey,crop,wrap"/>
|
||||
<xul:label class="toolbarbutton-multiline-text" flex="1"
|
||||
xbl:inherits="xbl:text=label,accesskey,wrap"/>
|
||||
</content>
|
||||
<implementation implements="nsIDOMEventListener, nsIObserver">
|
||||
<field name="inMenuPanel">false</field>
|
||||
|
|
|
@ -83,6 +83,8 @@ support-files =
|
|||
skip-if = (os == "linux" || os == "mac") && debug # bug 970052, bug 970053
|
||||
[browser_aboutAccounts.js]
|
||||
skip-if = os == "linux" # Bug 958026
|
||||
support-files =
|
||||
content_aboutAccounts.js
|
||||
[browser_aboutHealthReport.js]
|
||||
skip-if = os == "linux" # Bug 924307
|
||||
[browser_aboutHome.js]
|
||||
|
|
|
@ -9,22 +9,35 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
|
||||
"resource://gre/modules/FxAccounts.jsm");
|
||||
|
||||
const CHROME_BASE = "chrome://mochitests/content/browser/browser/base/content/test/general/";
|
||||
// Preference helpers.
|
||||
let changedPrefs = new Set();
|
||||
|
||||
function setPref(name, value) {
|
||||
changedPrefs.add(name);
|
||||
Services.prefs.setCharPref(name, value);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Ensure we don't pollute prefs for next tests.
|
||||
Services.prefs.clearUserPref("identity.fxaccounts.remote.uri");
|
||||
for (let name of changedPrefs) {
|
||||
Services.prefs.clearUserPref(name);
|
||||
}
|
||||
});
|
||||
|
||||
let gTests = [
|
||||
|
||||
{
|
||||
desc: "Test the remote commands",
|
||||
setup: function ()
|
||||
{
|
||||
Services.prefs.setCharPref("identity.fxaccounts.remote.uri",
|
||||
"https://example.com/browser/browser/base/content/test/general/accounts_testRemoteCommands.html");
|
||||
teardown: function* () {
|
||||
gBrowser.removeCurrentTab();
|
||||
yield fxAccounts.signOut();
|
||||
},
|
||||
run: function ()
|
||||
run: function* ()
|
||||
{
|
||||
setPref("identity.fxaccounts.remote.uri",
|
||||
"https://example.com/browser/browser/base/content/test/general/accounts_testRemoteCommands.html");
|
||||
yield promiseNewTabLoadEvent("about:accounts");
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let results = 0;
|
||||
|
@ -47,11 +60,135 @@ let gTests = [
|
|||
ok(false, "Failed to get all commands");
|
||||
deferred.reject();
|
||||
}
|
||||
return deferred.promise.then(() => fxAccounts.signOut());
|
||||
yield deferred.promise;
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test action=signin - no user logged in",
|
||||
teardown: () => gBrowser.removeCurrentTab(),
|
||||
run: function* ()
|
||||
{
|
||||
// When this loads with no user logged-in, we expect the "normal" URL
|
||||
const expected_url = "https://example.com/?is_sign_in";
|
||||
setPref("identity.fxaccounts.remote.signin.uri", expected_url);
|
||||
let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signin");
|
||||
is(url, expected_url, "action=signin got the expected URL");
|
||||
// we expect the remote iframe to be shown.
|
||||
yield checkVisibilities(tab, {
|
||||
stage: false, // parent of 'manage' and 'intro'
|
||||
manage: false,
|
||||
intro: false, // this is "get started"
|
||||
remote: true
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test action=signin - user logged in",
|
||||
teardown: function* () {
|
||||
gBrowser.removeCurrentTab();
|
||||
yield signOut();
|
||||
},
|
||||
run: function* ()
|
||||
{
|
||||
// When this loads with a user logged-in, we expect the normal URL to
|
||||
// have been ignored and the "manage" page to be shown.
|
||||
const expected_url = "https://example.com/?is_sign_in";
|
||||
setPref("identity.fxaccounts.remote.signin.uri", expected_url);
|
||||
yield setSignedInUser();
|
||||
let tab = yield promiseNewTabLoadEvent("about:accounts?action=signin");
|
||||
// about:accounts initializes after fetching the current user from Fxa -
|
||||
// so we also request it - by the time we get it we know it should have
|
||||
// done its thing.
|
||||
yield fxAccounts.getSignedInUser();
|
||||
// we expect "manage" to be shown.
|
||||
yield checkVisibilities(tab, {
|
||||
stage: true, // parent of 'manage' and 'intro'
|
||||
manage: true,
|
||||
intro: false, // this is "get started"
|
||||
remote: false
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Test action=signup - no user logged in",
|
||||
teardown: () => gBrowser.removeCurrentTab(),
|
||||
run: function* ()
|
||||
{
|
||||
const expected_url = "https://example.com/?is_sign_up";
|
||||
setPref("identity.fxaccounts.remote.uri", expected_url);
|
||||
let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=signup");
|
||||
is(url, expected_url, "action=signup got the expected URL");
|
||||
// we expect the remote iframe to be shown.
|
||||
yield checkVisibilities(tab, {
|
||||
stage: false, // parent of 'manage' and 'intro'
|
||||
manage: false,
|
||||
intro: false, // this is "get started"
|
||||
remote: true
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Test action=signup - user logged in",
|
||||
teardown: () => gBrowser.removeCurrentTab(),
|
||||
run: function* ()
|
||||
{
|
||||
const expected_url = "https://example.com/?is_sign_up";
|
||||
setPref("identity.fxaccounts.remote.uri", expected_url);
|
||||
yield setSignedInUser();
|
||||
let tab = yield promiseNewTabLoadEvent("about:accounts?action=signup");
|
||||
yield fxAccounts.getSignedInUser();
|
||||
// we expect "manage" to be shown.
|
||||
yield checkVisibilities(tab, {
|
||||
stage: true, // parent of 'manage' and 'intro'
|
||||
manage: true,
|
||||
intro: false, // this is "get started"
|
||||
remote: false
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Test action=reauth",
|
||||
teardown: function* () {
|
||||
gBrowser.removeCurrentTab();
|
||||
yield signOut();
|
||||
},
|
||||
run: function* ()
|
||||
{
|
||||
const expected_url = "https://example.com/?is_force_auth";
|
||||
setPref("identity.fxaccounts.remote.force_auth.uri", expected_url);
|
||||
let userData = {
|
||||
email: "foo@example.com",
|
||||
uid: "1234@lcip.org",
|
||||
assertion: "foobar",
|
||||
sessionToken: "dead",
|
||||
kA: "beef",
|
||||
kB: "cafe",
|
||||
verified: true
|
||||
};
|
||||
|
||||
|
||||
yield setSignedInUser();
|
||||
let [tab, url] = yield promiseNewTabWithIframeLoadEvent("about:accounts?action=reauth");
|
||||
// The current user will be appended to the url
|
||||
let expected = expected_url + "&email=foo%40example.com";
|
||||
is(url, expected, "action=reauth got the expected URL");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Test observers about:accounts",
|
||||
teardown: function() {
|
||||
gBrowser.removeCurrentTab();
|
||||
},
|
||||
run: function* () {
|
||||
setPref("identity.fxaccounts.remote.uri", "https://example.com/");
|
||||
yield setSignedInUser();
|
||||
let tab = yield promiseNewTabLoadEvent("about:accounts");
|
||||
// sign the user out - the tab should have action=signin
|
||||
yield signOut();
|
||||
// wait for the new load.
|
||||
yield promiseOneMessage(tab, "test:document:load");
|
||||
is(tab.linkedBrowser.contentDocument.location.href, "about:accounts?action=signin");
|
||||
}
|
||||
},
|
||||
]; // gTests
|
||||
|
||||
function test()
|
||||
|
@ -61,32 +198,91 @@ function test()
|
|||
Task.spawn(function () {
|
||||
for (let test of gTests) {
|
||||
info(test.desc);
|
||||
test.setup();
|
||||
|
||||
yield promiseNewTabLoadEvent("about:accounts");
|
||||
|
||||
yield test.run();
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
try {
|
||||
yield test.run();
|
||||
} finally {
|
||||
yield test.teardown();
|
||||
}
|
||||
}
|
||||
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseOneMessage(tab, messageName) {
|
||||
let mm = tab.linkedBrowser.messageManager;
|
||||
let deferred = Promise.defer();
|
||||
mm.addMessageListener(messageName, function onmessage(message) {
|
||||
mm.removeMessageListener(messageName, onmessage);
|
||||
deferred.resolve(message);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseNewTabLoadEvent(aUrl)
|
||||
{
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(aUrl);
|
||||
let browser = tab.linkedBrowser;
|
||||
let mm = browser.messageManager;
|
||||
|
||||
// give it an e10s-friendly content script to help with our tests.
|
||||
mm.loadFrameScript(CHROME_BASE + "content_aboutAccounts.js", true);
|
||||
// and wait for it to tell us about the load.
|
||||
return promiseOneMessage(tab, "test:document:load").then(
|
||||
() => tab
|
||||
);
|
||||
}
|
||||
|
||||
// Returns a promise which is resolved with the iframe's URL after a new
|
||||
// tab is created and the iframe in that tab loads.
|
||||
function promiseNewTabWithIframeLoadEvent(aUrl) {
|
||||
let deferred = Promise.defer();
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(aUrl);
|
||||
let browser = tab.linkedBrowser;
|
||||
let mm = browser.messageManager;
|
||||
|
||||
browser.addEventListener("load", function onLoad(event) {
|
||||
let iframe = browser.contentDocument.getElementById("remote");
|
||||
if (iframe && event.target == iframe.contentDocument) {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
deferred.resolve();
|
||||
}
|
||||
}, true);
|
||||
|
||||
// give it an e10s-friendly content script to help with our tests.
|
||||
mm.loadFrameScript(CHROME_BASE + "content_aboutAccounts.js", true);
|
||||
// and wait for it to tell us about the iframe load.
|
||||
mm.addMessageListener("test:iframe:load", function onFrameLoad(message) {
|
||||
mm.removeMessageListener("test:iframe:load", onFrameLoad);
|
||||
deferred.resolve([tab, message.data.url]);
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkVisibilities(tab, data) {
|
||||
let ids = Object.keys(data);
|
||||
let mm = tab.linkedBrowser.messageManager;
|
||||
let deferred = Promise.defer();
|
||||
mm.addMessageListener("test:check-visibilities-response", function onResponse(message) {
|
||||
mm.removeMessageListener("test:check-visibilities-response", onResponse);
|
||||
for (let id of ids) {
|
||||
is(message.data[id], data[id], "Element '" + id + "' has correct visibility");
|
||||
}
|
||||
deferred.resolve();
|
||||
});
|
||||
mm.sendAsyncMessage("test:check-visibilities", {ids: ids});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
// watch out - these will fire observers which if you aren't careful, may
|
||||
// interfere with the tests.
|
||||
function setSignedInUser(data) {
|
||||
if (!data) {
|
||||
data = {
|
||||
email: "foo@example.com",
|
||||
uid: "1234@lcip.org",
|
||||
assertion: "foobar",
|
||||
sessionToken: "dead",
|
||||
kA: "beef",
|
||||
kB: "cafe",
|
||||
verified: true
|
||||
}
|
||||
}
|
||||
return fxAccounts.setSignedInUser(data);
|
||||
}
|
||||
|
||||
function signOut() {
|
||||
return fxAccounts.signOut();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file is loaded as a "content script" for browser_aboutAccounts tests
|
||||
"use strict";
|
||||
|
||||
addEventListener("load", function load(event) {
|
||||
if (event.target != content.document) {
|
||||
return;
|
||||
}
|
||||
// content.document.removeEventListener("load", load, true);
|
||||
sendAsyncMessage("test:document:load");
|
||||
}, true);
|
||||
|
||||
addEventListener("DOMContentLoaded", function domContentLoaded(event) {
|
||||
removeEventListener("DOMContentLoaded", domContentLoaded, true);
|
||||
let iframe = content.document.getElementById("remote");
|
||||
iframe.addEventListener("load", function iframeLoaded(event) {
|
||||
if (iframe.contentWindow.location.href == "about:blank" ||
|
||||
event.target != iframe) {
|
||||
return;
|
||||
}
|
||||
iframe.removeEventListener("load", iframeLoaded, true);
|
||||
sendAsyncMessage("test:iframe:load", {url: iframe.getAttribute("src")});
|
||||
}, true);
|
||||
}, true);
|
||||
|
||||
// Return the visibility state of a list of ids.
|
||||
addMessageListener("test:check-visibilities", function (message) {
|
||||
let result = {};
|
||||
for (let id of message.data.ids) {
|
||||
let elt = content.document.getElementById(id);
|
||||
if (elt) {
|
||||
let displayStyle = content.window.getComputedStyle(elt).display;
|
||||
if (displayStyle == 'none') {
|
||||
result[id] = false;
|
||||
} else if (displayStyle == 'block') {
|
||||
result[id] = true;
|
||||
} else {
|
||||
result[id] = "strange: " + displayStyle; // tests should fail!
|
||||
}
|
||||
} else {
|
||||
result[id] = "doesn't exist: " + id;
|
||||
}
|
||||
}
|
||||
sendAsyncMessage("test:check-visibilities-response", result);
|
||||
});
|
|
@ -2196,12 +2196,14 @@
|
|||
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
|
||||
<content>
|
||||
<children includes="observes|template|menupopup|panel|tooltip"/>
|
||||
<xul:hbox class="toolbarbutton-badge-container" align="start" pack="end" flex="1">
|
||||
<xul:hbox class="toolbarbutton-badge-container" align="start" pack="end">
|
||||
<xul:hbox class="toolbarbutton-badge" xbl:inherits="badge"/>
|
||||
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label"/>
|
||||
</xul:hbox>
|
||||
<xul:label class="toolbarbutton-text" crop="right" flex="1"
|
||||
xbl:inherits="value=label,accesskey,crop"/>
|
||||
xbl:inherits="value=label,accesskey,crop,wrap"/>
|
||||
<xul:label class="toolbarbutton-multiline-text" flex="1"
|
||||
xbl:inherits="xbl:text=label,accesskey,wrap"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
|
|
|
@ -153,6 +153,11 @@
|
|||
<vbox id="PanelUI-developerItems" class="panel-subview-body"/>
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-sidebar" flex="1">
|
||||
<label value="&appMenuSidebars.label;" class="panel-subview-header"/>
|
||||
<vbox id="PanelUI-sidebarItems" class="panel-subview-body"/>
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-characterEncodingView" flex="1">
|
||||
<label value="&charsetMenu.label;" class="panel-subview-header"/>
|
||||
<vbox class="panel-subview-body">
|
||||
|
|
|
@ -320,6 +320,74 @@ const CustomizableWidgets = [{
|
|||
parent.appendChild(items);
|
||||
}
|
||||
}, {
|
||||
id: "sidebar-button",
|
||||
type: "view",
|
||||
viewId: "PanelUI-sidebar",
|
||||
onViewShowing: function(aEvent) {
|
||||
// Largely duplicated from the developer-button above with a couple minor
|
||||
// alterations.
|
||||
// Populate the subview with whatever menuitems are in the
|
||||
// sidebar menu. We skip menu elements, because the menu panel has no way
|
||||
// of dealing with those right now.
|
||||
let doc = aEvent.target.ownerDocument;
|
||||
let win = doc.defaultView;
|
||||
|
||||
let items = doc.getElementById("PanelUI-sidebarItems");
|
||||
let menu = doc.getElementById("viewSidebarMenu");
|
||||
|
||||
// First clear any existing menuitems then populate. Social sidebar
|
||||
// options may not have been added yet, so we do that here. Add it to the
|
||||
// standard menu first, then copy all sidebar options to the panel.
|
||||
win.SocialSidebar.clearProviderMenus();
|
||||
let providerMenuSeps = menu.getElementsByClassName("social-provider-menu");
|
||||
if (providerMenuSeps.length > 0)
|
||||
win.SocialSidebar.populateProviderMenu(providerMenuSeps[0]);
|
||||
|
||||
let attrs = ["oncommand", "onclick", "label", "key", "disabled",
|
||||
"command", "observes", "hidden", "class", "origin",
|
||||
"image", "checked"];
|
||||
|
||||
let fragment = doc.createDocumentFragment();
|
||||
let itemsToDisplay = [...menu.children];
|
||||
for (let node of itemsToDisplay) {
|
||||
if (node.hidden)
|
||||
continue;
|
||||
|
||||
let item;
|
||||
if (node.localName == "menuseparator") {
|
||||
item = doc.createElementNS(kNSXUL, "menuseparator");
|
||||
} else if (node.localName == "menuitem") {
|
||||
item = doc.createElementNS(kNSXUL, "toolbarbutton");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
for (let attr of attrs) {
|
||||
let attrVal = node.getAttribute(attr);
|
||||
if (attrVal)
|
||||
item.setAttribute(attr, attrVal);
|
||||
}
|
||||
if (node.localName == "menuitem")
|
||||
item.classList.add("subviewbutton");
|
||||
fragment.appendChild(item);
|
||||
}
|
||||
|
||||
items.appendChild(fragment);
|
||||
},
|
||||
onViewHiding: function(aEvent) {
|
||||
let doc = aEvent.target.ownerDocument;
|
||||
let items = doc.getElementById("PanelUI-sidebarItems");
|
||||
let parent = items.parentNode;
|
||||
// We'll take the container out of the document before cleaning it out
|
||||
// to avoid reflowing each time we remove something.
|
||||
parent.removeChild(items);
|
||||
|
||||
while (items.firstChild) {
|
||||
items.firstChild.remove();
|
||||
}
|
||||
|
||||
parent.appendChild(items);
|
||||
}
|
||||
}, {
|
||||
id: "add-ons-button",
|
||||
shortcutId: "key_openAddons",
|
||||
tooltiptext: "add-ons-button.tooltiptext2",
|
||||
|
|
|
@ -214,8 +214,6 @@ CustomizeMode.prototype = {
|
|||
customizeButton.setAttribute("label", customizeButton.getAttribute("exitLabel"));
|
||||
customizeButton.setAttribute("enterTooltiptext", customizeButton.getAttribute("tooltiptext"));
|
||||
customizeButton.setAttribute("tooltiptext", customizeButton.getAttribute("exitTooltiptext"));
|
||||
document.getElementById("PanelUI-help").setAttribute("disabled", true);
|
||||
document.getElementById("PanelUI-quit").setAttribute("disabled", true);
|
||||
|
||||
this._transitioning = true;
|
||||
|
||||
|
@ -246,6 +244,9 @@ CustomizeMode.prototype = {
|
|||
|
||||
window.gNavToolbox.addEventListener("toolbarvisibilitychange", this);
|
||||
|
||||
document.getElementById("PanelUI-help").setAttribute("disabled", true);
|
||||
document.getElementById("PanelUI-quit").setAttribute("disabled", true);
|
||||
|
||||
this._updateResetButton();
|
||||
this._updateUndoResetButton();
|
||||
|
||||
|
@ -336,7 +337,6 @@ CustomizeMode.prototype = {
|
|||
|
||||
this.document.removeEventListener("keypress", this);
|
||||
this.window.PanelUI.menuButton.removeEventListener("mousedown", this);
|
||||
this.window.PanelUI.menuButton.open = false;
|
||||
|
||||
this.window.PanelUI.beginBatchUpdate();
|
||||
|
||||
|
@ -425,6 +425,7 @@ CustomizeMode.prototype = {
|
|||
CustomizableUI.dispatchToolboxEvent("customizationending", {}, window);
|
||||
|
||||
window.PanelUI.setMainView(window.PanelUI.mainView);
|
||||
window.PanelUI.menuButton.open = false;
|
||||
window.PanelUI.menuButton.disabled = false;
|
||||
|
||||
let customizeButton = document.getElementById("PanelUI-customize");
|
||||
|
|
|
@ -1961,10 +1961,14 @@ VariableBubbleView.prototype = {
|
|||
/**
|
||||
* The mousemove listener for the source editor.
|
||||
*/
|
||||
_onMouseMove: function({ clientX: x, clientY: y }) {
|
||||
_onMouseMove: function({ clientX: x, clientY: y, buttons: btns }) {
|
||||
// Prevent the variable inspection popup from showing when the thread client
|
||||
// is not paused, or while a popup is already visible.
|
||||
if (gThreadClient && gThreadClient.state != "paused" || !this._tooltip.isHidden()) {
|
||||
// is not paused, or while a popup is already visible, or when the user tries
|
||||
// to select text in the editor.
|
||||
if (gThreadClient && gThreadClient.state != "paused"
|
||||
|| !this._tooltip.isHidden()
|
||||
|| (DebuggerView.editor.somethingSelected()
|
||||
&& btns > 0)) {
|
||||
clearNamedTimeout("editor-mouse-move");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -265,6 +265,7 @@ support-files =
|
|||
[browser_dbg_variables-view-popup-11.js]
|
||||
[browser_dbg_variables-view-popup-12.js]
|
||||
[browser_dbg_variables-view-popup-13.js]
|
||||
[browser_dbg_variables-view-popup-14.js]
|
||||
[browser_dbg_variables-view-reexpand-01.js]
|
||||
[browser_dbg_variables-view-reexpand-02.js]
|
||||
[browser_dbg_variables-view-webidl.js]
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the variable inspection popup is hidden when
|
||||
* selecting text in the editor.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function*() {
|
||||
let [tab, debuggee, panel] = yield initDebugger(TAB_URL);
|
||||
let win = panel.panelWin;
|
||||
let bubble = win.DebuggerView.VariableBubble;
|
||||
|
||||
// Allow this generator function to yield first.
|
||||
executeSoon(() => debuggee.start());
|
||||
yield waitForSourceAndCaretAndScopes(panel, ".html", 24);
|
||||
|
||||
// Select some text.
|
||||
let cursor = win.DebuggerView.editor.getOffset({ line: 15, ch: 12 });
|
||||
let [ anchor, head ] = win.DebuggerView.editor.getPosition(
|
||||
cursor,
|
||||
cursor + 3
|
||||
);
|
||||
win.DebuggerView.editor.setSelection(anchor, head);
|
||||
|
||||
// Try to Inspect variable during selection.
|
||||
let popupOpened = yield intendOpenVarPopup(panel, { line: 15, ch: 12 }, true);
|
||||
|
||||
// Ensure the bubble is not there
|
||||
ok(!popupOpened,
|
||||
"The popup is not opened");
|
||||
ok(!bubble._markedText,
|
||||
"The marked text in the editor is not there.");
|
||||
|
||||
// Try to Inspect variable after selection.
|
||||
popupOpened = yield intendOpenVarPopup(panel, { line: 15, ch: 12 }, false);
|
||||
|
||||
// Ensure the bubble is not there
|
||||
ok(popupOpened,
|
||||
"The popup is opened");
|
||||
ok(bubble._markedText,
|
||||
"The marked text in the editor is there.");
|
||||
|
||||
yield resumeDebuggerThenCloseAndFinish(panel);
|
||||
});
|
||||
}
|
|
@ -605,6 +605,41 @@ function openVarPopup(aPanel, aCoords, aWaitForFetchedProperties) {
|
|||
return promise.all([popupShown, fetchedProperties]).then(waitForTick);
|
||||
}
|
||||
|
||||
// Simulates the mouse hovering a variable in the debugger
|
||||
// Takes in account the position of the cursor in the text, if the text is
|
||||
// selected and if a button is currently pushed (aButtonPushed > 0).
|
||||
// The function returns a promise which returns true if the popup opened or
|
||||
// false if it didn't
|
||||
function intendOpenVarPopup(aPanel, aPosition, aButtonPushed) {
|
||||
let bubble = aPanel.panelWin.DebuggerView.VariableBubble;
|
||||
let editor = aPanel.panelWin.DebuggerView.editor;
|
||||
let tooltip = bubble._tooltip;
|
||||
|
||||
let { left, top } = editor.getCoordsFromPosition(aPosition);
|
||||
|
||||
const eventDescriptor = {
|
||||
clientX: left,
|
||||
clientY: top,
|
||||
buttons: aButtonPushed
|
||||
};
|
||||
|
||||
bubble._onMouseMove(eventDescriptor);
|
||||
|
||||
const deferred = promise.defer();
|
||||
window.setTimeout(
|
||||
function() {
|
||||
if(tooltip.isEmpty()) {
|
||||
deferred.resolve(false);
|
||||
} else {
|
||||
deferred.resolve(true);
|
||||
}
|
||||
},
|
||||
tooltip.defaultShowDelay + 1000
|
||||
);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function hideVarPopup(aPanel) {
|
||||
let bubble = aPanel.panelWin.DebuggerView.VariableBubble;
|
||||
let tooltip = bubble._tooltip.panel;
|
||||
|
@ -661,7 +696,6 @@ function filterTraces(aPanel, f) {
|
|||
.children;
|
||||
return Array.filter(traces, f);
|
||||
}
|
||||
|
||||
function attachAddonActorForUrl(aClient, aUrl) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
|
|
|
@ -11,12 +11,15 @@ function test() {
|
|||
|
||||
addTab("about:blank", function() {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
toolIDs = gDevTools.getToolDefinitionArray()
|
||||
.filter(def => def.isTargetSupported(target))
|
||||
.map(def => def.id);
|
||||
idIndex = 0;
|
||||
gDevTools.showToolbox(target, toolIDs[0], Toolbox.HostType.BOTTOM)
|
||||
.then(testShortcuts);
|
||||
|
||||
target.makeRemote().then(() => {
|
||||
toolIDs = gDevTools.getToolDefinitionArray()
|
||||
.filter(def => def.isTargetSupported(target))
|
||||
.map(def => def.id);
|
||||
gDevTools.showToolbox(target, toolIDs[0], Toolbox.HostType.BOTTOM)
|
||||
.then(testShortcuts);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
function test() {
|
||||
addTab().then(function(data) {
|
||||
data.target.makeRemote().then(performChecks.bind(null, data));
|
||||
}).then(null, console.error);
|
||||
|
||||
function performChecks(data) {
|
||||
let toolIds = gDevTools.getToolDefinitionArray()
|
||||
.filter(def => def.isTargetSupported(data.target))
|
||||
.map(def => def.id);
|
||||
|
@ -32,5 +36,5 @@ function test() {
|
|||
};
|
||||
|
||||
open(0);
|
||||
}).then(null, console.error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -253,21 +253,20 @@ Toolbox.prototype = {
|
|||
this._addZoomKeys();
|
||||
this._loadInitialZoom();
|
||||
|
||||
// Load the toolbox-level actor fronts and utilities now
|
||||
this._target.makeRemote().then(() => {
|
||||
this._telemetry.toolOpened("toolbox");
|
||||
this._telemetry.toolOpened("toolbox");
|
||||
|
||||
this.selectTool(this._defaultToolId).then(panel => {
|
||||
this.emit("ready");
|
||||
deferred.resolve();
|
||||
});
|
||||
this.selectTool(this._defaultToolId).then(panel => {
|
||||
this.emit("ready");
|
||||
deferred.resolve();
|
||||
});
|
||||
};
|
||||
|
||||
iframe.setAttribute("src", this._URL);
|
||||
|
||||
let domHelper = new DOMHelpers(iframe.contentWindow);
|
||||
domHelper.onceDOMReady(domReady);
|
||||
// Load the toolbox-level actor fronts and utilities now
|
||||
this._target.makeRemote().then(() => {
|
||||
iframe.setAttribute("src", this._URL);
|
||||
let domHelper = new DOMHelpers(iframe.contentWindow);
|
||||
domHelper.onceDOMReady(domReady);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
|
@ -465,7 +464,7 @@ Toolbox.prototype = {
|
|||
fireCustomKey: function(toolId) {
|
||||
let toolDefinition = gDevTools.getToolDefinition(toolId);
|
||||
|
||||
if (toolDefinition.onkey &&
|
||||
if (toolDefinition.onkey &&
|
||||
((this.currentToolId === toolId) ||
|
||||
(toolId == "webconsole" && this.splitConsole))) {
|
||||
toolDefinition.onkey(this.getCurrentPanel(), this);
|
||||
|
@ -1093,27 +1092,17 @@ Toolbox.prototype = {
|
|||
* Returns a promise that resolves when the fronts are initialized
|
||||
*/
|
||||
initInspector: function() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
if (!this._inspector) {
|
||||
this._inspector = InspectorFront(this._target.client, this._target.form);
|
||||
this._inspector.getWalker().then(walker => {
|
||||
this._walker = walker;
|
||||
if (!this._initInspector) {
|
||||
this._initInspector = Task.spawn(function*() {
|
||||
this._inspector = InspectorFront(this._target.client, this._target.form);
|
||||
this._walker = yield this._inspector.getWalker();
|
||||
this._selection = new Selection(this._walker);
|
||||
if (this.highlighterUtils.isRemoteHighlightable) {
|
||||
this._inspector.getHighlighter().then(highlighter => {
|
||||
this._highlighter = highlighter;
|
||||
deferred.resolve();
|
||||
});
|
||||
} else {
|
||||
deferred.resolve();
|
||||
this._highlighter = yield this._inspector.getHighlighter();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
deferred.resolve();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return this._initInspector;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -239,7 +239,8 @@ Tools.netMonitor = {
|
|||
inMenu: true,
|
||||
|
||||
isTargetSupported: function(target) {
|
||||
return !target.isApp;
|
||||
let root = target.client.mainRoot;
|
||||
return root.traits.networkMonitor || !target.isApp;
|
||||
},
|
||||
|
||||
build: function(iframeWindow, toolbox) {
|
||||
|
|
|
@ -78,7 +78,11 @@ const EVENTS = {
|
|||
// Fired when charts have been displayed in the PerformanceStatisticsView.
|
||||
PLACEHOLDER_CHARTS_DISPLAYED: "NetMonitor:PlaceholderChartsDisplayed",
|
||||
PRIMED_CACHE_CHART_DISPLAYED: "NetMonitor:PrimedChartsDisplayed",
|
||||
EMPTY_CACHE_CHART_DISPLAYED: "NetMonitor:EmptyChartsDisplayed"
|
||||
EMPTY_CACHE_CHART_DISPLAYED: "NetMonitor:EmptyChartsDisplayed",
|
||||
|
||||
// Fired once the NetMonitorController establishes a connection to the debug
|
||||
// target.
|
||||
CONNECTED: "connected",
|
||||
};
|
||||
|
||||
// Descriptions for what this frontend is currently doing.
|
||||
|
@ -200,7 +204,10 @@ let NetMonitorController = {
|
|||
this._startMonitoringTab(client, form, deferred.resolve);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
return deferred.promise.then((result) => {
|
||||
window.emit(EVENTS.CONNECTED);
|
||||
return result;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -362,6 +369,25 @@ let NetMonitorController = {
|
|||
return promise.reject(new Error("Invalid activity type"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Getter that tells if the server supports sending custom network requests.
|
||||
* @type boolean
|
||||
*/
|
||||
get supportsCustomRequest() {
|
||||
return this.webConsoleClient &&
|
||||
(this.webConsoleClient.traits.customNetworkRequest ||
|
||||
!this._target.isApp);
|
||||
},
|
||||
|
||||
/**
|
||||
* Getter that tells if the server can do network performance statistics.
|
||||
* @type boolean
|
||||
*/
|
||||
get supportsPerfStats() {
|
||||
return this.tabClient &&
|
||||
(this.tabClient.traits.reconfigure || !this._target.isApp);
|
||||
},
|
||||
|
||||
_startup: null,
|
||||
_shutdown: null,
|
||||
_connection: null,
|
||||
|
@ -493,6 +519,11 @@ NetworkEventsHandler.prototype = {
|
|||
* The message received from the server.
|
||||
*/
|
||||
_onNetworkEvent: function(aType, aPacket) {
|
||||
if (aPacket.from != this.webConsoleClient.actor) {
|
||||
// Skip events from different console actors.
|
||||
return;
|
||||
}
|
||||
|
||||
let { actor, startedDateTime, method, url, isXHR } = aPacket.eventActor;
|
||||
NetMonitorView.RequestsMenu.addRequest(actor, startedDateTime, method, url, isXHR);
|
||||
window.emit(EVENTS.NETWORK_EVENT);
|
||||
|
@ -508,6 +539,10 @@ NetworkEventsHandler.prototype = {
|
|||
*/
|
||||
_onNetworkEventUpdate: function(aType, aPacket) {
|
||||
let actor = aPacket.from;
|
||||
if (!NetMonitorView.RequestsMenu.getItemByValue(actor)) {
|
||||
// Skip events from unknown actors.
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aPacket.updateType) {
|
||||
case "requestHeaders":
|
||||
|
|
|
@ -374,16 +374,32 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
$("#request-menu-context-newtab").addEventListener("command", this._onContextNewTabCommand, false);
|
||||
$("#request-menu-context-copy-url").addEventListener("command", this._onContextCopyUrlCommand, false);
|
||||
$("#request-menu-context-copy-image-as-data-uri").addEventListener("command", this._onContextCopyImageAsDataUriCommand, false);
|
||||
$("#request-menu-context-resend").addEventListener("command", this._onContextResendCommand, false);
|
||||
$("#request-menu-context-perf").addEventListener("command", this._onContextPerfCommand, false);
|
||||
|
||||
$("#requests-menu-perf-notice-button").addEventListener("command", this._onContextPerfCommand, false);
|
||||
$("#requests-menu-network-summary-button").addEventListener("command", this._onContextPerfCommand, false);
|
||||
$("#requests-menu-network-summary-label").addEventListener("click", this._onContextPerfCommand, false);
|
||||
window.once("connected", this._onConnect.bind(this));
|
||||
},
|
||||
|
||||
$("#custom-request-send-button").addEventListener("click", this.sendCustomRequestEvent, false);
|
||||
$("#custom-request-close-button").addEventListener("click", this.closeCustomRequestEvent, false);
|
||||
$("#headers-summary-resend").addEventListener("click", this.cloneSelectedRequestEvent, false);
|
||||
_onConnect: function() {
|
||||
if (NetMonitorController.supportsCustomRequest) {
|
||||
$("#request-menu-context-resend").addEventListener("command", this._onContextResendCommand, false);
|
||||
$("#custom-request-send-button").addEventListener("click", this.sendCustomRequestEvent, false);
|
||||
$("#custom-request-close-button").addEventListener("click", this.closeCustomRequestEvent, false);
|
||||
$("#headers-summary-resend").addEventListener("click", this.cloneSelectedRequestEvent, false);
|
||||
} else {
|
||||
$("#request-menu-context-resend").hidden = true;
|
||||
$("#headers-summary-resend").hidden = true;
|
||||
}
|
||||
|
||||
if (NetMonitorController.supportsPerfStats) {
|
||||
$("#request-menu-context-perf").addEventListener("command", this._onContextPerfCommand, false);
|
||||
$("#requests-menu-perf-notice-button").addEventListener("command", this._onContextPerfCommand, false);
|
||||
$("#requests-menu-network-summary-button").addEventListener("command", this._onContextPerfCommand, false);
|
||||
$("#requests-menu-network-summary-label").addEventListener("click", this._onContextPerfCommand, false);
|
||||
} else {
|
||||
$("#notice-perf-message").hidden = true;
|
||||
$("#request-menu-context-perf").hidden = true;
|
||||
$("#requests-menu-network-summary-button").hidden = true;
|
||||
$("#requests-menu-network-summary-label").hidden = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -546,8 +562,12 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
*/
|
||||
sendCustomRequest: function() {
|
||||
let selected = this.selectedItem.attachment;
|
||||
let data = Object.create(selected);
|
||||
|
||||
let data = {
|
||||
method: selected.method,
|
||||
url: selected.url,
|
||||
httpVersion: selected.httpVersion,
|
||||
};
|
||||
if (selected.requestHeaders) {
|
||||
data.headers = selected.requestHeaders.headers;
|
||||
}
|
||||
|
@ -1534,7 +1554,8 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
|||
let selectedItem = this.selectedItem;
|
||||
|
||||
let resendElement = $("#request-menu-context-resend");
|
||||
resendElement.hidden = !selectedItem || selectedItem.attachment.isCustom;
|
||||
resendElement.hidden = !NetMonitorController.supportsCustomRequest ||
|
||||
!selectedItem || selectedItem.attachment.isCustom;
|
||||
|
||||
let copyUrlElement = $("#request-menu-context-copy-url");
|
||||
copyUrlElement.hidden = !selectedItem;
|
||||
|
|
|
@ -90,6 +90,10 @@ exports.RuleViewTool = RuleViewTool;
|
|||
|
||||
RuleViewTool.prototype = {
|
||||
onSelect: function RVT_onSelect(aEvent) {
|
||||
if (!this.view) {
|
||||
// Skip the event if RuleViewTool has been destroyed.
|
||||
return;
|
||||
}
|
||||
this.view.setPageStyle(this.inspector.pageStyle);
|
||||
|
||||
if (!this.inspector.selection.isConnected() ||
|
||||
|
@ -158,6 +162,10 @@ exports.ComputedViewTool = ComputedViewTool;
|
|||
ComputedViewTool.prototype = {
|
||||
onSelect: function CVT_onSelect(aEvent)
|
||||
{
|
||||
if (!this.view) {
|
||||
// Skip the event if ComputedViewTool has been destroyed.
|
||||
return;
|
||||
}
|
||||
this.view.setPageStyle(this.inspector.pageStyle);
|
||||
|
||||
if (!this.inspector.selection.isConnected() ||
|
||||
|
|
|
@ -9,6 +9,8 @@ const {Cc, Ci, Cu} = require("chrome");
|
|||
|
||||
loader.lazyImporter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm");
|
||||
loader.lazyImporter(this, "escapeHTML", "resource:///modules/devtools/VariablesView.jsm");
|
||||
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
|
||||
loader.lazyImporter(this, "Task","resource://gre/modules/Task.jsm");
|
||||
|
||||
const Heritage = require("sdk/core/heritage");
|
||||
const XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
|
@ -131,7 +133,7 @@ ConsoleOutput.prototype = {
|
|||
* @type DOMDocument
|
||||
*/
|
||||
get document() {
|
||||
return this.owner.document;
|
||||
return this.owner ? this.owner.document : null;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -150,6 +152,14 @@ ConsoleOutput.prototype = {
|
|||
return this.owner.webConsoleClient;
|
||||
},
|
||||
|
||||
/**
|
||||
* Getter for the current toolbox debuggee target.
|
||||
* @type Target
|
||||
*/
|
||||
get toolboxTarget() {
|
||||
return this.owner.owner.target;
|
||||
},
|
||||
|
||||
/**
|
||||
* Release an actor.
|
||||
*
|
||||
|
@ -507,6 +517,15 @@ Messages.BaseMessage.prototype = {
|
|||
{
|
||||
this.output.openLink(event.target.href);
|
||||
},
|
||||
|
||||
destroy: function()
|
||||
{
|
||||
// Destroy all widgets that have registered themselves in this.widgets
|
||||
for (let widget of this.widgets) {
|
||||
widget.destroy();
|
||||
}
|
||||
this.widgets.clear();
|
||||
}
|
||||
}; // Messages.BaseMessage.prototype
|
||||
|
||||
|
||||
|
@ -2017,6 +2036,7 @@ Widgets.ObjectRenderers.add({
|
|||
case Ci.nsIDOMNode.TEXT_NODE:
|
||||
case Ci.nsIDOMNode.COMMENT_NODE:
|
||||
case Ci.nsIDOMNode.DOCUMENT_FRAGMENT_NODE:
|
||||
case Ci.nsIDOMNode.ELEMENT_NODE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -2045,6 +2065,9 @@ Widgets.ObjectRenderers.add({
|
|||
case Ci.nsIDOMNode.DOCUMENT_FRAGMENT_NODE:
|
||||
this._renderDocumentFragmentNode();
|
||||
break;
|
||||
case Ci.nsIDOMNode.ELEMENT_NODE:
|
||||
this._renderElementNode();
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unsupported nodeType: " + preview.nodeType);
|
||||
}
|
||||
|
@ -2138,6 +2161,168 @@ Widgets.ObjectRenderers.add({
|
|||
|
||||
this._text(" ]");
|
||||
},
|
||||
|
||||
_renderElementNode: function()
|
||||
{
|
||||
let doc = this.document;
|
||||
let {attributes, nodeName} = this.objectActor.preview;
|
||||
|
||||
this.element = this.el("span." + "kind-" + this.objectActor.preview.kind + ".elementNode");
|
||||
|
||||
let openTag = this.el("span.cm-tag");
|
||||
openTag.textContent = "<";
|
||||
this.element.appendChild(openTag);
|
||||
|
||||
let tagName = this._anchor(nodeName, {
|
||||
className: "cm-tag",
|
||||
appendTo: openTag
|
||||
});
|
||||
|
||||
if (this.options.concise) {
|
||||
if (attributes.id) {
|
||||
tagName.appendChild(this.el("span.cm-attribute", "#" + attributes.id));
|
||||
}
|
||||
if (attributes.class) {
|
||||
tagName.appendChild(this.el("span.cm-attribute", "." + attributes.class.split(" ").join(".")));
|
||||
}
|
||||
} else {
|
||||
for (let name of Object.keys(attributes)) {
|
||||
let attr = this._renderAttributeNode(" " + name, attributes[name]);
|
||||
this.element.appendChild(attr);
|
||||
}
|
||||
}
|
||||
|
||||
let closeTag = this.el("span.cm-tag");
|
||||
closeTag.textContent = ">";
|
||||
this.element.appendChild(closeTag);
|
||||
|
||||
// Register this widget in the owner message so that it gets destroyed when
|
||||
// the message is destroyed.
|
||||
this.message.widgets.add(this);
|
||||
|
||||
this.linkToInspector();
|
||||
},
|
||||
|
||||
/**
|
||||
* If the DOMNode being rendered can be highlit in the page, this function
|
||||
* will attach mouseover/out event listeners to do so, and the inspector icon
|
||||
* to open the node in the inspector.
|
||||
* @return a promise (always the same) that resolves when the node has been
|
||||
* linked to the inspector, or rejects if it wasn't (either if no toolbox
|
||||
* could be found to access the inspector, or if the node isn't present in the
|
||||
* inspector, i.e. if the node is in a DocumentFragment or not part of the
|
||||
* tree, or not of type Ci.nsIDOMNode.ELEMENT_NODE).
|
||||
*/
|
||||
linkToInspector: function()
|
||||
{
|
||||
if (this._linkedToInspector) {
|
||||
return this._linkedToInspector;
|
||||
}
|
||||
|
||||
this._linkedToInspector = Task.spawn(function*() {
|
||||
// Checking the node type
|
||||
if (this.objectActor.preview.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
|
||||
throw null;
|
||||
}
|
||||
|
||||
// Checking the presence of a toolbox
|
||||
let target = this.message.output.toolboxTarget;
|
||||
this.toolbox = gDevTools.getToolbox(target);
|
||||
if (!this.toolbox) {
|
||||
throw null;
|
||||
}
|
||||
|
||||
// Checking that the inspector supports the node
|
||||
yield this.toolbox.initInspector();
|
||||
this._nodeFront = yield this.toolbox.walker.getNodeActorFromObjectActor(this.objectActor.actor);
|
||||
if (!this._nodeFront) {
|
||||
throw null;
|
||||
}
|
||||
|
||||
// At this stage, the message may have been cleared already
|
||||
if (!this.document) {
|
||||
throw null;
|
||||
}
|
||||
|
||||
this.highlightDomNode = this.highlightDomNode.bind(this);
|
||||
this.element.addEventListener("mouseover", this.highlightDomNode, false);
|
||||
this.unhighlightDomNode = this.unhighlightDomNode.bind(this);
|
||||
this.element.addEventListener("mouseout", this.unhighlightDomNode, false);
|
||||
|
||||
this._openInspectorNode = this._anchor("", {
|
||||
className: "open-inspector",
|
||||
onClick: this.openNodeInInspector.bind(this)
|
||||
});
|
||||
this._openInspectorNode.title = l10n.getStr("openNodeInInspector");
|
||||
}.bind(this));
|
||||
|
||||
return this._linkedToInspector;
|
||||
},
|
||||
|
||||
/**
|
||||
* Highlight the DOMNode corresponding to the ObjectActor in the page.
|
||||
* @return a promise that resolves when the node has been highlighted, or
|
||||
* rejects if the node cannot be highlighted (detached from the DOM)
|
||||
*/
|
||||
highlightDomNode: function()
|
||||
{
|
||||
return Task.spawn(function*() {
|
||||
yield this.linkToInspector();
|
||||
let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
|
||||
if (isAttached) {
|
||||
yield this.toolbox.highlighterUtils.highlightNodeFront(this._nodeFront);
|
||||
} else {
|
||||
throw null;
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Unhighlight a previously highlit node
|
||||
* @see highlightDomNode
|
||||
* @return a promise that resolves when the highlighter has been hidden
|
||||
*/
|
||||
unhighlightDomNode: function()
|
||||
{
|
||||
return this.linkToInspector().then(() => {
|
||||
return this.toolbox.highlighterUtils.unhighlight();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the DOMNode corresponding to the ObjectActor in the inspector panel
|
||||
* @return a promise that resolves when the inspector has been switched to
|
||||
* and the node has been selected, or rejects if the node cannot be selected
|
||||
* (detached from the DOM). Note that in any case, the inspector panel will
|
||||
* be switched to.
|
||||
*/
|
||||
openNodeInInspector: function()
|
||||
{
|
||||
return Task.spawn(function*() {
|
||||
yield this.linkToInspector();
|
||||
yield this.toolbox.selectTool("inspector");
|
||||
|
||||
let isAttached = yield this.toolbox.walker.isInDOMTree(this._nodeFront);
|
||||
if (isAttached) {
|
||||
let onReady = this.toolbox.inspector.once("inspector-updated");
|
||||
yield this.toolbox.selection.setNodeFront(this._nodeFront, "console");
|
||||
yield onReady;
|
||||
} else {
|
||||
throw null;
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
destroy: function()
|
||||
{
|
||||
if (this.toolbox && this._nodeFront) {
|
||||
this.element.removeEventListener("mouseover", this.highlightDomNode, false);
|
||||
this.element.removeEventListener("mouseout", this.unhighlightDomNode, false);
|
||||
this._openInspectorNode.removeEventListener("mousedown", this.openNodeInInspector, true);
|
||||
this.toolbox = null;
|
||||
this._nodeFront = null;
|
||||
}
|
||||
},
|
||||
}); // Widgets.ObjectRenderers.byKind.DOMNode
|
||||
|
||||
/**
|
||||
|
|
|
@ -69,6 +69,7 @@ support-files =
|
|||
test-console-output-02.html
|
||||
test-console-output-03.html
|
||||
test-console-output-04.html
|
||||
test-console-output-dom-elements.html
|
||||
test-console-output-events.html
|
||||
test-consoleiframes.html
|
||||
test-data.json
|
||||
|
@ -266,6 +267,11 @@ run-if = os == "mac"
|
|||
[browser_webconsole_output_02.js]
|
||||
[browser_webconsole_output_03.js]
|
||||
[browser_webconsole_output_04.js]
|
||||
[browser_webconsole_output_05.js]
|
||||
[browser_webconsole_output_dom_elements_01.js]
|
||||
[browser_webconsole_output_dom_elements_02.js]
|
||||
[browser_webconsole_output_dom_elements_03.js]
|
||||
[browser_webconsole_output_dom_elements_04.js]
|
||||
[browser_webconsole_output_events.js]
|
||||
[browser_console_variables_view_highlighter.js]
|
||||
[browser_webconsole_start_netmon_first.js]
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
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;
|
||||
|
@ -76,70 +75,6 @@ let inputTests = [
|
|||
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: "new Boolean(false)",
|
||||
output: "false",
|
||||
inspectable: true,
|
||||
},
|
||||
|
||||
// 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",
|
||||
},
|
||||
|
||||
// 16
|
||||
{
|
||||
input: "new Number(43)",
|
||||
output: "43",
|
||||
inspectable: true,
|
||||
},
|
||||
|
||||
// 17
|
||||
{
|
||||
input: "new String('hello world')",
|
||||
output: '"hello world"',
|
||||
inspectable: true,
|
||||
},
|
||||
];
|
||||
|
||||
longString = initialString = null;
|
||||
|
@ -150,11 +85,9 @@ function test() {
|
|||
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);
|
||||
Task.spawn(function*() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
return checkOutputForInputs(hud, inputTests);
|
||||
}).then(finishTest);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ let inputTests = [
|
|||
// 2
|
||||
{
|
||||
input: "testDocumentFragment()",
|
||||
output: 'DocumentFragment [ <div#foo1>, <div#foo3> ]',
|
||||
output: 'DocumentFragment [ <div#foo1.bar>, <div#foo3> ]',
|
||||
printOutput: "[object DocumentFragment]",
|
||||
inspectable: true,
|
||||
variablesViewLabel: "DocumentFragment[2]",
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 - 05";
|
||||
|
||||
let dateNow = Date.now();
|
||||
|
||||
let inputTests = [
|
||||
// 0
|
||||
{
|
||||
input: "/foo?b*\\s\"ar/igym",
|
||||
output: "/foo?b*\\s\"ar/gimy",
|
||||
printOutput: "/foo?b*\\s\"ar/gimy",
|
||||
inspectable: true,
|
||||
},
|
||||
|
||||
// 1
|
||||
{
|
||||
input: "null",
|
||||
output: "null",
|
||||
},
|
||||
|
||||
// 2
|
||||
{
|
||||
input: "undefined",
|
||||
output: "undefined",
|
||||
},
|
||||
|
||||
// 3
|
||||
{
|
||||
input: "true",
|
||||
output: "true",
|
||||
},
|
||||
|
||||
// 4
|
||||
{
|
||||
input: "new Boolean(false)",
|
||||
output: "false",
|
||||
inspectable: true,
|
||||
},
|
||||
|
||||
// 5
|
||||
{
|
||||
input: "new Date(" + dateNow + ")",
|
||||
output: "Date " + (new Date(dateNow)).toISOString(),
|
||||
printOutput: (new Date(dateNow)).toString(),
|
||||
inspectable: true,
|
||||
},
|
||||
|
||||
// 6
|
||||
{
|
||||
input: "new Date('test')",
|
||||
output: "Invalid Date",
|
||||
printOutput: "Invalid Date",
|
||||
inspectable: true,
|
||||
variablesViewLabel: "Invalid Date",
|
||||
},
|
||||
|
||||
// 7
|
||||
{
|
||||
input: "new Number(43)",
|
||||
output: "43",
|
||||
inspectable: true,
|
||||
},
|
||||
|
||||
// 8
|
||||
{
|
||||
input: "new String('hello world')",
|
||||
output: '"hello world"',
|
||||
inspectable: true,
|
||||
},
|
||||
];
|
||||
|
||||
function test() {
|
||||
Task.spawn(function*() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
return checkOutputForInputs(hud, inputTests);
|
||||
}).then(finishTest);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Test the webconsole output for various types of DOM Nodes.
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
|
||||
|
||||
let inputTests = [
|
||||
{
|
||||
input: "testBodyNode()",
|
||||
output: '<body id="body-id" class="body-class">',
|
||||
printOutput: "[object HTMLBodyElement]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: true
|
||||
},
|
||||
|
||||
{
|
||||
input: "testDocumentElement()",
|
||||
output: '<html lang="en-US" dir="ltr">',
|
||||
printOutput: "[object HTMLHtmlElement]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: true
|
||||
},
|
||||
|
||||
{
|
||||
input: "testDocument()",
|
||||
output: 'HTMLDocument \u2192 ' + TEST_URI,
|
||||
printOutput: "[object HTMLDocument]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: false
|
||||
},
|
||||
|
||||
{
|
||||
input: "testNode()",
|
||||
output: '<p some-attribute="some-value">',
|
||||
printOutput: "[object HTMLParagraphElement]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: true
|
||||
},
|
||||
|
||||
{
|
||||
input: "testNodeList()",
|
||||
output: 'NodeList [ <html>, <head>, <meta>, <title>, <body#body-id.body-class>, <p>, <iframe>, <script> ]',
|
||||
printOutput: "[object NodeList]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: true
|
||||
},
|
||||
|
||||
{
|
||||
input: "testNodeInIframe()",
|
||||
output: '<p>',
|
||||
printOutput: "[object HTMLParagraphElement]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: true
|
||||
},
|
||||
|
||||
{
|
||||
input: "testDocumentFragment()",
|
||||
output: 'DocumentFragment [ <span.foo>, <div#fragdiv> ]',
|
||||
printOutput: "[object DocumentFragment]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: false
|
||||
},
|
||||
|
||||
{
|
||||
input: "testNodeInDocumentFragment()",
|
||||
output: '<span class="foo" data-lolz="hehe">',
|
||||
printOutput: "[object HTMLSpanElement]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: false
|
||||
},
|
||||
|
||||
{
|
||||
input: "testUnattachedNode()",
|
||||
output: '<p class="such-class" data-data="such-data">',
|
||||
printOutput: "[object HTMLParagraphElement]",
|
||||
inspectable: true,
|
||||
noClick: true,
|
||||
inspectorIcon: false
|
||||
}
|
||||
];
|
||||
|
||||
function test() {
|
||||
Task.spawn(function*() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
yield checkOutputForInputs(hud, inputTests);
|
||||
}).then(finishTest);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Test the inspector links in the webconsole output for DOM Nodes actually
|
||||
// open the inspector and select the right node
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
// The first test shouldn't be returning the body element as this is the
|
||||
// default selected node, so re-selecting it won't fire the inspector-updated
|
||||
// event
|
||||
input: "testNode()",
|
||||
output: '<p some-attribute="some-value">'
|
||||
},
|
||||
{
|
||||
input: "testBodyNode()",
|
||||
output: '<body id="body-id" class="body-class">'
|
||||
},
|
||||
{
|
||||
input: "testNodeInIframe()",
|
||||
output: '<p>'
|
||||
},
|
||||
{
|
||||
input: "testDocumentElement()",
|
||||
output: '<html lang="en-US" dir="ltr">'
|
||||
}
|
||||
];
|
||||
|
||||
function test() {
|
||||
Task.spawn(function*() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
let toolbox = gDevTools.getToolbox(hud.target);
|
||||
|
||||
// Loading the inspector panel at first, to make it possible to listen for
|
||||
// new node selections
|
||||
yield toolbox.selectTool("inspector");
|
||||
let inspector = toolbox.getCurrentPanel();
|
||||
yield toolbox.selectTool("webconsole");
|
||||
|
||||
info("Iterating over the test data");
|
||||
for (let data of TEST_DATA) {
|
||||
let [result] = yield jsEval(data.input, hud, {text: data.output});
|
||||
let {widget, msg} = yield getWidgetAndMessage(result);
|
||||
|
||||
let inspectorIcon = msg.querySelector(".open-inspector");
|
||||
ok(inspectorIcon, "Inspector icon found in the ElementNode widget");
|
||||
|
||||
info("Clicking on the inspector icon and waiting for the inspector to be selected");
|
||||
let onInspectorSelected = toolbox.once("inspector-selected");
|
||||
let onInspectorUpdated = inspector.once("inspector-updated");
|
||||
let onNewNode = toolbox.selection.once("new-node");
|
||||
|
||||
EventUtils.synthesizeMouseAtCenter(inspectorIcon, {},
|
||||
inspectorIcon.ownerDocument.defaultView);
|
||||
yield onInspectorSelected;
|
||||
yield onInspectorUpdated;
|
||||
yield onNewNode;
|
||||
ok(true, "Inspector selected and new node got selected");
|
||||
|
||||
let rawNode = content.wrappedJSObject[data.input.replace(/\(\)/g, "")]();
|
||||
is(inspector.selection.node.wrappedJSObject, rawNode,
|
||||
"The current inspector selection is correct");
|
||||
|
||||
info("Switching back to the console");
|
||||
yield toolbox.selectTool("webconsole");
|
||||
}
|
||||
}).then(finishTest);
|
||||
}
|
||||
|
||||
function jsEval(input, hud, message) {
|
||||
info("Executing '" + input + "' in the web console");
|
||||
|
||||
hud.jsterm.clearOutput();
|
||||
hud.jsterm.execute(input);
|
||||
|
||||
return waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [message]
|
||||
});
|
||||
}
|
||||
|
||||
function* getWidgetAndMessage(result) {
|
||||
info("Getting the output ElementNode widget");
|
||||
|
||||
let msg = [...result.matched][0];
|
||||
let widget = [...msg._messageObject.widgets][0];
|
||||
ok(widget, "ElementNode widget found in the output");
|
||||
|
||||
info("Waiting for the ElementNode widget to be linked to the inspector");
|
||||
yield widget.linkToInspector();
|
||||
|
||||
return {widget: widget, msg: msg};
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Test that inspector links in webconsole outputs for DOM Nodes highlight
|
||||
// the actual DOM Nodes on hover
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
|
||||
|
||||
function test() {
|
||||
Task.spawn(function*() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
let toolbox = gDevTools.getToolbox(hud.target);
|
||||
|
||||
// Loading the inspector panel at first, to make it possible to listen for
|
||||
// new node selections
|
||||
yield toolbox.loadTool("inspector");
|
||||
let inspector = toolbox.getPanel("inspector");
|
||||
|
||||
info("Executing 'testNode()' in the web console to output a DOM Node");
|
||||
let [result] = yield jsEval("testNode()", hud, {
|
||||
text: '<p some-attribute="some-value">'
|
||||
});
|
||||
|
||||
let elementNodeWidget = yield getWidget(result);
|
||||
|
||||
let nodeFront = yield hoverOverWidget(elementNodeWidget, toolbox);
|
||||
let attrs = nodeFront.attributes;
|
||||
is(nodeFront.tagName, "P", "The correct node was highlighted");
|
||||
is(attrs[0].name, "some-attribute", "The correct node was highlighted");
|
||||
is(attrs[0].value, "some-value", "The correct node was highlighted");
|
||||
}).then(finishTest);
|
||||
}
|
||||
|
||||
function jsEval(input, hud, message) {
|
||||
hud.jsterm.execute(input);
|
||||
return waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [message]
|
||||
});
|
||||
}
|
||||
|
||||
function* getWidget(result) {
|
||||
info("Getting the output ElementNode widget");
|
||||
|
||||
let msg = [...result.matched][0];
|
||||
let elementNodeWidget = [...msg._messageObject.widgets][0];
|
||||
ok(elementNodeWidget, "ElementNode widget found in the output");
|
||||
|
||||
info("Waiting for the ElementNode widget to be linked to the inspector");
|
||||
yield elementNodeWidget.linkToInspector();
|
||||
|
||||
return elementNodeWidget;
|
||||
}
|
||||
|
||||
function* hoverOverWidget(widget, toolbox) {
|
||||
info("Hovering over the output to highlight the node");
|
||||
|
||||
let onHighlight = toolbox.once("node-highlight");
|
||||
EventUtils.sendMouseEvent({type: "mouseover"}, widget.element,
|
||||
widget.element.ownerDocument.defaultView);
|
||||
let nodeFront = yield onHighlight;
|
||||
ok(true, "The highlighter was shown on a node");
|
||||
return nodeFront;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Test that inspector links in the webconsole output for DOM Nodes do not try
|
||||
// to highlight or select nodes once they have been detached
|
||||
|
||||
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-output-dom-elements.html";
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
// The first test shouldn't be returning the body element as this is the
|
||||
// default selected node, so re-selecting it won't fire the inspector-updated
|
||||
// event
|
||||
input: "testNode()",
|
||||
output: '<p some-attribute="some-value">'
|
||||
},
|
||||
{
|
||||
input: "testBodyNode()",
|
||||
output: '<body id="body-id" class="body-class">'
|
||||
},
|
||||
{
|
||||
input: "testNodeInIframe()",
|
||||
output: '<p>'
|
||||
},
|
||||
{
|
||||
input: "testDocumentElement()",
|
||||
output: '<html lang="en-US" dir="ltr">'
|
||||
}
|
||||
];
|
||||
|
||||
const PREF = "devtools.webconsole.persistlog";
|
||||
|
||||
function test() {
|
||||
Services.prefs.setBoolPref(PREF, true);
|
||||
registerCleanupFunction(() => Services.prefs.clearUserPref(PREF));
|
||||
|
||||
Task.spawn(function*() {
|
||||
let {tab} = yield loadTab(TEST_URI);
|
||||
let hud = yield openConsole(tab);
|
||||
let toolbox = gDevTools.getToolbox(hud.target);
|
||||
|
||||
info("Executing the test data");
|
||||
let widgets = [];
|
||||
for (let data of TEST_DATA) {
|
||||
let [result] = yield jsEval(data.input, hud, {text: data.output});
|
||||
let {widget} = yield getWidgetAndMessage(result);
|
||||
widgets.push(widget);
|
||||
}
|
||||
|
||||
info("Reloading the page");
|
||||
yield reloadPage();
|
||||
|
||||
info("Iterating over the ElementNode widgets");
|
||||
for (let widget of widgets) {
|
||||
// Verify that openNodeInInspector rejects since the associated dom node
|
||||
// doesn't exist anymore
|
||||
yield widget.openNodeInInspector().then(() => {
|
||||
ok(false, "The openNodeInInspector promise resolved");
|
||||
}, () => {
|
||||
ok(true, "The openNodeInInspector promise rejected as expected");
|
||||
});
|
||||
yield toolbox.selectTool("webconsole");
|
||||
|
||||
// Verify that highlightDomNode rejects too, for the same reason
|
||||
yield widget.highlightDomNode().then(() => {
|
||||
ok(false, "The highlightDomNode promise resolved");
|
||||
}, () => {
|
||||
ok(true, "The highlightDomNode promise rejected as expected");
|
||||
});
|
||||
}
|
||||
}).then(finishTest);
|
||||
}
|
||||
|
||||
function jsEval(input, hud, message) {
|
||||
info("Executing '" + input + "' in the web console");
|
||||
hud.jsterm.execute(input);
|
||||
return waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [message]
|
||||
});
|
||||
}
|
||||
|
||||
function* getWidgetAndMessage(result) {
|
||||
info("Getting the output ElementNode widget");
|
||||
|
||||
let msg = [...result.matched][0];
|
||||
let widget = [...msg._messageObject.widgets][0];
|
||||
ok(widget, "ElementNode widget found in the output");
|
||||
|
||||
info("Waiting for the ElementNode widget to be linked to the inspector");
|
||||
yield widget.linkToInspector();
|
||||
|
||||
return {widget: widget, msg: msg};
|
||||
}
|
||||
|
||||
function reloadPage() {
|
||||
let def = promise.defer();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
def.resolve();
|
||||
}, true);
|
||||
content.location.reload();
|
||||
return def.promise;
|
||||
}
|
|
@ -1314,6 +1314,10 @@ function whenDelayedStartupFinished(aWindow, aCallback)
|
|||
* - variablesViewLabel: string|RegExp, optional, the expected variables
|
||||
* view label when the object is inspected. If this is not provided, then
|
||||
* |output| is used.
|
||||
*
|
||||
* - inspectorIcon: boolean, when true, the test runner expects the
|
||||
* result widget to contain an inspectorIcon element (className
|
||||
* open-inspector).
|
||||
*/
|
||||
function checkOutputForInputs(hud, inputTests)
|
||||
{
|
||||
|
@ -1338,12 +1342,12 @@ function checkOutputForInputs(hud, inputTests)
|
|||
yield checkJSEval(entry);
|
||||
}
|
||||
|
||||
function checkConsoleLog(entry)
|
||||
function* checkConsoleLog(entry)
|
||||
{
|
||||
hud.jsterm.clearOutput();
|
||||
hud.jsterm.execute("console.log(" + entry.input + ")");
|
||||
|
||||
return waitForMessages({
|
||||
let [result] = yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
name: "console.log() output: " + entry.output,
|
||||
|
@ -1352,6 +1356,11 @@ function checkOutputForInputs(hud, inputTests)
|
|||
severity: SEVERITY_LOG,
|
||||
}],
|
||||
});
|
||||
|
||||
if (typeof entry.inspectorIcon == "boolean") {
|
||||
let msg = [...result.matched][0];
|
||||
yield checkLinkToInspector(entry, msg);
|
||||
}
|
||||
}
|
||||
|
||||
function checkPrintOutput(entry)
|
||||
|
@ -1385,10 +1394,13 @@ function checkOutputForInputs(hud, inputTests)
|
|||
}],
|
||||
});
|
||||
|
||||
let msg = [...result.matched][0];
|
||||
if (!entry.noClick) {
|
||||
let msg = [...result.matched][0];
|
||||
yield checkObjectClick(entry, msg);
|
||||
}
|
||||
if (typeof entry.inspectorIcon == "boolean") {
|
||||
yield checkLinkToInspector(entry, msg);
|
||||
}
|
||||
}
|
||||
|
||||
function checkObjectClick(entry, msg)
|
||||
|
@ -1413,6 +1425,29 @@ function checkOutputForInputs(hud, inputTests)
|
|||
return promise.resolve(null);
|
||||
}
|
||||
|
||||
function checkLinkToInspector(entry, msg)
|
||||
{
|
||||
let elementNodeWidget = [...msg._messageObject.widgets][0];
|
||||
if (!elementNodeWidget) {
|
||||
ok(!entry.inspectorIcon, "The message has no ElementNode widget");
|
||||
return;
|
||||
}
|
||||
|
||||
return elementNodeWidget.linkToInspector().then(() => {
|
||||
// linkToInspector resolved, check for the .open-inspector element
|
||||
if (entry.inspectorIcon) {
|
||||
ok(msg.querySelectorAll(".open-inspector").length,
|
||||
"The ElementNode widget is linked to the inspector");
|
||||
} else {
|
||||
ok(!msg.querySelectorAll(".open-inspector").length,
|
||||
"The ElementNode widget isn't linked to the inspector");
|
||||
}
|
||||
}, () => {
|
||||
// linkToInspector promise rejected, node not linked to inspector
|
||||
ok(!entry.inspectorIcon, "The ElementNode widget isn't linked to the inspector");
|
||||
});
|
||||
}
|
||||
|
||||
function onVariablesViewOpen(entry, deferred, event, view, options)
|
||||
{
|
||||
let label = entry.variablesViewLabel || entry.output;
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html dir="ltr" lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test the web console output - 05</title>
|
||||
<!--
|
||||
- Any copyright is dedicated to the Public Domain.
|
||||
- http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
</head>
|
||||
<body class="body-class" id="body-id">
|
||||
<p some-attribute="some-value">hello world!</p>
|
||||
<iframe src="data:text/html,<p>hello from iframe</p>"></iframe>
|
||||
<script type="text/javascript">
|
||||
function testBodyNode() {
|
||||
return document.body;
|
||||
}
|
||||
|
||||
function testDocumentElement() {
|
||||
return document.documentElement;
|
||||
}
|
||||
|
||||
function testDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
function testNode() {
|
||||
return document.querySelector("p");
|
||||
}
|
||||
|
||||
function testNodeList() {
|
||||
return document.querySelectorAll("*");
|
||||
}
|
||||
|
||||
function testNodeInIframe() {
|
||||
return document.querySelector("iframe").contentWindow.document.querySelector("p");
|
||||
}
|
||||
|
||||
function testDocumentFragment() {
|
||||
var frag = document.createDocumentFragment();
|
||||
|
||||
var span = document.createElement("span");
|
||||
span.className = 'foo';
|
||||
span.dataset.lolz = 'hehe';
|
||||
|
||||
var div = document.createElement('div')
|
||||
div.id = 'fragdiv';
|
||||
|
||||
frag.appendChild(span);
|
||||
frag.appendChild(div);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
function testNodeInDocumentFragment() {
|
||||
var frag = testDocumentFragment();
|
||||
return frag.firstChild;
|
||||
}
|
||||
|
||||
function testUnattachedNode() {
|
||||
var p = document.createElement("p");
|
||||
p.className = "such-class";
|
||||
p.dataset.data = "such-data";
|
||||
return p;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -2362,6 +2362,10 @@ WebConsoleFrame.prototype = {
|
|||
*/
|
||||
removeOutputMessage: function WCF_removeOutputMessage(aNode)
|
||||
{
|
||||
if (aNode._messageObject) {
|
||||
aNode._messageObject.destroy();
|
||||
}
|
||||
|
||||
if (aNode._objectActors) {
|
||||
for (let actor of aNode._objectActors) {
|
||||
this._releaseObject(actor);
|
||||
|
|
|
@ -214,6 +214,11 @@ emptyPropertiesList=No properties to display
|
|||
# example: 3 repeats
|
||||
messageRepeats.tooltip2=#1 repeat;#1 repeats
|
||||
|
||||
# LOCALIZATION NOTE (openNodeInInspector): the text that is displayed in a
|
||||
# tooltip when hovering over the inspector icon next to a DOM Node in the console
|
||||
# output
|
||||
openNodeInInspector=Click to select the node in the inspector
|
||||
|
||||
# LOCALIZATION NOTE (cdFunctionInvalidArgument): the text that is displayed when
|
||||
# cd() is invoked with an invalid argument.
|
||||
cdFunctionInvalidArgument=Cannot cd() to the given window. Invalid argument.
|
||||
|
|
Двоичные данные
browser/themes/linux/Toolbar-inverted.png
До Ширина: | Высота: | Размер: 8.8 KiB После Ширина: | Высота: | Размер: 8.9 KiB |
Двоичные данные
browser/themes/linux/Toolbar.png
До Ширина: | Высота: | Размер: 14 KiB После Ширина: | Высота: | Размер: 14 KiB |
|
@ -29,6 +29,18 @@
|
|||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
/* subviewbutton entries for social sidebars have images that come from external
|
||||
/* sources, and are not guaranteed to be the size we want, so force the size on
|
||||
/* those icons. */
|
||||
toolbarbutton.social-provider-menuitem > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.subviewbutton:-moz-any([image],[targetURI],.cui-withicon, .restoreallitem, .bookmark-item)[checked="true"] > .toolbarbutton-icon {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.PanelUI-subView toolbarseparator,
|
||||
.PanelUI-subView menuseparator,
|
||||
.cui-widget-panelview menuseparator,
|
||||
|
|
Двоичные данные
browser/themes/linux/menuPanel.png
До Ширина: | Высота: | Размер: 23 KiB После Ширина: | Высота: | Размер: 23 KiB |
Двоичные данные
browser/themes/osx/Toolbar-inverted.png
До Ширина: | Высота: | Размер: 29 KiB После Ширина: | Высота: | Размер: 30 KiB |
Двоичные данные
browser/themes/osx/Toolbar-inverted@2x.png
До Ширина: | Высота: | Размер: 71 KiB После Ширина: | Высота: | Размер: 73 KiB |
Двоичные данные
browser/themes/osx/Toolbar.png
До Ширина: | Высота: | Размер: 23 KiB После Ширина: | Высота: | Размер: 24 KiB |
Двоичные данные
browser/themes/osx/Toolbar@2x.png
До Ширина: | Высота: | Размер: 63 KiB После Ширина: | Высота: | Размер: 63 KiB |
|
@ -724,6 +724,10 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
|||
-moz-image-region: rect(18px, 666px, 36px, 648px);
|
||||
}
|
||||
|
||||
#sidebar-button@toolbarButtonPressed@ {
|
||||
-moz-image-region: rect(18px, 684px, 36px, 666px);
|
||||
}
|
||||
|
||||
/**
|
||||
* OSX has a unique set of icons when fullscreen is in the checked state.
|
||||
*/
|
||||
|
@ -1027,6 +1031,14 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
|||
-moz-image-region: rect(36px, 1332px, 72px, 1296px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 1368px, 36px, 1332px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
|
||||
-moz-image-region: rect(36px, 1368px, 72px, 1332px);
|
||||
}
|
||||
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
|
||||
:-moz-any(@primaryToolbarButtons@) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
width: 18px;
|
||||
|
@ -1160,6 +1172,11 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
|||
-moz-image-region: rect(0px, 1600px, 64px, 1536px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #sidebar-button {
|
||||
-moz-image-region: rect(0px, 1728px, 64px, 1664px);
|
||||
}
|
||||
|
||||
/* Footer and wide panel control icons */
|
||||
#edit-controls@inAnyPanel@ > toolbarbutton,
|
||||
#zoom-controls@inAnyPanel@ > toolbarbutton,
|
||||
|
@ -3979,7 +3996,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
|
|||
position: relative;
|
||||
}
|
||||
.toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
margin: 7px 2px;
|
||||
margin: 4px 2px;
|
||||
}
|
||||
|
||||
.toolbarbutton-badge[badge]:not([badge=""]) {
|
||||
|
|
Двоичные данные
browser/themes/osx/menuPanel.png
До Ширина: | Высота: | Размер: 26 KiB После Ширина: | Высота: | Размер: 26 KiB |
Двоичные данные
browser/themes/osx/menuPanel@2x.png
До Ширина: | Высота: | Размер: 60 KiB После Ширина: | Высота: | Размер: 59 KiB |
|
@ -1,5 +1,5 @@
|
|||
%filter substitution
|
||||
|
||||
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #switch-to-metro-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button
|
||||
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #switch-to-metro-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button
|
||||
%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem=true])
|
||||
%define nestedButtons #zoom-out-button, #zoom-in-button, #cut-button, #copy-button, #paste-button
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
#main-window[customize-entered] .customization-target:not(#PanelUI-contents)::before,
|
||||
#main-window[customize-entered] .customization-target:not(:-moz-any(#PanelUI-contents, #TabsToolbar, #toolbar-menubar))::before,
|
||||
#PanelUI-contents > .panel-customization-placeholder {
|
||||
-moz-outline-radius: 2.5px;
|
||||
outline: 1px dashed transparent;
|
||||
}
|
||||
|
||||
#main-window[customize-entered] .customization-target:not(#PanelUI-contents)::before {
|
||||
#main-window[customize-entered] .customization-target:not(:-moz-any(#PanelUI-contents, #TabsToolbar, #toolbar-menubar))::before {
|
||||
/* Prevent jumping of tabs when switching a window between inactive and active (bug 853415). */
|
||||
-moz-box-ordinal-group: 0;
|
||||
content: "";
|
||||
|
@ -45,16 +45,16 @@
|
|||
}
|
||||
|
||||
/* The parents of the outline pseudo-elements need to be positioned so that the outline is positioned relative to it. */
|
||||
#main-window[customize-entered] .customization-target:not(#PanelUI-contents):hover,
|
||||
#main-window[customize-entered] .customization-target[customizing-dragovertarget]:not(#PanelUI-contents),
|
||||
#main-window[customize-entered] .customization-target:not(:-moz-any(#PanelUI-contents, #TabsToolbar, #toolbar-menubar)):hover,
|
||||
#main-window[customize-entered] .customization-target[customizing-dragovertarget]:not(:-moz-any(#PanelUI-contents, #TabsToolbar, #toolbar-menubar)),
|
||||
#main-window[customize-entered] #nav-bar-customization-target.customization-target {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Most target outlines are shown on hover and drag over but the panel menu uses
|
||||
placeholders instead. */
|
||||
#main-window[customize-entered] .customization-target:not(#PanelUI-contents):hover::before,
|
||||
#main-window[customize-entered] .customization-target[customizing-dragovertarget]:not(#PanelUI-contents)::before,
|
||||
#main-window[customize-entered] .customization-target:not(:-moz-any(#PanelUI-contents, #TabsToolbar, #toolbar-menubar)):hover::before,
|
||||
#main-window[customize-entered] .customization-target[customizing-dragovertarget]:not(:-moz-any(#PanelUI-contents, #TabsToolbar, #toolbar-menubar))::before,
|
||||
/* nav-bar and panel outlines are always shown */
|
||||
#nav-bar[showoutline=true] > #nav-bar-customization-target.customization-target::before {
|
||||
outline-color: rgb(102,102,102);
|
||||
|
|
|
@ -295,6 +295,7 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
|
|||
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
.customization-palette .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
.panelUI-grid #bookmarks-toolbar-placeholder > .toolbarbutton-icon,
|
||||
|
@ -317,6 +318,16 @@ toolbaritem[cui-areatype="menu-panel"][sdkstylewidget="true"]:not(.panel-wide-it
|
|||
margin: 4px calc(@menuPanelButtonWidth@ / 2 - 23px);
|
||||
}
|
||||
|
||||
/* above we treat the container as the icon for the margins, that is so the
|
||||
/* badge itself is positioned correctly. Here we make sure that the icon itself
|
||||
/* has the minum size we want, but no padding/margin. */
|
||||
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon {
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
|
|
@ -381,6 +381,23 @@ a {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Open DOMNode in inspector button */
|
||||
.open-inspector {
|
||||
background: url("chrome://browser/skin/devtools/vview-open-inspector.png") no-repeat 0 0;
|
||||
padding-left: 16px;
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.elementNode:hover .open-inspector,
|
||||
.open-inspector:hover {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
|
||||
.open-inspector:active {
|
||||
background-position: -16px 0;
|
||||
}
|
||||
|
||||
/* Replace these values with CSS variables as available */
|
||||
.theme-dark .jsterm-input-container {
|
||||
background-color: #252c33; /* tabToolbarBackgroundColor */
|
||||
|
|
|
@ -126,6 +126,15 @@ toolbarpaletteitem[place="palette"] > #email-link-button {
|
|||
-moz-image-region: rect(0, 800px, 32px, 768px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #sidebar-button {
|
||||
-moz-image-region: rect(0, 864px, 32px, 832px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
|
||||
-moz-image-region: rect(32px, 864px, 64px, 832px);
|
||||
}
|
||||
|
||||
/* Wide panel control icons */
|
||||
|
||||
#edit-controls@inAnyPanel@ > toolbarbutton,
|
||||
|
|
|
@ -64,10 +64,6 @@
|
|||
-moz-image-region: rect(0px, 306px, 18px, 288px);
|
||||
}
|
||||
|
||||
#email-link-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 666px, 18px, 648px);
|
||||
}
|
||||
|
||||
#characterencoding-button[cui-areatype="toolbar"]{
|
||||
-moz-image-region: rect(0, 324px, 18px, 306px);
|
||||
}
|
||||
|
@ -143,3 +139,11 @@
|
|||
#tabview-button {
|
||||
-moz-image-region: rect(0, 648px, 18px, 630px);
|
||||
}
|
||||
|
||||
#email-link-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 666px, 18px, 648px);
|
||||
}
|
||||
|
||||
#sidebar-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 684px, 18px, 666px);
|
||||
}
|
||||
|
|
Двоичные данные
browser/themes/windows/Toolbar-aero.png
До Ширина: | Высота: | Размер: 13 KiB После Ширина: | Высота: | Размер: 13 KiB |
Двоичные данные
browser/themes/windows/Toolbar-inverted.png
До Ширина: | Высота: | Размер: 8.8 KiB После Ширина: | Высота: | Размер: 8.9 KiB |
Двоичные данные
browser/themes/windows/Toolbar-lunaSilver.png
До Ширина: | Высота: | Размер: 14 KiB После Ширина: | Высота: | Размер: 14 KiB |
Двоичные данные
browser/themes/windows/Toolbar.png
До Ширина: | Высота: | Размер: 9.2 KiB После Ширина: | Высота: | Размер: 9.7 KiB |
|
@ -318,6 +318,36 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Win8 and beyond. */
|
||||
@media not all and (-moz-os-version: windows-vista) {
|
||||
@media not all and (-moz-os-version: windows-win7) {
|
||||
#urlbar:not(:-moz-lwtheme),
|
||||
.searchbar-textbox:not(:-moz-lwtheme) {
|
||||
background-color: hsla(0,0%,100%,.9);
|
||||
border: 1px solid transparent;
|
||||
border-color: hsla(210,54%,20%,.25) hsla(210,54%,20%,.27) hsla(210,54%,20%,.3);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,0%,.01) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.1);
|
||||
transition-property: border-color, background-color;
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
|
||||
#urlbar:not(:-moz-lwtheme)[focused],
|
||||
.searchbar-textbox:not(:-moz-lwtheme)[focused] {
|
||||
background-color: hsla(0,0%,100%,1);
|
||||
border-color: #4595e5;
|
||||
}
|
||||
|
||||
/* Introducing an additional hover state for the Bookmark button */
|
||||
#nav-bar .toolbarbutton-1[buttonover] > .toolbarbutton-menubutton-button:hover > .toolbarbutton-icon {
|
||||
background-color: hsla(210,4%,10%,.08);
|
||||
-moz-border-end: 1px solid;
|
||||
-moz-padding-end: 5px;
|
||||
border-color: hsla(210,4%,10%,.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ::::: fullscreen window controls ::::: */
|
||||
|
||||
#window-controls {
|
||||
|
|
|
@ -538,19 +538,38 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker:-moz-lwtheme-bri
|
|||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
|
||||
padding: 2px 6px;
|
||||
background: hsla(210,32%,93%,0) padding-box;
|
||||
border-radius: 2px;
|
||||
border: 1px solid;
|
||||
border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0);
|
||||
box-shadow: 0 1px hsla(0,0%,100%,0) inset,
|
||||
0 1px hsla(210,54%,20%,0),
|
||||
0 0 2px hsla(210,54%,20%,0);
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
border-color: transparent;
|
||||
transition-property: background-color, border-color;
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
background-color: hsla(210,32%,93%,0);
|
||||
background-origin: padding-box;
|
||||
border-radius: 2px;
|
||||
border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0);
|
||||
box-shadow: 0 1px hsla(0,0%,100%,0) inset,
|
||||
0 1px hsla(210,54%,20%,0),
|
||||
0 0 2px hsla(210,54%,20%,0);
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-badge-container,
|
||||
#nav-bar .toolbarbutton-1:not(:-moz-any(@primaryToolbarButtons@)) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
|
@ -599,26 +618,17 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
content: "";
|
||||
display: -moz-box;
|
||||
width: 1px;
|
||||
height: 18px;
|
||||
height: 16px;
|
||||
-moz-margin-end: -1px;
|
||||
background-image: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px);
|
||||
background-image: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 16px);
|
||||
background-clip: padding-box;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 1px 18px;
|
||||
box-shadow: 0 0 0 1px hsla(0,0%,100%,.2);
|
||||
background-size: 1px 16px;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl),
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
|
||||
border-color: hsla(210,4%,10%,.1);
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
|
@ -626,48 +636,114 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
|
||||
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled=true],:not([open]):not([disabled=true]):not(:active)) > .toolbarbutton-icon {
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.2) hsla(210,54%,20%,.25);
|
||||
box-shadow: 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px hsla(210,54%,20%,.03),
|
||||
0 0 2px hsla(210,54%,20%,.1);
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
|
||||
background-color: hsla(210,4%,10%,.08);
|
||||
border-color: hsla(210,4%,10%,.1);
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled=true]):hover > .toolbarbutton-icon {
|
||||
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
|
||||
background-color: hsla(210,48%,96%,.75);
|
||||
box-shadow: 0 0 1px hsla(210,54%,20%,.03),
|
||||
0 0 2px hsla(210,54%,20%,.1);
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
#nav-bar .toolbarbutton-1:not(:hover):not(:active):not([open]) > .toolbarbutton-menubutton-dropmarker::before,
|
||||
#nav-bar .toolbaritem-combined-buttons > .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled]) + .toolbarbutton-1:-moz-any(:not(:hover):not([open]),[disabled])::before {
|
||||
content: "";
|
||||
display: -moz-box;
|
||||
width: 1px;
|
||||
height: 18px;
|
||||
-moz-margin-end: -1px;
|
||||
background-image: linear-gradient(hsla(210,54%,20%,.2) 0, hsla(210,54%,20%,.2) 18px);
|
||||
background-clip: padding-box;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 1px 18px;
|
||||
box-shadow: 0 0 0 1px hsla(0,0%,100%,.2);
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(ltr),
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon:-moz-locale-dir(rtl),
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any(:hover,[open]) > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):hover > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):not([checked]):not([open]):not(:active):hover > .toolbarbutton-badge-container,
|
||||
@conditionalForwardWithUrlbar@ > .toolbarbutton-1:-moz-any([disabled],:not([open]):not([disabled]):not(:active)) > .toolbarbutton-icon {
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
background-color: transparent;
|
||||
border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.2) hsla(210,54%,20%,.25);
|
||||
box-shadow: 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px hsla(210,54%,20%,.03),
|
||||
0 0 2px hsla(210,54%,20%,.1);
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):not([open]):not(:active):hover > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([buttonover]):not([open]):not(:active):hover > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
|
||||
@conditionalForwardWithUrlbar@ > #forward-button:not([open]):not(:active):not([disabled]):hover > .toolbarbutton-icon {
|
||||
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
|
||||
background-color: hsla(210,48%,96%,.75);
|
||||
box-shadow: 0 0 1px hsla(210,54%,20%,.03),
|
||||
0 0 2px hsla(210,54%,20%,.1);
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover:active > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled=true]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
background-color: hsla(210,54%,20%,.15);
|
||||
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
/* allows windows-keyhole-forward-clip-path to be used for non-hover as well as hover: */
|
||||
0 1px 0 hsla(210,54%,20%,0),
|
||||
0 0 2px hsla(210,54%,20%,0);
|
||||
text-shadow: none;
|
||||
transition: none;
|
||||
background-color: hsla(210,4%,10%,.12);
|
||||
border-top-color: hsla(210,4%,10%,.2);
|
||||
box-shadow: 0 1px 0 0 hsla(210,4%,10%,.1) inset;
|
||||
transition-duration: 10ms;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled=true]) > .dropmarker-icon {
|
||||
-moz-border-start-color: hsla(210,54%,20%,.35);
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
#nav-bar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-text,
|
||||
#nav-bar .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-badge-container {
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
background-color: hsla(210,54%,20%,.15);
|
||||
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
/* allows windows-keyhole-forward-clip-path to be used for non-hover as well as hover: */
|
||||
0 1px 0 hsla(210,54%,20%,0),
|
||||
0 0 2px hsla(210,54%,20%,0);
|
||||
text-shadow: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
|
||||
background-color: rgba(90%,90%,90%,.4);
|
||||
transition: background-color .4s;
|
||||
#nav-bar .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
|
||||
-moz-border-start-color: hsla(210,54%,20%,.35);
|
||||
}
|
||||
|
||||
#nav-bar .toolbarbutton-1[checked]:not(:active):hover > .toolbarbutton-icon {
|
||||
background-color: rgba(90%,90%,90%,.4);
|
||||
transition: background-color .4s;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#TabsToolbar .toolbarbutton-1,
|
||||
#TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button,
|
||||
|
@ -702,15 +778,27 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
}
|
||||
|
||||
#forward-button > .toolbarbutton-icon {
|
||||
background-clip: padding-box !important;
|
||||
/*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
|
||||
clip-path: url(chrome://browser/content/browser.xul#windows-keyhole-forward-clip-path) !important;
|
||||
margin-left: -6px !important;
|
||||
margin-left: -7px !important;
|
||||
border-left-style: none !important;
|
||||
border-radius: 0 !important;
|
||||
padding-left: 7px !important;
|
||||
padding-right: 3px !important;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
#forward-button > .toolbarbutton-icon {
|
||||
margin-left: -6px !important;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
|
||||
transition: opacity @forwardTransitionLength@ ease-out;
|
||||
}
|
||||
|
@ -743,40 +831,65 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
|
||||
#back-button > .toolbarbutton-icon {
|
||||
border-radius: 10000px !important;
|
||||
background-clip: padding-box !important;
|
||||
background-color: hsla(210,25%,98%,.08) !important;
|
||||
padding: 5px !important;
|
||||
border: none !important;
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)) !important;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.25),
|
||||
0 1px 0 hsla(210,54%,20%,.35) !important;
|
||||
transition-property: background-color, box-shadow !important;
|
||||
border-color: hsla(210,4%,10%,.25) !important;
|
||||
transition-property: background-color, border-color !important;
|
||||
transition-duration: 250ms !important;
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
|
||||
background-color: hsla(210,48%,96%,.75) !important;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.3),
|
||||
0 1px 0 hsla(210,54%,20%,.4),
|
||||
0 0 4px hsla(210,54%,20%,.2) !important;
|
||||
background-color: hsla(210,4%,10%,.08) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
|
||||
#back-button[open="true"] > .toolbarbutton-icon {
|
||||
background-color: hsla(210,54%,20%,.15) !important;
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.4),
|
||||
0 1px 0 hsla(210,54%,20%,.2) !important;
|
||||
transition: none;
|
||||
background-color: hsla(210,4%,10%,.12) !important;
|
||||
box-shadow: 0 1px 0 0 hsla(210,80%,20%,.1) inset !important;
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
|
||||
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
|
||||
0 1px 0 hsla(210,54%,20%,.65) !important;
|
||||
transition: none;
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
#back-button > .toolbarbutton-icon {
|
||||
border: none !important;
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1)) !important;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.25),
|
||||
0 1px 0 hsla(210,54%,20%,.35) !important;
|
||||
transition-property: background-color, box-shadow !important;
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):not([open="true"]):not(:active):hover > .toolbarbutton-icon {
|
||||
background-color: hsla(210,48%,96%,.75) !important;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.3),
|
||||
0 1px 0 hsla(210,54%,20%,.4),
|
||||
0 0 4px hsla(210,54%,20%,.2) !important;
|
||||
}
|
||||
|
||||
#back-button:not([disabled="true"]):hover:active > .toolbarbutton-icon,
|
||||
#back-button[open="true"] > .toolbarbutton-icon {
|
||||
background-color: hsla(210,54%,20%,.15) !important;
|
||||
box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
|
||||
0 0 1px hsla(210,54%,20%,.2) inset,
|
||||
0 0 0 1px hsla(210,54%,20%,.4),
|
||||
0 1px 0 hsla(210,54%,20%,.2) !important;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
|
||||
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
|
||||
0 1px 0 hsla(210,54%,20%,.65) !important;
|
||||
transition: none;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
#forward-button:-moz-locale-dir(rtl) {
|
||||
|
@ -899,9 +1012,21 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
padding: 0;
|
||||
background-clip: padding-box;
|
||||
border: 1px solid ThreeDShadow;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
@media (-moz-os-version: windows-vista),
|
||||
(-moz-os-version: windows-win7) {
|
||||
%endif
|
||||
/* < Win8 */
|
||||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
border-radius: 2px;
|
||||
}
|
||||
%ifdef WINDOWS_AERO
|
||||
}
|
||||
%endif
|
||||
|
||||
#urlbar {
|
||||
-moz-padding-end: 2px;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,18 @@
|
|||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
/* subviewbutton entries for social sidebars have images that come from external
|
||||
/* sources, and are not guaranteed to be the size we want, so force the size on
|
||||
/* those icons. */
|
||||
toolbarbutton.social-provider-menuitem > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.subviewbutton:-moz-any([image],[targetURI],.cui-withicon, .restoreallitem, .bookmark-item)[checked="true"] > .toolbarbutton-icon {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
%ifdef WINDOWS_AERO
|
||||
/* Win8 and beyond. */
|
||||
@media not all and (-moz-os-version: windows-vista) {
|
||||
|
|
Двоичные данные
browser/themes/windows/menuPanel-aero.png
До Ширина: | Высота: | Размер: 28 KiB После Ширина: | Высота: | Размер: 28 KiB |
Двоичные данные
browser/themes/windows/menuPanel.png
До Ширина: | Высота: | Размер: 23 KiB После Ширина: | Высота: | Размер: 23 KiB |
|
@ -9,12 +9,13 @@ let Promise =
|
|||
|
||||
let bluetoothManager;
|
||||
|
||||
/* Get mozSettings value specified by @aKey.
|
||||
/**
|
||||
* Get mozSettings value specified by @aKey.
|
||||
*
|
||||
* Resolve if that mozSettings value is retrieved successfully, reject
|
||||
* otherwise.
|
||||
*
|
||||
* Forfill params:
|
||||
* Fulfill params:
|
||||
* The corresponding mozSettings value of the key.
|
||||
* Reject params: (none)
|
||||
*
|
||||
|
@ -39,11 +40,12 @@ function getSettings(aKey) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Set mozSettings values.
|
||||
/**
|
||||
* Set mozSettings values.
|
||||
*
|
||||
* Resolve if that mozSettings value is set successfully, reject otherwise.
|
||||
*
|
||||
* Forfill params: (none)
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aSettings
|
||||
|
@ -67,12 +69,13 @@ function setSettings(aSettings) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Get mozSettings value of 'bluetooth.enabled'.
|
||||
/**
|
||||
* Get mozSettings value of 'bluetooth.enabled'.
|
||||
*
|
||||
* Resolve if that mozSettings value is retrieved successfully, reject
|
||||
* otherwise.
|
||||
*
|
||||
* Forfill params:
|
||||
* Fulfill params:
|
||||
* A boolean value.
|
||||
* Reject params: (none)
|
||||
*
|
||||
|
@ -82,11 +85,12 @@ function getBluetoothEnabled() {
|
|||
return getSettings("bluetooth.enabled");
|
||||
}
|
||||
|
||||
/* Set mozSettings value of 'bluetooth.enabled'.
|
||||
/**
|
||||
* Set mozSettings value of 'bluetooth.enabled'.
|
||||
*
|
||||
* Resolve if that mozSettings value is set successfully, reject otherwise.
|
||||
*
|
||||
* Forfill params: (none)
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aEnabled
|
||||
|
@ -100,10 +104,11 @@ function setBluetoothEnabled(aEnabled) {
|
|||
return setSettings(obj);
|
||||
}
|
||||
|
||||
/* Push required permissions and test if |navigator.mozBluetooth| exists.
|
||||
/**
|
||||
* Push required permissions and test if |navigator.mozBluetooth| exists.
|
||||
* Resolve if it does, reject otherwise.
|
||||
*
|
||||
* Forfill params:
|
||||
* Fulfill params:
|
||||
* bluetoothManager -- an reference to navigator.mozBluetooth.
|
||||
* Reject params: (none)
|
||||
*
|
||||
|
@ -151,11 +156,12 @@ function ensureBluetoothManager(aPermissions) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Wait for one named BluetoothManager event.
|
||||
/**
|
||||
* Wait for one named BluetoothManager event.
|
||||
*
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
*
|
||||
* Forfill params: the DOMEvent passed.
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
|
@ -172,12 +178,13 @@ function waitForManagerEvent(aEventName) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Convenient function for setBluetoothEnabled and waitForManagerEvent
|
||||
/**
|
||||
* Convenient function for setBluetoothEnabled and waitForManagerEvent
|
||||
* combined.
|
||||
*
|
||||
* Resolve if that named event occurs. Reject if we can't set settings.
|
||||
*
|
||||
* Forfill params: the DOMEvent passed.
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @return A deferred promise.
|
||||
|
@ -198,11 +205,12 @@ function setBluetoothEnabledAndWait(aEnabled) {
|
|||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
/* Get default adapter.
|
||||
/**
|
||||
* Get default adapter.
|
||||
*
|
||||
* Resolve if that default adapter is got, reject otherwise.
|
||||
*
|
||||
* Forfill params: a BluetoothAdapter instance.
|
||||
* Fulfill params: a BluetoothAdapter instance.
|
||||
* Reject params: a DOMError, or null if if there is no adapter ready yet.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
|
@ -237,7 +245,8 @@ function getDefaultAdapter() {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Flush permission settings and call |finish()|.
|
||||
/**
|
||||
* Flush permission settings and call |finish()|.
|
||||
*/
|
||||
function cleanUp() {
|
||||
SpecialPowers.flushPermissions(function() {
|
||||
|
|
|
@ -0,0 +1,399 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
|
||||
|
||||
const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled";
|
||||
const SETTINGS_KEY_DATA_ROAMING_ENABLED = "ril.data.roaming_enabled";
|
||||
const SETTINGS_KEY_DATA_APN_SETTINGS = "ril.data.apnSettings";
|
||||
|
||||
let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
|
||||
|
||||
let _pendingEmulatorCmdCount = 0;
|
||||
|
||||
/**
|
||||
* Send emulator command with safe guard.
|
||||
*
|
||||
* We should only call |finish()| after all emulator command transactions
|
||||
* end, so here comes with the pending counter. Resolve when the emulator
|
||||
* gives positive response, and reject otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* result -- an array of emulator response lines.
|
||||
* Reject params:
|
||||
* result -- an array of emulator response lines.
|
||||
*
|
||||
* @param aCommand
|
||||
* A string command to be passed to emulator through its telnet console.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function runEmulatorCmdSafe(aCommand) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
++_pendingEmulatorCmdCount;
|
||||
runEmulatorCmd(aCommand, function(aResult) {
|
||||
--_pendingEmulatorCmdCount;
|
||||
|
||||
ok(true, "Emulator response: " + JSON.stringify(aResult));
|
||||
if (Array.isArray(aResult) && aResult[0] === "OK") {
|
||||
deferred.resolve(aResult);
|
||||
} else {
|
||||
deferred.reject(aResult);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mozSettings value specified by @aKey.
|
||||
*
|
||||
* Resolve if that mozSettings value is retrieved successfully, reject
|
||||
* otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* The corresponding mozSettings value of the key.
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aKey
|
||||
* A string.
|
||||
* @param aAllowError [optional]
|
||||
* A boolean value. If set to true, an error response won't be treated
|
||||
* as test failure. Default: false.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function getSettings(aKey, aAllowError) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = navigator.mozSettings.createLock().get(aKey);
|
||||
request.addEventListener("success", function(aEvent) {
|
||||
ok(true, "getSettings(" + aKey + ") - success");
|
||||
deferred.resolve(aEvent.target.result[aKey]);
|
||||
});
|
||||
request.addEventListener("error", function() {
|
||||
ok(aAllowError, "getSettings(" + aKey + ") - error");
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mozSettings values.
|
||||
*
|
||||
* Resolve if that mozSettings value is set successfully, reject otherwise.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aSettings
|
||||
* An object of format |{key1: value1, key2: value2, ...}|.
|
||||
* @param aAllowError [optional]
|
||||
* A boolean value. If set to true, an error response won't be treated
|
||||
* as test failure. Default: false.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setSettings(aSettings, aAllowError) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let request = navigator.mozSettings.createLock().set(aSettings);
|
||||
request.addEventListener("success", function() {
|
||||
ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
deferred.resolve();
|
||||
});
|
||||
request.addEventListener("error", function() {
|
||||
ok(aAllowError, "setSettings(" + JSON.stringify(aSettings) + ")");
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mozSettings value with only one key.
|
||||
*
|
||||
* Resolve if that mozSettings value is set successfully, reject otherwise.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aKey
|
||||
* A string key.
|
||||
* @param aValue
|
||||
* An object value.
|
||||
* @param aAllowError [optional]
|
||||
* A boolean value. If set to true, an error response won't be treated
|
||||
* as test failure. Default: false.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setSettings1(aKey, aValue, aAllowError) {
|
||||
let settings = {};
|
||||
settings[aKey] = aValue;
|
||||
return setSettings(settings, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient MozSettings getter for SETTINGS_KEY_DATA_ENABLED.
|
||||
*/
|
||||
function getDataEnabled(aAllowError) {
|
||||
return getSettings(SETTINGS_KEY_DATA_ENABLED, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient MozSettings setter for SETTINGS_KEY_DATA_ENABLED.
|
||||
*/
|
||||
function setDataEnabled(aEnabled, aAllowError) {
|
||||
return setSettings1(SETTINGS_KEY_DATA_ENABLED, aEnabled, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient MozSettings getter for SETTINGS_KEY_DATA_ROAMING_ENABLED.
|
||||
*/
|
||||
function getDataRoamingEnabled(aAllowError) {
|
||||
return getSettings(SETTINGS_KEY_DATA_ROAMING_ENABLED, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient MozSettings setter for SETTINGS_KEY_DATA_ROAMING_ENABLED.
|
||||
*/
|
||||
function setDataRoamingEnabled(aEnabled, aAllowError) {
|
||||
return setSettings1(SETTINGS_KEY_DATA_ROAMING_ENABLED, aEnabled, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient MozSettings getter for SETTINGS_KEY_DATA_APN_SETTINGS.
|
||||
*/
|
||||
function getDataApnSettings(aAllowError) {
|
||||
return getSettings(SETTINGS_KEY_DATA_APN_SETTINGS, aAllowError);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient MozSettings setter for SETTINGS_KEY_DATA_APN_SETTINGS.
|
||||
*/
|
||||
function setDataApnSettings(aApnSettings, aAllowError) {
|
||||
return setSettings1(SETTINGS_KEY_DATA_APN_SETTINGS, aApnSettings, aAllowError);
|
||||
}
|
||||
|
||||
let mobileConnection;
|
||||
|
||||
/**
|
||||
* Push required permissions and test if
|
||||
* |navigator.mozMobileConnections[<aServiceId>]| exists. Resolve if it does,
|
||||
* reject otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
* mobileConnection -- an reference to navigator.mozMobileMessage.
|
||||
*
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aAdditonalPermissions [optional]
|
||||
* An array of permission strings other than "mobileconnection" to be
|
||||
* pushed. Default: empty string.
|
||||
* @param aServiceId [optional]
|
||||
* A numeric DSDS service id. Default: 0.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function ensureMobileConnection(aAdditionalPermissions, aServiceId) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
aAdditionalPermissions = aAdditionalPermissions || [];
|
||||
aServiceId = aServiceId || 0;
|
||||
|
||||
if (aAdditionalPermissions.indexOf("mobileconnection") < 0) {
|
||||
aAdditionalPermissions.push("mobileconnection");
|
||||
}
|
||||
let permissions = [];
|
||||
for (let perm of aAdditionalPermissions) {
|
||||
permissions.push({ "type": perm, "allow": 1, "context": document });
|
||||
}
|
||||
|
||||
SpecialPowers.pushPermissions(permissions, function() {
|
||||
ok(true, "permissions pushed: " + JSON.stringify(permissions));
|
||||
|
||||
// Permission changes can't change existing Navigator.prototype
|
||||
// objects, so grab our objects from a new Navigator.
|
||||
let ifr = document.createElement("iframe");
|
||||
ifr.addEventListener("load", function load() {
|
||||
ifr.removeEventListener("load", load);
|
||||
|
||||
mobileConnection =
|
||||
ifr.contentWindow.navigator.mozMobileConnections[aServiceId];
|
||||
|
||||
if (mobileConnection) {
|
||||
log("navigator.mozMobileConnections[" + aServiceId + "] is instance of " +
|
||||
mobileConnection.constructor);
|
||||
} else {
|
||||
log("navigator.mozMobileConnections[" + aServiceId + "] is undefined");
|
||||
}
|
||||
|
||||
if (mobileConnection instanceof MozMobileConnection) {
|
||||
deferred.resolve(mobileConnection);
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
});
|
||||
|
||||
document.body.appendChild(ifr);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for one named MobileConnection event.
|
||||
*
|
||||
* Resolve if that named event occurs. Never reject.
|
||||
*
|
||||
* Fulfill params: the DOMEvent passed.
|
||||
*
|
||||
* @param aEventName
|
||||
* A string event name.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function waitForManagerEvent(aEventName) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
mobileConnection.addEventListener(aEventName, function onevent(aEvent) {
|
||||
mobileConnection.removeEventListener(aEventName, onevent);
|
||||
|
||||
ok(true, "MobileConnection event '" + aEventName + "' got.");
|
||||
deferred.resolve(aEvent);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data connection enabling state and wait for "datachange" event.
|
||||
*
|
||||
* Resolve if data connection state changed to the expected one. Never reject.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
*
|
||||
* @param aEnabled
|
||||
* A boolean state.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setDataEnabledAndWait(aEnabled) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let promises = [];
|
||||
promises.push(waitForManagerEvent("datachange"));
|
||||
promises.push(setDataEnabled(aEnabled));
|
||||
Promise.all(promises).then(function keepWaiting() {
|
||||
// To ignore some transient states, we only resolve that deferred promise
|
||||
// when the |connected| state equals to the expected one and never rejects.
|
||||
let connected = mobileConnection.data.connected;
|
||||
if (connected == aEnabled) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
return waitForManagerEvent("datachange").then(keepWaiting);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set voice/data roaming emulation and wait for state change.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
*
|
||||
* @param aRoaming
|
||||
* A boolean state.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function setEmulatorRoamingAndWait(aRoaming) {
|
||||
function doSetAndWait(aWhich, aRoaming) {
|
||||
let promises = [];
|
||||
promises.push(waitForManagerEvent(aWhich + "change"));
|
||||
|
||||
let cmd = "gsm " + aWhich + " " + (aRoaming ? "roaming" : "home");
|
||||
promises.push(runEmulatorCmdSafe(cmd));
|
||||
return Promise.all(promises)
|
||||
.then(() => is(mobileConnection[aWhich].roaming, aRoaming,
|
||||
aWhich + ".roaming"));
|
||||
}
|
||||
|
||||
// Set voice registration state first and then data registration state.
|
||||
return doSetAndWait("voice", aRoaming)
|
||||
.then(() => doSetAndWait("data", aRoaming));
|
||||
}
|
||||
|
||||
let _networkManager;
|
||||
|
||||
/**
|
||||
* Get internal NetworkManager service.
|
||||
*/
|
||||
function getNetworkManager() {
|
||||
if (!_networkManager) {
|
||||
_networkManager = Cc["@mozilla.org/network/manager;1"]
|
||||
.getService(Ci.nsINetworkManager);
|
||||
ok(_networkManager, "NetworkManager");
|
||||
}
|
||||
|
||||
return _networkManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush permission settings and call |finish()|.
|
||||
*/
|
||||
function cleanUp() {
|
||||
waitFor(function() {
|
||||
SpecialPowers.flushPermissions(function() {
|
||||
// Use ok here so that we have at least one test run.
|
||||
ok(true, "permissions flushed");
|
||||
|
||||
finish();
|
||||
});
|
||||
}, function() {
|
||||
return _pendingEmulatorCmdCount === 0;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic test routine helper for mobile connection tests.
|
||||
*
|
||||
* This helper does nothing but clean-ups.
|
||||
*
|
||||
* @param aTestCaseMain
|
||||
* A function that takes no parameter.
|
||||
*/
|
||||
function startTestBase(aTestCaseMain) {
|
||||
Promise.resolve()
|
||||
.then(aTestCaseMain)
|
||||
.then(cleanUp, function() {
|
||||
ok(false, 'promise rejects during test.');
|
||||
cleanUp();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Common test routine helper for mobile connection tests.
|
||||
*
|
||||
* This function ensures global |mobileConnection| variable is available during
|
||||
* the process and performs clean-ups as well.
|
||||
*
|
||||
* @param aTestCaseMain
|
||||
* A function that takes one parameter -- mobileConnection.
|
||||
* @param aAdditonalPermissions [optional]
|
||||
* An array of permission strings other than "mobileconnection" to be
|
||||
* pushed. Default: empty string.
|
||||
* @param aServiceId [optional]
|
||||
* A numeric DSDS service id. Default: 0.
|
||||
*/
|
||||
function startTestCommon(aTestCaseMain, aAdditionalPermissions, aServiceId) {
|
||||
startTestBase(function() {
|
||||
return ensureMobileConnection(aAdditionalPermissions, aServiceId)
|
||||
.then(aTestCaseMain);
|
||||
});
|
||||
}
|
|
@ -23,3 +23,5 @@ disabled = Bug 808783
|
|||
[test_mobile_last_known_network.js]
|
||||
[test_mobile_icc_change.js]
|
||||
[test_mobile_connections_array_uninitialized.js]
|
||||
[test_mobile_data_ipv6.js]
|
||||
disabled = Bug 978071
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = "head.js";
|
||||
|
||||
/**
|
||||
* Test resulting IP address format with given APN settings.
|
||||
*
|
||||
* This test utility function performs following steps:
|
||||
*
|
||||
* 1) set "ril.data.apnSettings" to a given settings object,
|
||||
* 2) enable data connection and wait for a "datachange" event,
|
||||
* 3) check the IP address type of the active network interface,
|
||||
* 4) disable data connection.
|
||||
*
|
||||
* Fulfill params: (none)
|
||||
* Reject params: (none)
|
||||
*
|
||||
* @param aApnSettings
|
||||
* An APN settings value.
|
||||
* @param aIsIPv6
|
||||
* A boolean value indicating whether we're expecting an IPv6 address.
|
||||
*
|
||||
* @return A deferred promise.
|
||||
*/
|
||||
function doTest(aApnSettings, aIsIPv6) {
|
||||
return setDataApnSettings([])
|
||||
.then(() => setDataApnSettings(aApnSettings))
|
||||
.then(() => setDataEnabledAndWait(true))
|
||||
.then(function() {
|
||||
let nm = getNetworkManager();
|
||||
let active = nm.active;
|
||||
ok(active, "Active network interface");
|
||||
|
||||
log(" Interface: " + active.name);
|
||||
log(" Address: " + active.ip);
|
||||
if (aIsIPv6) {
|
||||
ok(active.ip.indexOf(":") > 0, "IPv6 address");
|
||||
} else {
|
||||
ok(active.ip.indexOf(":") < 0, "IPv4 address");
|
||||
}
|
||||
})
|
||||
.then(() => setDataEnabledAndWait(false));
|
||||
}
|
||||
|
||||
function doTestHome(aApnSettings, aProtocol) {
|
||||
log("Testing \"" + aProtocol + "\"@HOME... ");
|
||||
|
||||
// aApnSettings is a double-array of per PDP context settings. The first
|
||||
// index is a DSDS service ID, and the second one is the index of pre-defined
|
||||
// PDP context settings of a specified radio interface. We use 0 for both as
|
||||
// default here.
|
||||
aApnSettings[0][0].protocol = aProtocol;
|
||||
delete aApnSettings[0][0].roaming_protocol;
|
||||
|
||||
return doTest(aApnSettings, aProtocol === "IPV6");
|
||||
}
|
||||
|
||||
function doTestRoaming(aApnSettings, aRoaminProtocol) {
|
||||
log("Testing \"" + aRoaminProtocol + "\"@ROMAING... ");
|
||||
|
||||
// aApnSettings is a double-array of per PDP context settings. The first
|
||||
// index is a DSDS service ID, and the second one is the index of pre-defined
|
||||
// PDP context settings of a specified radio interface. We use 0 for both as
|
||||
// default here.
|
||||
delete aApnSettings[0][0].protocol;
|
||||
aApnSettings[0][0].roaming_protocol = aRoaminProtocol;
|
||||
|
||||
return doTest(aApnSettings, aRoaminProtocol === "IPV6");
|
||||
}
|
||||
|
||||
startTestCommon(function() {
|
||||
let origApnSettings;
|
||||
|
||||
return setDataRoamingEnabled(true)
|
||||
.then(getDataApnSettings)
|
||||
.then(function(aResult) {
|
||||
// If already set, then save original APN settings.
|
||||
origApnSettings = JSON.parse(JSON.stringify(aResult));
|
||||
return aResult;
|
||||
}, function() {
|
||||
// Return our own default value.
|
||||
return [[{ "carrier": "T-Mobile US",
|
||||
"apn": "epc.tmobile.com",
|
||||
"mmsc": "http://mms.msg.eng.t-mobile.com/mms/wapenc",
|
||||
"types": ["default", "supl", "mms"] }]];
|
||||
})
|
||||
|
||||
.then(function(aApnSettings) {
|
||||
return Promise.resolve()
|
||||
|
||||
.then(() => doTestHome(aApnSettings, "NoSuchProtocol"))
|
||||
.then(() => doTestHome(aApnSettings, "IP"))
|
||||
.then(() => doTestHome(aApnSettings, "IPV6"))
|
||||
|
||||
.then(() => setEmulatorRoamingAndWait(true))
|
||||
|
||||
.then(() => doTestRoaming(aApnSettings, "NoSuchProtocol"))
|
||||
.then(() => doTestRoaming(aApnSettings, "IP"))
|
||||
.then(() => doTestRoaming(aApnSettings, "IPV6"))
|
||||
|
||||
.then(() => setEmulatorRoamingAndWait(false));
|
||||
})
|
||||
|
||||
.then(() => setDataRoamingEnabled(false))
|
||||
.then(function() {
|
||||
if (origApnSettings) {
|
||||
return setDataApnSettings(origApnSettings);
|
||||
}
|
||||
});
|
||||
}, ["settings-read", "settings-write"]);
|
|
@ -5,7 +5,8 @@ const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
|
|||
|
||||
let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
|
||||
|
||||
/* Push required permissions and test if |navigator.mozMobileMessage| exists.
|
||||
/**
|
||||
* Push required permissions and test if |navigator.mozMobileMessage| exists.
|
||||
* Resolve if it does, reject otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
|
@ -44,7 +45,8 @@ function ensureMobileMessage() {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Send a SMS message to a single receiver. Resolve if it succeeds, reject
|
||||
/**
|
||||
* Send a SMS message to a single receiver. Resolve if it succeeds, reject
|
||||
* otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
|
@ -72,7 +74,8 @@ function sendSmsWithSuccess(aReceiver, aText) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Send a MMS message with specified parameters. Resolve if it fails, reject
|
||||
/**
|
||||
* Send a MMS message with specified parameters. Resolve if it fails, reject
|
||||
* otherwise.
|
||||
*
|
||||
* Fulfill params:
|
||||
|
@ -100,7 +103,8 @@ function sendMmsWithFailure(aMmsParameters) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Retrieve messages from database.
|
||||
/**
|
||||
* Retrieve messages from database.
|
||||
*
|
||||
* Fulfill params:
|
||||
* messages -- an array of {Sms,Mms}Message instances.
|
||||
|
@ -136,7 +140,8 @@ function getMessages(aFilter, aReverse) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Retrieve all messages from database.
|
||||
/**
|
||||
* Retrieve all messages from database.
|
||||
*
|
||||
* Fulfill params:
|
||||
* messages -- an array of {Sms,Mms}Message instances.
|
||||
|
@ -150,7 +155,8 @@ function getAllMessages() {
|
|||
return getMessages(null, false);
|
||||
}
|
||||
|
||||
/* Retrieve all threads from database.
|
||||
/**
|
||||
* Retrieve all threads from database.
|
||||
*
|
||||
* Fulfill params:
|
||||
* threads -- an array of MozMobileMessageThread instances.
|
||||
|
@ -179,7 +185,8 @@ function getAllThreads() {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Retrieve a single specified thread from database.
|
||||
/**
|
||||
* Retrieve a single specified thread from database.
|
||||
*
|
||||
* Fulfill params:
|
||||
* thread -- a MozMobileMessageThread instance.
|
||||
|
@ -204,7 +211,8 @@ function getThreadById(aThreadId) {
|
|||
});
|
||||
}
|
||||
|
||||
/* Delete messages specified from database.
|
||||
/**
|
||||
* Delete messages specified from database.
|
||||
*
|
||||
* Fulfill params:
|
||||
* result -- an array of boolean values indicating whether delesion was
|
||||
|
@ -234,7 +242,8 @@ function deleteMessagesById(aMessageIds) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Delete messages specified from database.
|
||||
/**
|
||||
* Delete messages specified from database.
|
||||
*
|
||||
* Fulfill params:
|
||||
* result -- an array of boolean values indicating whether delesion was
|
||||
|
@ -252,7 +261,8 @@ function deleteMessages(aMessages) {
|
|||
return deleteMessagesById(ids);
|
||||
}
|
||||
|
||||
/* Delete all messages from database.
|
||||
/**
|
||||
* Delete all messages from database.
|
||||
*
|
||||
* Fulfill params:
|
||||
* ids -- an array of numeric values identifying those deleted
|
||||
|
@ -269,7 +279,8 @@ function deleteAllMessages() {
|
|||
|
||||
let pendingEmulatorCmdCount = 0;
|
||||
|
||||
/* Send emulator command with safe guard.
|
||||
/**
|
||||
* Send emulator command with safe guard.
|
||||
*
|
||||
* We should only call |finish()| after all emulator command transactions
|
||||
* end, so here comes with the pending counter. Resolve when the emulator
|
||||
|
@ -301,7 +312,8 @@ function runEmulatorCmdSafe(aCommand) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Send simple text SMS to emulator.
|
||||
/**
|
||||
* Send simple text SMS to emulator.
|
||||
*
|
||||
* Fulfill params:
|
||||
* result -- an array of emulator response lines.
|
||||
|
@ -316,7 +328,8 @@ function sendTextSmsToEmulator(aFrom, aText) {
|
|||
return runEmulatorCmdSafe(command);
|
||||
}
|
||||
|
||||
/* Send raw SMS TPDU to emulator.
|
||||
/**
|
||||
* Send raw SMS TPDU to emulator.
|
||||
*
|
||||
* Fulfill params:
|
||||
* result -- an array of emulator response lines.
|
||||
|
@ -331,7 +344,8 @@ function sendRawSmsToEmulator(aPdu) {
|
|||
return runEmulatorCmdSafe(command);
|
||||
}
|
||||
|
||||
/* Name space for MobileMessageDB.jsm. Only initialized after first call to
|
||||
/**
|
||||
* Name space for MobileMessageDB.jsm. Only initialized after first call to
|
||||
* newMobileMessageDB.
|
||||
*/
|
||||
let MMDB;
|
||||
|
@ -348,7 +362,8 @@ function newMobileMessageDB() {
|
|||
return mmdb;
|
||||
}
|
||||
|
||||
/* Initialize a MobileMessageDB. Resolve if initialized with success, reject
|
||||
/**
|
||||
* Initialize a MobileMessageDB. Resolve if initialized with success, reject
|
||||
* otherwise.
|
||||
*
|
||||
* Fulfill params: a MobileMessageDB instance.
|
||||
|
@ -378,7 +393,8 @@ function initMobileMessageDB(aMmdb, aDbName, aDbVersion) {
|
|||
return deferred.promise;
|
||||
}
|
||||
|
||||
/* Close a MobileMessageDB.
|
||||
/**
|
||||
* Close a MobileMessageDB.
|
||||
*
|
||||
* @return The passed MobileMessageDB instance.
|
||||
*/
|
||||
|
@ -387,7 +403,8 @@ function closeMobileMessageDB(aMmdb) {
|
|||
return aMmdb;
|
||||
}
|
||||
|
||||
/* Create a new array of id attribute of input messages.
|
||||
/**
|
||||
* Create a new array of id attribute of input messages.
|
||||
*
|
||||
* @param aMessages an array of {Sms,Mms}Message instances.
|
||||
*
|
||||
|
@ -404,7 +421,8 @@ function messagesToIds(aMessages) {
|
|||
// A reference to a nsIUUIDGenerator service.
|
||||
let uuidGenerator;
|
||||
|
||||
/* Generate a new UUID.
|
||||
/**
|
||||
* Generate a new UUID.
|
||||
*
|
||||
* @return A UUID string.
|
||||
*/
|
||||
|
@ -418,7 +436,8 @@ function newUUID() {
|
|||
return uuidGenerator.generateUUID().toString();
|
||||
}
|
||||
|
||||
/* Flush permission settings and call |finish()|.
|
||||
/**
|
||||
* Flush permission settings and call |finish()|.
|
||||
*/
|
||||
function cleanUp() {
|
||||
waitFor(function() {
|
||||
|
@ -433,6 +452,14 @@ function cleanUp() {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic test routine helper for mobile message tests.
|
||||
*
|
||||
* This helper does nothing but clean-ups.
|
||||
*
|
||||
* @param aTestCaseMain
|
||||
* A function that takes no parameter.
|
||||
*/
|
||||
function startTestBase(aTestCaseMain) {
|
||||
Promise.resolve()
|
||||
.then(aTestCaseMain)
|
||||
|
@ -442,6 +469,15 @@ function startTestBase(aTestCaseMain) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Common test routine helper for mobile message tests.
|
||||
*
|
||||
* This function ensures global |manager| variable is available during the
|
||||
* process and performs clean-ups as well.
|
||||
*
|
||||
* @param aTestCaseMain
|
||||
* A function that takes no parameter.
|
||||
*/
|
||||
function startTestCommon(aTestCaseMain) {
|
||||
startTestBase(function() {
|
||||
return ensureMobileMessage()
|
||||
|
|
|
@ -52,6 +52,10 @@ let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND =
|
|||
let RILQUIRKS_RADIO_OFF_WO_CARD =
|
||||
libcutils.property_get("ro.moz.ril.radio_off_wo_card", "false") == "true";
|
||||
|
||||
// Ril quirk to enable IPv6 protocol/roaming protocol in APN settings.
|
||||
let RILQUIRKS_HAVE_IPV6 =
|
||||
libcutils.property_get("ro.moz.ril.ipv6", "false") == "true";
|
||||
|
||||
const RADIOINTERFACELAYER_CID =
|
||||
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
|
||||
const RADIOINTERFACE_CID =
|
||||
|
@ -4525,12 +4529,25 @@ RILNetworkInterface.prototype = {
|
|||
}
|
||||
authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT);
|
||||
}
|
||||
let pdpType = RIL.GECKO_DATACALL_PDP_TYPE_IP;
|
||||
if (RILQUIRKS_HAVE_IPV6) {
|
||||
pdpType = !radioInterface.rilContext.data.roaming
|
||||
? this.apnSetting.protocol
|
||||
: this.apnSetting.roaming_protocol;
|
||||
if (RIL.RIL_DATACALL_PDP_TYPES.indexOf(pdpType) < 0) {
|
||||
if (DEBUG) {
|
||||
this.debug("Invalid pdpType '" + pdpType + "', using '" +
|
||||
RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT + "'");
|
||||
}
|
||||
pdpType = RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT;
|
||||
}
|
||||
}
|
||||
radioInterface.setupDataCall(radioTechnology,
|
||||
this.apnSetting.apn,
|
||||
this.apnSetting.user,
|
||||
this.apnSetting.password,
|
||||
authType,
|
||||
"IP");
|
||||
pdpType);
|
||||
this.connecting = true;
|
||||
},
|
||||
|
||||
|
|
|
@ -2361,6 +2361,15 @@ this.RIL_DATACALL_AUTH_TO_GECKO = [
|
|||
GECKO_DATACALL_AUTH_PAP_OR_CHAP // DATACALL_AUTH_PAP_OR_CHAP
|
||||
];
|
||||
|
||||
this.GECKO_DATACALL_PDP_TYPE_IP = "IP";
|
||||
this.GECKO_DATACALL_PDP_TYPE_IPV6 = "IPV6";
|
||||
this.GECKO_DATACALL_PDP_TYPE_DEFAULT = GECKO_DATACALL_PDP_TYPE_IP;
|
||||
this.RIL_DATACALL_PDP_TYPES = [
|
||||
GECKO_DATACALL_PDP_TYPE_IP,
|
||||
GECKO_DATACALL_PDP_TYPE_IPV6,
|
||||
// TODO: Bug 978711 - Support IPV4V6
|
||||
];
|
||||
|
||||
this.DATACALL_PROFILE_DEFAULT = 0;
|
||||
this.DATACALL_PROFILE_TETHERED = 1;
|
||||
this.DATACALL_PROFILE_OEM_BASE = 1000;
|
||||
|
|
|
@ -3962,8 +3962,9 @@ RilObject.prototype = {
|
|||
}
|
||||
currentDataCall.gw = updatedDataCall.gw;
|
||||
if (updatedDataCall.dns) {
|
||||
currentDataCall.dns[0] = updatedDataCall.dns[0];
|
||||
currentDataCall.dns[1] = updatedDataCall.dns[1];
|
||||
currentDataCall.dns = updatedDataCall.dns.slice();
|
||||
} else {
|
||||
currentDataCall.dns = [];
|
||||
}
|
||||
currentDataCall.rilMessageType = "datacallstatechange";
|
||||
this.sendChromeMessage(currentDataCall);
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.net.URL;
|
|||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
@ -678,10 +679,7 @@ public abstract class GeckoApp
|
|||
Intent intent = GeckoAppShell.getOpenURIIntent(sAppContext, message.optString("url"),
|
||||
message.optString("mime"), message.optString("action"), message.optString("title"));
|
||||
String[] handlers = GeckoAppShell.getHandlersForIntent(intent);
|
||||
ArrayList<String> appList = new ArrayList<String>(handlers.length);
|
||||
for (int i = 0; i < handlers.length; i++) {
|
||||
appList.add(handlers[i]);
|
||||
}
|
||||
List<String> appList = Arrays.asList(handlers);
|
||||
JSONObject handlersJSON = new JSONObject();
|
||||
handlersJSON.put("apps", new JSONArray(appList));
|
||||
EventDispatcher.sendResponse(message, handlersJSON);
|
||||
|
|
|
@ -9,7 +9,9 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.mozilla.apache.commons.codec.binary.Base64;
|
||||
import org.mozilla.apache.commons.codec.binary.StringUtils;
|
||||
|
@ -28,6 +30,7 @@ import org.mozilla.gecko.sync.Utils;
|
|||
public class JSONWebTokenUtils {
|
||||
public static final long DEFAULT_CERTIFICATE_DURATION_IN_MILLISECONDS = 60 * 60 * 1000;
|
||||
public static final long DEFAULT_ASSERTION_DURATION_IN_MILLISECONDS = 60 * 60 * 1000;
|
||||
public static final long DEFAULT_FUTURE_EXPIRES_AT_IN_MILLISECONDS = 9999999999999L;
|
||||
public static final String DEFAULT_CERTIFICATE_ISSUER = "127.0.0.1";
|
||||
public static final String DEFAULT_ASSERTION_ISSUER = "127.0.0.1";
|
||||
|
||||
|
@ -70,8 +73,12 @@ public class JSONWebTokenUtils {
|
|||
return payload;
|
||||
}
|
||||
|
||||
protected static String getPayloadString(String payloadString, String issuer,
|
||||
long issuedAt, String audience, long expiresAt) throws NonObjectJSONException,
|
||||
/**
|
||||
* Public for testing.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static String getPayloadString(String payloadString, String audience, String issuer,
|
||||
Long issuedAt, long expiresAt) throws NonObjectJSONException,
|
||||
IOException, ParseException {
|
||||
ExtendedJSONObject payload;
|
||||
if (payloadString != null) {
|
||||
|
@ -79,13 +86,16 @@ public class JSONWebTokenUtils {
|
|||
} else {
|
||||
payload = new ExtendedJSONObject();
|
||||
}
|
||||
payload.put("iss", issuer);
|
||||
payload.put("iat", issuedAt);
|
||||
if (audience != null) {
|
||||
payload.put("aud", audience);
|
||||
}
|
||||
payload.put("iss", issuer);
|
||||
if (issuedAt != null) {
|
||||
payload.put("iat", issuedAt);
|
||||
}
|
||||
payload.put("exp", expiresAt);
|
||||
return payload.toJSONString();
|
||||
// TreeMap so that keys are sorted. A small attempt to keep output stable over time.
|
||||
return JSONObject.toJSONString(new TreeMap<Object, Object>(payload.object));
|
||||
}
|
||||
|
||||
protected static String getCertificatePayloadString(VerifyingPublicKey publicKeyToSign, String email) throws NonObjectJSONException, IOException, ParseException {
|
||||
|
@ -100,33 +110,42 @@ public class JSONWebTokenUtils {
|
|||
public static String createCertificate(VerifyingPublicKey publicKeyToSign, String email,
|
||||
String issuer, long issuedAt, long expiresAt, SigningPrivateKey privateKey) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
|
||||
String certificatePayloadString = getCertificatePayloadString(publicKeyToSign, email);
|
||||
String payloadString = getPayloadString(certificatePayloadString, issuer, issuedAt, null, expiresAt);
|
||||
String payloadString = getPayloadString(certificatePayloadString, null, issuer, issuedAt, expiresAt);
|
||||
return JSONWebTokenUtils.encode(payloadString, privateKey);
|
||||
}
|
||||
|
||||
public static String createCertificate(VerifyingPublicKey publicKeyToSign, String email, SigningPrivateKey privateKey) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
|
||||
String issuer = DEFAULT_CERTIFICATE_ISSUER;
|
||||
long issuedAt = System.currentTimeMillis();
|
||||
long durationInMilliseconds = DEFAULT_CERTIFICATE_DURATION_IN_MILLISECONDS;
|
||||
return createCertificate(publicKeyToSign, email, issuer, issuedAt, issuedAt + durationInMilliseconds, privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Browser ID assertion.
|
||||
*
|
||||
* @param privateKeyToSignWith
|
||||
* private key to sign assertion with.
|
||||
* @param certificate
|
||||
* to include in assertion; no attempt is made to ensure the
|
||||
* certificate is valid, or corresponds to the private key, or any
|
||||
* other condition.
|
||||
* @param audience
|
||||
* to produce assertion for.
|
||||
* @param issuer
|
||||
* to produce assertion for.
|
||||
* @param issuedAt
|
||||
* timestamp for assertion, in milliseconds since the epoch; if null,
|
||||
* no timestamp is included.
|
||||
* @param expiresAt
|
||||
* expiration timestamp for assertion, in milliseconds since the epoch.
|
||||
* @return assertion.
|
||||
* @throws NonObjectJSONException
|
||||
* @throws IOException
|
||||
* @throws ParseException
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
public static String createAssertion(SigningPrivateKey privateKeyToSignWith, String certificate, String audience,
|
||||
String issuer, long issuedAt, long durationInMilliseconds) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
|
||||
long expiresAt = issuedAt + durationInMilliseconds;
|
||||
String issuer, Long issuedAt, long expiresAt) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
|
||||
String emptyAssertionPayloadString = "{}";
|
||||
String payloadString = getPayloadString(emptyAssertionPayloadString, issuer, issuedAt, audience, expiresAt);
|
||||
String payloadString = getPayloadString(emptyAssertionPayloadString, audience, issuer, issuedAt, expiresAt);
|
||||
String signature = JSONWebTokenUtils.encode(payloadString, privateKeyToSignWith);
|
||||
return certificate + "~" + signature;
|
||||
}
|
||||
|
||||
public static String createAssertion(SigningPrivateKey privateKeyToSignWith, String certificate, String audience) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
|
||||
String issuer = DEFAULT_ASSERTION_ISSUER;
|
||||
long issuedAt = System.currentTimeMillis();
|
||||
long durationInMilliseconds = DEFAULT_ASSERTION_DURATION_IN_MILLISECONDS;
|
||||
return createAssertion(privateKeyToSignWith, certificate, audience, issuer, issuedAt, durationInMilliseconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* For debugging only!
|
||||
*
|
||||
|
|
|
@ -40,18 +40,17 @@ public class MockMyIDTokenFactory {
|
|||
* sign username@mockmyid.com
|
||||
* @param issuedAt
|
||||
* timestamp for certificate, in milliseconds since the epoch.
|
||||
* @param durationInMilliseconds
|
||||
* lifespan of certificate, in milliseconds.
|
||||
* @param expiresAt
|
||||
* expiration timestamp for certificate, in milliseconds since the epoch.
|
||||
* @return encoded certificate string.
|
||||
* @throws Exception
|
||||
*/
|
||||
public String createMockMyIDCertificate(final VerifyingPublicKey publicKeyToSign, String username,
|
||||
final long issuedAt, final long durationInMilliseconds)
|
||||
final long issuedAt, final long expiresAt)
|
||||
throws Exception {
|
||||
if (!username.endsWith("@mockmyid.com")) {
|
||||
username = username + "@mockmyid.com";
|
||||
}
|
||||
long expiresAt = issuedAt + durationInMilliseconds;
|
||||
SigningPrivateKey mockMyIdPrivateKey = getMockMyIDPrivateKey();
|
||||
return JSONWebTokenUtils.createCertificate(publicKeyToSign, username, "mockmyid.com", issuedAt, expiresAt, mockMyIdPrivateKey);
|
||||
}
|
||||
|
@ -69,8 +68,9 @@ public class MockMyIDTokenFactory {
|
|||
*/
|
||||
public String createMockMyIDCertificate(final VerifyingPublicKey publicKeyToSign, final String username)
|
||||
throws Exception {
|
||||
return createMockMyIDCertificate(publicKeyToSign, username,
|
||||
System.currentTimeMillis(), JSONWebTokenUtils.DEFAULT_CERTIFICATE_DURATION_IN_MILLISECONDS );
|
||||
long ciat = System.currentTimeMillis();
|
||||
long cexp = ciat + JSONWebTokenUtils.DEFAULT_CERTIFICATE_DURATION_IN_MILLISECONDS;
|
||||
return createMockMyIDCertificate(publicKeyToSign, username, ciat, cexp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,23 +84,24 @@ public class MockMyIDTokenFactory {
|
|||
* sign username@mockmyid.com.
|
||||
* @param certificateIssuedAt
|
||||
* timestamp for certificate, in milliseconds since the epoch.
|
||||
* @param certificateDurationInMilliseconds
|
||||
* lifespan of certificate, in milliseconds.
|
||||
* @param certificateExpiresAt
|
||||
* expiration timestamp for certificate, in milliseconds since the epoch.
|
||||
* @param assertionIssuedAt
|
||||
* timestamp for assertion, in milliseconds since the epoch.
|
||||
* @param assertionDurationInMilliseconds
|
||||
* lifespan of assertion, in milliseconds.
|
||||
* timestamp for assertion, in milliseconds since the epoch; if null,
|
||||
* no timestamp is included.
|
||||
* @param assertionExpiresAt
|
||||
* expiration timestamp for assertion, in milliseconds since the epoch.
|
||||
* @return encoded assertion string.
|
||||
* @throws Exception
|
||||
*/
|
||||
public String createMockMyIDAssertion(BrowserIDKeyPair keyPair, String username, String audience,
|
||||
long certificateIssuedAt, long certificateDurationInMilliseconds,
|
||||
long assertionIssuedAt, long assertionDurationInMilliseconds)
|
||||
long certificateIssuedAt, long certificateExpiresAt,
|
||||
Long assertionIssuedAt, long assertionExpiresAt)
|
||||
throws Exception {
|
||||
String certificate = createMockMyIDCertificate(keyPair.getPublic(), username,
|
||||
certificateIssuedAt, certificateDurationInMilliseconds);
|
||||
certificateIssuedAt, certificateExpiresAt);
|
||||
return JSONWebTokenUtils.createAssertion(keyPair.getPrivate(), certificate, audience,
|
||||
JSONWebTokenUtils.DEFAULT_ASSERTION_ISSUER, assertionIssuedAt, assertionDurationInMilliseconds);
|
||||
JSONWebTokenUtils.DEFAULT_ASSERTION_ISSUER, assertionIssuedAt, assertionExpiresAt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -117,9 +118,11 @@ public class MockMyIDTokenFactory {
|
|||
*/
|
||||
public String createMockMyIDAssertion(BrowserIDKeyPair keyPair, String username, String audience)
|
||||
throws Exception {
|
||||
long now = System.currentTimeMillis();
|
||||
long ciat = System.currentTimeMillis();
|
||||
long cexp = ciat + JSONWebTokenUtils.DEFAULT_CERTIFICATE_DURATION_IN_MILLISECONDS;
|
||||
long aiat = ciat + 1;
|
||||
long aexp = aiat + JSONWebTokenUtils.DEFAULT_ASSERTION_DURATION_IN_MILLISECONDS;
|
||||
return createMockMyIDAssertion(keyPair, username, audience,
|
||||
now, JSONWebTokenUtils.DEFAULT_CERTIFICATE_DURATION_IN_MILLISECONDS,
|
||||
now + 1, JSONWebTokenUtils.DEFAULT_ASSERTION_DURATION_IN_MILLISECONDS);
|
||||
ciat, cexp, aiat, aexp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.net.URI;
|
|||
import java.net.URISyntaxException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
|
@ -118,9 +119,9 @@ public class BrowserIDRemoteVerifierClient implements BrowserIDVerifierClient {
|
|||
|
||||
r.delegate = new RemoteVerifierResourceDelegate(r, delegate);
|
||||
|
||||
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
|
||||
nvps.add(new BasicNameValuePair("audience", audience));
|
||||
nvps.add(new BasicNameValuePair("assertion", assertion));
|
||||
List<NameValuePair> nvps = Arrays.asList(new NameValuePair[] {
|
||||
new BasicNameValuePair("audience", audience),
|
||||
new BasicNameValuePair("assertion", assertion) });
|
||||
|
||||
try {
|
||||
r.post(new UrlEncodedFormEntity(nvps, "UTF-8"));
|
||||
|
|
|
@ -30,8 +30,10 @@ import java.io.File;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Favicons {
|
||||
|
@ -396,9 +398,9 @@ public class Favicons {
|
|||
|
||||
// Load and cache the built-in favicon in each of its sizes.
|
||||
// TODO: don't open the zip twice!
|
||||
ArrayList<Bitmap> toInsert = new ArrayList<Bitmap>(2);
|
||||
toInsert.add(loadBrandingBitmap(context, "favicon64.png"));
|
||||
toInsert.add(loadBrandingBitmap(context, "favicon32.png"));
|
||||
List<Bitmap> toInsert = Arrays.asList(loadBrandingBitmap(context, "favicon64.png"),
|
||||
loadBrandingBitmap(context, "favicon32.png"));
|
||||
|
||||
putFaviconsInMemCache(BUILT_IN_FAVICON_URL, toInsert.iterator(), true);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ public class FxAccountConstants {
|
|||
public static final String DEFAULT_AUTH_SERVER_ENDPOINT = "https://api.accounts.firefox.com/v1";
|
||||
public static final String DEFAULT_TOKEN_SERVER_ENDPOINT = "https://token.services.mozilla.com/1.0/sync/1.5";
|
||||
|
||||
public static final String STAGE_TOKEN_SERVER_ENDPOINT = "https://token.stage.mozaws.net/1.0/sync/1.5";
|
||||
|
||||
// For extra debugging. Not final so it can be changed from Fennec, or from
|
||||
// an add-on.
|
||||
public static boolean LOG_PERSONAL_INFORMATION = false;
|
||||
|
|
|
@ -56,8 +56,11 @@ public class Married extends TokensAndKeysState {
|
|||
delegate.handleTransition(new LogMessage("staying married"), this);
|
||||
}
|
||||
|
||||
public String generateAssertion(String audience, String issuer, long issuedAt, long durationInMilliseconds) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
|
||||
String assertion = JSONWebTokenUtils.createAssertion(keyPair.getPrivate(), certificate, audience, issuer, issuedAt, durationInMilliseconds);
|
||||
public String generateAssertion(String audience, String issuer) throws NonObjectJSONException, IOException, ParseException, GeneralSecurityException {
|
||||
// We generate assertions with no iat and an exp after 2050 to avoid
|
||||
// invalid-timestamp errors from the token server.
|
||||
final long expiresAt = JSONWebTokenUtils.DEFAULT_FUTURE_EXPIRES_AT_IN_MILLISECONDS;
|
||||
String assertion = JSONWebTokenUtils.createAssertion(keyPair.getPrivate(), certificate, audience, issuer, null, expiresAt);
|
||||
if (!FxAccountConstants.LOG_PERSONAL_INFORMATION) {
|
||||
return assertion;
|
||||
}
|
||||
|
|
|
@ -347,9 +347,9 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
// skew adjustment that the HawkAuthHeaderProvider uses to adjust its
|
||||
// timestamps. Eventually we might want this to adapt within the scope of a
|
||||
// global session.
|
||||
final SkewHandler tokenServerSkewHandler = SkewHandler.getSkewHandlerForHostname(storageHostname);
|
||||
final long tokenServerSkew = tokenServerSkewHandler.getSkewInSeconds();
|
||||
final AuthHeaderProvider authHeaderProvider = new HawkAuthHeaderProvider(token.id, token.key.getBytes("UTF-8"), false, tokenServerSkew);
|
||||
final SkewHandler storageServerSkewHandler = SkewHandler.getSkewHandlerForHostname(storageHostname);
|
||||
final long storageServerSkew = storageServerSkewHandler.getSkewInSeconds();
|
||||
final AuthHeaderProvider authHeaderProvider = new HawkAuthHeaderProvider(token.id, token.key.getBytes("UTF-8"), false, storageServerSkew);
|
||||
|
||||
final Context context = getContext();
|
||||
final SyncConfiguration syncConfig = new SyncConfiguration(token.uid, authHeaderProvider, sharedPrefs, syncKeyBundle);
|
||||
|
@ -503,11 +503,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
}
|
||||
|
||||
final Married married = (Married) state;
|
||||
SkewHandler skewHandler = SkewHandler.getSkewHandlerFromEndpointString(tokenServerEndpoint);
|
||||
final long now = System.currentTimeMillis();
|
||||
final long issuedAtMillis = now + skewHandler.getSkewInMillis();
|
||||
final long assertionDurationMillis = this.getAssertionDurationInMilliseconds();
|
||||
final String assertion = married.generateAssertion(audience, JSONWebTokenUtils.DEFAULT_ASSERTION_ISSUER, issuedAtMillis, assertionDurationMillis);
|
||||
final String assertion = married.generateAssertion(audience, JSONWebTokenUtils.DEFAULT_ASSERTION_ISSUER);
|
||||
|
||||
/*
|
||||
* At this point we're in the correct state to sync, and we're ready to fetch
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
@ -789,9 +790,9 @@ public class BrowserHealthRecorder implements HealthRecorder, GeckoEventListener
|
|||
new MeasurementFields() {
|
||||
@Override
|
||||
public Iterable<FieldSpec> getFields() {
|
||||
ArrayList<FieldSpec> out = new ArrayList<FieldSpec>(2);
|
||||
out.add(new FieldSpec("normal", Field.TYPE_JSON_DISCRETE));
|
||||
out.add(new FieldSpec("abnormal", Field.TYPE_JSON_DISCRETE));
|
||||
List<FieldSpec> out = Arrays.asList(
|
||||
new FieldSpec("normal", Field.TYPE_JSON_DISCRETE),
|
||||
new FieldSpec("abnormal", Field.TYPE_JSON_DISCRETE));
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -27,14 +27,15 @@ public abstract class CustomListPreference extends Preference implements View.On
|
|||
public static final int INDEX_SET_DEFAULT_BUTTON = 0;
|
||||
|
||||
// Dialog item labels.
|
||||
protected final String[] mDialogItems;
|
||||
private String[] mDialogItems;
|
||||
|
||||
// Dialog displayed when this element is tapped.
|
||||
protected AlertDialog mDialog;
|
||||
|
||||
// Cache label to avoid repeated use of the resource system.
|
||||
public final String LABEL_IS_DEFAULT;
|
||||
public final String LABEL_SET_AS_DEFAULT;
|
||||
protected final String LABEL_IS_DEFAULT;
|
||||
protected final String LABEL_SET_AS_DEFAULT;
|
||||
protected final String LABEL_REMOVE;
|
||||
|
||||
protected boolean mIsDefault;
|
||||
|
||||
|
@ -68,8 +69,7 @@ public abstract class CustomListPreference extends Preference implements View.On
|
|||
// Fetch these strings now, instead of every time we ever want to relabel a button.
|
||||
LABEL_IS_DEFAULT = res.getString(R.string.pref_default);
|
||||
LABEL_SET_AS_DEFAULT = res.getString(R.string.pref_dialog_set_default);
|
||||
|
||||
mDialogItems = getDialogStrings();
|
||||
LABEL_REMOVE = res.getString(R.string.pref_dialog_remove);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,10 +97,17 @@ public abstract class CustomListPreference extends Preference implements View.On
|
|||
}
|
||||
}
|
||||
|
||||
private String[] getCachedDialogItems() {
|
||||
if (mDialogItems == null) {
|
||||
mDialogItems = createDialogItems();
|
||||
}
|
||||
return mDialogItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the strings to be displayed in the dialog.
|
||||
*/
|
||||
abstract protected String[] getDialogStrings();
|
||||
abstract protected String[] createDialogItems();
|
||||
|
||||
/**
|
||||
* Display a dialog for this preference, when the preference is clicked.
|
||||
|
@ -108,7 +115,7 @@ public abstract class CustomListPreference extends Preference implements View.On
|
|||
public void showDialog() {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
builder.setTitle(getTitle().toString());
|
||||
builder.setItems(mDialogItems, new DialogInterface.OnClickListener() {
|
||||
builder.setItems(getCachedDialogItems(), new DialogInterface.OnClickListener() {
|
||||
// Forward relevant events to the container class for handling.
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int indexClicked) {
|
||||
|
|
|
@ -16,16 +16,22 @@ import android.widget.TextView;
|
|||
public class PanelsPreference extends CustomListPreference {
|
||||
protected String LOGTAG = "PanelsPreference";
|
||||
|
||||
private static final int INDEX_SHOW_BUTTON = 1;
|
||||
private static final int INDEX_REMOVE_BUTTON = 2;
|
||||
/**
|
||||
* Index of the context menu button for controlling display options.
|
||||
* For (removable) Dynamic panels, this button removes the panel.
|
||||
* For built-in panels, this button toggles showing or hiding the panel.
|
||||
*/
|
||||
private static final int INDEX_DISPLAY_BUTTON = 1;
|
||||
|
||||
private String LABEL_HIDE;
|
||||
private String LABEL_SHOW;
|
||||
|
||||
protected boolean mIsHidden = false;
|
||||
private boolean mIsRemovable;
|
||||
|
||||
public PanelsPreference(Context context, CustomListCategory parentCategory) {
|
||||
public PanelsPreference(Context context, CustomListCategory parentCategory, boolean isRemovable) {
|
||||
super(context, parentCategory);
|
||||
mIsRemovable = isRemovable;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,15 +55,17 @@ public class PanelsPreference extends CustomListPreference {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String[] getDialogStrings() {
|
||||
protected String[] createDialogItems() {
|
||||
if (mIsRemovable) {
|
||||
return new String[] { LABEL_SET_AS_DEFAULT, LABEL_REMOVE };
|
||||
}
|
||||
|
||||
// Built-in panels can't be removed, so use show/hide options.
|
||||
Resources res = getContext().getResources();
|
||||
LABEL_HIDE = res.getString(R.string.pref_panels_hide);
|
||||
LABEL_SHOW = res.getString(R.string.pref_panels_show);
|
||||
|
||||
// XXX: Don't provide the "Remove" string for now, because we only support built-in
|
||||
// panels, which can only be disabled.
|
||||
return new String[] { LABEL_SET_AS_DEFAULT,
|
||||
LABEL_HIDE };
|
||||
return new String[] { LABEL_SET_AS_DEFAULT, LABEL_HIDE };
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,12 +89,15 @@ public class PanelsPreference extends CustomListPreference {
|
|||
mParentCategory.setDefault(this);
|
||||
break;
|
||||
|
||||
case INDEX_SHOW_BUTTON:
|
||||
((PanelsPreferenceCategory) mParentCategory).setHidden(this, !mIsHidden);
|
||||
break;
|
||||
|
||||
case INDEX_REMOVE_BUTTON:
|
||||
mParentCategory.uninstall(this);
|
||||
case INDEX_DISPLAY_BUTTON:
|
||||
// Handle display options for the panel.
|
||||
if (mIsRemovable) {
|
||||
// For removable panels, the button displays text for removing the panel.
|
||||
mParentCategory.uninstall(this);
|
||||
} else {
|
||||
// Otherwise, the button toggles between text for showing or hiding the panel.
|
||||
((PanelsPreferenceCategory) mParentCategory).setHidden(this, !mIsHidden);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -99,8 +110,10 @@ public class PanelsPreference extends CustomListPreference {
|
|||
super.configureShownDialog();
|
||||
|
||||
// Handle Show/Hide buttons.
|
||||
final TextView hideButton = (TextView) mDialog.getListView().getChildAt(INDEX_SHOW_BUTTON);
|
||||
hideButton.setText(mIsHidden ? LABEL_SHOW : LABEL_HIDE);
|
||||
if (!mIsRemovable) {
|
||||
final TextView hideButton = (TextView) mDialog.getListView().getChildAt(INDEX_DISPLAY_BUTTON);
|
||||
hideButton.setText(mIsHidden ? LABEL_SHOW : LABEL_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setHidden(boolean toHide) {
|
||||
|
|
|
@ -86,8 +86,10 @@ public class PanelsPreferenceCategory extends CustomListCategory {
|
|||
|
||||
private void displayHomeConfig(HomeConfig.State configState) {
|
||||
for (PanelConfig panelConfig : configState) {
|
||||
final boolean isRemovable = panelConfig.isDynamic();
|
||||
|
||||
// Create and add the pref.
|
||||
final PanelsPreference pref = new PanelsPreference(getContext(), PanelsPreferenceCategory.this);
|
||||
final PanelsPreference pref = new PanelsPreference(getContext(), PanelsPreferenceCategory.this, isRemovable);
|
||||
pref.setTitle(panelConfig.getTitle());
|
||||
pref.setKey(panelConfig.getId());
|
||||
// XXX: Pull icon from PanelInfo.
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.mozilla.gecko.widget.FaviconView;
|
|||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.text.SpannableString;
|
||||
|
@ -66,10 +65,9 @@ public class SearchEnginePreference extends CustomListPreference {
|
|||
* Returns the strings to be displayed in the dialog.
|
||||
*/
|
||||
@Override
|
||||
protected String[] getDialogStrings() {
|
||||
Resources res = getContext().getResources();
|
||||
protected String[] createDialogItems() {
|
||||
return new String[] { LABEL_SET_AS_DEFAULT,
|
||||
res.getString(R.string.pref_dialog_remove) };
|
||||
LABEL_REMOVE };
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,7 @@ import android.util.Log;
|
|||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/*
|
||||
|
@ -200,9 +201,7 @@ public class SQLiteBridge {
|
|||
if (!TextUtils.isEmpty(whereClause)) {
|
||||
sb.append(" WHERE ");
|
||||
sb.append(whereClause);
|
||||
for (int i = 0; i < whereArgs.length; i++) {
|
||||
valueNames.add(whereArgs[i]);
|
||||
}
|
||||
valueNames.addAll(Arrays.asList(whereArgs));
|
||||
}
|
||||
|
||||
String[] binds = new String[valueNames.size()];
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.mozilla.gecko.sync.repositories.android;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
@ -313,9 +314,9 @@ public class FormHistoryRepositorySession extends
|
|||
}
|
||||
};
|
||||
|
||||
ArrayList<Callable<Cursor>> callableCursors = new ArrayList<Callable<Cursor>>();
|
||||
callableCursors.add(regularCallable);
|
||||
callableCursors.add(deletedCallable);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Callable<Cursor>> callableCursors = Arrays.asList(regularCallable, deletedCallable);
|
||||
|
||||
fetchHelper(delegate, sharedEnd, callableCursors);
|
||||
}
|
||||
|
||||
|
@ -348,9 +349,9 @@ public class FormHistoryRepositorySession extends
|
|||
}
|
||||
};
|
||||
|
||||
ArrayList<Callable<Cursor>> callableCursors = new ArrayList<Callable<Cursor>>();
|
||||
callableCursors.add(regularCallable);
|
||||
callableCursors.add(deletedCallable);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Callable<Cursor>> callableCursors = Arrays.asList(regularCallable, deletedCallable);
|
||||
|
||||
fetchHelper(delegate, sharedEnd, callableCursors);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.mozilla.gecko.sync.setup.activities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Intent;
|
||||
|
@ -50,10 +51,7 @@ public class SendTabData {
|
|||
|
||||
// For URL, take first URL from EXTRA_TEXT, EXTRA_SUBJECT, and EXTRA_TITLE
|
||||
// (in that order).
|
||||
List<String> strings = new ArrayList<String>();
|
||||
strings.add(text);
|
||||
strings.add(subject);
|
||||
strings.add(title);
|
||||
List<String> strings = Arrays.asList(text, subject, title);
|
||||
String theUri = new WebURLFinder(strings).bestWebURL();
|
||||
|
||||
return new SendTabData(theTitle, theUri);
|
||||
|
|
|
@ -44,6 +44,9 @@ abstract class UITest extends ActivityInstrumentationTestCase2<Activity>
|
|||
private static final String LAUNCHER_ACTIVITY = TestConstants.ANDROID_PACKAGE_NAME + ".App";
|
||||
private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko";
|
||||
|
||||
private static final String JUNIT_FAILURE_MSG = "A JUnit method was called. Make sure " +
|
||||
"you are using AssertionHelper to make assertions. Try `fAssert*(...);`";
|
||||
|
||||
private final static Class<Activity> sLauncherActivityClass;
|
||||
|
||||
private Activity mActivity;
|
||||
|
@ -226,4 +229,63 @@ abstract class UITest extends ActivityInstrumentationTestCase2<Activity>
|
|||
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an Exception. Called from overridden JUnit methods to ensure JUnit assertions
|
||||
* are not accidentally used over AssertionHelper assertions (the latter of which contains
|
||||
* additional logging facilities for use in our test harnesses).
|
||||
*/
|
||||
private static void junit() {
|
||||
throw new UnsupportedOperationException(JUNIT_FAILURE_MSG);
|
||||
}
|
||||
|
||||
// Note: inexplicably, javac does not think we're overriding these methods,
|
||||
// so we can't use the @Override annotation.
|
||||
public static void assertEquals(short e, short a) { junit(); }
|
||||
public static void assertEquals(String m, int e, int a) { junit(); }
|
||||
public static void assertEquals(String m, short e, short a) { junit(); }
|
||||
public static void assertEquals(char e, char a) { junit(); }
|
||||
public static void assertEquals(String m, String e, String a) { junit(); }
|
||||
public static void assertEquals(int e, int a) { junit(); }
|
||||
public static void assertEquals(String m, double e, double a, double delta) { junit(); }
|
||||
public static void assertEquals(String m, long e, long a) { junit(); }
|
||||
public static void assertEquals(byte e, byte a) { junit(); }
|
||||
public static void assertEquals(Object e, Object a) { junit(); }
|
||||
public static void assertEquals(boolean e, boolean a) { junit(); }
|
||||
public static void assertEquals(String m, float e, float a, float delta) { junit(); }
|
||||
public static void assertEquals(String m, boolean e, boolean a) { junit(); }
|
||||
public static void assertEquals(String e, String a) { junit(); }
|
||||
public static void assertEquals(float e, float a, float delta) { junit(); }
|
||||
public static void assertEquals(String m, byte e, byte a) { junit(); }
|
||||
public static void assertEquals(double e, double a, double delta) { junit(); }
|
||||
public static void assertEquals(String m, char e, char a) { junit(); }
|
||||
public static void assertEquals(String m, Object e, Object a) { junit(); }
|
||||
public static void assertEquals(long e, long a) { junit(); }
|
||||
|
||||
public static void assertFalse(String m, boolean c) { junit(); }
|
||||
public static void assertFalse(boolean c) { junit(); }
|
||||
|
||||
public static void assertNotNull(String m, Object o) { junit(); }
|
||||
public static void assertNotNull(Object o) { junit(); }
|
||||
|
||||
public static void assertNotSame(Object e, Object a) { junit(); }
|
||||
public static void assertNotSame(String m, Object e, Object a) { junit(); }
|
||||
|
||||
public static void assertNull(Object o) { junit(); }
|
||||
public static void assertNull(String m, Object o) { junit(); }
|
||||
|
||||
public static void assertSame(Object e, Object a) { junit(); }
|
||||
public static void assertSame(String m, Object e, Object a) { junit(); }
|
||||
|
||||
public static void assertTrue(String m, boolean c) { junit(); }
|
||||
public static void assertTrue(boolean c) { junit(); }
|
||||
|
||||
public static void fail(String m) { junit(); }
|
||||
public static void fail() { junit(); }
|
||||
|
||||
public static void failNotEquals(String m, Object e, Object a) { junit(); }
|
||||
public static void failNotSame(String m, Object e, Object a) { junit(); }
|
||||
public static void failSame(String m) { junit(); }
|
||||
|
||||
public static String format(String m, Object e, Object a) { junit(); return null; }
|
||||
}
|
||||
|
|
|
@ -75,10 +75,10 @@ public class testInputConnection extends UITest {
|
|||
assertTextAndSelectionAt("Can finish composition", ic, "foobar", 6);
|
||||
|
||||
// Test getTextBeforeCursor
|
||||
assertEquals("Can retrieve text before cursor", "bar", ic.getTextBeforeCursor(3, 0));
|
||||
fAssertEquals("Can retrieve text before cursor", "bar", ic.getTextBeforeCursor(3, 0));
|
||||
|
||||
// Test getTextAfterCursor
|
||||
assertEquals("Can retrieve text after cursor", "", ic.getTextAfterCursor(3, 0));
|
||||
fAssertEquals("Can retrieve text after cursor", "", ic.getTextAfterCursor(3, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|