mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
987aa4b78c
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -376,6 +376,20 @@ name = "cc"
|
||||
version = "1.0.23"
|
||||
source = "git+https://github.com/glandium/cc-rs?branch=1.0.23-clang-cl-aarch64#2aa71628b1261b5515bd8668afca591669ba195d"
|
||||
|
||||
[[package]]
|
||||
name = "cert_storage"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nserror 0.1.0",
|
||||
"nsstring 0.1.0",
|
||||
"rkv 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"style 0.0.1",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xpcom 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.3.3"
|
||||
@ -1127,6 +1141,7 @@ dependencies = [
|
||||
"arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"audioipc-client 0.4.0",
|
||||
"audioipc-server 0.2.3",
|
||||
"cert_storage 0.0.1",
|
||||
"cose-c 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cubeb-pulse 0.2.0",
|
||||
"cubeb-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1172,7 +1187,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gleam"
|
||||
version = "0.6.12"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3133,7 +3148,7 @@ dependencies = [
|
||||
"dwrote 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"freetype 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3184,7 +3199,7 @@ dependencies = [
|
||||
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"nsstring 0.1.0",
|
||||
"rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -3439,7 +3454,7 @@ dependencies = [
|
||||
"checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
|
||||
"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
|
||||
"checksum gl_generator 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0ffaf173cf76c73a73e080366bf556b4776ece104b06961766ff11449f38604"
|
||||
"checksum gleam 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f1519ca611d230e1deadbedfb79044b921ac4a961ab8823fef10e37271e2c38e"
|
||||
"checksum gleam 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "17bca843dd3cf25db1bf415d55de9c0f0ae09dd7fa952ec3cef9930f90de1339"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum goblin 0.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5911d7df7b8f65ab676c5327b50acea29d3c6a1a4ad05e444cf5dce321b26db2"
|
||||
"checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c"
|
||||
|
@ -10,12 +10,8 @@ ChromeUtils.defineModuleGetter(this, "Utils",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Logger",
|
||||
"resource://gre/modules/accessibility/Utils.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Roles",
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Events",
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "States",
|
||||
"resource://gre/modules/accessibility/Constants.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["EventManager"];
|
||||
|
||||
@ -85,27 +81,6 @@ this.EventManager.prototype = {
|
||||
}
|
||||
|
||||
switch (aEvent.eventType) {
|
||||
case Events.VIRTUALCURSOR_CHANGED:
|
||||
{
|
||||
if (!aEvent.isFromUserInput) {
|
||||
break;
|
||||
}
|
||||
|
||||
const event = aEvent.
|
||||
QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
|
||||
const position = event.newAccessible;
|
||||
|
||||
// We pass control to the vc in the embedded frame.
|
||||
if (position && position.role == Roles.INTERNAL_FRAME) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Blur to document if new position is not explicitly focused.
|
||||
if (!position || !Utils.getState(position).contains(States.FOCUSED)) {
|
||||
aEvent.accessibleDocument.takeFocus();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Events.NAME_CHANGE:
|
||||
{
|
||||
// XXX: Port to Android
|
||||
|
@ -23,6 +23,12 @@ function isEventForAutocompleteItem(event) {
|
||||
* search isn't finished yet.
|
||||
*/
|
||||
function waitForSearchFinish() {
|
||||
if (UrlbarPrefs.get("quantumbar")) {
|
||||
return Promise.all([
|
||||
gURLBar.lastQueryContextPromise,
|
||||
BrowserTestUtils.waitForCondition(() => gURLBar.view.isOpen)
|
||||
]);
|
||||
}
|
||||
return BrowserTestUtils.waitForCondition(() =>
|
||||
(gURLBar.popupOpen && gURLBar.controller.searchStatus >=
|
||||
Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH),
|
||||
|
@ -3318,7 +3318,7 @@ window._gBrowser = {
|
||||
this._isBusy = true;
|
||||
}
|
||||
|
||||
this._swapBrowserDocShells(aOurTab, otherBrowser, Ci.nsIBrowser.SWAP_DEFAULT, stateFlags);
|
||||
this._swapBrowserDocShells(aOurTab, otherBrowser, stateFlags);
|
||||
}
|
||||
|
||||
// Unregister the previously opened URI
|
||||
@ -3367,7 +3367,7 @@ window._gBrowser = {
|
||||
return true;
|
||||
},
|
||||
|
||||
swapBrowsers(aOurTab, aOtherTab, aFlags) {
|
||||
swapBrowsers(aOurTab, aOtherTab) {
|
||||
let otherBrowser = aOtherTab.linkedBrowser;
|
||||
let otherTabBrowser = otherBrowser.getTabBrowser();
|
||||
|
||||
@ -3378,7 +3378,7 @@ window._gBrowser = {
|
||||
filter.removeProgressListener(tabListener);
|
||||
|
||||
// Perform the docshell swap through the common mechanism.
|
||||
this._swapBrowserDocShells(aOurTab, otherBrowser, aFlags);
|
||||
this._swapBrowserDocShells(aOurTab, otherBrowser);
|
||||
|
||||
// Restore the listeners for the swapped in tab.
|
||||
tabListener = new otherTabBrowser.ownerGlobal.TabProgressListener(aOtherTab, otherBrowser, false, false);
|
||||
@ -3389,7 +3389,7 @@ window._gBrowser = {
|
||||
otherBrowser.webProgress.addProgressListener(filter, notifyAll);
|
||||
},
|
||||
|
||||
_swapBrowserDocShells(aOurTab, aOtherBrowser, aFlags, aStateFlags) {
|
||||
_swapBrowserDocShells(aOurTab, aOtherBrowser, aStateFlags) {
|
||||
// aOurTab's browser needs to be inserted now if it hasn't already.
|
||||
this._insertBrowser(aOurTab);
|
||||
|
||||
@ -3432,17 +3432,15 @@ window._gBrowser = {
|
||||
remoteBrowser._outerWindowIDBrowserMap.set(aOtherBrowser.outerWindowID, aOtherBrowser);
|
||||
}
|
||||
|
||||
if (!(aFlags & Ci.nsIBrowser.SWAP_KEEP_PERMANENT_KEY)) {
|
||||
// Swap permanentKey properties.
|
||||
let ourPermanentKey = ourBrowser.permanentKey;
|
||||
ourBrowser.permanentKey = aOtherBrowser.permanentKey;
|
||||
aOtherBrowser.permanentKey = ourPermanentKey;
|
||||
aOurTab.permanentKey = ourBrowser.permanentKey;
|
||||
if (remoteBrowser) {
|
||||
let otherTab = remoteBrowser.getTabForBrowser(aOtherBrowser);
|
||||
if (otherTab) {
|
||||
otherTab.permanentKey = aOtherBrowser.permanentKey;
|
||||
}
|
||||
// Swap permanentKey properties.
|
||||
let ourPermanentKey = ourBrowser.permanentKey;
|
||||
ourBrowser.permanentKey = aOtherBrowser.permanentKey;
|
||||
aOtherBrowser.permanentKey = ourPermanentKey;
|
||||
aOurTab.permanentKey = ourBrowser.permanentKey;
|
||||
if (remoteBrowser) {
|
||||
let otherTab = remoteBrowser.getTabForBrowser(aOtherBrowser);
|
||||
if (otherTab) {
|
||||
otherTab.permanentKey = aOtherBrowser.permanentKey;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,20 +14,6 @@
|
||||
|
||||
/* These reflows happen only the first time the panel opens. */
|
||||
const EXPECTED_REFLOWS_FIRST_OPEN = [
|
||||
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
|
||||
// 1359989, which was filed against the legacy awesomebar but applies here too
|
||||
// because it seems to be caused by platform code.
|
||||
{
|
||||
stack: [
|
||||
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||
"_notify@resource:///modules/UrlbarController.jsm",
|
||||
"receiveResults@resource:///modules/UrlbarController.jsm",
|
||||
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
|
||||
"add@resource:///modules/UrlbarProvidersManager.jsm",
|
||||
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
|
||||
],
|
||||
},
|
||||
{
|
||||
stack: [
|
||||
"__rebuild@chrome://browser/content/search/search-one-offs.js",
|
||||
@ -46,6 +32,15 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
|
||||
*/
|
||||
],
|
||||
},
|
||||
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
|
||||
// 1359989, which was filed against the legacy awesomebar but applies here too
|
||||
// because it seems to be caused by platform code.
|
||||
{
|
||||
stack: [
|
||||
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function quantumbar() {
|
||||
|
@ -14,17 +14,6 @@
|
||||
|
||||
/* These reflows happen only the first time the panel opens. */
|
||||
const EXPECTED_REFLOWS_FIRST_OPEN = [
|
||||
{
|
||||
stack: [
|
||||
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||
"_notify@resource:///modules/UrlbarController.jsm",
|
||||
"receiveResults@resource:///modules/UrlbarController.jsm",
|
||||
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
|
||||
"add@resource:///modules/UrlbarProvidersManager.jsm",
|
||||
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
|
||||
],
|
||||
},
|
||||
{
|
||||
stack: [
|
||||
"__rebuild@chrome://browser/content/search/search-one-offs.js",
|
||||
@ -43,6 +32,15 @@ const EXPECTED_REFLOWS_FIRST_OPEN = [
|
||||
*/
|
||||
],
|
||||
},
|
||||
// This is the this.panel.openPopup() call in UrlbarView._openPanel. See bug
|
||||
// 1359989, which was filed against the legacy awesomebar but applies here too
|
||||
// because it seems to be caused by platform code.
|
||||
{
|
||||
stack: [
|
||||
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
/* These reflows happen every time the panel opens. */
|
||||
@ -54,11 +52,6 @@ const EXPECTED_REFLOWS_SECOND_OPEN = [
|
||||
stack: [
|
||||
"_openPanel@resource:///modules/UrlbarView.jsm",
|
||||
"onQueryResults@resource:///modules/UrlbarView.jsm",
|
||||
"_notify@resource:///modules/UrlbarController.jsm",
|
||||
"receiveResults@resource:///modules/UrlbarController.jsm",
|
||||
"notifyResults@resource:///modules/UrlbarProvidersManager.jsm",
|
||||
"add@resource:///modules/UrlbarProvidersManager.jsm",
|
||||
"onSearchResult@resource:///modules/UrlbarProviderUnifiedComplete.jsm",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -693,6 +693,24 @@ async function runUrlbarTest(useAwesomebar,
|
||||
fn();
|
||||
}, ms);
|
||||
};
|
||||
} else {
|
||||
let popup = URLBar.view;
|
||||
let oldOnQueryResults = popup.onQueryResults.bind(popup);
|
||||
let oldOnQueryFinished = popup.onQueryFinished.bind(popup);
|
||||
|
||||
// We need to invalidate the frame tree outside of the normal
|
||||
// mechanism since invalidations and result additions to the
|
||||
// URL bar occur without firing JS events (which is how we
|
||||
// normally know to dirty the frame tree).
|
||||
popup.onQueryResults = (context) => {
|
||||
dirtyFrame(win);
|
||||
oldOnQueryResults(context);
|
||||
};
|
||||
|
||||
popup.onQueryFinished = (context) => {
|
||||
dirtyFrame(win);
|
||||
oldOnQueryFinished(context);
|
||||
};
|
||||
}
|
||||
|
||||
let waitExtra = async () => {
|
||||
|
@ -172,8 +172,6 @@ var whitelist = [
|
||||
// kvstore.jsm wraps the API in nsIKeyValue.idl in a more ergonomic API
|
||||
// It landed in bug 1490496, and we expect to start using it shortly.
|
||||
{file: "resource://gre/modules/kvstore.jsm"},
|
||||
{file: "chrome://devtools/content/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.ftl",
|
||||
isFromDevTools: true},
|
||||
// Bug 1526672
|
||||
{file: "resource://app/localization/en-US/browser/touchbar/touchbar.ftl",
|
||||
platforms: ["linux", "win"]},
|
||||
|
@ -2272,7 +2272,7 @@ BrowserGlue.prototype = {
|
||||
_migrateUI: function BG__migrateUI() {
|
||||
// Use an increasing number to keep track of the current migration state.
|
||||
// Completely unrelated to the current Firefox release number.
|
||||
const UI_VERSION = 80;
|
||||
const UI_VERSION = 81;
|
||||
const BROWSER_DOCURL = AppConstants.BROWSER_CHROME_URL;
|
||||
|
||||
let currentUIVersion;
|
||||
@ -2585,6 +2585,26 @@ BrowserGlue.prototype = {
|
||||
Services.prefs.setCharPref("network.proxy.no_proxies_on", hosts);
|
||||
}
|
||||
|
||||
if (currentUIVersion < 81) {
|
||||
// Reset homepage pref for users who have it set to a default from before Firefox 4:
|
||||
// <locale>.(start|start2|start3).mozilla.(com|org)
|
||||
const HOMEPAGE_PREF = "browser.startup.homepage";
|
||||
if (Services.prefs.prefHasUserValue(HOMEPAGE_PREF)) {
|
||||
const DEFAULT = Services.prefs.getDefaultBranch(HOMEPAGE_PREF).getCharPref("");
|
||||
let value = Services.prefs.getCharPref(HOMEPAGE_PREF);
|
||||
let updated = value.replace(
|
||||
/https?:\/\/([\w\-]+[.])?start[\d]*\.mozilla\.(org|com)[^|]*/ig, DEFAULT);
|
||||
if (updated != value) {
|
||||
if (updated == DEFAULT) {
|
||||
Services.prefs.clearUserPref(HOMEPAGE_PREF);
|
||||
} else {
|
||||
value = updated;
|
||||
Services.prefs.setCharPref(HOMEPAGE_PREF, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the migration version.
|
||||
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||
},
|
||||
|
@ -17,7 +17,6 @@ add_task(async function testAutoconfigReloadButton() {
|
||||
await openPreferencesViaOpenPreferencesAPI("general", { leaveOpen: true });
|
||||
const connectionURL = "chrome://browser/content/preferences/connection.xul";
|
||||
const promiseDialogLoaded = promiseLoadSubDialog(connectionURL);
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
gBrowser.contentDocument.getElementById("connectionSettings").click();
|
||||
const dialog = await promiseDialogLoaded;
|
||||
|
||||
|
@ -88,7 +88,6 @@ async function openNotificationsPermissionDialog() {
|
||||
|
||||
add_task(async function testExtensionControlledHomepage() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
is(gBrowser.currentURI.spec, "about:preferences#home",
|
||||
"#home should be in the URI for about:preferences");
|
||||
@ -158,7 +157,6 @@ add_task(async function testExtensionControlledHomepage() {
|
||||
|
||||
add_task(async function testPrefLockedHomepage() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
is(gBrowser.currentURI.spec, "about:preferences#home",
|
||||
"#home should be in the URI for about:preferences");
|
||||
@ -305,7 +303,6 @@ add_task(async function testPrefLockedHomepage() {
|
||||
|
||||
add_task(async function testExtensionControlledNewTab() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
is(gBrowser.currentURI.spec, "about:preferences#home",
|
||||
"#home should be in the URI for about:preferences");
|
||||
@ -533,7 +530,6 @@ add_task(async function testExtensionControlledDefaultSearch() {
|
||||
add_task(async function testExtensionControlledHomepageUninstalledAddon() {
|
||||
async function checkHomepageEnabled() {
|
||||
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
is(gBrowser.currentURI.spec, "about:preferences#home",
|
||||
"#home should be in the URI for about:preferences");
|
||||
|
@ -4,7 +4,6 @@ add_task(async function testSetHomepageUseCurrent() {
|
||||
is(gBrowser.currentURI.spec, "about:blank", "Test starts with about:blank open");
|
||||
await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:home");
|
||||
await openPreferencesViaOpenPreferencesAPI("paneHome", {leaveOpen: true});
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
let doc = gBrowser.contentDocument;
|
||||
is(gBrowser.currentURI.spec, "about:preferences#home",
|
||||
"#home should be in the URI for about:preferences");
|
||||
|
@ -91,6 +91,8 @@ class UrlbarInput {
|
||||
this.isPrivate = PrivateBrowsingUtils.isWindowPrivate(this.window);
|
||||
this.lastQueryContextPromise = Promise.resolve();
|
||||
this._actionOverrideKeyCount = 0;
|
||||
this._autofillPlaceholder = "";
|
||||
this._lastSearchString = "";
|
||||
this._resultForCurrentValue = null;
|
||||
this._suppressStartQuery = false;
|
||||
this._untrimmedValue = "";
|
||||
@ -468,12 +470,10 @@ class UrlbarInput {
|
||||
this._lastSearchString : this.textValue);
|
||||
if (canonizedUrl) {
|
||||
this.value = canonizedUrl;
|
||||
} else if (result.autofill) {
|
||||
this._autofillValue(result.autofill);
|
||||
} else {
|
||||
this.value = this._getValueFromResult(result);
|
||||
if (result.autofill) {
|
||||
this.selectionStart = result.autofill.selectionStart;
|
||||
this.selectionEnd = result.autofill.selectionEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._resultForCurrentValue = result;
|
||||
@ -497,37 +497,53 @@ class UrlbarInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a query based on the user input.
|
||||
* Starts a query based on the current input value.
|
||||
*
|
||||
* @param {boolean} [options.allowAutofill]
|
||||
* Whether or not to allow providers to include autofill results.
|
||||
* @param {number} [options.lastKey]
|
||||
* The last key the user entered (as a key code).
|
||||
* @param {string} [options.searchString]
|
||||
* The search string. If not given, the current input value is used.
|
||||
* Otherwise, the current input value must start with this value. The
|
||||
* intended use for this parameter is related to the autofill placeholder.
|
||||
* When the placeholder is autofilled before the new search starts, the
|
||||
* current input value will be the entire autofilled placeholder, not the
|
||||
* value the user typed, which is the value we should search with.
|
||||
* @param {boolean} [resetSearchState]
|
||||
* If this is the first search of a user interaction with the input, set
|
||||
* this to true (the default) so that search-related state from the previous
|
||||
* interaction doesn't interfere with the new interaction. Otherwise set it
|
||||
* to false so that state is maintained during a single interaction. The
|
||||
* intended use for this parameter is that it should be set to false when
|
||||
* this method is called due to input events.
|
||||
*/
|
||||
startQuery({
|
||||
allowAutofill = true,
|
||||
lastKey = null,
|
||||
searchString = null,
|
||||
resetSearchState = true,
|
||||
} = {}) {
|
||||
if (this._suppressStartQuery) {
|
||||
return;
|
||||
}
|
||||
|
||||
let searchString = this.textValue;
|
||||
if (resetSearchState) {
|
||||
this._resetSearchState();
|
||||
}
|
||||
|
||||
// We should autofill only when all of the following are true:
|
||||
// * The pref is enabled.
|
||||
// * The end of the selection is at the end of the input.
|
||||
// * The user hasn't deleted text at the end of the input since the last
|
||||
// query. Do a simple prefix comparison to guess whether that happened.
|
||||
let enableAutofill =
|
||||
UrlbarPrefs.get("autoFill") &&
|
||||
this.selectionEnd == searchString.length &&
|
||||
(!this._lastSearchString ||
|
||||
!this._lastSearchString.startsWith(searchString));
|
||||
if (!searchString) {
|
||||
searchString = this.textValue;
|
||||
} else if (!this.textValue.startsWith(searchString)) {
|
||||
throw new Error("The current value doesn't start with the search string");
|
||||
}
|
||||
this._lastSearchString = searchString;
|
||||
|
||||
// TODO (Bug 1522902): This promise is necessary for tests, because some
|
||||
// tests are not listening for completion when starting a query through
|
||||
// other methods than startQuery (input events for example).
|
||||
this.lastQueryContextPromise = this.controller.startQuery(new UrlbarQueryContext({
|
||||
enableAutofill,
|
||||
allowAutofill,
|
||||
isPrivate: this.isPrivate,
|
||||
lastKey,
|
||||
maxResults: UrlbarPrefs.get("maxRichResults"),
|
||||
@ -560,9 +576,10 @@ class UrlbarInput {
|
||||
// Note: proper IME Composition handling depends on the fact this generates
|
||||
// an input event, rather than directly invoking the controller; everything
|
||||
// goes through _on_input, that will properly skip the search until the
|
||||
// composition is committed.
|
||||
// If this assumption changes, we'll have to first check we are not
|
||||
// composing, before starting a search.
|
||||
// composition is committed. _on_input also skips the search when it's the
|
||||
// same as the previous search, but we want to allow consecutive searches
|
||||
// with the same string. So clear _lastSearchString first.
|
||||
this._lastSearchString = "";
|
||||
let event = this.document.createEvent("UIEvents");
|
||||
event.initUIEvent("input", true, false, this.window, 0);
|
||||
this.inputField.dispatchEvent(event);
|
||||
@ -605,6 +622,12 @@ class UrlbarInput {
|
||||
}
|
||||
|
||||
set value(val) {
|
||||
return this._setValue(val, true);
|
||||
}
|
||||
|
||||
// Private methods below.
|
||||
|
||||
_setValue(val, allowTrim) {
|
||||
this._untrimmedValue = val;
|
||||
|
||||
let originalUrl = ReaderMode.getOriginalUrlObjectForDisplay(val);
|
||||
@ -612,7 +635,7 @@ class UrlbarInput {
|
||||
val = originalUrl.displaySpec;
|
||||
}
|
||||
|
||||
val = this.trimValue(val);
|
||||
val = allowTrim ? this.trimValue(val) : val;
|
||||
|
||||
this.valueIsTyped = false;
|
||||
this._resultForCurrentValue = null;
|
||||
@ -628,13 +651,7 @@ class UrlbarInput {
|
||||
return val;
|
||||
}
|
||||
|
||||
// Private methods below.
|
||||
|
||||
_getValueFromResult(result) {
|
||||
if (result.autofill) {
|
||||
return result.autofill.value;
|
||||
}
|
||||
|
||||
switch (result.type) {
|
||||
case UrlbarUtils.RESULT_TYPE.KEYWORD:
|
||||
return result.payload.input;
|
||||
@ -655,6 +672,56 @@ class UrlbarInput {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets some state so that searches from the user's previous interaction
|
||||
* with the input don't interfere with searches from a new interaction.
|
||||
*/
|
||||
_resetSearchState() {
|
||||
this._lastSearchString = this.textValue;
|
||||
this._autofillPlaceholder = "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Autofills the autofill placeholder string if appropriate, and determines
|
||||
* whether autofill should be allowed for the new search started by an input
|
||||
* event.
|
||||
*
|
||||
* @param {string} value
|
||||
* The new search string.
|
||||
* @param {boolean} deletedAutofilledSubstring
|
||||
* Whether the user deleted the previously autofilled substring.
|
||||
* @returns {boolean}
|
||||
* Whether autofill should be allowed in the new search.
|
||||
*/
|
||||
_maybeAutofillOnInput(value, deletedAutofilledSubstring) {
|
||||
// Determine whether autofill should be allowed for the new search triggered
|
||||
// by the input event.
|
||||
let lastSearchStartsWithNewSearch =
|
||||
value.length < this._lastSearchString.length &&
|
||||
this._lastSearchString.startsWith(value);
|
||||
let allowAutofill =
|
||||
!lastSearchStartsWithNewSearch &&
|
||||
!deletedAutofilledSubstring &&
|
||||
this.selectionEnd == value.length;
|
||||
|
||||
// The autofill placeholder is a string that we autofill now, before we
|
||||
// start waiting on the new search's first result, in order to prevent a
|
||||
// flicker in the input caused by the previous autofilled substring
|
||||
// disappearing and reappearing when the new first result arrives. Of
|
||||
// course we can only autofill the placeholder if it starts with the new
|
||||
// search string.
|
||||
if (!allowAutofill ||
|
||||
this._autofillPlaceholder.length <= value.length ||
|
||||
!this._autofillPlaceholder.startsWith(value)) {
|
||||
this._autofillPlaceholder = "";
|
||||
}
|
||||
if (this._autofillPlaceholder) {
|
||||
this._autofillValueOnInput(this._autofillPlaceholder);
|
||||
}
|
||||
|
||||
return allowAutofill;
|
||||
}
|
||||
|
||||
_updateTextOverflow() {
|
||||
if (!this._overflowing) {
|
||||
this.removeAttribute("textoverflow");
|
||||
@ -860,6 +927,49 @@ class UrlbarInput {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Autofills a value into the input in response to the user's typing. The
|
||||
* autofill value must start with the value that's already in the input. If
|
||||
* it doesn't, this method doesn't do anything. If it does, this method will
|
||||
* autofill and set the selection automatically.
|
||||
*
|
||||
* @param {string} value
|
||||
* The value to autofill.
|
||||
*/
|
||||
_autofillValueOnInput(value) {
|
||||
// Don't ever autofill on input if the caret/selection isn't at the end, or
|
||||
// if the value doesn't start with what the user typed.
|
||||
if (this.selectionEnd != this.value.length ||
|
||||
!value.startsWith(this._lastSearchString)) {
|
||||
return;
|
||||
}
|
||||
this._autofillValue({
|
||||
value,
|
||||
selectionStart: this._lastSearchString.length,
|
||||
selectionEnd: value.length,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Autofills a value into the input. The value will be autofilled regardless
|
||||
* of the input's current value.
|
||||
*
|
||||
* @param {string} options.value
|
||||
* The value to autofill.
|
||||
* @param {integer} options.selectionStart
|
||||
* The new selectionStart.
|
||||
* @param {integer} options.selectionEnd
|
||||
* The new selectionEnd.
|
||||
*/
|
||||
_autofillValue({ value, selectionStart, selectionEnd } = {}) {
|
||||
// The autofilled value may be a URL that includes a scheme at the
|
||||
// beginning. Do not allow it to be trimmed.
|
||||
this._setValue(value, false);
|
||||
this.selectionStart = selectionStart;
|
||||
this.selectionEnd = selectionEnd;
|
||||
this._autofillPlaceholder = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the url in the appropriate place.
|
||||
*
|
||||
@ -1034,6 +1144,7 @@ class UrlbarInput {
|
||||
if (this.getAttribute("pageproxystate") != "valid") {
|
||||
this.window.UpdatePopupNotificationsVisibility();
|
||||
}
|
||||
this._resetSearchState();
|
||||
}
|
||||
|
||||
_on_focus(event) {
|
||||
@ -1099,18 +1210,40 @@ class UrlbarInput {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._compositionState == UrlbarUtils.COMPOSITION.COMMIT) {
|
||||
let handlingCompositionCommit =
|
||||
this._compositionState == UrlbarUtils.COMPOSITION.COMMIT;
|
||||
if (handlingCompositionCommit) {
|
||||
this._compositionState = UrlbarUtils.COMPOSITION.NONE;
|
||||
}
|
||||
|
||||
// Note: if in the future we should re-implement the legacy optimization
|
||||
// where we didn't search again when the string is the same, skip it if we
|
||||
// are committing a composition; since the search was canceled on
|
||||
// composition start, we should restart it.
|
||||
let sameSearchStrings = value == this._lastSearchString;
|
||||
|
||||
// TODO (bug 1524550): Properly detect autofill removal, rather than
|
||||
// guessing based on string prefixes.
|
||||
let deletedAutofilledSubstring =
|
||||
sameSearchStrings &&
|
||||
value.length < this._autofillPlaceholder.length &&
|
||||
this._autofillPlaceholder.startsWith(value);
|
||||
|
||||
// Don't search again when the new search would produce the same results.
|
||||
// If we're handling a composition commit, we must continue the search
|
||||
// because we canceled the previous search on composition start.
|
||||
if (sameSearchStrings &&
|
||||
!deletedAutofilledSubstring &&
|
||||
!handlingCompositionCommit &&
|
||||
value.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let allowAutofill =
|
||||
this._maybeAutofillOnInput(value, deletedAutofilledSubstring);
|
||||
|
||||
// XXX Fill in lastKey, and add anything else we need.
|
||||
this.startQuery({
|
||||
searchString: value,
|
||||
allowAutofill,
|
||||
lastKey: null,
|
||||
resetSearchState: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1194,6 +1327,7 @@ class UrlbarInput {
|
||||
}
|
||||
|
||||
_on_TabSelect(event) {
|
||||
this._resetSearchState();
|
||||
this.controller.viewContextChanged();
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ class ProviderUnifiedComplete extends UrlbarProvider {
|
||||
if (queryContext.userContextId) {
|
||||
params.push(`user-context-id:${queryContext.userContextId}}`);
|
||||
}
|
||||
if (!queryContext.enableAutofill) {
|
||||
if (!queryContext.allowAutofill) {
|
||||
params.push("prohibit-autofill");
|
||||
}
|
||||
|
||||
|
@ -389,12 +389,12 @@ class UrlbarQueryContext {
|
||||
* Set to true if this query was started from a private browsing window.
|
||||
* @param {number} options.maxResults
|
||||
* The maximum number of results that will be displayed for this query.
|
||||
* @param {boolean} options.enableAutofill
|
||||
* Whether or not to include autofill results.
|
||||
* @param {boolean} options.allowAutofill
|
||||
* Whether or not to allow providers to include autofill results.
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this._checkRequiredOptions(options, [
|
||||
"enableAutofill",
|
||||
"allowAutofill",
|
||||
"isPrivate",
|
||||
"lastKey",
|
||||
"maxResults",
|
||||
|
@ -46,15 +46,24 @@ var UrlbarTestUtils = {
|
||||
let urlbar = getUrlbarAbstraction(win);
|
||||
let restoreAnimationsFn = urlbar.disableAnimations();
|
||||
await new Promise(resolve => waitForFocus(resolve, win));
|
||||
let lastSearchString = urlbar.lastSearchString;
|
||||
urlbar.focus();
|
||||
urlbar.value = inputText;
|
||||
if (fireInputEvent) {
|
||||
// This is necessary to get the urlbar to set gBrowser.userTypedValue.
|
||||
urlbar.fireInputEvent();
|
||||
}
|
||||
// In the quantum bar it's enough to fire the input event to start a query,
|
||||
// invoking startSearch would do it twice.
|
||||
if (!urlbar.quantumbar || !fireInputEvent) {
|
||||
// With awesomebar, we must call startSearch to start the search. With
|
||||
// quantumbar, we can either fire an input event or call start search, so be
|
||||
// careful not to do both since that would start two searches. However,
|
||||
// there's one wrinkle with quantumbar: If the new search and old search are
|
||||
// the same, the input event will *not* start a new search, by design. Many
|
||||
// existing tests do consecutive searches with the same string and expect
|
||||
// new searches to start. To keep those tests running, call startSearch
|
||||
// directly in those cases.
|
||||
if (!urlbar.quantumbar ||
|
||||
!fireInputEvent ||
|
||||
inputText == lastSearchString) {
|
||||
urlbar.startSearch(inputText);
|
||||
}
|
||||
return this.promiseSearchComplete(win, restoreAnimationsFn);
|
||||
@ -288,6 +297,11 @@ class UrlbarAbstraction {
|
||||
return this.urlbar.value;
|
||||
}
|
||||
|
||||
get lastSearchString() {
|
||||
return this.quantumbar ? this.urlbar._lastSearchString :
|
||||
this.urlbar.controller.searchString;
|
||||
}
|
||||
|
||||
get panel() {
|
||||
return this.quantumbar ? this.urlbar.panel : this.urlbar.popup;
|
||||
}
|
||||
|
@ -24,13 +24,10 @@ skip-if = true # Bug 1524539 - need to fix a11y. When removing this line, uncomm
|
||||
skip-if = os != "mac" # Mac only feature
|
||||
[browser_autocomplete_tag_star_visibility.js]
|
||||
[browser_autoFill_backspaced.js]
|
||||
skip-if = true # Bug 1531348 - Failing with QuantumBar.
|
||||
[browser_autoFill_canonize.js]
|
||||
skip-if = true # Bug 1531348 - Failing with QuantumBar.
|
||||
[browser_autoFill_caretNotAtEnd.js]
|
||||
[browser_autoFill_preserveCase.js]
|
||||
skip-if = true # Bug 1531348 - Failing with QuantumBar.
|
||||
[browser_autoFill_trimURLs.js]
|
||||
skip-if = true # Bug 1531348 - Failing with QuantumBar.
|
||||
[browser_canonizeURL.js]
|
||||
[browser_caret_navigation.js]
|
||||
[browser_dragdropURL.js]
|
||||
@ -108,7 +105,6 @@ support-files =
|
||||
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux/e10s
|
||||
[browser_urlbarFocusedCmdK.js]
|
||||
[browser_urlbarHashChangeProxyState.js]
|
||||
[browser_UrlbarInput_autofill.js]
|
||||
[browser_UrlbarInput_formatValue.js]
|
||||
[browser_UrlbarInput_hiddenFocus.js]
|
||||
[browser_UrlbarInput_overflow.js]
|
||||
|
@ -1,54 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests the autofill functionality of UrlbarInput.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function setValueFromResult() {
|
||||
gURLBar.setValueFromResult({
|
||||
autofill: {
|
||||
value: "foobar",
|
||||
selectionStart: "foo".length,
|
||||
selectionEnd: "foobar".length,
|
||||
},
|
||||
type: UrlbarUtils.RESULT_TYPE.URL,
|
||||
});
|
||||
Assert.equal(gURLBar.value, "foobar",
|
||||
"The input value should be correct");
|
||||
Assert.equal(gURLBar.selectionStart, "foo".length,
|
||||
"The start of the selection should be correct");
|
||||
Assert.equal(gURLBar.selectionEnd, "foobar".length,
|
||||
"The end of the selection should be correct");
|
||||
});
|
||||
|
||||
add_task(async function noAutofillWhenCaretNotAtEnd() {
|
||||
gURLBar.focus();
|
||||
|
||||
// Autofill is disabled when the new search starts with the previous search,
|
||||
// so to make sure that doesn't mess up this test, trigger a search now.
|
||||
EventUtils.sendString("blah");
|
||||
|
||||
// Add a visit that can be autofilled.
|
||||
await PlacesUtils.history.clear();
|
||||
await PlacesTestUtils.addVisits([{
|
||||
uri: "http://example.com/",
|
||||
}]);
|
||||
|
||||
// Fill the input with xample.com.
|
||||
gURLBar.inputField.value = "xample.com";
|
||||
|
||||
// Move the caret to the beginning and type e.
|
||||
gURLBar.selectionStart = 0;
|
||||
gURLBar.selectionEnd = 0;
|
||||
EventUtils.sendString("e");
|
||||
|
||||
// Get the first result.
|
||||
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
|
||||
Assert.ok(!result.autofill, "The first result should not be autofill");
|
||||
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
@ -165,7 +165,7 @@ add_task(async function test_autofill_disabled_on_prefix_search() {
|
||||
});
|
||||
checkStartQueryCall(fakeController.startQuery, {
|
||||
searchString: "autofill",
|
||||
enableAutofill: true,
|
||||
allowAutofill: true,
|
||||
});
|
||||
|
||||
// search for "auto" -- autofill should be disabled since the previous
|
||||
@ -177,7 +177,7 @@ add_task(async function test_autofill_disabled_on_prefix_search() {
|
||||
});
|
||||
checkStartQueryCall(fakeController.startQuery, {
|
||||
searchString: "auto",
|
||||
enableAutofill: false,
|
||||
allowAutofill: false,
|
||||
}, 1);
|
||||
|
||||
// search for "autofill" again -- autofill should be enabled
|
||||
@ -188,7 +188,7 @@ add_task(async function test_autofill_disabled_on_prefix_search() {
|
||||
});
|
||||
checkStartQueryCall(fakeController.startQuery, {
|
||||
searchString: "autofill",
|
||||
enableAutofill: true,
|
||||
allowAutofill: true,
|
||||
}, 2);
|
||||
|
||||
sandbox.resetHistory();
|
||||
|
@ -16,6 +16,7 @@ async function test_autocomplete(data) {
|
||||
if (onAutoFill)
|
||||
onAutoFill();
|
||||
|
||||
info("Synthesizing keys");
|
||||
keys.forEach(key => EventUtils.synthesizeKey(key));
|
||||
|
||||
Assert.equal(gURLBar.textValue, modified, "backspaced value is as expected");
|
||||
|
@ -0,0 +1,33 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function noAutofillWhenCaretNotAtEnd() {
|
||||
gURLBar.focus();
|
||||
|
||||
// Add a visit that can be autofilled.
|
||||
await PlacesUtils.history.clear();
|
||||
await PlacesTestUtils.addVisits([{
|
||||
uri: "http://example.com/",
|
||||
}]);
|
||||
|
||||
// Fill the input with xample.
|
||||
gURLBar.inputField.value = "xample";
|
||||
|
||||
// Move the caret to the beginning and type e.
|
||||
gURLBar.selectionStart = 0;
|
||||
gURLBar.selectionEnd = 0;
|
||||
EventUtils.sendString("e");
|
||||
|
||||
// Check the first result and input.
|
||||
let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 0);
|
||||
Assert.ok(!result.autofill, "The first result should not be autofill");
|
||||
|
||||
Assert.equal(gURLBar.value, "example");
|
||||
Assert.equal(gURLBar.selectionStart, 1);
|
||||
Assert.equal(gURLBar.selectionEnd, 1);
|
||||
|
||||
await UrlbarTestUtils.promisePopupClose(window);
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
@ -38,7 +38,7 @@ async function promiseSearch(searchtext) {
|
||||
}
|
||||
|
||||
async function promiseTestResult(test) {
|
||||
info("Searching for '${test.search}'");
|
||||
info(`Searching for '${test.search}'`);
|
||||
|
||||
await promiseSearch(test.search);
|
||||
|
||||
@ -61,31 +61,34 @@ async function promiseTestResult(test) {
|
||||
Assert.equal(result.type, test.resultListType,
|
||||
`Autocomplete result should have searchengine for the type for search '${test.search}'`);
|
||||
|
||||
if (UrlbarPrefs.get("quantumbar")) {
|
||||
Assert.equal(result.url, test.expectedUrl, "Should have the correct URL");
|
||||
} else {
|
||||
let actualValue = gURLBar.mController.getFinalCompleteValueAt(0);
|
||||
let actualAction = PlacesUtils.parseActionUrl(actualValue);
|
||||
let expectedAction = PlacesUtils.parseActionUrl(test.finalCompleteValue);
|
||||
Assert.equal(!!actualAction, !!expectedAction,
|
||||
"Should have an action if expected");
|
||||
if (actualAction) {
|
||||
Assert.deepEqual(actualAction, expectedAction,
|
||||
"Should have the correct action details");
|
||||
} else {
|
||||
Assert.equal(actualValue, test.finalCompleteValue,
|
||||
"Should have the correct action details");
|
||||
Assert.equal(!!result.searchParams, !!test.searchParams,
|
||||
"Should have search params if expected");
|
||||
if (test.searchParams) {
|
||||
let definedParams = {};
|
||||
for (let [k, v] of Object.entries(result.searchParams)) {
|
||||
if (v !== undefined) {
|
||||
definedParams[k] = v;
|
||||
}
|
||||
}
|
||||
Assert.deepEqual(definedParams, test.searchParams,
|
||||
"Shoud have the correct search params");
|
||||
} else {
|
||||
Assert.equal(result.url, test.finalCompleteValue,
|
||||
"Should have the correct URL/finalCompleteValue");
|
||||
}
|
||||
}
|
||||
|
||||
const tests = [{
|
||||
const tests = [
|
||||
{
|
||||
search: "http://",
|
||||
autofilledValue: "http://",
|
||||
resultListDisplayTitle: "http://",
|
||||
resultListActionText: "Search with Google",
|
||||
resultListType: UrlbarUtils.RESULT_TYPE.SEARCH,
|
||||
finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"http%3A%2F%2F","searchQuery":"http%3A%2F%2F"}',
|
||||
searchParams: {
|
||||
engine: "Google",
|
||||
query: "http://",
|
||||
},
|
||||
},
|
||||
{
|
||||
search: "https://",
|
||||
@ -93,7 +96,10 @@ const tests = [{
|
||||
resultListDisplayTitle: "https://",
|
||||
resultListActionText: "Search with Google",
|
||||
resultListType: UrlbarUtils.RESULT_TYPE.SEARCH,
|
||||
finalCompleteValue: 'moz-action:searchengine,{"engineName":"Google","input":"https%3A%2F%2F","searchQuery":"https%3A%2F%2F"}',
|
||||
searchParams: {
|
||||
engine: "Google",
|
||||
query: "https://",
|
||||
},
|
||||
},
|
||||
{
|
||||
search: "au",
|
||||
|
@ -320,8 +320,8 @@ async function doSimpleTest(revertBetweenSteps) {
|
||||
});
|
||||
|
||||
// "@tes" -- not an alias, no highlight
|
||||
gURLBar.search(ALIAS.substr(0, ALIAS.length - 1));
|
||||
await promiseSearchComplete();
|
||||
await promiseAutocompleteResultPopup(ALIAS.substr(0, ALIAS.length - 1),
|
||||
window, true);
|
||||
await waitForAutocompleteResultAt(0);
|
||||
await assertAlias(false);
|
||||
|
||||
@ -331,8 +331,7 @@ async function doSimpleTest(revertBetweenSteps) {
|
||||
}
|
||||
|
||||
// "@test" -- alias, highlight
|
||||
gURLBar.search(ALIAS);
|
||||
await promiseSearchComplete();
|
||||
await promiseAutocompleteResultPopup(ALIAS, window, true);
|
||||
await waitForAutocompleteResultAt(0);
|
||||
await assertAlias(true);
|
||||
|
||||
@ -342,8 +341,7 @@ async function doSimpleTest(revertBetweenSteps) {
|
||||
}
|
||||
|
||||
// "@test foo" -- alias, highlight
|
||||
gURLBar.search(ALIAS + " foo");
|
||||
await promiseSearchComplete();
|
||||
await promiseAutocompleteResultPopup(ALIAS + " foo", window, true);
|
||||
await waitForAutocompleteResultAt(0);
|
||||
await assertAlias(true);
|
||||
|
||||
@ -353,8 +351,7 @@ async function doSimpleTest(revertBetweenSteps) {
|
||||
}
|
||||
|
||||
// "@test" -- alias, highlight
|
||||
gURLBar.search(ALIAS);
|
||||
await promiseSearchComplete();
|
||||
await promiseAutocompleteResultPopup(ALIAS, window, true);
|
||||
await waitForAutocompleteResultAt(0);
|
||||
await assertAlias(true);
|
||||
|
||||
@ -364,8 +361,8 @@ async function doSimpleTest(revertBetweenSteps) {
|
||||
}
|
||||
|
||||
// "@tes" -- not an alias, no highlight
|
||||
gURLBar.search(ALIAS.substr(0, ALIAS.length - 1));
|
||||
await promiseSearchComplete();
|
||||
await promiseAutocompleteResultPopup(ALIAS.substr(0, ALIAS.length - 1),
|
||||
window, true);
|
||||
await waitForAutocompleteResultAt(0);
|
||||
await assertAlias(false);
|
||||
|
||||
|
@ -35,7 +35,7 @@ const {sinon} = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||
*/
|
||||
function createContext(searchString = "foo", properties = {}) {
|
||||
let context = new UrlbarQueryContext({
|
||||
enableAutofill: UrlbarPrefs.get("autoFill"),
|
||||
allowAutofill: UrlbarPrefs.get("autoFill"),
|
||||
isPrivate: true,
|
||||
lastKey: searchString ? searchString[searchString.length - 1] : "",
|
||||
maxResults: UrlbarPrefs.get("maxRichResults"),
|
||||
|
@ -149,7 +149,7 @@ add_task(function test_handle_query_starts_search() {
|
||||
sandbox.resetHistory();
|
||||
});
|
||||
|
||||
add_task(function test_handle_query_starts_search_sets_enableAutofill() {
|
||||
add_task(function test_handle_query_starts_search_sets_allowAutofill() {
|
||||
let originalValue = Services.prefs.getBoolPref("browser.urlbar.autoFill");
|
||||
Services.prefs.setBoolPref("browser.urlbar.autoFill", !originalValue);
|
||||
|
||||
@ -161,7 +161,7 @@ add_task(function test_handle_query_starts_search_sets_enableAutofill() {
|
||||
"Should have called startQuery with two arguments");
|
||||
|
||||
assertContextMatches(fPM.startQuery.args[0][0], {
|
||||
enableAutofill: !originalValue,
|
||||
allowAutofill: !originalValue,
|
||||
});
|
||||
Assert.equal(fPM.startQuery.args[0][1], controller,
|
||||
"Should have passed the controller as the second argument");
|
||||
|
@ -5,11 +5,11 @@
|
||||
|
||||
add_task(function test_constructor() {
|
||||
Assert.throws(() => new UrlbarQueryContext(),
|
||||
/Missing or empty enableAutofill provided to UrlbarQueryContext/,
|
||||
/Missing or empty allowAutofill provided to UrlbarQueryContext/,
|
||||
"Should throw with no arguments");
|
||||
|
||||
Assert.throws(() => new UrlbarQueryContext({
|
||||
enableAutofill: true,
|
||||
allowAutofill: true,
|
||||
isPrivate: false,
|
||||
maxResults: 1,
|
||||
searchString: "foo",
|
||||
@ -17,7 +17,7 @@ add_task(function test_constructor() {
|
||||
"Should throw with a missing lastKey parameter");
|
||||
|
||||
Assert.throws(() => new UrlbarQueryContext({
|
||||
enableAutofill: true,
|
||||
allowAutofill: true,
|
||||
isPrivate: false,
|
||||
lastKey: "b",
|
||||
searchString: "foo",
|
||||
@ -25,7 +25,7 @@ add_task(function test_constructor() {
|
||||
"Should throw with a missing maxResults parameter");
|
||||
|
||||
Assert.throws(() => new UrlbarQueryContext({
|
||||
enableAutofill: true,
|
||||
allowAutofill: true,
|
||||
lastKey: "b",
|
||||
maxResults: 1,
|
||||
searchString: "foo",
|
||||
@ -37,19 +37,19 @@ add_task(function test_constructor() {
|
||||
lastKey: "b",
|
||||
maxResults: 1,
|
||||
searchString: "foo",
|
||||
}), /Missing or empty enableAutofill provided to UrlbarQueryContext/,
|
||||
"Should throw with a missing enableAutofill parameter");
|
||||
}), /Missing or empty allowAutofill provided to UrlbarQueryContext/,
|
||||
"Should throw with a missing allowAutofill parameter");
|
||||
|
||||
let qc = new UrlbarQueryContext({
|
||||
enableAutofill: false,
|
||||
allowAutofill: false,
|
||||
isPrivate: true,
|
||||
lastKey: "b",
|
||||
maxResults: 1,
|
||||
searchString: "foo",
|
||||
});
|
||||
|
||||
Assert.strictEqual(qc.enableAutofill, false,
|
||||
"Should have saved the correct value for enableAutofill");
|
||||
Assert.strictEqual(qc.allowAutofill, false,
|
||||
"Should have saved the correct value for allowAutofill");
|
||||
Assert.strictEqual(qc.isPrivate, true,
|
||||
"Should have saved the correct value for isPrivate");
|
||||
Assert.equal(qc.lastKey, "b",
|
||||
|
@ -55,7 +55,10 @@ It is augmented as it progresses through the system, with various information:
|
||||
.. code::
|
||||
|
||||
UrlbarQueryContext {
|
||||
enableAutofill; // {boolean} Whether or not to include autofill results.
|
||||
allowAutofill; // {boolean} If true, providers are allowed to return
|
||||
// autofill results. Even if true, it's up to providers
|
||||
// whether to include autofill results, but when false, no
|
||||
// provider should include them.
|
||||
isPrivate; // {boolean} Whether the search started in a private context.
|
||||
lastKey; // {string} The last key pressed by the user. This can affect the
|
||||
// behavior, for example by not autofilling again when the user
|
||||
|
@ -592,7 +592,7 @@ toolbarpaletteitem[place=toolbar] > toolbarspring {
|
||||
|
||||
%ifdef XP_UNIX
|
||||
%ifndef XP_MACOSX
|
||||
#customization-palette[whimsypong] > toolbarpaletteitem > toolbarspring {
|
||||
#customization-palette[whimsypong] > toolbarpaletteitem[id^="wrapper-customizableui-special-spring"] {
|
||||
font-size: 12px;
|
||||
}
|
||||
%endif
|
||||
|
@ -111,9 +111,17 @@ void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
|
||||
unless(
|
||||
anyOf(
|
||||
MozKnownLiveCall,
|
||||
// MOZ_KnownLive applied to a RefPtr or nsCOMPtr just returns that
|
||||
// same RefPtr/nsCOMPtr type which causes us to have a conversion
|
||||
// operator applied after the MOZ_KnownLive.
|
||||
// MOZ_KnownLive applied to a smartptr just returns that
|
||||
// same smartptr type which causes us to have a conversion
|
||||
// operator applied after the MOZ_KnownLive. Allow that by
|
||||
// allowing member calls on the result of MOZ_KnownLive, but only
|
||||
// if the type is a known smartptr type. Otherwise we would think
|
||||
// that things of the form "MOZ_KnownLive(someptr)->foo()" are
|
||||
// live!
|
||||
//
|
||||
// This relies on member calls on smartptr types that return a
|
||||
// refcounted pointer only returning the pointer the smartptr is
|
||||
// keeping alive.
|
||||
cxxMemberCallExpr(on(allOf(hasType(isSmartPtrToRefCounted()),
|
||||
MozKnownLiveCall)))
|
||||
)
|
||||
@ -331,6 +339,6 @@ void CanRunScriptChecker::check(const MatchFinder::MatchResult &Result) {
|
||||
<< CallRange;
|
||||
|
||||
diag(ParentFunction->getCanonicalDecl()->getLocation(),
|
||||
NoteNonCanRunScriptParent, DiagnosticIDs::Note);
|
||||
NoteNonCanRunScriptParent, DiagnosticIDs::Note);
|
||||
}
|
||||
}
|
||||
|
@ -282,3 +282,29 @@ struct AllowKnownLiveMemberArgs {
|
||||
test2(MOZ_KnownLive(mRefCounted));
|
||||
}
|
||||
};
|
||||
|
||||
struct WeakPtrReturner : public RefCountedBase {
|
||||
RefCountedBase* getWeakPtr() { return new RefCountedBase(); }
|
||||
};
|
||||
|
||||
struct DisallowMemberCallsOnRandomKnownLive {
|
||||
RefPtr<WeakPtrReturner> mWeakPtrReturner1;
|
||||
WeakPtrReturner* mWeakPtrReturner2;
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void test_refptr_method() {
|
||||
MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void test_refptr_function() {
|
||||
test2(MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void test_raw_method() {
|
||||
MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT void test_raw_function() {
|
||||
test2(MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()); // expected-error {{arguments must all be strong refs or parent parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument)}}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1198,7 +1198,8 @@ def check_have_64_bit(have_64_bit, compiler_have_64_bit):
|
||||
def default_debug_flags(compiler_info, target):
|
||||
# Debug info is ON by default.
|
||||
if compiler_info.type == 'clang-cl':
|
||||
return '-Z7'
|
||||
# -fno-limit-debug-info works around https://llvm.org/pr38944
|
||||
return '-Z7 -fno-limit-debug-info'
|
||||
elif target.kernel == 'WINNT' and compiler_info.type == 'clang':
|
||||
return '-g -gcodeview'
|
||||
return '-g'
|
||||
|
@ -109,7 +109,6 @@ const AboutDebugging = {
|
||||
async destroy() {
|
||||
const width = this.getRoundedViewportWidth();
|
||||
this.actions.recordTelemetryEvent("close_adbg", { width });
|
||||
l10n.destroy();
|
||||
|
||||
const state = this.store.getState();
|
||||
const currentRuntimeId = state.runtimes.selectedRuntimeId;
|
||||
|
@ -17,7 +17,7 @@ const Switch = createFactory(require("devtools/client/shared/vendor/react-router
|
||||
const Redirect = createFactory(require("devtools/client/shared/vendor/react-router-dom").Redirect);
|
||||
|
||||
const Types = require("../types/index");
|
||||
const { RUNTIMES } = require("../constants");
|
||||
const { PAGE_TYPES, RUNTIMES } = require("../constants");
|
||||
|
||||
const ConnectPage = createFactory(require("./connect/ConnectPage"));
|
||||
const RuntimePage = createFactory(require("./RuntimePage"));
|
||||
@ -34,13 +34,11 @@ class App extends PureComponent {
|
||||
// getString prop is injected by the withLocalization wrapper
|
||||
getString: PropTypes.func.isRequired,
|
||||
isScanningUsb: PropTypes.bool.isRequired,
|
||||
networkEnabled: PropTypes.bool.isRequired,
|
||||
networkLocations: PropTypes.arrayOf(Types.location).isRequired,
|
||||
networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
|
||||
selectedPage: Types.page,
|
||||
selectedRuntimeId: PropTypes.string,
|
||||
usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
|
||||
wifiEnabled: PropTypes.bool.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
@ -51,34 +49,24 @@ class App extends PureComponent {
|
||||
updateTitle() {
|
||||
const { getString, selectedPage, selectedRuntimeId } = this.props;
|
||||
|
||||
const runtimeTitle = selectedRuntimeId ?
|
||||
getString(
|
||||
"about-debugging-page-title-with-runtime",
|
||||
{ selectedPage, selectedRuntimeId }
|
||||
)
|
||||
: getString(
|
||||
"about-debugging-page-title",
|
||||
{ selectedPage }
|
||||
);
|
||||
const pageTitle = selectedPage === PAGE_TYPES.RUNTIME ?
|
||||
getString("about-debugging-page-title-runtime-page", { selectedRuntimeId }) :
|
||||
getString("about-debugging-page-title-setup-page");
|
||||
|
||||
document.title = runtimeTitle;
|
||||
document.title = pageTitle;
|
||||
}
|
||||
|
||||
renderConnect() {
|
||||
const {
|
||||
adbAddonStatus,
|
||||
dispatch,
|
||||
networkEnabled,
|
||||
networkLocations,
|
||||
wifiEnabled,
|
||||
} = this.props;
|
||||
|
||||
return ConnectPage({
|
||||
adbAddonStatus,
|
||||
dispatch,
|
||||
networkEnabled,
|
||||
networkLocations,
|
||||
wifiEnabled,
|
||||
});
|
||||
}
|
||||
|
||||
@ -182,13 +170,11 @@ const mapStateToProps = state => {
|
||||
return {
|
||||
adbAddonStatus: state.ui.adbAddonStatus,
|
||||
isScanningUsb: state.ui.isScanningUsb,
|
||||
networkEnabled: state.ui.networkEnabled,
|
||||
networkLocations: state.ui.networkLocations,
|
||||
networkRuntimes: state.runtimes.networkRuntimes,
|
||||
selectedPage: state.ui.selectedPage,
|
||||
selectedRuntimeId: state.runtimes.selectedRuntimeId,
|
||||
usbRuntimes: state.runtimes.usbRuntimes,
|
||||
wifiEnabled: state.ui.wifiEnabled,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -62,14 +62,19 @@ class RuntimeInfo extends PureComponent {
|
||||
deviceName
|
||||
) : null,
|
||||
runtimeId !== RUNTIMES.THIS_FIREFOX ?
|
||||
dom.button(
|
||||
Localized(
|
||||
{
|
||||
className: "default-button runtime-info__action qa-runtime-info__action",
|
||||
onClick() {
|
||||
dispatch(Actions.disconnectRuntime(runtimeId, true));
|
||||
},
|
||||
id: "about-debugging-runtime-disconnect-button",
|
||||
},
|
||||
"Disconnect"
|
||||
dom.button(
|
||||
{
|
||||
className: "default-button runtime-info__action qa-runtime-info__action",
|
||||
onClick() {
|
||||
dispatch(Actions.disconnectRuntime(runtimeId, true));
|
||||
},
|
||||
},
|
||||
"Disconnect"
|
||||
)
|
||||
) : null,
|
||||
);
|
||||
}
|
||||
|
@ -2,10 +2,6 @@
|
||||
* 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/. */
|
||||
|
||||
.connect-page__disabled-section {
|
||||
color: var(--grey-40);
|
||||
}
|
||||
|
||||
.connect-page__breather {
|
||||
margin-block-start: calc(var(--base-unit) * 6);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ const ConnectSteps = createFactory(require("./ConnectSteps"));
|
||||
const NetworkLocationsForm = createFactory(require("./NetworkLocationsForm"));
|
||||
const NetworkLocationsList = createFactory(require("./NetworkLocationsList"));
|
||||
|
||||
const { PREFERENCES, PAGE_TYPES, RUNTIMES } = require("../../constants");
|
||||
const { PAGE_TYPES, RUNTIMES } = require("../../constants");
|
||||
const Types = require("../../types/index");
|
||||
|
||||
const USB_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-usb-icon.svg";
|
||||
@ -36,11 +36,7 @@ class ConnectPage extends PureComponent {
|
||||
return {
|
||||
adbAddonStatus: Types.adbAddonStatus,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
// Provided by wrapping the component with FluentReact.withLocalization.
|
||||
getString: PropTypes.func.isRequired,
|
||||
networkEnabled: PropTypes.bool.isRequired,
|
||||
networkLocations: PropTypes.arrayOf(Types.location).isRequired,
|
||||
wifiEnabled: PropTypes.bool.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
@ -180,41 +176,23 @@ class ConnectPage extends PureComponent {
|
||||
}
|
||||
|
||||
renderNetwork() {
|
||||
const { dispatch, networkEnabled, networkLocations } = this.props;
|
||||
const { dispatch, networkLocations } = this.props;
|
||||
|
||||
return Localized(
|
||||
{
|
||||
id: "about-debugging-connect-network",
|
||||
id: "about-debugging-setup-network",
|
||||
attrs: { title: true },
|
||||
},
|
||||
ConnectSection(
|
||||
{
|
||||
className: "connect-page__breather",
|
||||
icon: GLOBE_ICON_SRC,
|
||||
title: "Network Location",
|
||||
extraContent: networkEnabled
|
||||
? dom.div(
|
||||
{},
|
||||
NetworkLocationsList({ dispatch, networkLocations }),
|
||||
NetworkLocationsForm({ dispatch }),
|
||||
)
|
||||
: null,
|
||||
},
|
||||
networkEnabled
|
||||
? null
|
||||
: Localized(
|
||||
{
|
||||
id: "about-debugging-connect-network-disabled",
|
||||
$pref: PREFERENCES.NETWORK_ENABLED,
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
className: "connect-page__disabled-section",
|
||||
},
|
||||
"about-debugging-connect-network-disabled"
|
||||
)
|
||||
),
|
||||
)
|
||||
ConnectSection({
|
||||
className: "connect-page__breather",
|
||||
icon: GLOBE_ICON_SRC,
|
||||
title: "Network Location",
|
||||
extraContent: dom.div(
|
||||
{},
|
||||
NetworkLocationsList({ dispatch, networkLocations }),
|
||||
NetworkLocationsForm({ dispatch }),
|
||||
),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@ -225,7 +203,7 @@ class ConnectPage extends PureComponent {
|
||||
},
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-connect-title",
|
||||
id: "about-debugging-setup-title",
|
||||
},
|
||||
dom.h1(
|
||||
{
|
||||
@ -243,12 +221,12 @@ class ConnectPage extends PureComponent {
|
||||
"Configure the connection method you wish to remotely debug your device with."
|
||||
)
|
||||
),
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-setup-link-android-devices",
|
||||
},
|
||||
dom.p(
|
||||
{},
|
||||
dom.p(
|
||||
{},
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-setup-link-android-devices",
|
||||
},
|
||||
dom.a(
|
||||
{
|
||||
href: "https://support.mozilla.org/kb/will-firefox-work-my-mobile-device#w_android-devices",
|
||||
|
@ -132,7 +132,7 @@ class ExtensionDetail extends PureComponent {
|
||||
|
||||
return Localized(
|
||||
{
|
||||
id: "about-debugging-extension-manifest-link",
|
||||
id: "about-debugging-extension-manifest-url",
|
||||
attrs: { label: true },
|
||||
},
|
||||
FieldPair(
|
||||
|
@ -48,6 +48,20 @@ class ServiceWorkerAction extends PureComponent {
|
||||
});
|
||||
}
|
||||
|
||||
_getStatusLocalizationId(status) {
|
||||
switch (status) {
|
||||
case SERVICE_WORKER_STATUSES.REGISTERING.toLowerCase():
|
||||
return "about-debugging-worker-status-registering";
|
||||
case SERVICE_WORKER_STATUSES.RUNNING.toLowerCase():
|
||||
return "about-debugging-worker-status-running";
|
||||
case SERVICE_WORKER_STATUSES.STOPPED.toLowerCase():
|
||||
return "about-debugging-worker-status-stopped";
|
||||
default:
|
||||
// Assume status is stopped for unknown status value.
|
||||
return "about-debugging-worker-status-stopped";
|
||||
}
|
||||
}
|
||||
|
||||
_renderStatus() {
|
||||
const status = this.props.target.details.status.toLowerCase();
|
||||
const statusClassName = status === SERVICE_WORKER_STATUSES.RUNNING.toLowerCase()
|
||||
@ -55,8 +69,7 @@ class ServiceWorkerAction extends PureComponent {
|
||||
|
||||
return Localized(
|
||||
{
|
||||
id: "about-debugging-worker-status",
|
||||
$status: status,
|
||||
id: this._getStatusLocalizationId(status),
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
|
@ -95,14 +95,10 @@ const PAGE_TYPES = {
|
||||
};
|
||||
|
||||
const PREFERENCES = {
|
||||
// Temporary preference without any default value until network locations are enabled.
|
||||
NETWORK_ENABLED: "devtools.aboutdebugging.network",
|
||||
// Preference that drives the display of the "Processes" debug target category.
|
||||
PROCESS_DEBUGGING_ENABLED: "devtools.aboutdebugging.process-debugging",
|
||||
// Preference that drives the display of system addons in about:debugging.
|
||||
SHOW_SYSTEM_ADDONS: "devtools.aboutdebugging.showSystemAddons",
|
||||
// Temporary preference without any default value until wifi is enabled.
|
||||
WIFI_ENABLED: "devtools.aboutdebugging.wifi",
|
||||
};
|
||||
|
||||
const RUNTIME_PREFERENCE = {
|
||||
|
@ -49,12 +49,9 @@ function configureStore() {
|
||||
function getUiState() {
|
||||
const collapsibilities = getDebugTargetCollapsibilities();
|
||||
const locations = getNetworkLocations();
|
||||
const networkEnabled = Services.prefs.getBoolPref(PREFERENCES.NETWORK_ENABLED, false);
|
||||
const wifiEnabled = Services.prefs.getBoolPref(PREFERENCES.WIFI_ENABLED, false);
|
||||
const showSystemAddons = Services.prefs.getBoolPref(PREFERENCES.SHOW_SYSTEM_ADDONS,
|
||||
false);
|
||||
return new UiState(locations, collapsibilities, networkEnabled, wifiEnabled,
|
||||
showSystemAddons);
|
||||
return new UiState(locations, collapsibilities, showSystemAddons);
|
||||
}
|
||||
|
||||
exports.configureStore = configureStore;
|
||||
|
@ -7,26 +7,15 @@
|
||||
const Services = require("Services");
|
||||
|
||||
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
|
||||
const { L10nRegistry, FileSource } =
|
||||
require("resource://gre/modules/L10nRegistry.jsm");
|
||||
const { L10nRegistry } = require("resource://gre/modules/L10nRegistry.jsm");
|
||||
|
||||
class L10n {
|
||||
async init() {
|
||||
// XXX Until the strings for the updated about:debugging stabilize, we
|
||||
// locate them outside the regular directory for locale resources so that
|
||||
// they don't get picked up by localization tools.
|
||||
if (!L10nRegistry.sources.has("aboutdebugging")) {
|
||||
const temporarySource = new FileSource(
|
||||
"aboutdebugging",
|
||||
["en-US"],
|
||||
"chrome://devtools/content/aboutdebugging-new/tmp-locale/{locale}/"
|
||||
);
|
||||
L10nRegistry.registerSource(temporarySource);
|
||||
}
|
||||
|
||||
const locales = Services.locale.appLocalesAsBCP47;
|
||||
const generator =
|
||||
L10nRegistry.generateBundles(locales, ["aboutdebugging.ftl"]);
|
||||
const generator = L10nRegistry.generateBundles(locales, [
|
||||
"branding/brand.ftl",
|
||||
"devtools/aboutdebugging.ftl",
|
||||
]);
|
||||
|
||||
this._bundles = [];
|
||||
for await (const bundle of generator) {
|
||||
@ -51,10 +40,6 @@ class L10n {
|
||||
// - add new arguments
|
||||
return this._reactLocalization.getString.apply(this._reactLocalization, arguments);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
L10nRegistry.removeSource("aboutdebugging");
|
||||
}
|
||||
}
|
||||
|
||||
// Export a singleton that will be shared by all aboutdebugging modules.
|
||||
|
@ -18,19 +18,16 @@ const {
|
||||
} = require("../constants");
|
||||
|
||||
function UiState(locations = [], debugTargetCollapsibilities = {},
|
||||
networkEnabled = false, wifiEnabled = false,
|
||||
showSystemAddons = false) {
|
||||
return {
|
||||
adbAddonStatus: null,
|
||||
debugTargetCollapsibilities,
|
||||
isScanningUsb: false,
|
||||
networkEnabled,
|
||||
networkLocations: locations,
|
||||
selectedPage: null,
|
||||
showProfilerDialog: false,
|
||||
showSystemAddons,
|
||||
temporaryInstallError: null,
|
||||
wifiEnabled,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,8 @@ add_task(async function() {
|
||||
const connectLink = connectSidebarItem.querySelector(".js-sidebar-link");
|
||||
ok(connectSidebarItem, "Found the Connect sidebar item");
|
||||
|
||||
const thisFirefoxSidebarItem = findSidebarItemByText("This Firefox", document);
|
||||
const thisFirefoxString = getThisFirefoxString(window);
|
||||
const thisFirefoxSidebarItem = findSidebarItemByText(thisFirefoxString, document);
|
||||
const thisFirefoxLink = thisFirefoxSidebarItem.querySelector(".js-sidebar-link");
|
||||
ok(thisFirefoxSidebarItem, "Found the ThisFirefox sidebar item");
|
||||
ok(isSidebarItemSelected(thisFirefoxSidebarItem),
|
||||
|
@ -44,7 +44,8 @@ add_task(async function() {
|
||||
await waitUntil(() => findDebugTargetByText(WORKER_NAME, document));
|
||||
|
||||
info("Go to This Firefox again");
|
||||
const thisFirefoxSidebarItem = findSidebarItemByText("This Firefox", document);
|
||||
const thisFirefoxString = getThisFirefoxString(window);
|
||||
const thisFirefoxSidebarItem = findSidebarItemByText(thisFirefoxString, document);
|
||||
const thisFirefoxLink = thisFirefoxSidebarItem.querySelector(".js-sidebar-link");
|
||||
info("Click on the ThisFirefox item in the sidebar");
|
||||
const requestsSuccess = waitForRequestsSuccess(window.AboutDebugging.store);
|
||||
|
@ -21,11 +21,13 @@ add_task(async function() {
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
await selectThisFirefoxPage(document, window.AboutDebugging.store);
|
||||
|
||||
// Check that the selected sidebar item is "This Firefox"
|
||||
// Check that the selected sidebar item is "This Firefox"/"This Nightly"/...
|
||||
const selectedSidebarItem = document.querySelector(".js-sidebar-item-selected");
|
||||
ok(selectedSidebarItem, "An item is selected in the sidebar");
|
||||
is(selectedSidebarItem.textContent, "This Firefox",
|
||||
"The selected sidebar item is This Firefox");
|
||||
|
||||
const thisFirefoxString = getThisFirefoxString(window);
|
||||
is(selectedSidebarItem.textContent, thisFirefoxString,
|
||||
"The selected sidebar item is " + thisFirefoxString);
|
||||
|
||||
const paneTitlesEls = document.querySelectorAll(".js-debug-target-pane-title");
|
||||
is(paneTitlesEls.length, EXPECTED_TARGET_PANES.length,
|
||||
|
@ -41,7 +41,6 @@ registerCleanupFunction(async function() {
|
||||
*/
|
||||
async function enableNewAboutDebugging() {
|
||||
await pushPref("devtools.aboutdebugging.new-enabled", true);
|
||||
await pushPref("devtools.aboutdebugging.network", true);
|
||||
}
|
||||
|
||||
async function openAboutDebugging({ enableWorkerUpdates } = {}) {
|
||||
@ -113,8 +112,8 @@ async function reloadAboutDebugging(tab) {
|
||||
const browser = tab.linkedBrowser;
|
||||
const document = browser.contentDocument;
|
||||
const window = browser.contentWindow;
|
||||
info("wait for the initial about:debugging requests to be successful");
|
||||
await waitForRequestsSuccess(window.AboutDebugging.store);
|
||||
info("wait for the initial about:debugging requests to settle");
|
||||
await waitForRequestsToSettle(window.AboutDebugging.store);
|
||||
|
||||
return document;
|
||||
}
|
||||
@ -289,3 +288,13 @@ async function openProfilerDialog(client, doc) {
|
||||
info("Wait for the loadPerformanceProfiler callback to be executed on client-wrapper");
|
||||
return onProfilerLoaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "This Firefox" string depends on the brandShortName, which will be different
|
||||
* depending on the channel where tests are running.
|
||||
*/
|
||||
function getThisFirefoxString(aboutDebuggingWindow) {
|
||||
const loader = aboutDebuggingWindow.getBrowserLoaderForWindow();
|
||||
const { l10n } = loader.require("devtools/client/aboutdebugging-new/src/modules/l10n");
|
||||
return l10n.getString("about-debugging-this-firefox-runtime-name");
|
||||
}
|
||||
|
@ -159,7 +159,6 @@ export type TabPayload = {
|
||||
animationsActor: ActorId,
|
||||
consoleActor: ActorId,
|
||||
cssPropertiesActor: ActorId,
|
||||
cssUsageActor: ActorId,
|
||||
directorManagerActor: ActorId,
|
||||
emulationActor: ActorId,
|
||||
eventLoopLagActor: ActorId,
|
||||
|
@ -7,7 +7,7 @@
|
||||
import * as firefox from "./firefox";
|
||||
import * as chrome from "./chrome";
|
||||
|
||||
import { prefs, asyncStore, verifyPrefSchema } from "../utils/prefs";
|
||||
import { asyncStore, verifyPrefSchema } from "../utils/prefs";
|
||||
import { setupHelper } from "../utils/dbg";
|
||||
|
||||
import {
|
||||
@ -19,16 +19,6 @@ import { initialBreakpointsState } from "../reducers/breakpoints";
|
||||
|
||||
import type { Panel } from "./firefox/types";
|
||||
|
||||
function loadFromPrefs(actions: Object) {
|
||||
const { pauseOnExceptions, pauseOnCaughtExceptions } = prefs;
|
||||
if (pauseOnExceptions || pauseOnCaughtExceptions) {
|
||||
return actions.pauseOnExceptions(
|
||||
pauseOnExceptions,
|
||||
pauseOnCaughtExceptions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function syncBreakpoints() {
|
||||
const breakpoints = await asyncStore.pendingBreakpoints;
|
||||
const breakpointValues = (Object.values(breakpoints): any);
|
||||
@ -94,7 +84,6 @@ export async function onConnect(
|
||||
const workers = bootstrapWorkers();
|
||||
await client.onConnect(connection, actions);
|
||||
|
||||
await loadFromPrefs(actions);
|
||||
syncBreakpoints();
|
||||
syncXHRBreakpoints();
|
||||
setupHelper({
|
||||
|
@ -968,7 +968,7 @@ function invokeInTab(fnc, ...args) {
|
||||
fnc,
|
||||
args
|
||||
}) {
|
||||
return content.wrappedJSObject[fnc](...args); // eslint-disable-line mozilla/no-cpows-in-tests, max-len
|
||||
return content.wrappedJSObject[fnc](...args); // max-len
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,6 @@ devtools.jar:
|
||||
content/aboutdebugging/aboutdebugging.css (aboutdebugging/aboutdebugging.css)
|
||||
content/aboutdebugging-new/index.html (aboutdebugging-new/index.html)
|
||||
content/aboutdebugging-new/aboutdebugging.css (aboutdebugging-new/aboutdebugging.css)
|
||||
# The following line is temporary until the strings for the new
|
||||
# about:debugging feature stabilize.
|
||||
content/aboutdebugging-new/tmp-locale/en-US/aboutdebugging.ftl (aboutdebugging-new/tmp-locale/en-US/aboutdebugging.notftl)
|
||||
content/responsive.html/index.xhtml (responsive.html/index.xhtml)
|
||||
content/dom/index.html (dom/index.html)
|
||||
content/dom/main.js (dom/main.js)
|
||||
|
@ -2,15 +2,22 @@
|
||||
# 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/.
|
||||
|
||||
### These strings are used inside the about:debugging panel which is available
|
||||
### by setting the preference `devtools.aboutdebugging.new-enabled` to true.
|
||||
### These strings are used inside the about:debugging UI.
|
||||
|
||||
# Display name of the runtime "This Firefox". Reused as the sidebar name for This Firefox
|
||||
# (about-debugging-sidebar-this-firefox.name). Not displayed elsewhere in the application
|
||||
# at the moment.
|
||||
# This should the same string as the part outside of the parentheses in toolbox.properties
|
||||
# toolbox.debugTargetInfo.runtimeLabel.thisFirefox. See 1520525.
|
||||
about-debugging-this-firefox-runtime-name = This Firefox
|
||||
# Page Title strings
|
||||
|
||||
# Page title (ie tab title) for the Setup page
|
||||
about-debugging-page-title-setup-page = Debugging - Setup
|
||||
|
||||
# Page title (ie tab title) for the Runtime page
|
||||
# { $selectedRuntimeId } is the id of the current runtime, such as "this-firefox", "localhost:6080", ...
|
||||
about-debugging-page-title-runtime-page = Debugging - Runtime / { $selectedRuntimeId }
|
||||
|
||||
# Sidebar strings
|
||||
|
||||
# Display name of the runtime for the currently running instance of Firefox. Used in the
|
||||
# Sidebar and in the Setup page.
|
||||
about-debugging-this-firefox-runtime-name = This { -brand-shorter-name }
|
||||
|
||||
# Sidebar heading for selecting the currently running instance of Firefox
|
||||
about-debugging-sidebar-this-firefox =
|
||||
@ -56,21 +63,43 @@ about-debugging-sidebar-runtime-item-name =
|
||||
about-debugging-sidebar-runtime-item-name-no-device =
|
||||
.title = { $displayName }
|
||||
|
||||
# Temporary text displayed in a sidebar button to refresh USB devices. Temporary
|
||||
# UI, do not localize.
|
||||
# Text displayed in a sidebar button to refresh the list of USB devices. Clicking on it
|
||||
# will attempt to update the list of devices displayed in the sidebar.
|
||||
about-debugging-refresh-usb-devices-button = Refresh devices
|
||||
|
||||
# Setup Page strings
|
||||
|
||||
# Title of the Setup page.
|
||||
about-debugging-connect-title = Setup
|
||||
about-debugging-setup-title = Setup
|
||||
|
||||
# Introduction text in the Setup page to explain how to configure remote debugging.
|
||||
about-debugging-setup-intro = Configure the connection method you wish to remotely debug your device with.
|
||||
|
||||
# Link displayed in the Setup page that leads to MDN page with list of supported devices.
|
||||
# Temporarily leads to https://support.mozilla.org/en-US/kb/will-firefox-work-my-mobile-device#w_android-devices
|
||||
about-debugging-setup-link-android-devices = View list of supported Android devices
|
||||
|
||||
# Explanatory text in the Setup page about what the 'This Firefox' page is for
|
||||
about-debugging-setup-this-firefox = Use <a>This Firefox</a> to debug tags, extensions and service workers on this version of Firefox.
|
||||
about-debugging-setup-this-firefox = Use <a>{ about-debugging-this-firefox-runtime-name }</a> to debug tabs, extensions and service workers on this version of { -brand-shorter-name }.
|
||||
|
||||
# Title of the heading Connect section of the Setup page.
|
||||
about-debugging-setup-connect-heading = Connect a Device
|
||||
|
||||
# USB section of the Setup page
|
||||
about-debugging-setup-usb-title = USB
|
||||
about-debugging-setup-usb-disabled = Enabling this will download and add the required Android USB debugging components to Firefox.
|
||||
|
||||
# Explanatory text displayed in the Setup page when USB debugging is disabled
|
||||
about-debugging-setup-usb-disabled = Enabling this will download and add the required Android USB debugging components to { -brand-shorter-name }.
|
||||
|
||||
# Text of the button displayed in the USB section of the setup page when USB debugging is disabled.
|
||||
# Clicking on it will download components needed to debug USB Devices remotely.
|
||||
about-debugging-setup-usb-enable-button = Enable USB Devices
|
||||
|
||||
# Text of the button displayed in the USB section of the setup page when USB debugging is enabled.
|
||||
about-debugging-setup-usb-disable-button = Disable USB Devices
|
||||
|
||||
# Text of the button displayed in the USB section of the setup page while USB debugging
|
||||
# components are downloaded and installed.
|
||||
about-debugging-setup-usb-updating-button = Updating…
|
||||
|
||||
# USB section of the Setup page (USB status)
|
||||
@ -90,14 +119,27 @@ about-debugging-setup-usb-step-enable-debug-firefox = Enable USB Debugging in Fi
|
||||
# USB section step by step guide
|
||||
about-debugging-setup-usb-step-plug-device = Connect the Android device to your computer.
|
||||
|
||||
# Network section of the Connect page
|
||||
about-debugging-connect-network =
|
||||
# Network section of the Setup page
|
||||
about-debugging-setup-network =
|
||||
.title = Network Location
|
||||
|
||||
# Temporary text displayed when network location support is turned off via preferences.
|
||||
# { $pref } is the name of the preference that enables network locations
|
||||
# Do not localize
|
||||
about-debugging-connect-network-disabled = Network location support currently under development. You can enable it with the preference “{ $pref }”.
|
||||
# Text of a button displayed after the network locations "Host" input.
|
||||
# Clicking on it will add the new network location to the list.
|
||||
about-debugging-network-locations-add-button = Add
|
||||
|
||||
# Text to display when there are no locations to show.
|
||||
about-debugging-network-locations-empty-text = No network locations have been added yet.
|
||||
|
||||
# Text of the label for the text input that allows users to add new network locations in
|
||||
# the Connect page. A host is a hostname and a port separated by a colon, as suggested by
|
||||
# the input's placeholder "localhost:6080".
|
||||
about-debugging-network-locations-host-input-label = Host
|
||||
|
||||
# Text of a button displayed next to existing network locations in the Connect page.
|
||||
# Clicking on it removes the network location from the list.
|
||||
about-debugging-network-locations-remove-button = Remove
|
||||
|
||||
# Runtime Page strings
|
||||
|
||||
# Below are the titles for the various categories of debug targets that can be found
|
||||
# on "runtime" pages of about:debugging.
|
||||
@ -119,6 +161,9 @@ about-debugging-runtime-shared-workers =
|
||||
# Title of the other workers category.
|
||||
about-debugging-runtime-other-workers =
|
||||
.name = Other Workers
|
||||
# Title of the processes category.
|
||||
about-debugging-runtime-processes =
|
||||
.name = Processes
|
||||
|
||||
# Label of the button opening the performance profiler panel in runtime pages for remote
|
||||
# runtimes.
|
||||
@ -149,7 +194,40 @@ about-debugging-runtime-version-too-old-67-debugger = The Debugger panel may not
|
||||
# { $localID } is the build ID of the current Firefox instance (same format)
|
||||
# { $runtimeVersion } is the version of the remote runtime (for instance "67.0a1")
|
||||
# { $localVersion } is the version of your current runtime (same format)
|
||||
about-debugging-runtime-version-too-recent = The connected runtime is more recent ({ $runtimeVersion }, buildID { $runtimeID }) than your desktop Firefox ({ $localVersion }, buildID { $localID }). This is an unsupported setup and may cause DevTools to fail. Please update Firefox. <a>Troubleshooting</a>
|
||||
about-debugging-runtime-version-too-recent = The connected runtime is more recent ({ $runtimeVersion }, buildID { $runtimeID }) than your { -brand-shorter-name } ({ $localVersion }, buildID { $localID }). This is an unsupported setup and may cause DevTools to fail. Please update Firefox. <a>Troubleshooting</a>
|
||||
|
||||
# Displayed for runtime info in runtime pages.
|
||||
# { $name } is brand name such as "Firefox Nightly"
|
||||
# { $version } is version such as "64.0a1"
|
||||
about-debugging-runtime-name = { $name } ({ $version })
|
||||
|
||||
# Text of a button displayed in Runtime pages for remote runtimes.
|
||||
# Clicking on the button will close the connection to the runtime.
|
||||
about-debugging-runtime-disconnect-button = Disconnect
|
||||
|
||||
# Text of the connection prompt button displayed in Runtime pages, when the preference
|
||||
# "devtools.debugger.prompt-connection" is false on the target runtime.
|
||||
about-debugging-connection-prompt-enable-button = Enable connection prompt
|
||||
|
||||
# Text of the connection prompt button displayed in Runtime pages, when the preference
|
||||
# "devtools.debugger.prompt-connection" is true on the target runtime.
|
||||
about-debugging-connection-prompt-disable-button = Disable connection prompt
|
||||
|
||||
# Title of a modal dialog displayed on remote runtime pages after clicking on the Profile Runtime button.
|
||||
about-debugging-profiler-dialog-title = Performance Profiler
|
||||
|
||||
# Label of a checkbox displayed in the runtime page for "This Firefox".
|
||||
# This checkbox will toggle preferences that enable local addon debugging.
|
||||
# The "Learn more" link points to MDN.
|
||||
# https://developer.mozilla.org/docs/Tools/about:debugging#Enabling_add-on_debugging
|
||||
about-debugging-extension-debug-setting-label = Enable extension debugging. <a>Learn more</a>
|
||||
|
||||
# Clicking on the header of a debug target category will expand or collapse the debug
|
||||
# target items in the category. This text is used as ’title’ attribute of the header,
|
||||
# to describe this feature.
|
||||
about-debugging-collapse-expand-debug-targets = Collapse / expand
|
||||
|
||||
# Debug Targets strings
|
||||
|
||||
# Displayed in the categories of "runtime" pages that don't have any debug target to
|
||||
# show. Debug targets depend on the category (extensions, tabs, workers...).
|
||||
@ -184,9 +262,10 @@ about-debugging-tmp-extension-install-message = Select manifest.json file or .xp
|
||||
# This string is displayed as a message about the add-on having a temporaryID.
|
||||
about-debugging-tmp-extension-temporary-id = This WebExtension has a temporary ID. <a>Learn more</a>
|
||||
|
||||
# Text of a link displayed for extensions in "runtime" pages.
|
||||
# Clicking on the link should open the manifest file in a new tab.
|
||||
about-debugging-extension-manifest-link = Manifest URL
|
||||
# Text displayed for extensions in "runtime" pages, before displaying a link the extension's
|
||||
# manifest URL.
|
||||
about-debugging-extension-manifest-url =
|
||||
.label = Manifest URL
|
||||
|
||||
# Text displayed for extensions in "runtime" pages, before displaying the extension's uuid.
|
||||
# UUIDs look like b293e463-481e-5148-a487-5aaf7a130429
|
||||
@ -200,23 +279,8 @@ about-debugging-extension-location =
|
||||
|
||||
# Text displayed for extensions in "runtime" pages, before displaying the extension's ID.
|
||||
# For instance "geckoprofiler@mozilla.com" or "{ed26ddcb-5611-4512-a89a-51b8db81cfb2}".
|
||||
about-debugging-extension-id = Extension ID
|
||||
|
||||
# Text of a button displayed after the network locations "Host" input.
|
||||
# Clicking on it will add the new network location to the list.
|
||||
about-debugging-network-locations-add-button = Add
|
||||
|
||||
# Text to display when there are no locations to show.
|
||||
about-debugging-network-locations-empty-text = No network locations have been added yet.
|
||||
|
||||
# Text of the label for the text input that allows users to add new network locations in
|
||||
# the Connect page. A host is a hostname and a port separated by a colon, as suggested by
|
||||
# the input's placeholder "localhost:6080".
|
||||
about-debugging-network-locations-host-input-label = Host
|
||||
|
||||
# Text of a button displayed next to existing network locations in the Connect page.
|
||||
# Clicking on it removes the network location from the list.
|
||||
about-debugging-network-locations-remove-button = Remove
|
||||
about-debugging-extension-id =
|
||||
.label = Extension ID
|
||||
|
||||
# This string is displayed as a label of the button that pushes a test payload
|
||||
# to a service worker.
|
||||
@ -230,29 +294,25 @@ about-debugging-worker-action-start = Start
|
||||
# This string is displayed as a label of the button that unregisters a service worker.
|
||||
about-debugging-worker-action-unregister = Unregister
|
||||
|
||||
# Reused for the service worker fetch status labels.
|
||||
# "Fetch" is an event type and should not be localized.
|
||||
-worker-fetch-label = Fetch
|
||||
|
||||
# Displayed for service workers in runtime pages that listen to Fetch events.
|
||||
about-debugging-worker-fetch-listening =
|
||||
.label = { -worker-fetch-label }
|
||||
.label = Fetch
|
||||
.value = Listening for fetch events
|
||||
|
||||
# Displayed for service workers in runtime pages that do not listen to Fetch events.
|
||||
about-debugging-worker-fetch-not-listening =
|
||||
.label = { -worker-fetch-label }
|
||||
.label = Fetch
|
||||
.value = Not listening for fetch events
|
||||
|
||||
# Displayed for service workers in runtime pages, to indicate the status of a worker.
|
||||
# For workers for which no registration could be found yet, they are considered as
|
||||
# 'registering' (only active registrations are visible from about:debugging).
|
||||
about-debugging-worker-status =
|
||||
{ $status ->
|
||||
[running] Running
|
||||
*[stopped] Stopped
|
||||
[registering] Registering
|
||||
}
|
||||
# Displayed for service workers in runtime pages that are currently running (service
|
||||
# worker instance is active).
|
||||
about-debugging-worker-status-running = Running
|
||||
|
||||
# Displayed for service workers in runtime pages that are registered but stopped.
|
||||
about-debugging-worker-status-stopped = Stopped
|
||||
|
||||
# Displayed for service workers in runtime pages that are registering.
|
||||
about-debugging-worker-status-registering = Registering
|
||||
|
||||
# Displayed for service workers in runtime pages, to label the scope of a worker
|
||||
about-debugging-worker-scope =
|
||||
@ -263,51 +323,10 @@ about-debugging-worker-scope =
|
||||
about-debugging-worker-push-service =
|
||||
.label = Push Service
|
||||
|
||||
# Displayed for runtime info in runtime pages.
|
||||
# { $name } is brand name such as "Firefox Nightly"
|
||||
# { $version } is version such as "64.0a1"
|
||||
about-debugging-runtime-name = { $name } ({ $version })
|
||||
|
||||
# Text of the connection prompt button displayed in Runtime pages, when the preference
|
||||
# "devtools.debugger.prompt-connection" is false on the target runtime.
|
||||
about-debugging-connection-prompt-enable-button = Enable connection prompt
|
||||
|
||||
# Text of the connection prompt button displayed in Runtime pages, when the preference
|
||||
# "devtools.debugger.prompt-connection" is true on the target runtime.
|
||||
about-debugging-connection-prompt-disable-button = Disable connection prompt
|
||||
|
||||
# Title of the application displayed in the tab
|
||||
-application-title = Debugging
|
||||
|
||||
# Page title of connect / runtime page
|
||||
# Part of "about-debugging-page-title" string defined below
|
||||
about-debugging-page-title-selected-page =
|
||||
{ $selectedPage ->
|
||||
[connect] Setup
|
||||
*[runtime] Runtime
|
||||
}
|
||||
|
||||
# Page title with the runtime displayed in the tab
|
||||
# { $selectedRuntimeId } is the id of the current runtime, such as "this-firefox", "localhost:6080", ...
|
||||
about-debugging-page-title-with-runtime = { -application-title } - { about-debugging-page-title-selected-page } / { $selectedRuntimeId }
|
||||
|
||||
# Page title without the runtime displayed in the tab
|
||||
about-debugging-page-title = { -application-title } - { about-debugging-page-title-selected-page }
|
||||
|
||||
# Title of a modal dialog displayed on remote runtime pages after clicking on the Profile Runtime button.
|
||||
about-debugging-profiler-dialog-title = Performance Profiler
|
||||
|
||||
# Label of a checkbox displayed in the runtime page for "This Firefox".
|
||||
# This checkbox will toggle preferences that enable local addon debugging.
|
||||
# The "Learn more" link points to MDN.
|
||||
# https://developer.mozilla.org/docs/Tools/about:debugging#Enabling_add-on_debugging
|
||||
about-debugging-extension-debug-setting-label = Enable extension debugging <a>Learn more</a>
|
||||
|
||||
# Clicking on the header of a debug target category will expand or collapse the debug
|
||||
# target items in the category. This text is used as ’title’ attribute of the header,
|
||||
# to describe this feature.
|
||||
about-debugging-collapse-expand-debug-targets = Collapse / expand
|
||||
|
||||
# Displayed as name for the Main Process debug target in the Processes category. Only for
|
||||
# remote runtimes, if `devtools.aboutdebugging.process-debugging` is true.
|
||||
about-debugging-main-process-name = Main Process
|
||||
about-debugging-main-process-description = Main Process for the target runtime
|
||||
|
||||
# Displayed as description for the Main Process debug target in the Processes category.
|
||||
# Only for remote runtimes, if `devtools.aboutdebugging.process-debugging` is true.
|
||||
about-debugging-main-process-description = Main Process for the target runtime
|
@ -98,20 +98,6 @@ ToolboxStyleEditor.tooltip3=Stylesheet Editor (CSS) (%S)
|
||||
# editor.
|
||||
open.accesskey=l
|
||||
|
||||
# LOCALIZATION NOTE (ToolboxWebAudioEditor1.label):
|
||||
# This string is displayed in the title of the tab when the Web Audio Editor
|
||||
# is displayed inside the developer tools window and in the Developer Tools Menu.
|
||||
ToolboxWebAudioEditor1.label=Web Audio
|
||||
|
||||
# LOCALIZATION NOTE (ToolboxWebAudioEditor1.panelLabel):
|
||||
# This is used as the label for the toolbox panel.
|
||||
ToolboxWebAudioEditor1.panelLabel=Web Audio Panel
|
||||
|
||||
# LOCALIZATION NOTE (ToolboxWebAudioEditor1.tooltip):
|
||||
# This string is displayed in the tooltip of the tab when the Web Audio Editor is
|
||||
# displayed inside the developer tools window.
|
||||
ToolboxWebAudioEditor1.tooltip=Web Audio context visualizer and audio node inspector
|
||||
|
||||
# LOCALIZATION NOTE (inspector.*)
|
||||
# Used for the menuitem in the tool menu
|
||||
inspector.label=Inspector
|
||||
|
@ -32,10 +32,6 @@ error-load=Style sheet could not be loaded.
|
||||
# LOCALIZATION NOTE (error-save): This is shown when saving fails.
|
||||
error-save=Style sheet could not be saved.
|
||||
|
||||
# LOCALIZATION NOTE (error-compressed): This is shown when we can't show
|
||||
# coverage information because the css source is compressed.
|
||||
error-compressed=Can’t show coverage information for compressed stylesheets
|
||||
|
||||
# LOCALIZATION NOTE (importStyleSheet.title): This is the file picker title,
|
||||
# when you import a style sheet into the Style Editor.
|
||||
importStyleSheet.title=Import style sheet
|
||||
|
@ -341,10 +341,6 @@ pref("devtools.responsive.showUserAgentInput", false);
|
||||
|
||||
// Enable new about:debugging.
|
||||
pref("devtools.aboutdebugging.new-enabled", false);
|
||||
// Enable the network location feature.
|
||||
pref("devtools.aboutdebugging.network", false);
|
||||
// Enable the wifi feature.
|
||||
pref("devtools.aboutdebugging.wifi", false);
|
||||
// Show process debug targets.
|
||||
pref("devtools.aboutdebugging.process-debugging", false);
|
||||
// Stringified array of network locations that users can connect to.
|
||||
|
@ -706,7 +706,6 @@ function getChartsFromToolId(id) {
|
||||
case "STORAGE":
|
||||
case "STYLEEDITOR":
|
||||
case "TOOLBOX":
|
||||
case "WEBAUDIOEDITOR":
|
||||
case "WEBCONSOLE":
|
||||
case "WEBIDE":
|
||||
timerHist = `DEVTOOLS_${id}_TIME_ACTIVE_SECONDS`;
|
||||
|
@ -80,7 +80,6 @@ const ITEM_NAME_MAX_LENGTH = 32;
|
||||
class StorageUI {
|
||||
constructor(front, target, panelWin, toolbox) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._target = target;
|
||||
this._window = panelWin;
|
||||
this._panelDoc = panelWin.document;
|
||||
@ -601,7 +600,8 @@ class StorageUI {
|
||||
}
|
||||
|
||||
try {
|
||||
if (reason === REASON.POPULATE) {
|
||||
if (reason === REASON.POPULATE ||
|
||||
(reason === REASON.NEW_ROW && this.table.items.size === 0)) {
|
||||
let subType = null;
|
||||
// The indexedDB type could have sub-type data to fetch.
|
||||
// If having names specified, then it means
|
||||
@ -630,6 +630,8 @@ class StorageUI {
|
||||
const {data} = await storageType.getStoreObjects(host, names, fetchOpts);
|
||||
if (data.length) {
|
||||
await this.populateTable(data, reason);
|
||||
} else if (reason === REASON.POPULATE) {
|
||||
await this.clearHeaders();
|
||||
}
|
||||
this.updateToolbar();
|
||||
this.emit("store-objects-updated");
|
||||
@ -653,9 +655,6 @@ class StorageUI {
|
||||
this._addButton.hidden = false;
|
||||
this._addButton.setAttribute("tooltiptext",
|
||||
L10N.getFormatStr("storage.popupMenu.addItemLabel"));
|
||||
} else {
|
||||
this._addButton.hidden = true;
|
||||
this._addButton.removeAttribute("tooltiptext");
|
||||
}
|
||||
}
|
||||
|
||||
@ -985,6 +984,8 @@ class StorageUI {
|
||||
|
||||
let names = null;
|
||||
if (!host) {
|
||||
// If selected item has no host then reset table headers
|
||||
await this.clearHeaders();
|
||||
return;
|
||||
}
|
||||
if (item.length > 2) {
|
||||
@ -994,6 +995,13 @@ class StorageUI {
|
||||
this.itemOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the column headers in the storage table
|
||||
*/
|
||||
async clearHeaders() {
|
||||
this.table.setColumns({}, null, {}, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the column headers in the storage table with the pased object `data`
|
||||
*
|
||||
@ -1119,6 +1127,10 @@ class StorageUI {
|
||||
this.sidebarToggledOpen = false;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
} else if (event.keyCode == KeyCodes.DOM_VK_BACK_SPACE && this.table.selectedRow) {
|
||||
this.onRemoveItem();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1300,13 +1312,17 @@ class StorageUI {
|
||||
onRemoveItem() {
|
||||
const [, host, ...path] = this.tree.selectedItem;
|
||||
const front = this.getCurrentFront();
|
||||
const rowId = this.table.contextMenuRowId;
|
||||
const uniqueId = this.table.uniqueId;
|
||||
const rowId = this.table.contextMenuRowId || this.table.selectedRow[uniqueId];
|
||||
const data = this.table.items.get(rowId);
|
||||
|
||||
let name = data[this.table.uniqueId];
|
||||
if (path.length > 0) {
|
||||
name = JSON.stringify([...path, name]);
|
||||
}
|
||||
front.removeItem(host, name);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -649,30 +649,6 @@ StyleEditorUI.prototype = {
|
||||
showEditor.onShow();
|
||||
|
||||
this.emit("editor-selected", showEditor);
|
||||
|
||||
// Is there any CSS coverage markup to include?
|
||||
const usage = await this._target.getFront("cssUsage");
|
||||
if (usage == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sheet = showEditor.styleSheet;
|
||||
const {reports} = await usage.createEditorReportForSheet(sheet);
|
||||
|
||||
showEditor.removeAllUnusedRegions();
|
||||
|
||||
if (reports.length > 0) {
|
||||
// Only apply if this file isn't compressed. We detect a
|
||||
// compressed file if there are more rules than lines.
|
||||
const editorText = showEditor.sourceEditor.getText();
|
||||
const lineCount = editorText.split("\n").length;
|
||||
const ruleCount = showEditor.styleSheet.ruleCount;
|
||||
if (lineCount >= ruleCount) {
|
||||
showEditor.addUnusedRegions(reports);
|
||||
} else {
|
||||
this.emit("error", { key: "error-compressed", level: "info" });
|
||||
}
|
||||
}
|
||||
}.bind(this))().catch(console.error);
|
||||
},
|
||||
});
|
||||
|
@ -42,9 +42,6 @@ const CHECK_LINKED_SHEET_DELAY = 500;
|
||||
// How many times to check for linked file changes
|
||||
const MAX_CHECK_COUNT = 10;
|
||||
|
||||
// The classname used to show a line that is not used
|
||||
const UNUSED_CLASS = "cm-unused-line";
|
||||
|
||||
// How much time should the mouse be still before the selector at that position
|
||||
// gets highlighted?
|
||||
const SELECTOR_HIGHLIGHT_TIMEOUT = 500;
|
||||
@ -305,41 +302,6 @@ StyleSheetEditor.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Add markup to a region. UNUSED_CLASS is added to specified lines
|
||||
* @param region An object shaped like
|
||||
* {
|
||||
* start: { line: L1, column: C1 },
|
||||
* end: { line: L2, column: C2 } // optional
|
||||
* }
|
||||
*/
|
||||
addUnusedRegion: function(region) {
|
||||
this.sourceEditor.addLineClass(region.start.line - 1, UNUSED_CLASS);
|
||||
if (region.end) {
|
||||
for (let i = region.start.line; i <= region.end.line; i++) {
|
||||
this.sourceEditor.addLineClass(i - 1, UNUSED_CLASS);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* As addUnusedRegion except that it takes an array of regions
|
||||
*/
|
||||
addUnusedRegions: function(regions) {
|
||||
for (const region of regions) {
|
||||
this.addUnusedRegion(region);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all the unused markup regions added by addUnusedRegion
|
||||
*/
|
||||
removeAllUnusedRegions: function() {
|
||||
for (let i = 0; i < this.sourceEditor.lineCount(); i++) {
|
||||
this.sourceEditor.removeLineClass(i, UNUSED_CLASS);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Forward property-change event from stylesheet.
|
||||
*
|
||||
|
@ -9,8 +9,6 @@
|
||||
%editMenuStrings;
|
||||
<!ENTITY % sourceEditorStrings SYSTEM "chrome://devtools/locale/sourceeditor.dtd">
|
||||
%sourceEditorStrings;
|
||||
<!ENTITY % csscoverageDTD SYSTEM "chrome://devtools-shared/locale/csscoverage.dtd">
|
||||
%csscoverageDTD;
|
||||
]>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
|
||||
@ -169,60 +167,6 @@
|
||||
</html:div> <!-- #splitview-templates -->
|
||||
</box> <!-- .splitview-root -->
|
||||
|
||||
<box class="csscoverage-template" hidden="true">
|
||||
<toolbar class="devtools-toolbar csscoverage-toolbar">
|
||||
<button class="devtools-toolbarbutton csscoverage-toolbarbutton"
|
||||
label="&csscoverage.backButton;"
|
||||
onclick="${onback}"/>
|
||||
</toolbar>
|
||||
<!-- The data for this comes from CSSUsageActor.createPageReport -->
|
||||
<html:div class="csscoverage-report-container">
|
||||
<html:div class="csscoverage-report-content">
|
||||
<html:div class="csscoverage-report-summary">
|
||||
<html:div class="csscoverage-report-chart"/>
|
||||
</html:div>
|
||||
<html:div class="csscoverage-report-unused">
|
||||
<html:h2>&csscoverage.unused;</html:h2>
|
||||
<html:p>&csscoverage.noMatches;</html:p>
|
||||
<html:div foreach="page in ${unused}">
|
||||
<html:h3>${page.url}</html:h3>
|
||||
<html:code foreach="rule in ${page.rules}"
|
||||
href="${rule.url}"
|
||||
class="csscoverage-list">${rule.selectorText}</html:code>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<html:div class="csscoverage-report-optimize">
|
||||
<html:h2>&csscoverage.optimize.header;</html:h2>
|
||||
<html:p>
|
||||
&csscoverage.optimize.body1;
|
||||
<html:code><link ...></html:code>
|
||||
&csscoverage.optimize.body2;
|
||||
<html:code><style>...</html:code>
|
||||
&csscoverage.optimize.body3;
|
||||
</html:p>
|
||||
<html:div if="${preload.length == 0}">&csscoverage.optimize.bodyX;</html:div>
|
||||
<html:div if="${preload.length > 0}">
|
||||
<html:div foreach="page in ${preload}">
|
||||
<html:h3>${page.url}</html:h3>
|
||||
<html:textarea><style>
|
||||
<html:loop foreach="rule in ${page.rules}"
|
||||
onclick="${rule.onclick}">${rule.formattedCssText}</html:loop></style></html:textarea>
|
||||
</html:div>
|
||||
</html:div>
|
||||
<html:p>
|
||||
&csscoverage.footer1;
|
||||
<html:a target="_blank" href="&csscoverage.footer2a;">&csscoverage.footer3;</html:a>
|
||||
&csscoverage.footer4;
|
||||
</html:p>
|
||||
</html:div>
|
||||
<html:p> </html:p>
|
||||
</html:div>
|
||||
</html:div>
|
||||
</box>
|
||||
|
||||
<box class="csscoverage-report" hidden="true">
|
||||
</box>
|
||||
|
||||
</stack>
|
||||
|
||||
</window>
|
||||
|
@ -278,142 +278,3 @@ h3 {
|
||||
-moz-box-flex: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* CSS coverage */
|
||||
.csscoverage-report {
|
||||
background-color: var(--theme-toolbar-background);
|
||||
-moz-box-orient: horizontal;
|
||||
}
|
||||
|
||||
.csscoverage-report-container {
|
||||
height: 100vh;
|
||||
padding: 0 10px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
.csscoverage-report-content {
|
||||
margin: 20px auto;
|
||||
-moz-column-width: 300px;
|
||||
font-size: 13px;
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
.csscoverage-report-summary,
|
||||
.csscoverage-report-unused,
|
||||
.csscoverage-report-optimize {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.csscoverage-report-unused,
|
||||
.csscoverage-report-optimize {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 950px) {
|
||||
.csscoverage-report-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.csscoverage-report-summary {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.csscoverage-report h1 {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
.csscoverage-report h2 {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.csscoverage-report h1,
|
||||
.csscoverage-report h2,
|
||||
.csscoverage-report h3 {
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.csscoverage-report code,
|
||||
.csscoverage-report textarea {
|
||||
font-family: var(--monospace-font-family);
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.csscoverage-list:after {
|
||||
content: ', ';
|
||||
}
|
||||
|
||||
.csscoverage-list:last-child:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.csscoverage-report textarea {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.csscoverage-report a {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.csscoverage-report > .csscoverage-toolbar {
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.csscoverage-report > .csscoverage-toolbarbutton {
|
||||
min-width: 4em;
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
border-inline-start: none;
|
||||
}
|
||||
|
||||
.csscoverage-report .pie-table-chart-container {
|
||||
-moz-box-orient: vertical;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.chart-colored-blob[name="Used Preload"] {
|
||||
fill: var(--theme-highlight-pink);
|
||||
background: var(--theme-highlight-pink);
|
||||
}
|
||||
|
||||
.chart-colored-blob[name=Used] {
|
||||
fill: var(--theme-highlight-green);
|
||||
background: var(--theme-highlight-green);
|
||||
}
|
||||
|
||||
.chart-colored-blob[name=Unused] {
|
||||
fill: var(--theme-highlight-lightorange);
|
||||
background: var(--theme-highlight-lightorange);
|
||||
}
|
||||
|
||||
/* Undo 'largest' customization */
|
||||
.theme-dark .pie-chart-slice[largest] {
|
||||
stroke-width: 1px;
|
||||
stroke: rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.theme-light .pie-chart-slice[largest] {
|
||||
stroke-width: 1px;
|
||||
stroke: rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
.csscoverage-report .pie-chart-slice {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.csscoverage-report-chart {
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
@ -1,715 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Ci } = require("chrome");
|
||||
|
||||
const InspectorUtils = require("InspectorUtils");
|
||||
const Services = require("Services");
|
||||
const ChromeUtils = require("ChromeUtils");
|
||||
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const { cssUsageSpec } = require("devtools/shared/specs/csscoverage");
|
||||
|
||||
loader.lazyRequireGetter(this, "prettifyCSS", "devtools/shared/inspector/css-logic", true);
|
||||
|
||||
const MAX_UNUSED_RULES = 10000;
|
||||
|
||||
/**
|
||||
* Allow: let foo = l10n.lookup("csscoverageFoo");
|
||||
*/
|
||||
const l10n = exports.l10n = {
|
||||
_URI: "chrome://devtools-shared/locale/csscoverage.properties",
|
||||
lookup: function(msg) {
|
||||
if (this._stringBundle == null) {
|
||||
this._stringBundle = Services.strings.createBundle(this._URI);
|
||||
}
|
||||
return this._stringBundle.GetStringFromName(msg);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* CSSUsage manages the collection of CSS usage data.
|
||||
* The core of a CSSUsage is a JSON-able data structure called _knownRules
|
||||
* which looks like this:
|
||||
* This records the CSSStyleRules and their usage.
|
||||
* The format is:
|
||||
* Map({
|
||||
* <CSS-URL>|<START-LINE>|<START-COLUMN>: {
|
||||
* selectorText: <CSSStyleRule.selectorText>,
|
||||
* test: <simplify(CSSStyleRule.selectorText)>,
|
||||
* cssText: <CSSStyleRule.cssText>,
|
||||
* isUsed: <TRUE|FALSE>,
|
||||
* presentOn: Set([ <HTML-URL>, ... ]),
|
||||
* preLoadOn: Set([ <HTML-URL>, ... ]),
|
||||
* isError: <TRUE|FALSE>,
|
||||
* }
|
||||
* })
|
||||
*
|
||||
* For example:
|
||||
* this._knownRules = Map({
|
||||
* "http://eg.com/styles1.css|15|0": {
|
||||
* selectorText: "p.quote:hover",
|
||||
* test: "p.quote",
|
||||
* cssText: "p.quote { color: red; }",
|
||||
* isUsed: true,
|
||||
* presentOn: Set([ "http://eg.com/page1.html", ... ]),
|
||||
* preLoadOn: Set([ "http://eg.com/page1.html" ]),
|
||||
* isError: false,
|
||||
* }, ...
|
||||
* });
|
||||
*/
|
||||
var CSSUsageActor = protocol.ActorClassWithSpec(cssUsageSpec, {
|
||||
initialize: function(conn, targetActor) {
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
|
||||
this._targetActor = targetActor;
|
||||
this._running = false;
|
||||
|
||||
this._onTabLoad = this._onTabLoad.bind(this);
|
||||
this._onChange = this._onChange.bind(this);
|
||||
|
||||
this._notifyOn = Ci.nsIWebProgress.NOTIFY_STATE_ALL;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._targetActor = undefined;
|
||||
|
||||
delete this._onTabLoad;
|
||||
delete this._onChange;
|
||||
|
||||
protocol.Actor.prototype.destroy.call(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Begin recording usage data
|
||||
* @param noreload It's best if we start by reloading the current page
|
||||
* because that starts the test at a known point, but there could be reasons
|
||||
* why we don't want to do that (e.g. the page contains state that will be
|
||||
* lost across a reload)
|
||||
*/
|
||||
start: function(noreload) {
|
||||
if (this._running) {
|
||||
throw new Error(l10n.lookup("csscoverageRunningError"));
|
||||
}
|
||||
|
||||
this._isOneShot = false;
|
||||
this._visitedPages = new Set();
|
||||
this._knownRules = new Map();
|
||||
this._running = true;
|
||||
this._tooManyUnused = false;
|
||||
|
||||
this._progressListener = {
|
||||
QueryInterface: ChromeUtils.generateQI([ Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference ]),
|
||||
|
||||
onStateChange: (progress, request, flags, status) => {
|
||||
const isStop = flags & Ci.nsIWebProgressListener.STATE_STOP;
|
||||
const isWindow = flags & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
|
||||
|
||||
if (isStop && isWindow) {
|
||||
this._onTabLoad(progress.DOMWindow.document);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: () => {},
|
||||
};
|
||||
|
||||
this._progress = this._targetActor.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
this._progress.addProgressListener(this._progressListener, this._notifyOn);
|
||||
|
||||
if (noreload) {
|
||||
// If we're not starting by reloading the page, then pretend that onload
|
||||
// has just happened.
|
||||
this._onTabLoad(this._targetActor.window.document);
|
||||
} else {
|
||||
this._targetActor.window.location.reload();
|
||||
}
|
||||
|
||||
this.emit("state-change", { isRunning: true });
|
||||
},
|
||||
|
||||
/**
|
||||
* Cease recording usage data
|
||||
*/
|
||||
stop: function() {
|
||||
if (!this._running) {
|
||||
throw new Error(l10n.lookup("csscoverageNotRunningError"));
|
||||
}
|
||||
|
||||
this._progress.removeProgressListener(this._progressListener, this._notifyOn);
|
||||
this._progress = undefined;
|
||||
|
||||
this._running = false;
|
||||
this.emit("state-change", { isRunning: false });
|
||||
},
|
||||
|
||||
/**
|
||||
* Start/stop recording usage data depending on what we're currently doing.
|
||||
*/
|
||||
toggle: function() {
|
||||
return this._running ? this.stop() : this.start();
|
||||
},
|
||||
|
||||
/**
|
||||
* Running start() quickly followed by stop() does a bunch of unnecessary
|
||||
* work, so this cuts all that out
|
||||
*/
|
||||
oneshot: function() {
|
||||
if (this._running) {
|
||||
throw new Error(l10n.lookup("csscoverageRunningError"));
|
||||
}
|
||||
|
||||
this._isOneShot = true;
|
||||
this._visitedPages = new Set();
|
||||
this._knownRules = new Map();
|
||||
|
||||
this._populateKnownRules(this._targetActor.window.document);
|
||||
this._updateUsage(this._targetActor.window.document, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called by the ProgressListener to simulate a "load" event
|
||||
*/
|
||||
_onTabLoad: function(document) {
|
||||
this._populateKnownRules(document);
|
||||
this._updateUsage(document, true);
|
||||
|
||||
this._observeMutations(document);
|
||||
},
|
||||
|
||||
/**
|
||||
* Setup a MutationObserver on the current document
|
||||
*/
|
||||
_observeMutations: function(document) {
|
||||
const MutationObserver = document.defaultView.MutationObserver;
|
||||
const observer = new MutationObserver(mutations => {
|
||||
// It's possible that one of the mutations in this list adds a 'use' of
|
||||
// a CSS rule, and another takes it away. See Bug 1010189
|
||||
this._onChange(document);
|
||||
});
|
||||
|
||||
observer.observe(document, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: false,
|
||||
subtree: true,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for whenever we think the page has changed in a way that
|
||||
* means the CSS usage might have changed.
|
||||
*/
|
||||
_onChange: function(document) {
|
||||
// Ignore changes pre 'load'
|
||||
if (!this._visitedPages.has(getURL(document))) {
|
||||
return;
|
||||
}
|
||||
this._updateUsage(document, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called whenever we think the list of stylesheets might have changed so
|
||||
* we can update the list of rules that we should be checking
|
||||
*/
|
||||
_populateKnownRules: function(document) {
|
||||
const url = getURL(document);
|
||||
this._visitedPages.add(url);
|
||||
// Go through all the rules in the current sheets adding them to knownRules
|
||||
// if needed and adding the current url to the list of pages they're on
|
||||
for (const rule of getAllSelectorRules(document)) {
|
||||
const ruleId = ruleToId(rule);
|
||||
let ruleData = this._knownRules.get(ruleId);
|
||||
if (ruleData == null) {
|
||||
ruleData = {
|
||||
selectorText: rule.selectorText,
|
||||
cssText: rule.cssText,
|
||||
test: getTestSelector(rule.selectorText),
|
||||
isUsed: false,
|
||||
presentOn: new Set(),
|
||||
preLoadOn: new Set(),
|
||||
isError: false,
|
||||
};
|
||||
this._knownRules.set(ruleId, ruleData);
|
||||
}
|
||||
|
||||
ruleData.presentOn.add(url);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update knownRules with usage information from the current page
|
||||
*/
|
||||
_updateUsage: function(document, isLoad) {
|
||||
let qsaCount = 0;
|
||||
|
||||
// Update this._data with matches to say 'used at load time' by sheet X
|
||||
const url = getURL(document);
|
||||
|
||||
for (const [ , ruleData ] of this._knownRules) {
|
||||
// If it broke before, don't try again selectors don't change
|
||||
if (ruleData.isError) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's used somewhere already, don't bother checking again unless
|
||||
// this is a load event in which case we need to add preLoadOn
|
||||
if (!isLoad && ruleData.isUsed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore rules that are not present on this page
|
||||
if (!ruleData.presentOn.has(url)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
qsaCount++;
|
||||
if (qsaCount > MAX_UNUSED_RULES) {
|
||||
console.error("Too many unused rules on " + url + " ");
|
||||
this._tooManyUnused = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const match = document.querySelector(ruleData.test);
|
||||
if (match != null) {
|
||||
ruleData.isUsed = true;
|
||||
if (isLoad) {
|
||||
ruleData.preLoadOn.add(url);
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
ruleData.isError = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a JSONable structure designed to help marking up the style editor,
|
||||
* which describes the CSS selector usage.
|
||||
* Example:
|
||||
* [
|
||||
* {
|
||||
* selectorText: "p#content",
|
||||
* usage: "unused|used",
|
||||
* start: { line: 3, column: 0 },
|
||||
* },
|
||||
* ...
|
||||
* ]
|
||||
*/
|
||||
createEditorReport: function(url) {
|
||||
if (this._knownRules == null) {
|
||||
return { reports: [] };
|
||||
}
|
||||
|
||||
const reports = [];
|
||||
for (const [ruleId, ruleData] of this._knownRules) {
|
||||
const { url: ruleUrl, line, column } = deconstructRuleId(ruleId);
|
||||
if (ruleUrl !== url || ruleData.isUsed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ruleReport = {
|
||||
selectorText: ruleData.selectorText,
|
||||
start: { line: line, column: column },
|
||||
};
|
||||
|
||||
if (ruleData.end) {
|
||||
ruleReport.end = ruleData.end;
|
||||
}
|
||||
|
||||
reports.push(ruleReport);
|
||||
}
|
||||
|
||||
return { reports: reports };
|
||||
},
|
||||
|
||||
/**
|
||||
* Compute the stylesheet URL and delegate the report creation to createEditorReport.
|
||||
* See createEditorReport documentation.
|
||||
*
|
||||
* @param {StyleSheetActor} stylesheetActor
|
||||
* the stylesheet actor for which the coverage report should be generated.
|
||||
*/
|
||||
createEditorReportForSheet: function(stylesheetActor) {
|
||||
const url = sheetToUrl(stylesheetActor.rawSheet);
|
||||
return this.createEditorReport(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a JSONable structure designed for the page report which shows
|
||||
* the recommended changes to a page.
|
||||
*
|
||||
* "preload" means that a rule is used before the load event happens, which
|
||||
* means that the page could by optimized by placing it in a <style> element
|
||||
* at the top of the page, moving the <link> elements to the bottom.
|
||||
*
|
||||
* Example:
|
||||
* {
|
||||
* preload: [
|
||||
* {
|
||||
* url: "http://example.org/page1.html",
|
||||
* shortUrl: "page1.html",
|
||||
* rules: [
|
||||
* {
|
||||
* url: "http://example.org/style1.css",
|
||||
* shortUrl: "style1.css",
|
||||
* start: { line: 3, column: 4 },
|
||||
* selectorText: "p#content",
|
||||
* formattedCssText: "p#content {\n color: red;\n }\n"
|
||||
* },
|
||||
* ...
|
||||
* ]
|
||||
* }
|
||||
* ],
|
||||
* unused: [
|
||||
* {
|
||||
* url: "http://example.org/style1.css",
|
||||
* shortUrl: "style1.css",
|
||||
* rules: [ ... ]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
*/
|
||||
createPageReport: function() {
|
||||
if (this._running) {
|
||||
throw new Error(l10n.lookup("csscoverageRunningError"));
|
||||
}
|
||||
|
||||
if (this._visitedPages == null) {
|
||||
throw new Error(l10n.lookup("csscoverageNotRunError"));
|
||||
}
|
||||
|
||||
if (this._isOneShot) {
|
||||
throw new Error(l10n.lookup("csscoverageOneShotReportError"));
|
||||
}
|
||||
|
||||
// Helper function to create a JSONable data structure representing a rule
|
||||
const ruleToRuleReport = function(rule, ruleData) {
|
||||
return {
|
||||
url: rule.url,
|
||||
shortUrl: rule.url.split("/").slice(-1)[0],
|
||||
start: { line: rule.line, column: rule.column },
|
||||
selectorText: ruleData.selectorText,
|
||||
formattedCssText: prettifyCSS(ruleData.cssText),
|
||||
};
|
||||
};
|
||||
|
||||
// A count of each type of rule for the bar chart
|
||||
const summary = { used: 0, unused: 0, preload: 0 };
|
||||
|
||||
// Create the set of the unused rules
|
||||
const unusedMap = new Map();
|
||||
for (const [ruleId, ruleData] of this._knownRules) {
|
||||
const rule = deconstructRuleId(ruleId);
|
||||
let rules = unusedMap.get(rule.url);
|
||||
if (rules == null) {
|
||||
rules = [];
|
||||
unusedMap.set(rule.url, rules);
|
||||
}
|
||||
if (!ruleData.isUsed) {
|
||||
const ruleReport = ruleToRuleReport(rule, ruleData);
|
||||
rules.push(ruleReport);
|
||||
} else {
|
||||
summary.unused++;
|
||||
}
|
||||
}
|
||||
const unused = [];
|
||||
for (const [url, rules] of unusedMap) {
|
||||
unused.push({
|
||||
url: url,
|
||||
shortUrl: url.split("/").slice(-1),
|
||||
rules: rules,
|
||||
});
|
||||
}
|
||||
|
||||
// Create the set of rules that could be pre-loaded
|
||||
const preload = [];
|
||||
for (const url of this._visitedPages) {
|
||||
const page = {
|
||||
url: url,
|
||||
shortUrl: url.split("/").slice(-1),
|
||||
rules: [],
|
||||
};
|
||||
|
||||
for (const [ruleId, ruleData] of this._knownRules) {
|
||||
if (ruleData.preLoadOn.has(url)) {
|
||||
const rule = deconstructRuleId(ruleId);
|
||||
const ruleReport = ruleToRuleReport(rule, ruleData);
|
||||
page.rules.push(ruleReport);
|
||||
summary.preload++;
|
||||
} else {
|
||||
summary.used++;
|
||||
}
|
||||
}
|
||||
|
||||
if (page.rules.length > 0) {
|
||||
preload.push(page);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
summary: summary,
|
||||
preload: preload,
|
||||
unused: unused,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* For testing only. What pages did we visit.
|
||||
*/
|
||||
_testOnlyVisitedPages: function() {
|
||||
return [...this._visitedPages];
|
||||
},
|
||||
});
|
||||
|
||||
exports.CSSUsageActor = CSSUsageActor;
|
||||
|
||||
/**
|
||||
* Generator that filters the CSSRules out of _getAllRules so it only
|
||||
* iterates over the CSSStyleRules
|
||||
*/
|
||||
function* getAllSelectorRules(document) {
|
||||
for (const rule of getAllRules(document)) {
|
||||
if (rule.type === CSSRule.STYLE_RULE && rule.selectorText !== "") {
|
||||
yield rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generator to iterate over the CSSRules in all the stylesheets the
|
||||
* current document (i.e. it includes import rules, media rules, etc)
|
||||
*/
|
||||
function* getAllRules(document) {
|
||||
// sheets is an array of the <link> and <style> element in this document
|
||||
const sheets = getAllSheets(document);
|
||||
for (let i = 0; i < sheets.length; i++) {
|
||||
for (let j = 0; j < sheets[i].cssRules.length; j++) {
|
||||
yield sheets[i].cssRules[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all the stylesheets that affect this document. That means
|
||||
* the <link> and <style> based sheets, and the @imported sheets (recursively)
|
||||
* but not the sheets in nested frames.
|
||||
*/
|
||||
function getAllSheets(document) {
|
||||
// sheets is an array of the <link> and <style> element in this document
|
||||
let sheets = Array.slice(document.styleSheets);
|
||||
// Add @imported sheets
|
||||
for (let i = 0; i < sheets.length; i++) {
|
||||
const subSheets = getImportedSheets(sheets[i]);
|
||||
sheets = sheets.concat(...subSheets);
|
||||
}
|
||||
return sheets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively find @import rules in the given stylesheet.
|
||||
* We're relying on the browser giving rule.styleSheet == null to resolve
|
||||
* @import loops
|
||||
*/
|
||||
function getImportedSheets(stylesheet) {
|
||||
let sheets = [];
|
||||
for (let i = 0; i < stylesheet.cssRules.length; i++) {
|
||||
const rule = stylesheet.cssRules[i];
|
||||
// rule.styleSheet == null with duplicate @imports for the same URL.
|
||||
if (rule.type === CSSRule.IMPORT_RULE && rule.styleSheet != null) {
|
||||
sheets.push(rule.styleSheet);
|
||||
const subSheets = getImportedSheets(rule.styleSheet);
|
||||
sheets = sheets.concat(...subSheets);
|
||||
}
|
||||
}
|
||||
return sheets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique identifier for a rule. This is currently the string
|
||||
* <CSS-URL>|<START-LINE>|<START-COLUMN>
|
||||
* @see deconstructRuleId(ruleId)
|
||||
*/
|
||||
function ruleToId(rule) {
|
||||
const line = InspectorUtils.getRelativeRuleLine(rule);
|
||||
const column = InspectorUtils.getRuleColumn(rule);
|
||||
return sheetToUrl(rule.parentStyleSheet) + "|" + line + "|" + column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a ruleId to an object with { url, line, column } properties
|
||||
* @see ruleToId(rule)
|
||||
*/
|
||||
const deconstructRuleId = exports.deconstructRuleId = function(ruleId) {
|
||||
const split = ruleId.split("|");
|
||||
if (split.length > 3) {
|
||||
const replace = split.slice(0, split.length - 3 + 1).join("|");
|
||||
split.splice(0, split.length - 3 + 1, replace);
|
||||
}
|
||||
const [ url, line, column ] = split;
|
||||
return {
|
||||
url: url,
|
||||
line: parseInt(line, 10),
|
||||
column: parseInt(column, 10),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* We're only interested in the origin and pathname, because changes to the
|
||||
* username, password, hash, or query string probably don't significantly
|
||||
* change the CSS usage properties of a page.
|
||||
* @param document
|
||||
*/
|
||||
const getURL = exports.getURL = function(document) {
|
||||
const url = new document.defaultView.URL(document.documentURI);
|
||||
return url == "about:blank" ? "" : "" + url.origin + url.pathname;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pseudo class handling constants:
|
||||
* We split pseudo-classes into a number of categories so we can decide how we
|
||||
* should match them. See getTestSelector for how we use these constants.
|
||||
*
|
||||
* @see http://dev.w3.org/csswg/selectors4/#overview
|
||||
* @see https://developer.mozilla.org/en-US/docs/tag/CSS%20Pseudo-class
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements
|
||||
*/
|
||||
|
||||
/**
|
||||
* Category 1: Pseudo-classes that depend on external browser/OS state
|
||||
* This includes things like the time, locale, position of mouse/caret/window,
|
||||
* contents of browser history, etc. These can be hard to mimic.
|
||||
* Action: Remove from selectors
|
||||
*/
|
||||
const SEL_EXTERNAL = [
|
||||
"active", "active-drop", "current", "dir", "focus", "future", "hover",
|
||||
"invalid-drop", "lang", "past", "placeholder-shown", "target", "valid-drop",
|
||||
"visited",
|
||||
];
|
||||
|
||||
/**
|
||||
* Category 2: Pseudo-classes that depend on user-input state
|
||||
* These are pseudo-classes that arguably *should* be covered by unit tests but
|
||||
* which probably aren't and which are unlikely to be covered by manual tests.
|
||||
* We're currently stripping them out,
|
||||
* Action: Remove from selectors (but consider future command line flag to
|
||||
* enable them in the future. e.g. 'csscoverage start --strict')
|
||||
*/
|
||||
const SEL_FORM = [
|
||||
"checked", "default", "disabled", "enabled", "fullscreen", "in-range",
|
||||
"indeterminate", "invalid", "optional", "out-of-range", "required", "valid",
|
||||
];
|
||||
|
||||
/**
|
||||
* Category 3: Pseudo-elements
|
||||
* querySelectorAll doesn't return matches with pseudo-elements because there
|
||||
* is no element to match (they're pseudo) so we have to remove them all.
|
||||
* (See http://codepen.io/joewalker/pen/sanDw for a demo)
|
||||
* Action: Remove from selectors (including deprecated single colon versions)
|
||||
*/
|
||||
const SEL_ELEMENT = [
|
||||
"after", "before", "first-letter", "first-line", "selection",
|
||||
];
|
||||
|
||||
/**
|
||||
* Category 4: Structural pseudo-classes
|
||||
* This is a category defined by the spec (also called tree-structural and
|
||||
* grid-structural) for selection based on relative position in the document
|
||||
* tree that cannot be represented by other simple selectors or combinators.
|
||||
* Action: Require a page-match
|
||||
*/
|
||||
const SEL_STRUCTURAL = [
|
||||
"empty", "first-child", "first-of-type", "last-child", "last-of-type",
|
||||
"nth-column", "nth-last-column", "nth-child", "nth-last-child",
|
||||
"nth-last-of-type", "nth-of-type", "only-child", "only-of-type", "root",
|
||||
];
|
||||
|
||||
/**
|
||||
* Category 4a: Semi-structural pseudo-classes
|
||||
* These are not structural according to the spec, but act nevertheless on
|
||||
* information in the document tree.
|
||||
* Action: Require a page-match
|
||||
*/
|
||||
const SEL_SEMI = [ "any-link", "link", "read-only", "read-write", "scope" ];
|
||||
|
||||
/**
|
||||
* Category 5: Combining pseudo-classes
|
||||
* has(), not() etc join selectors together in various ways. We take care when
|
||||
* removing pseudo-classes to convert "not(:hover)" into "not(*)" and so on.
|
||||
* With these changes the combining pseudo-classes should probably stand on
|
||||
* their own.
|
||||
* Action: Require a page-match
|
||||
*/
|
||||
const SEL_COMBINING = [ "not", "has", "matches" ];
|
||||
|
||||
/**
|
||||
* Category 6: Media pseudo-classes
|
||||
* Pseudo-classes that should be ignored because they're only relevant to
|
||||
* media queries
|
||||
* Action: Don't need removing from selectors as they appear in media queries
|
||||
*/
|
||||
const SEL_MEDIA = [ "blank", "first", "left", "right" ];
|
||||
|
||||
/**
|
||||
* A test selector is a reduced form of a selector that we actually test
|
||||
* against. This code strips out pseudo-elements and some pseudo-classes that
|
||||
* we think should not have to match in order for the selector to be relevant.
|
||||
*/
|
||||
function getTestSelector(selector) {
|
||||
let replacement = selector;
|
||||
const replaceSelector = pseudo => {
|
||||
replacement = replacement.replace(" :" + pseudo, " *")
|
||||
.replace("(:" + pseudo, "(*")
|
||||
.replace(":" + pseudo, "");
|
||||
};
|
||||
|
||||
SEL_EXTERNAL.forEach(replaceSelector);
|
||||
SEL_FORM.forEach(replaceSelector);
|
||||
SEL_ELEMENT.forEach(replaceSelector);
|
||||
|
||||
// Pseudo elements work in : and :: forms
|
||||
SEL_ELEMENT.forEach(pseudo => {
|
||||
replacement = replacement.replace("::" + pseudo, "");
|
||||
});
|
||||
|
||||
return replacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* I've documented all known pseudo-classes above for 2 reasons: To allow
|
||||
* checking logic and what might be missing, but also to allow a unit test
|
||||
* that fetches the list of supported pseudo-classes and pseudo-elements from
|
||||
* the platform and check that they were all represented here.
|
||||
*/
|
||||
exports.SEL_ALL = [
|
||||
SEL_EXTERNAL, SEL_FORM, SEL_ELEMENT, SEL_STRUCTURAL, SEL_SEMI,
|
||||
SEL_COMBINING, SEL_MEDIA,
|
||||
].reduce(function(prev, curr) {
|
||||
return prev.concat(curr);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Find a URL for a given stylesheet
|
||||
* @param {StyleSheet} stylesheet raw stylesheet
|
||||
*/
|
||||
const sheetToUrl = function(stylesheet) {
|
||||
// For <link> elements
|
||||
if (stylesheet.href) {
|
||||
return stylesheet.href;
|
||||
}
|
||||
|
||||
// For <style> elements
|
||||
if (stylesheet.ownerNode) {
|
||||
const document = stylesheet.ownerNode.ownerDocument;
|
||||
const sheets = [...document.querySelectorAll("style")];
|
||||
const index = sheets.indexOf(stylesheet.ownerNode);
|
||||
return getURL(document) + " → <style> index " + index;
|
||||
}
|
||||
|
||||
throw new Error("Unknown sheet source");
|
||||
};
|
@ -28,7 +28,6 @@ DevToolsModules(
|
||||
'changes.js',
|
||||
'common.js',
|
||||
'css-properties.js',
|
||||
'csscoverage.js',
|
||||
'device.js',
|
||||
'emulation.js',
|
||||
'environment.js',
|
||||
@ -72,9 +71,6 @@ with Files('breakpoint.js'):
|
||||
with Files('css-properties.js'):
|
||||
BUG_COMPONENT = ('DevTools', 'Inspector: Rules')
|
||||
|
||||
with Files('csscoverage.js'):
|
||||
BUG_COMPONENT = ('DevTools', 'Graphics Commandline and Toolbar')
|
||||
|
||||
with Files('memory.js'):
|
||||
BUG_COMPONENT = ('DevTools', 'Memory')
|
||||
|
||||
|
@ -193,11 +193,6 @@ const ActorRegistry = {
|
||||
constructor: "CssPropertiesActor",
|
||||
type: { target: true },
|
||||
});
|
||||
this.registerModule("devtools/server/actors/csscoverage", {
|
||||
prefix: "cssUsage",
|
||||
constructor: "CSSUsageActor",
|
||||
type: { target: true },
|
||||
});
|
||||
if ("nsIProfiler" in Ci &&
|
||||
!Services.prefs.getBoolPref("devtools.performance.new-panel-enabled", false)) {
|
||||
this.registerModule("devtools/server/actors/performance", {
|
||||
|
@ -1,105 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {cssUsageSpec} = require("devtools/shared/specs/csscoverage");
|
||||
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol");
|
||||
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
const L10N = new LocalizationHelper("devtools/shared/locales/csscoverage.properties");
|
||||
|
||||
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
|
||||
|
||||
/**
|
||||
* Allow: let foo = l10n.lookup("csscoverageFoo");
|
||||
*/
|
||||
const l10n = exports.l10n = {
|
||||
lookup: (msg) => L10N.getStr(msg),
|
||||
};
|
||||
|
||||
/**
|
||||
* Running more than one usage report at a time is probably bad for performance
|
||||
* and it isn't particularly useful, and it's confusing from a notification POV
|
||||
* so we only allow one.
|
||||
*/
|
||||
var isRunning = false;
|
||||
var notification;
|
||||
var target;
|
||||
var chromeWindow;
|
||||
|
||||
/**
|
||||
* Front for CSSUsageActor
|
||||
*/
|
||||
class CSSUsageFront extends FrontClassWithSpec(cssUsageSpec) {
|
||||
constructor(client) {
|
||||
super(client);
|
||||
this.before("state-change", this._onStateChange.bind(this));
|
||||
|
||||
// Attribute name from which to retrieve the actorID out of the target actor's form
|
||||
this.formAttributeName = "cssUsageActor";
|
||||
}
|
||||
|
||||
_onStateChange(ev) {
|
||||
isRunning = ev.isRunning;
|
||||
ev.target = target;
|
||||
|
||||
if (isRunning) {
|
||||
const gnb = chromeWindow.gNotificationBox;
|
||||
notification = gnb.getNotificationWithValue("csscoverage-running");
|
||||
|
||||
if (notification == null) {
|
||||
const notifyStop = reason => {
|
||||
if (reason == "removed") {
|
||||
this.stop();
|
||||
}
|
||||
};
|
||||
|
||||
const msg = l10n.lookup("csscoverageRunningReply");
|
||||
notification = gnb.appendNotification(msg, "csscoverage-running",
|
||||
"",
|
||||
gnb.PRIORITY_INFO_HIGH,
|
||||
null,
|
||||
notifyStop);
|
||||
}
|
||||
} else {
|
||||
if (notification) {
|
||||
notification.close();
|
||||
notification = undefined;
|
||||
}
|
||||
|
||||
gDevTools.showToolbox(target, "styleeditor");
|
||||
target = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side start is above. Client-side start adds a notification box
|
||||
*/
|
||||
start(newChromeWindow, newTarget, noreload = false) {
|
||||
target = newTarget;
|
||||
chromeWindow = newChromeWindow;
|
||||
|
||||
return super.start(noreload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side start is above. Client-side start adds a notification box
|
||||
*/
|
||||
toggle(newChromeWindow, newTarget) {
|
||||
target = newTarget;
|
||||
chromeWindow = newChromeWindow;
|
||||
|
||||
return super.toggle();
|
||||
}
|
||||
|
||||
/**
|
||||
* We count STARTING and STOPPING as 'running'
|
||||
*/
|
||||
isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
}
|
||||
|
||||
exports.CSSUsageFront = CSSUsageFront;
|
||||
registerFront(CSSUsageFront);
|
@ -17,7 +17,6 @@ DevToolsModules(
|
||||
'animation.js',
|
||||
'changes.js',
|
||||
'css-properties.js',
|
||||
'csscoverage.js',
|
||||
'device.js',
|
||||
'emulation.js',
|
||||
'framerate.js',
|
||||
|
@ -1,47 +0,0 @@
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE This file contains the CSS Coverage Report
|
||||
- strings. See the 'csscoverage' command for more information, and
|
||||
- devtools/client/styleeditor/index.xul for context -->
|
||||
|
||||
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
|
||||
- keep it in English, or another language commonly spoken among web developers.
|
||||
- You want to make that choice consistent across the developer tools.
|
||||
- A good criteria is the language in which you'd find the best
|
||||
- documentation on web development on the web. -->
|
||||
|
||||
<!-- LOCALIZATION NOTE (csscoverage.backButton):
|
||||
- Text on the button to go back to the main style editor -->
|
||||
<!ENTITY csscoverage.backButton "Back">
|
||||
|
||||
<!-- LOCALIZATION NOTE (csscoverage.unused, csscoverage.noMatches):
|
||||
- This is the heading and body text for the CSS usage part of the report -->
|
||||
<!ENTITY csscoverage.unused "Unused Rules">
|
||||
<!ENTITY csscoverage.noMatches "No matches found for the following rules:">
|
||||
|
||||
<!-- LOCALIZATION NOTE (csscoverage.optimize.header):
|
||||
- This is the heading for the CSS optimization part of the report -->
|
||||
<!ENTITY csscoverage.optimize.header "Optimizable Pages">
|
||||
|
||||
<!-- LOCALIZATION NOTE (csscoverage.preload1, csscoverage.preload2,
|
||||
- csscoverage.preload3): These 3 are part of a paragraph with 1 and 2
|
||||
- separated by a styled <link> tag and 2 and 3 separated by a styled
|
||||
- <style> tag -->
|
||||
<!ENTITY csscoverage.optimize.body1 "You can sometimes speed up loading by moving">
|
||||
<!ENTITY csscoverage.optimize.body2 "tags to the bottom of the page and creating a new inline">
|
||||
<!ENTITY csscoverage.optimize.body3 "element with the styles needed before the ‘load’ event to the top. Here are the style blocks you need:">
|
||||
|
||||
<!-- LOCALIZATION NOTE (csscoverage.optimize.bodyX):
|
||||
- This is what we say when we have no optimization suggestions -->
|
||||
<!ENTITY csscoverage.optimize.bodyX "All rules are inlined.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (csscoverage.footer1, csscoverage.footer2a,
|
||||
- csscoverage.footer3, csscoverage.footer4): The text displayed at the
|
||||
- bottom of the page, with 2a being the URL opened when the link text in 3
|
||||
- is clicked -->
|
||||
<!ENTITY csscoverage.footer1 "See">
|
||||
<!ENTITY csscoverage.footer2a "https://developer.mozilla.org/docs/Tools/CSS_Coverage">
|
||||
<!ENTITY csscoverage.footer3 "the MDN article on the CSS Coverage Tool">
|
||||
<!ENTITY csscoverage.footer4 "for caveats in the generation of this report.">
|
@ -1,32 +0,0 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used in the 'csscoverage' command and in
|
||||
# the user interface that this command creates.
|
||||
|
||||
# LOCALIZATION NOTE (csscoverageDesc, csscoverageStartDesc2,
|
||||
# csscoverageStopDesc2, csscoverageOneShotDesc2, csscoverageToggleDesc2,
|
||||
# csscoverageReportDesc2): Short descriptions of the csscoverage commands
|
||||
csscoverageDesc=Control CSS coverage analysis
|
||||
csscoverageStartDesc2=Begin collecting CSS coverage data
|
||||
csscoverageStopDesc2=Stop collecting CSS coverage data
|
||||
csscoverageOneShotDesc2=Collect instantaneous CSS coverage data
|
||||
csscoverageToggleDesc2=Toggle collecting CSS coverage data
|
||||
csscoverageReportDesc2=Show CSS coverage report
|
||||
csscoverageStartNoReloadDesc=Don’t start with a page reload
|
||||
csscoverageStartNoReloadManual=It’s best if we start by reloading the current page because that starts the test at a known point, but there could be reasons why we don’t want to do that (e.g. the page contains state that will be lost across a reload)
|
||||
|
||||
# LOCALIZATION NOTE (csscoverageRunningReply, csscoverageDoneReply): Text that
|
||||
# describes the current state of the css coverage system
|
||||
csscoverageRunningReply=Running CSS coverage analysis
|
||||
csscoverageDoneReply=CSS Coverage analysis completed
|
||||
|
||||
# LOCALIZATION NOTE (csscoverageRunningError, csscoverageNotRunningError,
|
||||
# csscoverageNotRunError): Error message that describe things that can go wrong
|
||||
# with the css coverage system
|
||||
csscoverageRunningError=CSS coverage analysis already running
|
||||
csscoverageNotRunningError=CSS coverage analysis not running
|
||||
csscoverageNotRunError=CSS coverage analysis has not been run
|
||||
csscoverageNoRemoteError=Target does not support CSS Coverage
|
||||
csscoverageOneShotReportError=CSS coverage report is not available for ‘oneshot’ data. Please use start/stop.
|
@ -1,42 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {Arg, RetVal, generateActorSpec} = require("devtools/shared/protocol");
|
||||
|
||||
const cssUsageSpec = generateActorSpec({
|
||||
typeName: "cssUsage",
|
||||
|
||||
events: {
|
||||
"state-change": {
|
||||
type: "stateChange",
|
||||
stateChange: Arg(0, "json"),
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
start: {
|
||||
request: { url: Arg(0, "boolean") },
|
||||
},
|
||||
stop: {},
|
||||
toggle: {},
|
||||
oneshot: {},
|
||||
createEditorReport: {
|
||||
request: { url: Arg(0, "string") },
|
||||
response: { reports: RetVal("array:json") },
|
||||
},
|
||||
createEditorReportForSheet: {
|
||||
request: { url: Arg(0, "stylesheet") },
|
||||
response: { reports: RetVal("array:json") },
|
||||
},
|
||||
createPageReport: {
|
||||
response: RetVal("json"),
|
||||
},
|
||||
_testOnlyVisitedPages: {
|
||||
response: { value: RetVal("array:string") },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
exports.cssUsageSpec = cssUsageSpec;
|
@ -52,11 +52,6 @@ const Types = exports.__TypesForTests = [
|
||||
spec: "devtools/shared/specs/css-properties",
|
||||
front: "devtools/shared/fronts/css-properties",
|
||||
},
|
||||
{
|
||||
types: ["cssUsage"],
|
||||
spec: "devtools/shared/specs/csscoverage",
|
||||
front: "devtools/shared/fronts/csscoverage",
|
||||
},
|
||||
{
|
||||
types: ["device"],
|
||||
spec: "devtools/shared/specs/device",
|
||||
|
@ -16,7 +16,6 @@ DevToolsModules(
|
||||
'animation.js',
|
||||
'changes.js',
|
||||
'css-properties.js',
|
||||
'csscoverage.js',
|
||||
'device.js',
|
||||
'emulation.js',
|
||||
'environment.js',
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Unused.h"
|
||||
@ -135,6 +136,8 @@ class ContentPermissionRequestParent : public PContentPermissionRequestParent {
|
||||
nsTArray<PermissionRequest> mRequests;
|
||||
|
||||
private:
|
||||
// Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
virtual mozilla::ipc::IPCResult Recvprompt() override;
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyVisibility(
|
||||
const bool& aIsVisible) override;
|
||||
@ -162,7 +165,8 @@ ContentPermissionRequestParent::~ContentPermissionRequestParent() {
|
||||
mozilla::ipc::IPCResult ContentPermissionRequestParent::Recvprompt() {
|
||||
mProxy = new nsContentPermissionRequestProxy(this);
|
||||
if (NS_FAILED(mProxy->Init(mRequests))) {
|
||||
mProxy->Cancel();
|
||||
RefPtr<nsContentPermissionRequestProxy> proxy(mProxy);
|
||||
proxy->Cancel();
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
@ -631,11 +635,14 @@ class RequestAllowEvent : public Runnable {
|
||||
mAllow(allow),
|
||||
mRequest(request) {}
|
||||
|
||||
// Not MOZ_CAN_RUN_SCRIPT because we can't annotate the thing we override yet.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
NS_IMETHOD Run() override {
|
||||
// MOZ_KnownLive is OK, because we never drop the ref to mRequest.
|
||||
if (mAllow) {
|
||||
mRequest->Allow(JS::UndefinedHandleValue);
|
||||
MOZ_KnownLive(mRequest)->Allow(JS::UndefinedHandleValue);
|
||||
} else {
|
||||
mRequest->Cancel();
|
||||
MOZ_KnownLive(mRequest)->Cancel();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -931,12 +938,14 @@ RemotePermissionRequest::~RemotePermissionRequest() {
|
||||
|
||||
void RemotePermissionRequest::DoCancel() {
|
||||
NS_ASSERTION(mRequest, "We need a request");
|
||||
mRequest->Cancel();
|
||||
nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
|
||||
request->Cancel();
|
||||
}
|
||||
|
||||
void RemotePermissionRequest::DoAllow(JS::HandleValue aChoices) {
|
||||
NS_ASSERTION(mRequest, "We need a request");
|
||||
mRequest->Allow(aChoices);
|
||||
nsCOMPtr<nsIContentPermissionRequest> request(mRequest);
|
||||
request->Allow(aChoices);
|
||||
}
|
||||
|
||||
// PContentPermissionRequestChild
|
||||
|
@ -220,7 +220,9 @@ class RemotePermissionRequest final
|
||||
RemotePermissionRequest(nsIContentPermissionRequest* aRequest,
|
||||
nsPIDOMWindowInner* aWindow);
|
||||
|
||||
// It will be called when prompt dismissed.
|
||||
// It will be called when prompt dismissed. MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
// because we don't have MOZ_CAN_RUN_SCRIPT bits in IPC code yet.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
mozilla::ipc::IPCResult RecvNotifyResult(
|
||||
const bool& aAllow, InfallibleTArray<PermissionChoice>&& aChoices);
|
||||
|
||||
@ -243,7 +245,9 @@ class RemotePermissionRequest final
|
||||
private:
|
||||
virtual ~RemotePermissionRequest();
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
void DoAllow(JS::HandleValue aChoices);
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
void DoCancel();
|
||||
|
||||
nsCOMPtr<nsIContentPermissionRequest> mRequest;
|
||||
|
@ -1,6 +1,7 @@
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
let [status, statusText, body] = request.queryString.split("&");
|
||||
let [status, statusText, encodedBody] = request.queryString.split("&");
|
||||
let body = decodeURIComponent(encodedBody);
|
||||
response.setStatusLine(request.httpVersion, status, statusText);
|
||||
response.setHeader("Content-Type", "text/xml", false);
|
||||
response.setHeader("Content-Length", "" + body.length, false);
|
||||
|
@ -19,6 +19,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=884693
|
||||
|
||||
const SERVER_URL = "http://mochi.test:8888/tests/dom/base/test/chrome/bug884693.sjs";
|
||||
const INVALID_XML = "InvalidXML";
|
||||
const XML_WITHOUT_ROOT = "<?xml version='1.0'?>";
|
||||
|
||||
let consoleService = Cc["@mozilla.org/consoleservice;1"].
|
||||
getService(Ci.nsIConsoleService)
|
||||
@ -63,7 +64,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=884693
|
||||
then(() => { return runTest(205, "Reset Content", INVALID_XML, "", []); }).
|
||||
then(() => { return runTest(304, "Not modified", "", "", []); }).
|
||||
then(() => { return runTest(304, "Not modified", INVALID_XML, "", []); }).
|
||||
then(() => { return runTest(200, "OK", "", "", ["no root element found"]); }).
|
||||
then(() => { return runTest(200, "OK", "", "", []); }).
|
||||
then(() => { return runTest(200, "OK", XML_WITHOUT_ROOT, XML_WITHOUT_ROOT, ["no root element found"]); }).
|
||||
then(() => { return runTest(200, "OK", INVALID_XML, INVALID_XML, ["syntax error"]); }).
|
||||
then(SimpleTest.finish);
|
||||
|
||||
|
@ -553,8 +553,13 @@ void ImplCycleCollectionUnlink(CallbackObjectHolder<T, U>& aField) {
|
||||
// subclass. This class is used in bindings to safely handle Fast* callbacks;
|
||||
// it ensures that the callback is traced, and that if something is holding onto
|
||||
// the callback when we're done with it HoldJSObjects is called.
|
||||
//
|
||||
// Since we effectively hold a ref to a refcounted thing (like RefPtr or
|
||||
// OwningNonNull), we are also MOZ_IS_SMARTPTR_TO_REFCOUNTED for static analysis
|
||||
// purposes.
|
||||
template <typename T>
|
||||
class MOZ_RAII RootedCallback : public JS::Rooted<T> {
|
||||
class MOZ_RAII MOZ_IS_SMARTPTR_TO_REFCOUNTED RootedCallback
|
||||
: public JS::Rooted<T> {
|
||||
public:
|
||||
explicit RootedCallback(JSContext* cx) : JS::Rooted<T>(cx), mCx(cx) {}
|
||||
|
||||
|
@ -7321,7 +7321,7 @@ class CGCallGenerator(CGThing):
|
||||
|
||||
# If it's a refcounted object, let the static analysis know it's
|
||||
# alive for the duration of the call.
|
||||
if a.type.isGeckoInterface():
|
||||
if a.type.isGeckoInterface() or a.type.isCallback():
|
||||
arg = CGWrapper(arg, pre="MOZ_KnownLive(", post=")")
|
||||
|
||||
args.append(arg)
|
||||
@ -10645,7 +10645,7 @@ class ClassMethod(ClassItem):
|
||||
virtual=False, const=False, bodyInHeader=False,
|
||||
templateArgs=None, visibility='public', body=None,
|
||||
breakAfterReturnDecl="\n",
|
||||
breakAfterSelf="\n", override=False):
|
||||
breakAfterSelf="\n", override=False, canRunScript=False):
|
||||
"""
|
||||
override indicates whether to flag the method as override
|
||||
"""
|
||||
@ -10663,10 +10663,13 @@ class ClassMethod(ClassItem):
|
||||
self.breakAfterReturnDecl = breakAfterReturnDecl
|
||||
self.breakAfterSelf = breakAfterSelf
|
||||
self.override = override
|
||||
self.canRunScript = canRunScript;
|
||||
ClassItem.__init__(self, name, visibility)
|
||||
|
||||
def getDecorators(self, declaring):
|
||||
decorators = []
|
||||
if self.canRunScript:
|
||||
decorators.append('MOZ_CAN_RUN_SCRIPT')
|
||||
if self.inline:
|
||||
decorators.append('inline')
|
||||
if declaring:
|
||||
@ -14783,7 +14786,7 @@ class CGNativeMember(ClassMethod):
|
||||
breakAfter=True, passJSBitsAsNeeded=True, visibility="public",
|
||||
spiderMonkeyInterfacesAreStructs=True,
|
||||
variadicIsSequence=False, resultNotAddRefed=False,
|
||||
virtual=False, override=False):
|
||||
virtual=False, override=False, canRunScript=False):
|
||||
"""
|
||||
If spiderMonkeyInterfacesAreStructs is false, SpiderMonkey interfaces
|
||||
will be passed as JS::Handle<JSObject*>. If it's true they will be
|
||||
@ -14813,7 +14816,8 @@ class CGNativeMember(ClassMethod):
|
||||
breakAfterSelf=breakAfterSelf,
|
||||
visibility=visibility,
|
||||
virtual=virtual,
|
||||
override=override)
|
||||
override=override,
|
||||
canRunScript=canRunScript)
|
||||
|
||||
def getReturnType(self, type, isMember):
|
||||
return self.getRetvalInfo(type, isMember)[0]
|
||||
@ -16227,17 +16231,21 @@ class CGCallback(CGClass):
|
||||
return [ClassMethod(method.name, method.returnType, args,
|
||||
bodyInHeader=True,
|
||||
templateArgs=["typename T"],
|
||||
body=bodyWithThis),
|
||||
body=bodyWithThis,
|
||||
canRunScript=method.canRunScript),
|
||||
ClassMethod(method.name, method.returnType, argsWithoutThis,
|
||||
bodyInHeader=True,
|
||||
body=bodyWithoutThis),
|
||||
body=bodyWithoutThis,
|
||||
canRunScript=method.canRunScript),
|
||||
ClassMethod(method.name, method.returnType, argsWithoutRv,
|
||||
bodyInHeader=True,
|
||||
templateArgs=["typename T"],
|
||||
body=bodyWithThisWithoutRv),
|
||||
body=bodyWithThisWithoutRv,
|
||||
canRunScript=method.canRunScript),
|
||||
ClassMethod(method.name, method.returnType, argsWithoutThisAndRv,
|
||||
bodyInHeader=True,
|
||||
body=bodyWithoutThisAndRv),
|
||||
body=bodyWithoutThisAndRv,
|
||||
canRunScript=method.canRunScript),
|
||||
method]
|
||||
|
||||
def deps(self):
|
||||
@ -16388,7 +16396,8 @@ class CallbackMember(CGNativeMember):
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling,
|
||||
rethrowContentException=False,
|
||||
spiderMonkeyInterfacesAreStructs=False,
|
||||
wrapScope='CallbackKnownNotGray()'):
|
||||
wrapScope='CallbackKnownNotGray()',
|
||||
canRunScript=False):
|
||||
"""
|
||||
needThisHandling is True if we need to be able to accept a specified
|
||||
thisObj, False otherwise.
|
||||
@ -16422,7 +16431,8 @@ class CallbackMember(CGNativeMember):
|
||||
extendedAttrs={},
|
||||
passJSBitsAsNeeded=False,
|
||||
visibility=visibility,
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
|
||||
canRunScript=canRunScript)
|
||||
# We have to do all the generation of our body now, because
|
||||
# the caller relies on us throwing if we can't manage it.
|
||||
self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n"
|
||||
@ -16644,10 +16654,12 @@ class CallbackMember(CGNativeMember):
|
||||
class CallbackMethod(CallbackMember):
|
||||
def __init__(self, sig, name, descriptorProvider, needThisHandling,
|
||||
rethrowContentException=False,
|
||||
spiderMonkeyInterfacesAreStructs=False):
|
||||
spiderMonkeyInterfacesAreStructs=False,
|
||||
canRunScript=False):
|
||||
CallbackMember.__init__(self, sig, name, descriptorProvider,
|
||||
needThisHandling, rethrowContentException,
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs)
|
||||
spiderMonkeyInterfacesAreStructs=spiderMonkeyInterfacesAreStructs,
|
||||
canRunScript=canRunScript)
|
||||
|
||||
def getRvalDecl(self):
|
||||
return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n"
|
||||
@ -16680,7 +16692,8 @@ class CallCallback(CallbackMethod):
|
||||
def __init__(self, callback, descriptorProvider):
|
||||
self.callback = callback
|
||||
CallbackMethod.__init__(self, callback.signatures()[0], "Call",
|
||||
descriptorProvider, needThisHandling=True)
|
||||
descriptorProvider, needThisHandling=True,
|
||||
canRunScript=not callback.isRunScriptBoundary())
|
||||
|
||||
def getThisDecl(self):
|
||||
return ""
|
||||
|
@ -4664,6 +4664,7 @@ class IDLCallback(IDLObjectWithScope):
|
||||
|
||||
self._treatNonCallableAsNull = False
|
||||
self._treatNonObjectAsNull = False
|
||||
self._isRunScriptBoundary = False
|
||||
|
||||
def isCallback(self):
|
||||
return True
|
||||
@ -4701,6 +4702,8 @@ class IDLCallback(IDLObjectWithScope):
|
||||
self._treatNonCallableAsNull = True
|
||||
elif attr.identifier() == "TreatNonObjectAsNull":
|
||||
self._treatNonObjectAsNull = True
|
||||
elif attr.identifier() == "MOZ_CAN_RUN_SCRIPT_BOUNDARY":
|
||||
self._isRunScriptBoundary = True
|
||||
else:
|
||||
unhandledAttrs.append(attr)
|
||||
if self._treatNonCallableAsNull and self._treatNonObjectAsNull:
|
||||
@ -4712,6 +4715,9 @@ class IDLCallback(IDLObjectWithScope):
|
||||
def _getDependentObjects(self):
|
||||
return set([self._returnType] + self._arguments)
|
||||
|
||||
def isRunScriptBoundary(self):
|
||||
return self._isRunScriptBoundary;
|
||||
|
||||
|
||||
class IDLCallbackType(IDLType):
|
||||
def __init__(self, location, callback):
|
||||
|
@ -28,6 +28,7 @@ class TestFunctions : public NonRefcountedDOMObject {
|
||||
|
||||
static Promise* PassThroughPromise(GlobalObject& aGlobal, Promise& aPromise);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static already_AddRefed<Promise> PassThroughCallbackPromise(
|
||||
GlobalObject& aGlobal, PromiseReturner& aCallback, ErrorResult& aRv);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
|
||||
callback PlacesEventCallback = void (sequence<PlacesEvent> events);
|
||||
|
||||
[ChromeOnly, Exposed=Window,
|
||||
|
@ -8,6 +8,7 @@ interface nsISupports;
|
||||
/**
|
||||
* A callback passed to SessionStoreUtils.forEachNonDynamicChildFrame().
|
||||
*/
|
||||
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
|
||||
callback SessionStoreUtilsFrameCallback = void (WindowProxy frame, unsigned long index);
|
||||
|
||||
/**
|
||||
|
@ -5,6 +5,7 @@
|
||||
interface URI;
|
||||
interface WindowProxy;
|
||||
|
||||
[MOZ_CAN_RUN_SCRIPT_BOUNDARY]
|
||||
callback WebExtensionLocalizeCallback = DOMString (DOMString unlocalizedText);
|
||||
|
||||
/**
|
||||
|
@ -47,7 +47,7 @@ JSObject* PositionError::WrapObject(JSContext* aCx,
|
||||
void PositionError::NotifyCallback(const GeoPositionErrorCallback& aCallback) {
|
||||
nsAutoMicroTask mt;
|
||||
if (aCallback.HasWebIDLCallback()) {
|
||||
PositionErrorCallback* callback = aCallback.GetWebIDLCallback();
|
||||
RefPtr<PositionErrorCallback> callback = aCallback.GetWebIDLCallback();
|
||||
|
||||
if (callback) {
|
||||
callback->Call(*this);
|
||||
|
@ -38,6 +38,7 @@ class PositionError final : public nsWrapperCache {
|
||||
|
||||
void GetMessage(nsAString& aMessage) const;
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
void NotifyCallback(const GeoPositionErrorCallback& callback);
|
||||
|
||||
private:
|
||||
|
@ -83,19 +83,24 @@ class nsGeolocationRequest final
|
||||
int32_t aWatchId = 0);
|
||||
|
||||
// nsIContentPermissionRequest
|
||||
NS_IMETHOD Cancel(void) override;
|
||||
NS_IMETHOD Allow(JS::HandleValue choices) override;
|
||||
MOZ_CAN_RUN_SCRIPT NS_IMETHOD Cancel(void) override;
|
||||
MOZ_CAN_RUN_SCRIPT NS_IMETHOD Allow(JS::HandleValue choices) override;
|
||||
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsGeolocationRequest)
|
||||
|
||||
void Shutdown();
|
||||
|
||||
// MOZ_CAN_RUN_SCRIPT_BOUNDARY is OK here because we're always called from a
|
||||
// runnable. Ideally nsIRunnable::Run and its overloads would just be
|
||||
// MOZ_CAN_RUN_SCRIPT and then we could be too...
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
void SendLocation(nsIDOMGeoPosition* aLocation);
|
||||
bool WantsHighAccuracy() {
|
||||
return !mShutdown && mOptions && mOptions->mEnableHighAccuracy;
|
||||
}
|
||||
void SetTimeoutTimer();
|
||||
void StopTimeoutTimer();
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
void NotifyErrorAndShutdown(uint16_t);
|
||||
using ContentPermissionRequestBase::GetPrincipal;
|
||||
nsIPrincipal* GetPrincipal();
|
||||
@ -124,7 +129,8 @@ class nsGeolocationRequest final
|
||||
WeakPtr<nsGeolocationRequest> mRequest;
|
||||
};
|
||||
|
||||
void Notify();
|
||||
// Only called from a timer, so MOZ_CAN_RUN_SCRIPT_BOUNDARY ok for now.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY void Notify();
|
||||
|
||||
bool mIsWatchPositionRequest;
|
||||
|
||||
@ -332,7 +338,8 @@ nsGeolocationRequest::Allow(JS::HandleValue aChoices) {
|
||||
}
|
||||
|
||||
// Kick off the geo device, if it isn't already running
|
||||
nsresult rv = gs->StartDevice(GetPrincipal());
|
||||
nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
|
||||
nsresult rv = gs->StartDevice(principal);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// Location provider error
|
||||
@ -410,7 +417,7 @@ void nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition) {
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
if (mCallback.HasWebIDLCallback()) {
|
||||
PositionCallback* callback = mCallback.GetWebIDLCallback();
|
||||
RefPtr<PositionCallback> callback = mCallback.GetWebIDLCallback();
|
||||
|
||||
MOZ_ASSERT(callback);
|
||||
callback->Call(*wrapped);
|
||||
@ -942,13 +949,15 @@ Geolocation::NotifyError(uint16_t aErrorCode) {
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
|
||||
|
||||
for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
|
||||
mPendingCallbacks[i - 1]->NotifyErrorAndShutdown(aErrorCode);
|
||||
RefPtr<nsGeolocationRequest> request = mPendingCallbacks[i - 1];
|
||||
request->NotifyErrorAndShutdown(aErrorCode);
|
||||
// NotifyErrorAndShutdown() removes the request from the array
|
||||
}
|
||||
|
||||
// notify everyone that is watching
|
||||
for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
|
||||
mWatchingCallbacks[i]->NotifyErrorAndShutdown(aErrorCode);
|
||||
RefPtr<nsGeolocationRequest> request = mWatchingCallbacks[i];
|
||||
request->NotifyErrorAndShutdown(aErrorCode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -76,6 +76,7 @@ class nsGeolocationService final : public nsIGeolocationUpdate,
|
||||
CachedPositionAndAccuracy GetCachedPosition();
|
||||
|
||||
// Find and startup a geolocation device (gps, nmea, etc.)
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult StartDevice(nsIPrincipal* aPrincipal);
|
||||
|
||||
// Stop the started geolocation device (gps, nmea, etc.)
|
||||
@ -132,6 +133,7 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
||||
virtual JSObject* WrapObject(JSContext* aCtx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
int32_t WatchPosition(PositionCallback& aCallback,
|
||||
PositionErrorCallback* aErrorCallback,
|
||||
const PositionOptions& aOptions, CallerType aCallerType,
|
||||
@ -143,6 +145,7 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
||||
void ClearWatch(int32_t aWatchId);
|
||||
|
||||
// A WatchPosition for C++ use. Returns -1 if we failed to actually watch.
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
int32_t WatchPosition(nsIDOMGeoPositionCallback* aCallback,
|
||||
nsIDOMGeoPositionErrorCallback* aErrorCallback,
|
||||
UniquePtr<PositionOptions>&& aOptions);
|
||||
@ -186,6 +189,7 @@ class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
|
||||
GeoPositionErrorCallback aErrorCallback,
|
||||
UniquePtr<PositionOptions>&& aOptions,
|
||||
CallerType aCallerType);
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
int32_t WatchPosition(GeoPositionCallback aCallback,
|
||||
GeoPositionErrorCallback aErrorCallback,
|
||||
UniquePtr<PositionOptions>&& aOptions,
|
||||
|
@ -5,7 +5,6 @@ async function idbCheckFunc() {
|
||||
factory = indexedDB;
|
||||
} catch (ex) {
|
||||
// in a frame-script, we need to pierce "content"
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
factory = content.indexedDB;
|
||||
}
|
||||
try {
|
||||
@ -73,7 +72,6 @@ const workerScriptBlob = new Blob([workerScript]);
|
||||
*/
|
||||
async function workerCheckDeployer({ srcBlob, workerType }) {
|
||||
let worker, port;
|
||||
// eslint-disable-next-line mozilla/no-cpows-in-tests
|
||||
const url = content.URL.createObjectURL(srcBlob);
|
||||
if (workerType === "dedicated") {
|
||||
worker = new content.Worker(url);
|
||||
|
@ -33,22 +33,6 @@ interface nsIBrowser : nsISupports
|
||||
[array, size_is(linksCount)] in wstring links,
|
||||
in nsIPrincipal aTriggeringPrincipal);
|
||||
|
||||
/**
|
||||
* Flags for controlling the behavior of swapBrowsers
|
||||
*/
|
||||
|
||||
/**
|
||||
* The default options. This is used for swapping browsers between windows
|
||||
*/
|
||||
const unsigned long SWAP_DEFAULT = 0;
|
||||
|
||||
/**
|
||||
* If this bit is set, swapping the browsers will not swap the permanentKey of
|
||||
* the browsers. This is used when performing cross process loads by swapping
|
||||
* browsers.
|
||||
*/
|
||||
const unsigned long SWAP_KEEP_PERMANENT_KEY = 0x1;
|
||||
|
||||
/**
|
||||
* Swapping of frameloaders are usually initiated from a frameloader owner
|
||||
* or other components operating on frameloader owners. This is done by calling
|
||||
@ -61,7 +45,7 @@ interface nsIBrowser : nsISupports
|
||||
* frameloader owners such as <xul:browser> can setup their properties and /
|
||||
* or listeners properly on swapping.
|
||||
*/
|
||||
void swapBrowsers(in nsIBrowser aOtherBrowser, in unsigned long aFlags);
|
||||
void swapBrowsers(in nsIBrowser aOtherBrowser);
|
||||
|
||||
/**
|
||||
* Close the browser (usually means to remove a tab).
|
||||
|
@ -98,8 +98,9 @@ interface nsIContentPermissionRequest : nsISupports {
|
||||
/**
|
||||
* allow or cancel the request
|
||||
*/
|
||||
|
||||
[can_run_script]
|
||||
void cancel();
|
||||
[can_run_script]
|
||||
void allow([optional] in jsval choices); // {"type1": "choice1", "type2": "choiceA"}
|
||||
};
|
||||
|
||||
|
@ -376,6 +376,9 @@ class ContentChild final : public PContentChild,
|
||||
|
||||
mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition);
|
||||
|
||||
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
|
||||
// in IPC code yet.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
mozilla::ipc::IPCResult RecvGeolocationError(const uint16_t& errorCode);
|
||||
|
||||
mozilla::ipc::IPCResult RecvUpdateDictionaryList(
|
||||
|
@ -4001,6 +4001,7 @@ mozilla::ipc::IPCResult ContentParent::RecvAsyncMessage(
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static int32_t AddGeolocationListener(
|
||||
nsIDOMGeoPositionCallback* watcher,
|
||||
nsIDOMGeoPositionErrorCallback* errorCallBack, bool highAccuracy) {
|
||||
|
@ -989,10 +989,16 @@ class ContentParent final : public PContentParent,
|
||||
const IPC::Principal& aPrincipal,
|
||||
const ClonedMessageData& aData);
|
||||
|
||||
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
|
||||
// in IPC code yet.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
mozilla::ipc::IPCResult RecvAddGeolocationListener(
|
||||
const IPC::Principal& aPrincipal, const bool& aHighAccuracy);
|
||||
mozilla::ipc::IPCResult RecvRemoveGeolocationListener();
|
||||
|
||||
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we don't have MOZ_CAN_RUN_SCRIPT bits
|
||||
// in IPC code yet.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
mozilla::ipc::IPCResult RecvSetGeolocationHigherAccuracy(const bool& aEnable);
|
||||
|
||||
mozilla::ipc::IPCResult RecvConsoleMessage(const nsString& aMessage);
|
||||
|
@ -50,7 +50,10 @@ ValueExtractor.prototype = {
|
||||
const value = this.extractValue(spec);
|
||||
let color;
|
||||
if (InspectorUtils.isValidCSSColor(value)) {
|
||||
color = value;
|
||||
const rgba = InspectorUtils.colorToRGBA(value);
|
||||
color = "#" + ((rgba.r << 16) |
|
||||
(rgba.g << 8) |
|
||||
rgba.b).toString(16);
|
||||
} else if (value) {
|
||||
this.console.warn(this.domBundle.formatStringFromName("ManifestInvalidCSSColor",
|
||||
[spec.property, value],
|
||||
|
@ -20,3 +20,106 @@ const data = {
|
||||
manifestURL,
|
||||
docURL,
|
||||
};
|
||||
|
||||
const validThemeColors = [
|
||||
["maroon", "#800000"],
|
||||
["#f00", "#ff0000"],
|
||||
["#ff0000", "#ff0000"],
|
||||
["rgb(255,0,0)", "#ff0000"],
|
||||
["rgb(255,0,0,1)", "#ff0000"],
|
||||
["rgb(255,0,0,1.0)", "#ff0000"],
|
||||
["rgb(255,0,0,100%)", "#ff0000"],
|
||||
["rgb(255 0 0)", "#ff0000"],
|
||||
["rgb(255 0 0 / 1)", "#ff0000"],
|
||||
["rgb(255 0 0 / 1.0)", "#ff0000"],
|
||||
["rgb(255 0 0 / 100%)", "#ff0000"],
|
||||
["rgb(100%, 0%, 0%)", "#ff0000"],
|
||||
["rgb(100%, 0%, 0%, 1)", "#ff0000"],
|
||||
["rgb(100%, 0%, 0%, 1.0)", "#ff0000"],
|
||||
["rgb(100%, 0%, 0%, 100%)", "#ff0000"],
|
||||
["rgb(100% 0% 0%)", "#ff0000"],
|
||||
["rgb(100% 0% 0% / 1)", "#ff0000"],
|
||||
["rgb(100%, 0%, 0%, 1.0)", "#ff0000"],
|
||||
["rgb(100%, 0%, 0%, 100%)", "#ff0000"],
|
||||
["rgb(300,0,0)", "#ff0000"],
|
||||
["rgb(300 0 0)", "#ff0000"],
|
||||
["rgb(255,-10,0)", "#ff0000"],
|
||||
["rgb(110%, 0%, 0%)", "#ff0000"],
|
||||
["rgba(255,0,0)", "#ff0000"],
|
||||
["rgba(255,0,0,1)", "#ff0000"],
|
||||
["rgba(255 0 0 / 1)", "#ff0000"],
|
||||
["rgba(100%,0%,0%,1)", "#ff0000"],
|
||||
["rgba(0,0,255,0.5)", "#ff"],
|
||||
["rgba(100%, 50%, 0%, 0.1)", "#ff8000"],
|
||||
["hsl(120, 100%, 50%)", "#ff00"],
|
||||
["hsl(120 100% 50%)", "#ff00"],
|
||||
["hsl(120, 100%, 50%, 1.0)", "#ff00"],
|
||||
["hsl(120 100% 50% / 1.0)", "#ff00"],
|
||||
["hsla(120, 100%, 50%)", "#ff00"],
|
||||
["hsla(120 100% 50%)", "#ff00"],
|
||||
["hsla(120, 100%, 50%, 1.0)", "#ff00"],
|
||||
["hsla(120 100% 50% / 1.0)", "#ff00"],
|
||||
["hsl(120deg, 100%, 50%)", "#ff00"],
|
||||
["hsl(133.33333333grad, 100%, 50%)", "#ff00"],
|
||||
["hsl(2.0943951024rad, 100%, 50%)", "#ff00"],
|
||||
["hsl(0.3333333333turn, 100%, 50%)", "#ff00"],
|
||||
];
|
||||
|
||||
function setupManifest(key, value) {
|
||||
const manifest = {};
|
||||
manifest[key] = value;
|
||||
data.jsonText = JSON.stringify(manifest);
|
||||
}
|
||||
|
||||
function testValidColors(key) {
|
||||
validThemeColors.forEach(item => {
|
||||
const [manifest_color, parsed_color] = item;
|
||||
setupManifest(key, manifest_color);
|
||||
const result = processor.process(data);
|
||||
|
||||
is(result[key], parsed_color, `Expect ${key} to be returned for ${manifest_color}`);
|
||||
});
|
||||
|
||||
// Trim tests
|
||||
validThemeColors.forEach(item => {
|
||||
const [manifest_color, parsed_color] = item;
|
||||
const expandedThemeColor = `${seperators}${lineTerminators}${manifest_color}${lineTerminators}${seperators}`;
|
||||
setupManifest(key, expandedThemeColor);
|
||||
const result = processor.process(data);
|
||||
|
||||
is(result[key], parsed_color, `Expect trimmed ${key} to be returned for ${manifest_color}`);
|
||||
});
|
||||
}
|
||||
|
||||
const invalidThemeColors = [
|
||||
"marooon",
|
||||
"f000000",
|
||||
"#ff00000",
|
||||
"rgb(100, 0%, 0%)",
|
||||
"rgb(255,0)",
|
||||
"rbg(255,-10,0)",
|
||||
"rgb(110, 0%, 0%)",
|
||||
"(255,0,0) }",
|
||||
"rgba(255)",
|
||||
" rgb(100%,0%,0%) }",
|
||||
"hsl(120, 100%, 50)",
|
||||
"hsl(120, 100%, 50.0)",
|
||||
"hsl 120, 100%, 50%",
|
||||
"hsla{120, 100%, 50%, 1}",
|
||||
];
|
||||
|
||||
function testInvalidColors(key) {
|
||||
typeTests.forEach(type => {
|
||||
setupManifest(key, type);
|
||||
const result = processor.process(data);
|
||||
|
||||
is(result[key], undefined, `Expect non-string ${key} to be undefined: ${typeof type}.`);
|
||||
});
|
||||
|
||||
invalidThemeColors.forEach(manifest_color => {
|
||||
setupManifest(key, manifest_color);
|
||||
const result = processor.process(data);
|
||||
|
||||
is(result[key], undefined, `Expect ${key} to be undefined: ${manifest_color}.`);
|
||||
});
|
||||
}
|
||||
|
@ -16,103 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1195018
|
||||
**/
|
||||
"use strict";
|
||||
|
||||
typeTests.forEach(type => {
|
||||
data.jsonText = JSON.stringify({
|
||||
background_color: type,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.background_color, undefined, `Expect non-string background_color to be undefined: ${typeof type}.`);
|
||||
});
|
||||
|
||||
var validThemeColors = [
|
||||
"maroon",
|
||||
"#f00",
|
||||
"#ff0000",
|
||||
"rgb(255,0,0)",
|
||||
"rgb(255,0,0,1)",
|
||||
"rgb(255,0,0,1.0)",
|
||||
"rgb(255,0,0,100%)",
|
||||
"rgb(255 0 0)",
|
||||
"rgb(255 0 0 / 1)",
|
||||
"rgb(255 0 0 / 1.0)",
|
||||
"rgb(255 0 0 / 100%)",
|
||||
"rgb(100%, 0%, 0%)",
|
||||
"rgb(100%, 0%, 0%, 1)",
|
||||
"rgb(100%, 0%, 0%, 1.0)",
|
||||
"rgb(100%, 0%, 0%, 100%)",
|
||||
"rgb(100% 0% 0%)",
|
||||
"rgb(100% 0% 0% / 1)",
|
||||
"rgb(100%, 0%, 0%, 1.0)",
|
||||
"rgb(100%, 0%, 0%, 100%)",
|
||||
"rgb(300,0,0)",
|
||||
"rgb(300 0 0)",
|
||||
"rgb(255,-10,0)",
|
||||
"rgb(110%, 0%, 0%)",
|
||||
"rgba(255,0,0)",
|
||||
"rgba(255,0,0,1)",
|
||||
"rgba(255 0 0 / 1)",
|
||||
"rgba(100%,0%,0%,1)",
|
||||
"rgba(0,0,255,0.5)",
|
||||
"rgba(100%, 50%, 0%, 0.1)",
|
||||
"hsl(120, 100%, 50%)",
|
||||
"hsl(120 100% 50%)",
|
||||
"hsl(120, 100%, 50%, 1.0)",
|
||||
"hsl(120 100% 50% / 1.0)",
|
||||
"hsla(120, 100%, 50%)",
|
||||
"hsla(120 100% 50%)",
|
||||
"hsla(120, 100%, 50%, 1.0)",
|
||||
"hsla(120 100% 50% / 1.0)",
|
||||
"hsl(120deg, 100%, 50%)",
|
||||
"hsl(133.33333333grad, 100%, 50%)",
|
||||
"hsl(2.0943951024rad, 100%, 50%)",
|
||||
"hsl(0.3333333333turn, 100%, 50%)",
|
||||
];
|
||||
|
||||
validThemeColors.forEach(background_color => {
|
||||
data.jsonText = JSON.stringify({
|
||||
background_color,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.background_color, background_color, `Expect background_color to be returned: ${background_color}.`);
|
||||
});
|
||||
|
||||
var invalidThemeColors = [
|
||||
"marooon",
|
||||
"f000000",
|
||||
"#ff00000",
|
||||
"rgb(100, 0%, 0%)",
|
||||
"rgb(255,0)",
|
||||
"rbg(255,-10,0)",
|
||||
"rgb(110, 0%, 0%)",
|
||||
"(255,0,0) }",
|
||||
"rgba(255)",
|
||||
" rgb(100%,0%,0%) }",
|
||||
"hsl(120, 100%, 50)",
|
||||
"hsl(120, 100%, 50.0)",
|
||||
"hsl 120, 100%, 50%",
|
||||
"hsla{120, 100%, 50%, 1}",
|
||||
];
|
||||
|
||||
invalidThemeColors.forEach(background_color => {
|
||||
data.jsonText = JSON.stringify({
|
||||
background_color,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.background_color, undefined, `Expect background_color to be undefined: ${background_color}.`);
|
||||
});
|
||||
|
||||
// Trim tests
|
||||
validThemeColors.forEach(background_color => {
|
||||
var expandedThemeColor = `${seperators}${lineTerminators}${background_color}${lineTerminators}${seperators}`;
|
||||
data.jsonText = JSON.stringify({
|
||||
background_color: expandedThemeColor,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.background_color, background_color, `Expect trimmed background_color to be returned.`);
|
||||
});
|
||||
testValidColors("background_color");
|
||||
testInvalidColors("background_color");
|
||||
</script>
|
||||
</head>
|
||||
|
@ -16,103 +16,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1195018
|
||||
**/
|
||||
"use strict";
|
||||
|
||||
typeTests.forEach(type => {
|
||||
data.jsonText = JSON.stringify({
|
||||
theme_color: type,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.theme_color, undefined, `Expect non-string theme_color to be undefined: ${typeof type}.`);
|
||||
});
|
||||
|
||||
var validThemeColors = [
|
||||
"maroon",
|
||||
"#f00",
|
||||
"#ff0000",
|
||||
"rgb(255,0,0)",
|
||||
"rgb(255,0,0,1)",
|
||||
"rgb(255,0,0,1.0)",
|
||||
"rgb(255,0,0,100%)",
|
||||
"rgb(255 0 0)",
|
||||
"rgb(255 0 0 / 1)",
|
||||
"rgb(255 0 0 / 1.0)",
|
||||
"rgb(255 0 0 / 100%)",
|
||||
"rgb(100%, 0%, 0%)",
|
||||
"rgb(100%, 0%, 0%, 1)",
|
||||
"rgb(100%, 0%, 0%, 1.0)",
|
||||
"rgb(100%, 0%, 0%, 100%)",
|
||||
"rgb(100% 0% 0%)",
|
||||
"rgb(100% 0% 0% / 1)",
|
||||
"rgb(100%, 0%, 0%, 1.0)",
|
||||
"rgb(100%, 0%, 0%, 100%)",
|
||||
"rgb(300,0,0)",
|
||||
"rgb(300 0 0)",
|
||||
"rgb(255,-10,0)",
|
||||
"rgb(110%, 0%, 0%)",
|
||||
"rgba(255,0,0)",
|
||||
"rgba(255,0,0,1)",
|
||||
"rgba(255 0 0 / 1)",
|
||||
"rgba(100%,0%,0%,1)",
|
||||
"rgba(0,0,255,0.5)",
|
||||
"rgba(100%, 50%, 0%, 0.1)",
|
||||
"hsl(120, 100%, 50%)",
|
||||
"hsl(120 100% 50%)",
|
||||
"hsl(120, 100%, 50%, 1.0)",
|
||||
"hsl(120 100% 50% / 1.0)",
|
||||
"hsla(120, 100%, 50%)",
|
||||
"hsla(120 100% 50%)",
|
||||
"hsla(120, 100%, 50%, 1.0)",
|
||||
"hsla(120 100% 50% / 1.0)",
|
||||
"hsl(120deg, 100%, 50%)",
|
||||
"hsl(133.33333333grad, 100%, 50%)",
|
||||
"hsl(2.0943951024rad, 100%, 50%)",
|
||||
"hsl(0.3333333333turn, 100%, 50%)",
|
||||
];
|
||||
|
||||
validThemeColors.forEach(theme_color => {
|
||||
data.jsonText = JSON.stringify({
|
||||
theme_color,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.theme_color, theme_color, `Expect theme_color to be returned: ${theme_color}.`);
|
||||
});
|
||||
|
||||
var invalidThemeColors = [
|
||||
"marooon",
|
||||
"f000000",
|
||||
"#ff00000",
|
||||
"rgb(100, 0%, 0%)",
|
||||
"rgb(255,0)",
|
||||
"rbg(255,-10,0)",
|
||||
"rgb(110, 0%, 0%)",
|
||||
"(255,0,0) }",
|
||||
"rgba(255)",
|
||||
" rgb(100%,0%,0%) }",
|
||||
"hsl(120, 100%, 50)",
|
||||
"hsl(120, 100%, 50.0)",
|
||||
"hsl 120, 100%, 50%",
|
||||
"hsla{120, 100%, 50%, 1}",
|
||||
];
|
||||
|
||||
invalidThemeColors.forEach(theme_color => {
|
||||
data.jsonText = JSON.stringify({
|
||||
theme_color,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.theme_color, undefined, `Expect theme_color to be undefined: ${theme_color}.`);
|
||||
});
|
||||
|
||||
// Trim tests
|
||||
validThemeColors.forEach(theme_color => {
|
||||
var expandedThemeColor = `${seperators}${lineTerminators}${theme_color}${lineTerminators}${seperators}`;
|
||||
data.jsonText = JSON.stringify({
|
||||
theme_color: expandedThemeColor,
|
||||
});
|
||||
var result = processor.process(data);
|
||||
|
||||
is(result.theme_color, theme_color, `Expect trimmed theme_color to be returned.`);
|
||||
});
|
||||
testValidColors("theme_color");
|
||||
testInvalidColors("theme_color");
|
||||
</script>
|
||||
</head>
|
||||
|
@ -1677,12 +1677,10 @@ class PeerConnectionObserver {
|
||||
}
|
||||
|
||||
onSetLocalDescriptionSuccess() {
|
||||
this._dompc._syncTransceivers();
|
||||
this._dompc._onSetLocalDescriptionSuccess();
|
||||
}
|
||||
|
||||
onSetRemoteDescriptionSuccess() {
|
||||
this._dompc._syncTransceivers();
|
||||
this._dompc._processTrackAdditionsAndRemovals();
|
||||
this._dompc._fireLegacyAddStreamEvents();
|
||||
this._dompc._transceivers = this._dompc._transceivers.filter(t => !t.shouldRemove);
|
||||
|
@ -1101,7 +1101,6 @@ Result<Ok, nsresult> Sbgp::Parse(Box& aBox) {
|
||||
uint32_t flags;
|
||||
MOZ_TRY_VAR(flags, reader->ReadU32());
|
||||
const uint8_t version = flags >> 24;
|
||||
flags = flags & 0xffffff;
|
||||
|
||||
uint32_t type;
|
||||
MOZ_TRY_VAR(type, reader->ReadU32());
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIGeolocationProvider.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/*
|
||||
* The CoreLocationObjects class contains the CoreLocation objects
|
||||
@ -30,6 +31,10 @@ class CoreLocationLocationProvider : public nsIGeolocationProvider {
|
||||
NS_DECL_NSIGEOLOCATIONPROVIDER
|
||||
|
||||
CoreLocationLocationProvider();
|
||||
// MOZ_CAN_RUN_SCRIPT_BOUNDARY because we can't mark Objective-C methods as
|
||||
// MOZ_CAN_RUN_SCRIPT as far as I can tell, and this method is called from
|
||||
// Objective-C.
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
void NotifyError(uint16_t aErrorCode);
|
||||
void Update(nsIDOMGeoPosition* aSomewhere);
|
||||
void CreateMLSFallbackProvider();
|
||||
|
@ -224,7 +224,8 @@ void CoreLocationLocationProvider::Update(nsIDOMGeoPosition* aSomewhere) {
|
||||
}
|
||||
}
|
||||
void CoreLocationLocationProvider::NotifyError(uint16_t aErrorCode) {
|
||||
mCallback->NotifyError(aErrorCode);
|
||||
nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
|
||||
callback->NotifyError(aErrorCode);
|
||||
}
|
||||
void CoreLocationLocationProvider::CreateMLSFallbackProvider() {
|
||||
if (mMLSFallbackProvider) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "prtime.h"
|
||||
#include "MLSFallback.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/dom/PositionErrorBinding.h"
|
||||
@ -40,7 +41,8 @@ WindowsLocationProvider::MLSUpdate::NotifyError(uint16_t aError) {
|
||||
if (!mCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return mCallback->NotifyError(aError);
|
||||
nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
|
||||
return callback->NotifyError(aError);
|
||||
}
|
||||
|
||||
class LocationEvent final : public ILocationEvents {
|
||||
@ -55,6 +57,7 @@ class LocationEvent final : public ILocationEvents {
|
||||
STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override;
|
||||
|
||||
// ILocationEvents interface
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY
|
||||
STDMETHODIMP OnStatusChanged(REFIID aReportType,
|
||||
LOCATION_REPORT_STATUS aStatus) override;
|
||||
STDMETHODIMP OnLocationChanged(REFIID aReportType,
|
||||
@ -127,7 +130,8 @@ LocationEvent::OnStatusChanged(REFIID aReportType,
|
||||
default:
|
||||
return S_OK;
|
||||
}
|
||||
mCallback->NotifyError(err);
|
||||
nsCOMPtr<nsIGeolocationUpdate> callback(mCallback);
|
||||
callback->NotifyError(err);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user