summaryrefslogtreecommitdiffstats
path: root/browser/components/preferences
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/preferences')
-rw-r--r--browser/components/preferences/containers.js2
-rw-r--r--browser/components/preferences/dialogs/addEngine.js2
-rw-r--r--browser/components/preferences/dialogs/blocklists.js14
-rw-r--r--browser/components/preferences/dialogs/clearSiteData.js2
-rw-r--r--browser/components/preferences/dialogs/colors.xhtml10
-rw-r--r--browser/components/preferences/dialogs/connection.js10
-rw-r--r--browser/components/preferences/dialogs/connection.xhtml14
-rw-r--r--browser/components/preferences/dialogs/containers.js4
-rw-r--r--browser/components/preferences/dialogs/dohExceptions.js1
-rw-r--r--browser/components/preferences/dialogs/fonts.xhtml4
-rw-r--r--browser/components/preferences/dialogs/translationExceptions.js20
-rw-r--r--browser/components/preferences/dialogs/translations.js20
-rw-r--r--browser/components/preferences/findInPage.js43
-rw-r--r--browser/components/preferences/home.js18
-rw-r--r--browser/components/preferences/main.inc.xhtml13
-rw-r--r--browser/components/preferences/main.js26
-rw-r--r--browser/components/preferences/preferences.js9
-rw-r--r--browser/components/preferences/preferences.xhtml3
-rw-r--r--browser/components/preferences/privacy.inc.xhtml9
-rw-r--r--browser/components/preferences/privacy.js13
-rw-r--r--browser/components/preferences/search.js1113
-rw-r--r--browser/components/preferences/sync.js2
-rw-r--r--browser/components/preferences/tests/browser.toml4
-rw-r--r--browser/components/preferences/tests/browser_about_settings.js29
-rw-r--r--browser/components/preferences/tests/browser_basic_rebuild_fonts_test.js2
-rw-r--r--browser/components/preferences/tests/browser_browser_languages_subdialog.js20
-rw-r--r--browser/components/preferences/tests/browser_cert_export.js2
-rw-r--r--browser/components/preferences/tests/browser_connection.js2
-rw-r--r--browser/components/preferences/tests/browser_connection_bug388287.js2
-rw-r--r--browser/components/preferences/tests/browser_cookies_exceptions.js26
-rw-r--r--browser/components/preferences/tests/browser_dns_over_https_exceptions_subdialog.js185
-rw-r--r--browser/components/preferences/tests/browser_fluent.js4
-rw-r--r--browser/components/preferences/tests/browser_localSearchShortcuts.js4
-rw-r--r--browser/components/preferences/tests/browser_permissions_urlFieldHidden.js2
-rw-r--r--browser/components/preferences/tests/browser_proxy_backup.js2
-rw-r--r--browser/components/preferences/tests/browser_searchChangedEngine.js11
-rw-r--r--browser/components/preferences/tests/browser_search_within_preferences_2.js84
-rw-r--r--browser/components/preferences/tests/browser_sync_chooseWhatToSync.js2
-rw-r--r--browser/components/preferences/tests/browser_sync_pairing.js2
-rw-r--r--browser/components/preferences/tests/browser_trendingsuggestions.js17
-rw-r--r--browser/components/preferences/tests/head.js2
-rw-r--r--browser/components/preferences/tests/siteData/browser_clearSiteData.js2
-rw-r--r--browser/components/preferences/tests/siteData/head.js2
-rw-r--r--browser/components/preferences/tests/siteData/service_worker_test.html2
-rw-r--r--browser/components/preferences/translations.inc.xhtml7
45 files changed, 1137 insertions, 630 deletions
diff --git a/browser/components/preferences/containers.js b/browser/components/preferences/containers.js
index 80d1ec7cc3..171fd47ce1 100644
--- a/browser/components/preferences/containers.js
+++ b/browser/components/preferences/containers.js
@@ -123,7 +123,7 @@ let gContainersPane = {
this.openPreferenceDialog(button.getAttribute("value"));
},
- onAddButtonCommand(button) {
+ onAddButtonCommand() {
this.openPreferenceDialog(null);
},
diff --git a/browser/components/preferences/dialogs/addEngine.js b/browser/components/preferences/dialogs/addEngine.js
index 1faf8622b3..6b9d8f663b 100644
--- a/browser/components/preferences/dialogs/addEngine.js
+++ b/browser/components/preferences/dialogs/addEngine.js
@@ -26,7 +26,7 @@ let gAddEngineDialog = {
document.addEventListener("dialogaccept", this.onAddEngine.bind(this));
},
- async onAddEngine(event) {
+ async onAddEngine() {
let url = document
.getElementById("engineUrl")
.value.replace(/%s/, "{searchTerms}");
diff --git a/browser/components/preferences/dialogs/blocklists.js b/browser/components/preferences/dialogs/blocklists.js
index c28ee09f96..89e21c476f 100644
--- a/browser/components/preferences/dialogs/blocklists.js
+++ b/browser/components/preferences/dialogs/blocklists.js
@@ -26,28 +26,28 @@ var gBlocklistManager = {
return "";
},
- isSeparator(index) {
+ isSeparator() {
return false;
},
isSorted() {
return false;
},
- isContainer(index) {
+ isContainer() {
return false;
},
- setTree(tree) {},
- getImageSrc(row, column) {},
+ setTree() {},
+ getImageSrc() {},
getCellValue(row, column) {
if (column.id == "selectionCol") {
return gBlocklistManager._blockLists[row].selected;
}
return undefined;
},
- cycleHeader(column) {},
- getRowProperties(row) {
+ cycleHeader() {},
+ getRowProperties() {
return "";
},
- getColumnProperties(column) {
+ getColumnProperties() {
return "";
},
getCellProperties(row, column) {
diff --git a/browser/components/preferences/dialogs/clearSiteData.js b/browser/components/preferences/dialogs/clearSiteData.js
index 061534b52a..664ad114fa 100644
--- a/browser/components/preferences/dialogs/clearSiteData.js
+++ b/browser/components/preferences/dialogs/clearSiteData.js
@@ -58,7 +58,7 @@ var gClearSiteDataDialog = {
);
},
- onCheckboxCommand(event) {
+ onCheckboxCommand() {
this._dialog.setAttribute(
"buttondisabledaccept",
!(this._clearSiteDataCheckbox.checked || this._clearCacheCheckbox.checked)
diff --git a/browser/components/preferences/dialogs/colors.xhtml b/browser/components/preferences/dialogs/colors.xhtml
index 1720cf3498..3181dd5c6d 100644
--- a/browser/components/preferences/dialogs/colors.xhtml
+++ b/browser/components/preferences/dialogs/colors.xhtml
@@ -41,7 +41,11 @@
<hbox>
<groupbox flex="1">
- <label><html:h2 data-l10n-id="colors-text-and-background" /></label>
+ <label
+ ><html:h2
+ class="heading-medium"
+ data-l10n-id="colors-text-and-background"
+ /></label>
<hbox align="center">
<label
data-l10n-id="colors-text-header"
@@ -74,7 +78,9 @@
</groupbox>
<groupbox flex="1">
- <label><html:h2 data-l10n-id="colors-links-header" /></label>
+ <label
+ ><html:h2 class="heading-medium" data-l10n-id="colors-links-header"
+ /></label>
<hbox align="center">
<label
data-l10n-id="colors-unvisited-links"
diff --git a/browser/components/preferences/dialogs/connection.js b/browser/components/preferences/dialogs/connection.js
index 0b21b1b5a5..33e8deb279 100644
--- a/browser/components/preferences/dialogs/connection.js
+++ b/browser/components/preferences/dialogs/connection.js
@@ -16,6 +16,7 @@ Preferences.addAll([
// both initialized when network.proxy.type initialization triggers a call to
// gConnectionsDialog.updateReloadButton().
{ id: "network.proxy.autoconfig_url", type: "string" },
+ { id: "network.proxy.system_wpad", type: "bool" },
{ id: "network.proxy.type", type: "int" },
{ id: "network.proxy.http", type: "string" },
{ id: "network.proxy.http_port", type: "int" },
@@ -130,11 +131,20 @@ var gConnectionsDialog = {
checkForSystemProxy() {
if ("@mozilla.org/system-proxy-settings;1" in Cc) {
document.getElementById("systemPref").removeAttribute("hidden");
+
+ var systemWpadAllowed = Preferences.get(
+ "network.proxy.system_wpad.allowed"
+ );
+ if (systemWpadAllowed && Services.appinfo.OS == "WINNT") {
+ document.getElementById("systemWpad").removeAttribute("hidden");
+ }
}
},
proxyTypeChanged() {
var proxyTypePref = Preferences.get("network.proxy.type");
+ var systemWpadPref = Preferences.get("network.proxy.system_wpad");
+ systemWpadPref.updateControlDisabledState(proxyTypePref.value != 5);
// Update http
var httpProxyURLPref = Preferences.get("network.proxy.http");
diff --git a/browser/components/preferences/dialogs/connection.xhtml b/browser/components/preferences/dialogs/connection.xhtml
index 2a1a3c0115..bb9a932033 100644
--- a/browser/components/preferences/dialogs/connection.xhtml
+++ b/browser/components/preferences/dialogs/connection.xhtml
@@ -63,7 +63,11 @@
</hbox>
<groupbox>
- <label><html:h2 data-l10n-id="connection-proxy-configure" /></label>
+ <label
+ ><html:h2
+ class="heading-medium"
+ data-l10n-id="connection-proxy-configure"
+ /></label>
<radiogroup id="networkProxyType" preference="network.proxy.type">
<radio value="0" data-l10n-id="connection-proxy-option-no" />
@@ -74,6 +78,14 @@
id="systemPref"
hidden="true"
/>
+ <checkbox
+ value="true"
+ data-l10n-id="connection-proxy-option-wpad"
+ id="systemWpad"
+ hidden="true"
+ preference="network.proxy.system_wpad"
+ class="indent"
+ />
<radio value="1" data-l10n-id="connection-proxy-option-manual" />
<box id="proxy-grid" class="indent" flex="1">
<html:div class="proxy-grid-row">
diff --git a/browser/components/preferences/dialogs/containers.js b/browser/components/preferences/dialogs/containers.js
index 14526545b6..87368689a0 100644
--- a/browser/components/preferences/dialogs/containers.js
+++ b/browser/components/preferences/dialogs/containers.js
@@ -88,7 +88,7 @@ let gContainersManager = {
this._dialog.setAttribute("buttondisabledaccept", !name.value.trim());
},
- createIconButtons(defaultIcon) {
+ createIconButtons() {
let radiogroup = document.createXULElement("radiogroup");
radiogroup.setAttribute("id", "icon");
radiogroup.className = "icon-buttons radio-buttons";
@@ -116,7 +116,7 @@ let gContainersManager = {
return radiogroup;
},
- createColorSwatches(defaultColor) {
+ createColorSwatches() {
let radiogroup = document.createXULElement("radiogroup");
radiogroup.setAttribute("id", "color");
radiogroup.className = "radio-buttons";
diff --git a/browser/components/preferences/dialogs/dohExceptions.js b/browser/components/preferences/dialogs/dohExceptions.js
index f4c1d4d80d..9bf64bd4ed 100644
--- a/browser/components/preferences/dialogs/dohExceptions.js
+++ b/browser/components/preferences/dialogs/dohExceptions.js
@@ -31,7 +31,6 @@ var gDoHExceptionsManager = {
"network.trr.excluded-domains"
);
- this._btnAddException.disabled = this._prefLocked;
document.getElementById("exceptionDialog").getButton("accept").disabled =
this._prefLocked;
this._urlField.disabled = this._prefLocked;
diff --git a/browser/components/preferences/dialogs/fonts.xhtml b/browser/components/preferences/dialogs/fonts.xhtml
index 44dc473ccb..cd35371324 100644
--- a/browser/components/preferences/dialogs/fonts.xhtml
+++ b/browser/components/preferences/dialogs/fonts.xhtml
@@ -43,7 +43,9 @@
<groupbox>
<hbox align="center">
<label control="selectLangs"
- ><html:h2 data-l10n-id="fonts-langgroup-header"
+ ><html:h2
+ class="heading-medium"
+ data-l10n-id="fonts-langgroup-header"
/></label>
</hbox>
<menulist id="selectLangs" preference="font.language.group">
diff --git a/browser/components/preferences/dialogs/translationExceptions.js b/browser/components/preferences/dialogs/translationExceptions.js
index 27579594c9..a83f7a3de1 100644
--- a/browser/components/preferences/dialogs/translationExceptions.js
+++ b/browser/components/preferences/dialogs/translationExceptions.js
@@ -46,29 +46,29 @@ Tree.prototype = {
get rowCount() {
return this._data.length;
},
- getCellText(aRow, aColumn) {
+ getCellText(aRow) {
return this._data[aRow];
},
- isSeparator(aIndex) {
+ isSeparator() {
return false;
},
isSorted() {
return false;
},
- isContainer(aIndex) {
+ isContainer() {
return false;
},
- setTree(aTree) {},
- getImageSrc(aRow, aColumn) {},
- getCellValue(aRow, aColumn) {},
- cycleHeader(column) {},
- getRowProperties(row) {
+ setTree() {},
+ getImageSrc() {},
+ getCellValue() {},
+ cycleHeader() {},
+ getRowProperties() {
return "";
},
- getColumnProperties(column) {
+ getColumnProperties() {
return "";
},
- getCellProperties(row, column) {
+ getCellProperties() {
return "";
},
QueryInterface: ChromeUtils.generateQI(["nsITreeView"]),
diff --git a/browser/components/preferences/dialogs/translations.js b/browser/components/preferences/dialogs/translations.js
index 826e6efb4b..7af2412b44 100644
--- a/browser/components/preferences/dialogs/translations.js
+++ b/browser/components/preferences/dialogs/translations.js
@@ -60,29 +60,29 @@ Tree.prototype = {
get rowCount() {
return this._data.length;
},
- getCellText(aRow, aColumn) {
+ getCellText(aRow) {
return this._data[aRow];
},
- isSeparator(aIndex) {
+ isSeparator() {
return false;
},
isSorted() {
return false;
},
- isContainer(aIndex) {
+ isContainer() {
return false;
},
- setTree(aTree) {},
- getImageSrc(aRow, aColumn) {},
- getCellValue(aRow, aColumn) {},
- cycleHeader(column) {},
- getRowProperties(row) {
+ setTree() {},
+ getImageSrc() {},
+ getCellValue() {},
+ cycleHeader() {},
+ getRowProperties() {
return "";
},
- getColumnProperties(column) {
+ getColumnProperties() {
return "";
},
- getCellProperties(row, column) {
+ getCellProperties() {
return "";
},
QueryInterface: ChromeUtils.generateQI(["nsITreeView"]),
diff --git a/browser/components/preferences/findInPage.js b/browser/components/preferences/findInPage.js
index 9fcd7b629b..7ee0a0bc06 100644
--- a/browser/components/preferences/findInPage.js
+++ b/browser/components/preferences/findInPage.js
@@ -117,9 +117,9 @@ var gSearchResultsPane = {
},
/**
- * Finds and returns text nodes within node and all descendants
- * Iterates through all the sibilings of the node object and adds the sibilings
- * to an array if sibiling is a TEXT_NODE else checks the text nodes with in current node
+ * Finds and returns text nodes within node and all descendants.
+ * Iterates through all the siblings of the node object and adds each sibling to an
+ * array if it's a TEXT_NODE, and otherwise recurses to check text nodes within it.
* Source - http://stackoverflow.com/questions/10730309/find-all-text-nodes-in-html-page
*
* @param Node nodeObject
@@ -414,14 +414,20 @@ var gSearchResultsPane = {
let matchesFound = false;
if (
nodeObject.childElementCount == 0 ||
- nodeObject.tagName == "button" ||
- nodeObject.tagName == "label" ||
- nodeObject.tagName == "description" ||
- nodeObject.tagName == "menulist" ||
- nodeObject.tagName == "menuitem" ||
- nodeObject.tagName == "checkbox"
+ nodeObject.localName == "button" ||
+ nodeObject.localName == "label" ||
+ nodeObject.localName == "description" ||
+ nodeObject.localName == "menulist" ||
+ nodeObject.localName == "menuitem" ||
+ nodeObject.localName == "checkbox" ||
+ nodeObject.localName == "moz-toggle"
) {
let simpleTextNodes = this.textNodeDescendants(nodeObject);
+ if (nodeObject.shadowRoot) {
+ simpleTextNodes.push(
+ ...this.textNodeDescendants(nodeObject.shadowRoot)
+ );
+ }
for (let node of simpleTextNodes) {
let result = this.highlightMatches(
[node],
@@ -440,8 +446,8 @@ var gSearchResultsPane = {
let accessKeyTextNodes = [];
if (
- nodeObject.tagName == "label" ||
- nodeObject.tagName == "description"
+ nodeObject.localName == "label" ||
+ nodeObject.localName == "description"
) {
accessKeyTextNodes.push(...simpleTextNodes);
}
@@ -469,7 +475,7 @@ var gSearchResultsPane = {
// Searching some elements, such as xul:label, store their user-visible text in a "value" attribute.
// Value will be skipped for menuitem since value in menuitem could represent index number to distinct each item.
let valueResult =
- nodeObject.tagName !== "menuitem" && nodeObject.tagName !== "radio"
+ nodeObject.localName !== "menuitem" && nodeObject.localName !== "radio"
? this.queryMatchesContent(
nodeObject.getAttribute("value"),
searchPhrase
@@ -497,12 +503,13 @@ var gSearchResultsPane = {
// Creating tooltips for buttons
if (
keywordsResult &&
- (nodeObject.tagName === "button" || nodeObject.tagName == "menulist")
+ (nodeObject.localName === "button" ||
+ nodeObject.localName == "menulist")
) {
this.listSearchTooltips.add(nodeObject);
}
- if (keywordsResult && nodeObject.tagName === "menuitem") {
+ if (keywordsResult && nodeObject.localName === "menuitem") {
nodeObject.setAttribute("indicator", "true");
this.listSearchMenuitemIndicators.add(nodeObject);
let menulist = nodeObject.closest("menulist");
@@ -512,8 +519,8 @@ var gSearchResultsPane = {
}
if (
- (nodeObject.tagName == "menulist" ||
- nodeObject.tagName == "menuitem") &&
+ (nodeObject.localName == "menulist" ||
+ nodeObject.localName == "menuitem") &&
(labelResult || valueResult || keywordsResult)
) {
nodeObject.setAttribute("highlightable", "true");
@@ -529,7 +536,7 @@ var gSearchResultsPane = {
// Should not search unselected child nodes of a <xul:deck> element
// except the "historyPane" <xul:deck> element.
- if (nodeObject.tagName == "deck" && nodeObject.id != "historyPane") {
+ if (nodeObject.localName == "deck" && nodeObject.id != "historyPane") {
let index = nodeObject.selectedIndex;
if (index != -1) {
let result = await this.searchChildNodeIfVisible(
@@ -572,7 +579,7 @@ var gSearchResultsPane = {
) {
result = await this.searchWithinNode(child, searchPhrase);
// Creating tooltips for menulist element
- if (result && nodeObject.tagName === "menulist") {
+ if (result && nodeObject.localName === "menulist") {
this.listSearchTooltips.add(nodeObject);
}
diff --git a/browser/components/preferences/home.js b/browser/components/preferences/home.js
index 6aa72b84b8..093248cff6 100644
--- a/browser/components/preferences/home.js
+++ b/browser/components/preferences/home.js
@@ -160,13 +160,14 @@ var gHomePane = {
}
let extensionOptions;
+ await ExtensionSettingsStore.initialize();
if (select.id === "homeMode") {
- extensionOptions = await ExtensionSettingsStore.getAllSettings(
+ extensionOptions = ExtensionSettingsStore.getAllSettings(
PREF_SETTING_TYPE,
HOMEPAGE_OVERRIDE_KEY
);
} else {
- extensionOptions = await ExtensionSettingsStore.getAllSettings(
+ extensionOptions = ExtensionSettingsStore.getAllSettings(
URL_OVERRIDES_TYPE,
NEW_TAB_KEY
);
@@ -344,12 +345,15 @@ var gHomePane = {
},
/**
- * _isTabAboutPreferences: Is a given tab set to about:preferences?
+ * _isTabAboutPreferencesOrSettings: Is a given tab set to about:preferences or about:settings?
* @param {Element} aTab A tab element
- * @returns {bool} Is the linkedBrowser of aElement set to about:preferences?
+ * @returns {bool} Is the linkedBrowser of aElement set to about:preferences or about:settings?
*/
- _isTabAboutPreferences(aTab) {
- return aTab.linkedBrowser.currentURI.spec.startsWith("about:preferences");
+ _isTabAboutPreferencesOrSettings(aTab) {
+ return (
+ aTab.linkedBrowser.currentURI.spec.startsWith("about:preferences") ||
+ aTab.linkedBrowser.currentURI.spec.startsWith("about:settings")
+ );
},
/**
@@ -367,7 +371,7 @@ var gHomePane = {
"navigator:browser"
) {
tabs = win.gBrowser.visibleTabs.slice(win.gBrowser._numPinnedTabs);
- tabs = tabs.filter(tab => !this._isTabAboutPreferences(tab));
+ tabs = tabs.filter(tab => !this._isTabAboutPreferencesOrSettings(tab));
// XXX: Bug 1441637 - Fix tabbrowser to report tab.closing before it blurs it
tabs = tabs.filter(tab => !tab.closing);
}
diff --git a/browser/components/preferences/main.inc.xhtml b/browser/components/preferences/main.inc.xhtml
index aaacdb6d97..1eb2189c41 100644
--- a/browser/components/preferences/main.inc.xhtml
+++ b/browser/components/preferences/main.inc.xhtml
@@ -159,14 +159,10 @@
<html:h2 data-l10n-id="preferences-web-appearance-header"/>
<html:div id="webAppearanceSettings">
<description class="description-deemphasized" data-l10n-id="preferences-web-appearance-description"/>
- <html:div id="web-appearance-override-warning" class="info-box-container">
- <html:div class="info-icon-container">
- <html:img class="info-icon"/>
- </html:div>
- <description data-l10n-id="preferences-web-appearance-override-warning">
- <html:a class="text-link" data-l10n-name="colors-link" id="web-appearance-manage-colors-link" href="#"/>
- </description>
- </html:div>
+ <html:moz-message-bar id="web-appearance-override-warning" data-l10n-id="preferences-web-appearance-override-warning2"
+ data-l10n-attrs="message">
+ <button slot="actions" class="accessory-button" data-l10n-id="preferences-colors-manage-button" id="web-appearance-manage-colors-button"/>
+ </html:moz-message-bar>
<form xmlns="http://www.w3.org/1999/xhtml" id="web-appearance-chooser" autocomplete="off">
<label class="web-appearance-choice" data-l10n-id="preferences-web-appearance-choice-tooltip-auto">
<div class="web-appearance-choice-image-container"><img role="presentation" alt="" width="54" height="42" /></div>
@@ -817,6 +813,7 @@
connection-proxy-option-no.label,
connection-proxy-option-auto.label,
connection-proxy-option-system.label,
+ connection-proxy-option-wpad.label,
connection-proxy-option-manual.label,
connection-proxy-http,
connection-proxy-https,
diff --git a/browser/components/preferences/main.js b/browser/components/preferences/main.js
index b9487ece26..b578e0e29f 100644
--- a/browser/components/preferences/main.js
+++ b/browser/components/preferences/main.js
@@ -278,7 +278,10 @@ var gMainPane = {
let uri = win.gBrowser.currentURI.spec;
if (
- (uri == "about:preferences" || uri == "about:preferences#general") &&
+ (uri == "about:preferences" ||
+ uri == "about:preferences#general" ||
+ uri == "about:settings" ||
+ uri == "about:settings#general") &&
document.visibilityState == "visible"
) {
this.updateSetDefaultBrowser();
@@ -879,7 +882,7 @@ var gMainPane = {
this.readBrowserContainersCheckbox();
},
- async onGetStarted(aEvent) {
+ async onGetStarted() {
if (!AppConstants.MOZ_DEV_EDITION) {
return;
}
@@ -1915,6 +1918,11 @@ var gMainPane = {
if (
Services.prefs.getBoolPref("browser.translations.newSettingsUI.enable")
) {
+ const translationsSettings = document.getElementById(
+ "translations-settings-page"
+ );
+ translationsSettings.setAttribute("data-hidden-from-search", "false");
+ translationsSettings.hidden = false;
gotoPref("translations");
} else {
gSubDialog.open(
@@ -1980,7 +1988,7 @@ var gMainPane = {
}
},
- async checkBrowserContainers(event) {
+ async checkBrowserContainers() {
let checkbox = document.getElementById("browserContainersCheckbox");
if (checkbox.checked) {
Services.prefs.setBoolPref("privacy.userContext.enabled", true);
@@ -2135,7 +2143,7 @@ var gMainPane = {
})().catch(console.error);
},
- onMigrationButtonCommand(command) {
+ onMigrationButtonCommand() {
// Even though we're going to be showing the migration wizard here in
// about:preferences, we'll delegate the call to
// `MigrationUtils.showMigrationWizard`, as this will allow us to
@@ -2288,7 +2296,7 @@ var gMainPane = {
}
},
- updatePerformanceSettingsBox({ duringChangeEvent }) {
+ updatePerformanceSettingsBox() {
let defaultPerformancePref = Preferences.get(
"browser.preferences.defaultPerformanceSettings.enabled"
);
@@ -3333,7 +3341,7 @@ var gMainPane = {
// Prompt the user to pick an app. If they pick one, and it's a valid
// selection, then add it to the list of possible handlers.
- fp.init(window, winTitle, Ci.nsIFilePicker.modeOpen);
+ fp.init(window.browsingContext, winTitle, Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
fp.open(fpCallback);
}
@@ -3451,7 +3459,7 @@ var gMainPane = {
let defDownloads = await this._indexToFolder(1);
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
- fp.init(window, title, Ci.nsIFilePicker.modeGetFolder);
+ fp.init(window.browsingContext, title, Ci.nsIFilePicker.modeGetFolder);
fp.appendFilters(Ci.nsIFilePicker.filterAll);
// First try to open what's currently configured
if (currentDirPref && currentDirPref.exists()) {
@@ -4189,7 +4197,7 @@ const AppearanceChooser = {
if (e.type == "click") {
switch (e.target.id) {
// Forward the click to the "colors" button.
- case "web-appearance-manage-colors-link":
+ case "web-appearance-manage-colors-button":
document.getElementById("colors").click();
e.preventDefault();
break;
@@ -4206,7 +4214,7 @@ const AppearanceChooser = {
this._update();
},
- observe(subject, topic, data) {
+ observe() {
this._update();
},
diff --git a/browser/components/preferences/preferences.js b/browser/components/preferences/preferences.js
index 31ae84f382..c30a51c67c 100644
--- a/browser/components/preferences/preferences.js
+++ b/browser/components/preferences/preferences.js
@@ -204,7 +204,10 @@ function init_all() {
register_module("paneSearch", gSearchPane);
register_module("panePrivacy", gPrivacyPane);
register_module("paneContainers", gContainersPane);
- register_module("paneTranslations", gTranslationsPane);
+
+ if (Services.prefs.getBoolPref("browser.translations.newSettingsUI.enable")) {
+ register_module("paneTranslations", gTranslationsPane);
+ }
if (Services.prefs.getBoolPref("browser.preferences.experimental")) {
// Set hidden based on previous load's hidden value.
document.getElementById("category-experimental").hidden =
@@ -475,7 +478,7 @@ async function spotlight(subcategory, category) {
}
}
-async function scrollAndHighlight(subcategory, category) {
+async function scrollAndHighlight(subcategory) {
let element = document.querySelector(`[data-subcategory="${subcategory}"]`);
if (!element) {
return;
@@ -643,7 +646,7 @@ async function ensureScrollPadding() {
let stickyContainer = document.querySelector(".sticky-container");
let height = await window.browsingContext.topChromeWindow
.promiseDocumentFlushed(() => stickyContainer.clientHeight)
- .catch(err => Cu.reportError); // Can reject if the window goes away.
+ .catch(() => Cu.reportError); // Can reject if the window goes away.
// Make it a bit more, to ensure focus rectangles etc. don't get cut off.
// This being 8px causes us to end up with 90px if the policies container
diff --git a/browser/components/preferences/preferences.xhtml b/browser/components/preferences/preferences.xhtml
index 38fba9a726..eee227822a 100644
--- a/browser/components/preferences/preferences.xhtml
+++ b/browser/components/preferences/preferences.xhtml
@@ -12,7 +12,7 @@
<head>
<!-- @CSP: We should remove 'unsafe-inline' from style-src, see Bug 1579160 -->
- <meta http-equiv="Content-Security-Policy" content="default-src chrome:; img-src chrome: moz-icon: https: data:; style-src chrome: data: 'unsafe-inline'; object-src 'none'" />
+ <meta http-equiv="Content-Security-Policy" content="default-src chrome:; img-src chrome: moz-icon: https: blob: data:; style-src chrome: data: 'unsafe-inline'; object-src 'none'" />
<title data-l10n-id="settings-page-title"></title>
@@ -84,6 +84,7 @@
<script src="chrome://browser/content/migration/migration-wizard.mjs" type="module"></script>
<script type="module" src="chrome://global/content/elements/moz-toggle.mjs"/>
<script type="module" src="chrome://global/content/elements/moz-message-bar.mjs" />
+ <script type="module" src="chrome://global/content/elements/moz-label.mjs"/>
</head>
<html:body xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
diff --git a/browser/components/preferences/privacy.inc.xhtml b/browser/components/preferences/privacy.inc.xhtml
index a81764e34f..224a5f5cbb 100644
--- a/browser/components/preferences/privacy.inc.xhtml
+++ b/browser/components/preferences/privacy.inc.xhtml
@@ -985,11 +985,12 @@
<html:input type="checkbox"
id="automaticallySubmitCrashesBox"
preference="browser.crashReports.unsubmittedCheck.autoSubmit2"/>
- <label for="automaticallySubmitCrashesBox"
+ <html:label is="moz-label"
+ for="automaticallySubmitCrashesBox"
id="crashReporterLabel"
- data-l10n-id="collection-backlogged-crash-reports-with-link">
- <html:a data-l10n-name="crash-reports-link" id="crashReporterLearnMore" target="_blank"/>
- </label>
+ data-l10n-id="collection-backlogged-crash-reports"
+ data-l10n-attrs="accesskey"/>
+ <html:a id="crashReporterLearnMore" is="moz-support-link" class="learnMore"/>
</hbox>
#endif
</vbox>
diff --git a/browser/components/preferences/privacy.js b/browser/components/preferences/privacy.js
index 178bc560c7..3b07b9cabf 100644
--- a/browser/components/preferences/privacy.js
+++ b/browser/components/preferences/privacy.js
@@ -435,7 +435,7 @@ var gPrivacyPane = {
);
let trackingProtectionObserver = {
- observe(subject, topic, data) {
+ observe() {
gPrivacyPane._updateTrackingProtectionUI();
},
};
@@ -3230,13 +3230,6 @@ var gPrivacyPane = {
"toolkit.crashreporter.infoURL",
"crashReporterLearnMore"
);
- setEventListener("crashReporterLabel", "click", function (event) {
- if (event.target.localName == "a") {
- return;
- }
- const checkboxId = event.target.getAttribute("for");
- document.getElementById(checkboxId).click();
- });
},
initPrivacySegmentation() {
@@ -3317,7 +3310,7 @@ var gPrivacyPane = {
* Initialize the opt-out-study preference checkbox into about:preferences and
* handles events coming from the UI for it.
*/
- initOptOutStudyCheckbox(doc) {
+ initOptOutStudyCheckbox() {
// The checkbox should be disabled if any of the below are true. This
// prevents the user from changing the value in the box.
//
@@ -3361,7 +3354,7 @@ var gPrivacyPane = {
});
},
- observe(aSubject, aTopic, aData) {
+ observe(aSubject, aTopic) {
switch (aTopic) {
case "sitedatamanager:updating-sites":
// While updating, we want to disable this section and display loading message until updated
diff --git a/browser/components/preferences/search.js b/browser/components/preferences/search.js
index 42776cfa96..a491d6c5ca 100644
--- a/browser/components/preferences/search.js
+++ b/browser/components/preferences/search.js
@@ -9,6 +9,7 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
SearchUIUtils: "resource:///modules/SearchUIUtils.sys.mjs",
+ SearchUtils: "resource://gre/modules/SearchUtils.sys.mjs",
});
const PREF_URLBAR_QUICKSUGGEST_BLOCKLIST =
@@ -34,16 +35,27 @@ const ENGINE_FLAVOR = "text/x-moz-search-engine";
const SEARCH_TYPE = "default_search";
const SEARCH_KEY = "defaultSearch";
-// The name of in built engines that support trending results.
-const TRENDING_ENGINES = ["Google", "Bing"];
-
var gEngineView = null;
var gSearchPane = {
+ _engineStore: null,
+ _engineDropDown: null,
+ _engineDropDownPrivate: null,
+
init() {
- gEngineView = new EngineView(new EngineStore());
- document.getElementById("engineList").view = gEngineView;
- this.buildDefaultEngineDropDowns().catch(console.error);
+ this._engineStore = new EngineStore();
+ gEngineView = new EngineView(this._engineStore);
+
+ this._engineDropDown = new DefaultEngineDropDown(
+ "normal",
+ this._engineStore
+ );
+ this._engineDropDownPrivate = new DefaultEngineDropDown(
+ "private",
+ this._engineStore
+ );
+
+ this._engineStore.init().catch(console.error);
if (
Services.policies &&
@@ -55,12 +67,7 @@ var gSearchPane = {
addEnginesLink.setAttribute("href", lazy.SearchUIUtils.searchEnginesURL);
}
- window.addEventListener("click", this);
window.addEventListener("command", this);
- window.addEventListener("dragstart", this);
- window.addEventListener("keypress", this);
- window.addEventListener("select", this);
- window.addEventListener("dblclick", this);
Services.obs.addObserver(this, "browser-search-engine-modified");
Services.obs.addObserver(this, "intl:app-locales-changed");
@@ -115,7 +122,6 @@ var gSearchPane = {
this._initDefaultEngines();
this._initShowSearchTermsCheckbox();
this._updateSuggestionCheckboxes();
- this._showAddEngineButton();
this._initRecentSeachesCheckbox();
this._initAddressBar();
},
@@ -140,7 +146,7 @@ var gSearchPane = {
const listener = () => {
this._updatePrivateEngineDisplayBoxes();
- this.buildDefaultEngineDropDowns().catch(console.error);
+ this._engineStore.notifyRebuildViews();
};
this._separatePrivateDefaultEnabledPref.on("change", listener);
@@ -256,17 +262,6 @@ var gSearchPane = {
this._updateTrendingCheckbox(!suggestsPref.value || permanentPB);
},
- _showAddEngineButton() {
- let aliasRefresh = Services.prefs.getBoolPref(
- "browser.urlbar.update2.engineAliasRefresh",
- false
- );
- if (aliasRefresh) {
- let addButton = document.getElementById("addEngineButton");
- addButton.hidden = false;
- }
- },
-
_initRecentSeachesCheckbox() {
this._recentSearchesEnabledPref = Preferences.get(
"browser.urlbar.recentsearches.featureGate"
@@ -285,38 +280,14 @@ var gSearchPane = {
async _updateTrendingCheckbox(suggestDisabled) {
let trendingBox = document.getElementById("showTrendingSuggestionsBox");
let trendingCheckBox = document.getElementById("showTrendingSuggestions");
- let trendingSupported = TRENDING_ENGINES.includes(
- (await Services.search.getDefault()).name
- );
+ let trendingSupported = (
+ await Services.search.getDefault()
+ ).supportsResponseType(lazy.SearchUtils.URL_TYPE.TRENDING_JSON);
trendingBox.hidden = !Preferences.get("browser.urlbar.trending.featureGate")
.value;
trendingCheckBox.disabled = suggestDisabled || !trendingSupported;
},
- /**
- * Builds the default and private engines drop down lists. This is called
- * each time something affects the list of engines.
- */
- async buildDefaultEngineDropDowns() {
- await this._buildEngineDropDown(
- document.getElementById("defaultEngine"),
- (
- await Services.search.getDefault()
- ).name,
- false
- );
-
- if (this._separatePrivateDefaultEnabledPref.value) {
- await this._buildEngineDropDown(
- document.getElementById("defaultPrivateEngine"),
- (
- await Services.search.getDefaultPrivate()
- ).name,
- true
- );
- }
- },
-
// ADDRESS BAR
/**
@@ -486,125 +457,24 @@ var gSearchPane = {
Services.prefs.clearUserPref(PREF_URLBAR_WEATHER_USER_ENABLED);
},
- /**
- * Builds a drop down menu of search engines.
- *
- * @param {DOMMenuList} list
- * The menu list element to attach the list of engines.
- * @param {string} currentEngine
- * The name of the current default engine.
- * @param {boolean} isPrivate
- * True if we are dealing with the default engine for private mode.
- */
- async _buildEngineDropDown(list, currentEngine, isPrivate) {
- // If the current engine isn't in the list any more, select the first item.
- let engines = gEngineView._engineStore._engines;
- if (!engines.length) {
+ handleEvent(aEvent) {
+ if (aEvent.type != "command") {
return;
}
- if (!engines.some(e => e.name == currentEngine)) {
- currentEngine = engines[0].name;
- }
-
- // Now clean-up and rebuild the list.
- list.removeAllItems();
- gEngineView._engineStore._engines.forEach(e => {
- let item = list.appendItem(e.name);
- item.setAttribute(
- "class",
- "menuitem-iconic searchengine-menuitem menuitem-with-favicon"
- );
- if (e.iconURL) {
- item.setAttribute("image", e.iconURL);
- }
- item.engine = e;
- if (e.name == currentEngine) {
- list.selectedItem = item;
- }
- });
- },
-
- handleEvent(aEvent) {
- switch (aEvent.type) {
- case "dblclick":
- if (aEvent.target.id == "engineChildren") {
- let cell = aEvent.target.parentNode.getCellAt(
- aEvent.clientX,
- aEvent.clientY
- );
- if (cell.col?.id == "engineKeyword") {
- this.startEditingAlias(gEngineView.selectedIndex);
+ switch (aEvent.target.id) {
+ case "":
+ if (aEvent.target.parentNode && aEvent.target.parentNode.parentNode) {
+ if (aEvent.target.parentNode.parentNode.id == "defaultEngine") {
+ gSearchPane.setDefaultEngine();
+ } else if (
+ aEvent.target.parentNode.parentNode.id == "defaultPrivateEngine"
+ ) {
+ gSearchPane.setDefaultPrivateEngine();
}
}
break;
- case "click":
- if (
- aEvent.target.id != "engineChildren" &&
- !aEvent.target.classList.contains("searchEngineAction")
- ) {
- let engineList = document.getElementById("engineList");
- // We don't want to toggle off selection while editing keyword
- // so proceed only when the input field is hidden.
- // We need to check that engineList.view is defined here
- // because the "click" event listener is on <window> and the
- // view might have been destroyed if the pane has been navigated
- // away from.
- if (engineList.inputField.hidden && engineList.view) {
- let selection = engineList.view.selection;
- if (selection?.count > 0) {
- selection.toggleSelect(selection.currentIndex);
- }
- engineList.blur();
- }
- }
- break;
- case "command":
- switch (aEvent.target.id) {
- case "":
- if (
- aEvent.target.parentNode &&
- aEvent.target.parentNode.parentNode
- ) {
- if (aEvent.target.parentNode.parentNode.id == "defaultEngine") {
- gSearchPane.setDefaultEngine();
- } else if (
- aEvent.target.parentNode.parentNode.id == "defaultPrivateEngine"
- ) {
- gSearchPane.setDefaultPrivateEngine();
- }
- }
- break;
- case "restoreDefaultSearchEngines":
- gSearchPane.onRestoreDefaults();
- break;
- case "removeEngineButton":
- Services.search.removeEngine(
- gEngineView.selectedEngine.originalEngine
- );
- break;
- case "addEngineButton":
- gSubDialog.open(
- "chrome://browser/content/preferences/dialogs/addEngine.xhtml",
- { features: "resizable=no, modal=yes" }
- );
- break;
- }
- break;
- case "dragstart":
- if (aEvent.target.id == "engineChildren") {
- onDragEngineStart(aEvent);
- }
- break;
- case "keypress":
- if (aEvent.target.id == "engineList") {
- gSearchPane.onTreeKeyPress(aEvent);
- }
- break;
- case "select":
- if (aEvent.target.id == "engineList") {
- gSearchPane.onTreeSelect();
- }
- break;
+ default:
+ gEngineView.handleEvent(aEvent);
}
},
@@ -617,60 +487,6 @@ var gSearchPane = {
},
/**
- * Update the default engine UI and engine tree view as appropriate when engine changes
- * or locale changes occur.
- *
- * @param {Object} engine
- * @param {string} data
- */
- browserSearchEngineModified(engine, data) {
- engine.QueryInterface(Ci.nsISearchEngine);
- switch (data) {
- case "engine-added":
- gEngineView._engineStore.addEngine(engine);
- gEngineView.rowCountChanged(gEngineView.lastEngineIndex, 1);
- gSearchPane.buildDefaultEngineDropDowns();
- break;
- case "engine-changed":
- gSearchPane.buildDefaultEngineDropDowns();
- gEngineView._engineStore.updateEngine(engine);
- gEngineView.invalidate();
- break;
- case "engine-removed":
- gSearchPane.remove(engine);
- break;
- case "engine-default": {
- // If the user is going through the drop down using up/down keys, the
- // dropdown may still be open (eg. on Windows) when engine-default is
- // fired, so rebuilding the list unconditionally would get in the way.
- let selectedEngine =
- document.getElementById("defaultEngine").selectedItem.engine;
- if (selectedEngine.name != engine.name) {
- gSearchPane.buildDefaultEngineDropDowns();
- }
- gSearchPane._updateSuggestionCheckboxes();
- break;
- }
- case "engine-default-private": {
- if (
- this._separatePrivateDefaultEnabledPref.value &&
- this._separatePrivateDefaultPref.value
- ) {
- // If the user is going through the drop down using up/down keys, the
- // dropdown may still be open (eg. on Windows) when engine-default is
- // fired, so rebuilding the list unconditionally would get in the way.
- const selectedEngine = document.getElementById("defaultPrivateEngine")
- .selectedItem.engine;
- if (selectedEngine.name != engine.name) {
- gSearchPane.buildDefaultEngineDropDowns();
- }
- }
- break;
- }
- }
- },
-
- /**
* nsIObserver implementation.
*/
observe(subject, topic, data) {
@@ -680,144 +496,25 @@ var gSearchPane = {
break;
}
case "browser-search-engine-modified": {
- this.browserSearchEngineModified(subject, data);
- break;
- }
- }
- },
-
- onTreeSelect() {
- document.getElementById("removeEngineButton").disabled =
- !gEngineView.isEngineSelectedAndRemovable();
- },
-
- onTreeKeyPress(aEvent) {
- let index = gEngineView.selectedIndex;
- let tree = document.getElementById("engineList");
- if (tree.hasAttribute("editing")) {
- return;
- }
-
- if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
- // Space toggles the checkbox.
- let newValue = !gEngineView.getCellValue(
- index,
- tree.columns.getNamedColumn("engineShown")
- );
- gEngineView.setCellValue(
- index,
- tree.columns.getFirstColumn(),
- newValue.toString()
- );
- // Prevent page from scrolling on the space key.
- aEvent.preventDefault();
- } else {
- let isMac = Services.appinfo.OS == "Darwin";
- if (
- (isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
- (!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2)
- ) {
- this.startEditingAlias(index);
- } else if (
- aEvent.keyCode == KeyEvent.DOM_VK_DELETE ||
- (isMac &&
- aEvent.shiftKey &&
- aEvent.keyCode == KeyEvent.DOM_VK_BACK_SPACE &&
- gEngineView.isEngineSelectedAndRemovable())
- ) {
- // Delete and Shift+Backspace (Mac) removes selected engine.
- Services.search.removeEngine(gEngineView.selectedEngine.originalEngine);
+ let engine = subject.QueryInterface(Ci.nsISearchEngine);
+ switch (data) {
+ case "engine-default": {
+ // Pass through to the engine store to handle updates.
+ this._engineStore.browserSearchEngineModified(engine, data);
+ gSearchPane._updateSuggestionCheckboxes();
+ break;
+ }
+ default:
+ this._engineStore.browserSearchEngineModified(engine, data);
+ }
}
}
},
- startEditingAlias(index) {
- // Local shortcut aliases can't be edited.
- if (gEngineView._getLocalShortcut(index)) {
- return;
- }
-
- let tree = document.getElementById("engineList");
- let engine = gEngineView._engineStore.engines[index];
- tree.startEditing(index, tree.columns.getLastColumn());
- tree.inputField.value = engine.alias || "";
- tree.inputField.select();
- },
-
- async onRestoreDefaults() {
- let num = await gEngineView._engineStore.restoreDefaultEngines();
- gEngineView.rowCountChanged(0, num);
- gEngineView.invalidate();
- },
-
showRestoreDefaults(aEnable) {
document.getElementById("restoreDefaultSearchEngines").disabled = !aEnable;
},
- remove(aEngine) {
- let index = gEngineView._engineStore.removeEngine(aEngine);
- if (!gEngineView.tree) {
- // Only update the selection if it's visible in the UI.
- return;
- }
-
- gEngineView.rowCountChanged(index, -1);
- gEngineView.invalidate();
-
- gEngineView.selection.select(Math.min(index, gEngineView.rowCount - 1));
- gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
-
- document.getElementById("engineList").focus();
- },
-
- async editKeyword(aEngine, aNewKeyword) {
- let keyword = aNewKeyword.trim();
- if (keyword) {
- let eduplicate = false;
- let dupName = "";
-
- // Check for duplicates in Places keywords.
- let bduplicate = !!(await PlacesUtils.keywords.fetch(keyword));
-
- // Check for duplicates in changes we haven't committed yet
- let engines = gEngineView._engineStore.engines;
- let lc_keyword = keyword.toLocaleLowerCase();
- for (let engine of engines) {
- if (
- engine.alias &&
- engine.alias.toLocaleLowerCase() == lc_keyword &&
- engine.name != aEngine.name
- ) {
- eduplicate = true;
- dupName = engine.name;
- break;
- }
- }
-
- // Notify the user if they have chosen an existing engine/bookmark keyword
- if (eduplicate || bduplicate) {
- let msgids = [{ id: "search-keyword-warning-title" }];
- if (eduplicate) {
- msgids.push({
- id: "search-keyword-warning-engine",
- args: { name: dupName },
- });
- } else {
- msgids.push({ id: "search-keyword-warning-bookmark" });
- }
-
- let [dtitle, msg] = await document.l10n.formatValues(msgids);
-
- Services.prompt.alert(window, dtitle, msg);
- return false;
- }
- }
-
- gEngineView._engineStore.changeEngine(aEngine, "alias", keyword);
- gEngineView.invalidate();
- return true;
- },
-
async setDefaultEngine() {
await Services.search.setDefault(
document.getElementById("defaultEngine").selectedItem.engine,
@@ -840,92 +537,162 @@ var gSearchPane = {
},
};
-function onDragEngineStart(event) {
- var selectedIndex = gEngineView.selectedIndex;
+/**
+ * Keeps track of the search engine objects and notifies the views for updates.
+ */
+class EngineStore {
+ /**
+ * A list of engines that are currently visible in the UI.
+ *
+ * @type {Object[]}
+ */
+ engines = [];
- // Local shortcut rows can't be dragged or re-ordered.
- if (gEngineView._getLocalShortcut(selectedIndex)) {
- event.preventDefault();
- return;
- }
+ /**
+ * A list of application provided engines used when restoring the list of
+ * engines to the default set and order.
+ *
+ * @type {nsISearchEngine[]}
+ */
+ #appProvidedEngines = [];
- var tree = document.getElementById("engineList");
- let cell = tree.getCellAt(event.clientX, event.clientY);
- if (selectedIndex >= 0 && !gEngineView.isCheckBox(cell.row, cell.col)) {
- event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
- event.dataTransfer.effectAllowed = "move";
- }
-}
+ /**
+ * A list of listeners to be notified when the engine list changes.
+ *
+ * @type {Object[]}
+ */
+ #listeners = [];
-function EngineStore() {
- this._engines = [];
- this._defaultEngines = [];
- Promise.all([
- Services.search.getVisibleEngines(),
- Services.search.getAppProvidedEngines(),
- ]).then(([visibleEngines, defaultEngines]) => {
+ async init() {
+ let visibleEngines = await Services.search.getVisibleEngines();
for (let engine of visibleEngines) {
this.addEngine(engine);
- gEngineView.rowCountChanged(gEngineView.lastEngineIndex, 1);
}
- this._defaultEngines = defaultEngines.map(this._cloneEngine, this);
- gSearchPane.buildDefaultEngineDropDowns();
+
+ let appProvidedEngines = await Services.search.getAppProvidedEngines();
+ this.#appProvidedEngines = appProvidedEngines.map(this._cloneEngine, this);
+
+ this.notifyRowCountChanged(0, visibleEngines.length);
// check if we need to disable the restore defaults button
- var someHidden = this._defaultEngines.some(e => e.hidden);
+ var someHidden = this.#appProvidedEngines.some(e => e.hidden);
gSearchPane.showRestoreDefaults(someHidden);
- });
-}
-EngineStore.prototype = {
- _engines: null,
- _defaultEngines: null,
+ }
- get engines() {
- return this._engines;
- },
- set engines(val) {
- this._engines = val;
- },
+ /**
+ * Adds a listener to be notified when the engine list changes.
+ *
+ * @param {object} aListener
+ */
+ addListener(aListener) {
+ this.#listeners.push(aListener);
+ }
+
+ /**
+ * Notifies all listeners that the engine list has changed and they should
+ * rebuild.
+ */
+ notifyRebuildViews() {
+ for (let listener of this.#listeners) {
+ try {
+ listener.rebuild(this.engines);
+ } catch (ex) {
+ console.error("Error notifying EngineStore listener", ex);
+ }
+ }
+ }
+
+ /**
+ * Notifies all listeners that the number of engines in the list has changed.
+ *
+ * @param {number} index
+ * @param {number} count
+ */
+ notifyRowCountChanged(index, count) {
+ for (let listener of this.#listeners) {
+ listener.rowCountChanged(index, count, this.engines);
+ }
+ }
+
+ /**
+ * Notifies all listeners that the default engine has changed.
+ *
+ * @param {string} type
+ * @param {object} engine
+ */
+ notifyDefaultEngineChanged(type, engine) {
+ for (let listener of this.#listeners) {
+ if ("defaultEngineChanged" in listener) {
+ listener.defaultEngineChanged(type, engine, this.engines);
+ }
+ }
+ }
+
+ notifyEngineIconUpdated(engine) {
+ // Check the engine is still in the list.
+ let index = this._getIndexForEngine(engine);
+ if (index != -1) {
+ for (let listener of this.#listeners) {
+ listener.engineIconUpdated(index, this.engines);
+ }
+ }
+ }
_getIndexForEngine(aEngine) {
- return this._engines.indexOf(aEngine);
- },
+ return this.engines.indexOf(aEngine);
+ }
_getEngineByName(aName) {
- return this._engines.find(engine => engine.name == aName);
- },
+ return this.engines.find(engine => engine.name == aName);
+ }
_cloneEngine(aEngine) {
var clonedObj = {
- iconURL: aEngine.getIconURL(),
+ iconURL: null,
};
for (let i of ["id", "name", "alias", "hidden"]) {
clonedObj[i] = aEngine[i];
}
clonedObj.originalEngine = aEngine;
+
+ // Trigger getting the iconURL for this engine.
+ aEngine.getIconURL().then(iconURL => {
+ if (iconURL) {
+ clonedObj.iconURL = iconURL;
+ } else if (window.devicePixelRatio > 1) {
+ clonedObj.iconURL =
+ "chrome://browser/skin/search-engine-placeholder@2x.png";
+ } else {
+ clonedObj.iconURL =
+ "chrome://browser/skin/search-engine-placeholder.png";
+ }
+
+ this.notifyEngineIconUpdated(clonedObj);
+ });
+
return clonedObj;
- },
+ }
// Callback for Array's some(). A thisObj must be passed to some()
_isSameEngine(aEngineClone) {
return aEngineClone.originalEngine.id == this.originalEngine.id;
- },
+ }
addEngine(aEngine) {
- this._engines.push(this._cloneEngine(aEngine));
- },
+ this.engines.push(this._cloneEngine(aEngine));
+ }
updateEngine(newEngine) {
- let engineToUpdate = this._engines.findIndex(
+ let engineToUpdate = this.engines.findIndex(
e => e.originalEngine.id == newEngine.id
);
if (engineToUpdate != -1) {
this.engines[engineToUpdate] = this._cloneEngine(newEngine);
}
- },
+ }
moveEngine(aEngine, aNewIndex) {
- if (aNewIndex < 0 || aNewIndex > this._engines.length - 1) {
+ if (aNewIndex < 0 || aNewIndex > this.engines.length - 1) {
throw new Error("ES_moveEngine: invalid aNewIndex!");
}
var index = this._getIndexForEngine(aEngine);
@@ -938,41 +705,73 @@ EngineStore.prototype = {
} // nothing to do
// Move the engine in our internal store
- var removedEngine = this._engines.splice(index, 1)[0];
- this._engines.splice(aNewIndex, 0, removedEngine);
+ var removedEngine = this.engines.splice(index, 1)[0];
+ this.engines.splice(aNewIndex, 0, removedEngine);
return Services.search.moveEngine(aEngine.originalEngine, aNewIndex);
- },
+ }
removeEngine(aEngine) {
- if (this._engines.length == 1) {
+ if (this.engines.length == 1) {
throw new Error("Cannot remove last engine!");
}
let engineName = aEngine.name;
- let index = this._engines.findIndex(element => element.name == engineName);
+ let index = this.engines.findIndex(element => element.name == engineName);
if (index == -1) {
throw new Error("invalid engine?");
}
- this._engines.splice(index, 1)[0];
+ this.engines.splice(index, 1)[0];
if (aEngine.isAppProvided) {
gSearchPane.showRestoreDefaults(true);
}
- gSearchPane.buildDefaultEngineDropDowns();
- return index;
- },
+
+ this.notifyRowCountChanged(index, -1);
+
+ document.getElementById("engineList").focus();
+ }
+
+ /**
+ * Update the default engine UI and engine tree view as appropriate when engine changes
+ * or locale changes occur.
+ *
+ * @param {nsISearchEngine} engine
+ * @param {string} data
+ */
+ browserSearchEngineModified(engine, data) {
+ engine.QueryInterface(Ci.nsISearchEngine);
+ switch (data) {
+ case "engine-added":
+ this.addEngine(engine);
+ this.notifyRowCountChanged(gEngineView.lastEngineIndex, 1);
+ break;
+ case "engine-changed":
+ this.updateEngine(engine);
+ this.notifyRebuildViews();
+ break;
+ case "engine-removed":
+ this.removeEngine(engine);
+ break;
+ case "engine-default":
+ this.notifyDefaultEngineChanged("normal", engine);
+ break;
+ case "engine-default-private":
+ this.notifyDefaultEngineChanged("private", engine);
+ break;
+ }
+ }
async restoreDefaultEngines() {
var added = 0;
- for (var i = 0; i < this._defaultEngines.length; ++i) {
- var e = this._defaultEngines[i];
+ for (var i = 0; i < this.#appProvidedEngines.length; ++i) {
+ var e = this.#appProvidedEngines[i];
// If the engine is already in the list, just move it.
- if (this._engines.some(this._isSameEngine, e)) {
+ if (this.engines.some(this._isSameEngine, e)) {
await this.moveEngine(this._getEngineByName(e.name), i);
} else {
// Otherwise, add it back to our internal store
@@ -981,7 +780,7 @@ EngineStore.prototype = {
// so clear any alias we may have cached before unhiding the engine.
e.alias = "";
- this._engines.splice(i, 0, e);
+ this.engines.splice(i, 0, e);
let engine = e.originalEngine;
engine.hidden = false;
await Services.search.moveEngine(engine, i);
@@ -1006,9 +805,9 @@ EngineStore.prototype = {
Services.search.resetToAppDefaultEngine();
gSearchPane.showRestoreDefaults(false);
- gSearchPane.buildDefaultEngineDropDowns();
+ this.notifyRebuildViews();
return added;
- },
+ }
changeEngine(aEngine, aProp, aNewValue) {
var index = this._getIndexForEngine(aEngine);
@@ -1016,22 +815,31 @@ EngineStore.prototype = {
throw new Error("invalid engine?");
}
- this._engines[index][aProp] = aNewValue;
+ this.engines[index][aProp] = aNewValue;
aEngine.originalEngine[aProp] = aNewValue;
- },
-};
-
-function EngineView(aEngineStore) {
- this._engineStore = aEngineStore;
-
- UrlbarPrefs.addObserver(this);
-
- this.loadL10nNames();
+ }
}
-EngineView.prototype = {
- _engineStore: null,
- tree: null,
+/**
+ * Manages the view of the Search Shortcuts tree on the search pane of preferences.
+ */
+class EngineView {
+ _engineStore = null;
+ _engineList = null;
+ tree = null;
+
+ constructor(aEngineStore) {
+ this._engineStore = aEngineStore;
+ this._engineList = document.getElementById("engineList");
+ this._engineList.view = this;
+
+ UrlbarPrefs.addObserver(this);
+ aEngineStore.addListener(this);
+
+ this.loadL10nNames();
+ this.#addListeners();
+ this.#showAddEngineButton();
+ }
loadL10nNames() {
// This maps local shortcut sources to their l10n names. The names are needed
@@ -1053,11 +861,33 @@ EngineView.prototype = {
// called before name retrieval finished.
this.invalidate();
});
- },
+ }
+
+ #addListeners() {
+ this._engineList.addEventListener("click", this);
+ this._engineList.addEventListener("dragstart", this);
+ this._engineList.addEventListener("keypress", this);
+ this._engineList.addEventListener("select", this);
+ this._engineList.addEventListener("dblclick", this);
+ }
+
+ /**
+ * Shows the "Add Search Engine" button if the pref is enabled.
+ */
+ #showAddEngineButton() {
+ let aliasRefresh = Services.prefs.getBoolPref(
+ "browser.urlbar.update2.engineAliasRefresh",
+ false
+ );
+ if (aliasRefresh) {
+ let addButton = document.getElementById("addEngineButton");
+ addButton.hidden = false;
+ }
+ }
get lastEngineIndex() {
return this._engineStore.engines.length - 1;
- },
+ }
get selectedIndex() {
var seln = this.selection;
@@ -1067,34 +897,52 @@ EngineView.prototype = {
return min.value;
}
return -1;
- },
+ }
get selectedEngine() {
return this._engineStore.engines[this.selectedIndex];
- },
+ }
// Helpers
+ rebuild() {
+ this.invalidate();
+ }
+
rowCountChanged(index, count) {
- if (this.tree) {
- this.tree.rowCountChanged(index, count);
+ if (!this.tree) {
+ return;
}
- },
+ this.tree.rowCountChanged(index, count);
+
+ // If we're removing elements, ensure that we still have a selection.
+ if (count < 0) {
+ this.selection.select(Math.min(index, this.rowCount - 1));
+ this.ensureRowIsVisible(this.currentIndex);
+ }
+ }
+
+ engineIconUpdated(index) {
+ this.tree?.invalidateCell(
+ index,
+ this.tree.columns.getNamedColumn("engineName")
+ );
+ }
invalidate() {
this.tree?.invalidate();
- },
+ }
ensureRowIsVisible(index) {
this.tree.ensureRowIsVisible(index);
- },
+ }
getSourceIndexFromDrag(dataTransfer) {
return parseInt(dataTransfer.getData(ENGINE_FLAVOR));
- },
+ }
isCheckBox(index, column) {
return column.id == "engineShown";
- },
+ }
isEngineSelectedAndRemovable() {
let defaultEngine = Services.search.defaultEngine;
@@ -1109,7 +957,7 @@ EngineView.prototype = {
this.selectedEngine.name != defaultEngine.name &&
this.selectedEngine.name != defaultPrivateEngine.name
);
- },
+ }
/**
* Returns the local shortcut corresponding to a tree row, or null if the row
@@ -1126,7 +974,7 @@ EngineView.prototype = {
return null;
}
return UrlbarUtils.LOCAL_SEARCH_MODES[index - engineCount];
- },
+ }
/**
* Called by UrlbarPrefs when a urlbar pref changes.
@@ -1141,14 +989,170 @@ EngineView.prototype = {
if (parts[0] == "shortcuts" && parts[1] && parts.length == 2) {
this.invalidate();
}
- },
+ }
+
+ handleEvent(aEvent) {
+ switch (aEvent.type) {
+ case "dblclick":
+ if (aEvent.target.id == "engineChildren") {
+ let cell = aEvent.target.parentNode.getCellAt(
+ aEvent.clientX,
+ aEvent.clientY
+ );
+ if (cell.col?.id == "engineKeyword") {
+ this.#startEditingAlias(this.selectedIndex);
+ }
+ }
+ break;
+ case "click":
+ if (
+ aEvent.target.id != "engineChildren" &&
+ !aEvent.target.classList.contains("searchEngineAction")
+ ) {
+ // We don't want to toggle off selection while editing keyword
+ // so proceed only when the input field is hidden.
+ // We need to check that engineList.view is defined here
+ // because the "click" event listener is on <window> and the
+ // view might have been destroyed if the pane has been navigated
+ // away from.
+ if (this._engineList.inputField.hidden && this._engineList.view) {
+ let selection = this._engineList.view.selection;
+ if (selection?.count > 0) {
+ selection.toggleSelect(selection.currentIndex);
+ }
+ this._engineList.blur();
+ }
+ }
+ break;
+ case "command":
+ switch (aEvent.target.id) {
+ case "restoreDefaultSearchEngines":
+ this.#onRestoreDefaults();
+ break;
+ case "removeEngineButton":
+ Services.search.removeEngine(this.selectedEngine.originalEngine);
+ break;
+ case "addEngineButton":
+ gSubDialog.open(
+ "chrome://browser/content/preferences/dialogs/addEngine.xhtml",
+ { features: "resizable=no, modal=yes" }
+ );
+ break;
+ }
+ break;
+ case "dragstart":
+ if (aEvent.target.id == "engineChildren") {
+ this.#onDragEngineStart(aEvent);
+ }
+ break;
+ case "keypress":
+ if (aEvent.target.id == "engineList") {
+ this.#onTreeKeyPress(aEvent);
+ }
+ break;
+ case "select":
+ if (aEvent.target.id == "engineList") {
+ this.#onTreeSelect();
+ }
+ break;
+ }
+ }
+
+ /**
+ * Called when the restore default engines button is clicked to reset the
+ * list of engines to their defaults.
+ */
+ async #onRestoreDefaults() {
+ let num = await this._engineStore.restoreDefaultEngines();
+ this.rowCountChanged(0, num);
+ }
+
+ #onDragEngineStart(event) {
+ let selectedIndex = this.selectedIndex;
+
+ // Local shortcut rows can't be dragged or re-ordered.
+ if (this._getLocalShortcut(selectedIndex)) {
+ event.preventDefault();
+ return;
+ }
+
+ let tree = document.getElementById("engineList");
+ let cell = tree.getCellAt(event.clientX, event.clientY);
+ if (selectedIndex >= 0 && !this.isCheckBox(cell.row, cell.col)) {
+ event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
+ event.dataTransfer.effectAllowed = "move";
+ }
+ }
+
+ #onTreeSelect() {
+ document.getElementById("removeEngineButton").disabled =
+ !this.isEngineSelectedAndRemovable();
+ }
+
+ #onTreeKeyPress(aEvent) {
+ let index = this.selectedIndex;
+ let tree = document.getElementById("engineList");
+ if (tree.hasAttribute("editing")) {
+ return;
+ }
+
+ if (aEvent.charCode == KeyEvent.DOM_VK_SPACE) {
+ // Space toggles the checkbox.
+ let newValue = !this.getCellValue(
+ index,
+ tree.columns.getNamedColumn("engineShown")
+ );
+ this.setCellValue(
+ index,
+ tree.columns.getFirstColumn(),
+ newValue.toString()
+ );
+ // Prevent page from scrolling on the space key.
+ aEvent.preventDefault();
+ } else {
+ let isMac = Services.appinfo.OS == "Darwin";
+ if (
+ (isMac && aEvent.keyCode == KeyEvent.DOM_VK_RETURN) ||
+ (!isMac && aEvent.keyCode == KeyEvent.DOM_VK_F2)
+ ) {
+ this.#startEditingAlias(index);
+ } else if (
+ aEvent.keyCode == KeyEvent.DOM_VK_DELETE ||
+ (isMac &&
+ aEvent.shiftKey &&
+ aEvent.keyCode == KeyEvent.DOM_VK_BACK_SPACE &&
+ this.isEngineSelectedAndRemovable())
+ ) {
+ // Delete and Shift+Backspace (Mac) removes selected engine.
+ Services.search.removeEngine(this.selectedEngine.originalEngine);
+ }
+ }
+ }
+
+ /**
+ * Triggers editing of an alias in the tree.
+ *
+ * @param {number} index
+ */
+ #startEditingAlias(index) {
+ // Local shortcut aliases can't be edited.
+ if (this._getLocalShortcut(index)) {
+ return;
+ }
+
+ let tree = document.getElementById("engineList");
+ let engine = this._engineStore.engines[index];
+ tree.startEditing(index, tree.columns.getLastColumn());
+ tree.inputField.value = engine.alias || "";
+ tree.inputField.select();
+ }
// nsITreeView
get rowCount() {
return (
this._engineStore.engines.length + UrlbarUtils.LOCAL_SEARCH_MODES.length
);
- },
+ }
getImageSrc(index, column) {
if (column.id == "engineName") {
@@ -1157,18 +1161,11 @@ EngineView.prototype = {
return shortcut.icon;
}
- if (this._engineStore.engines[index].iconURL) {
- return this._engineStore.engines[index].iconURL;
- }
-
- if (window.devicePixelRatio > 1) {
- return "chrome://browser/skin/search-engine-placeholder@2x.png";
- }
- return "chrome://browser/skin/search-engine-placeholder.png";
+ return this._engineStore.engines[index].iconURL;
}
return "";
- },
+ }
getCellText(index, column) {
if (column.id == "engineName") {
@@ -1185,11 +1182,11 @@ EngineView.prototype = {
return this._engineStore.engines[index].originalEngine.aliases.join(", ");
}
return "";
- },
+ }
setTree(tree) {
this.tree = tree;
- },
+ }
canDrop(targetIndex, orientation, dataTransfer) {
var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
@@ -1200,7 +1197,7 @@ EngineView.prototype = {
// Local shortcut rows can't be dragged or dropped on.
targetIndex < this._engineStore.engines.length
);
- },
+ }
async drop(dropIndex, orientation, dataTransfer) {
// Local shortcut rows can't be dragged or dropped on. This can sometimes
@@ -1223,17 +1220,16 @@ EngineView.prototype = {
await this._engineStore.moveEngine(sourceEngine, dropIndex);
gSearchPane.showRestoreDefaults(true);
- gSearchPane.buildDefaultEngineDropDowns();
// Redraw, and adjust selection
this.invalidate();
this.selection.select(dropIndex);
- },
+ }
- selection: null,
- getRowProperties(index) {
+ selection = null;
+ getRowProperties() {
return "";
- },
+ }
getCellProperties(index, column) {
if (column.id == "engineName") {
// For local shortcut rows, return the result source name so we can style
@@ -1244,34 +1240,34 @@ EngineView.prototype = {
}
}
return "";
- },
- getColumnProperties(column) {
+ }
+ getColumnProperties() {
return "";
- },
- isContainer(index) {
+ }
+ isContainer() {
return false;
- },
- isContainerOpen(index) {
+ }
+ isContainerOpen() {
return false;
- },
- isContainerEmpty(index) {
+ }
+ isContainerEmpty() {
return false;
- },
- isSeparator(index) {
+ }
+ isSeparator() {
return false;
- },
- isSorted(index) {
+ }
+ isSorted() {
return false;
- },
- getParentIndex(index) {
+ }
+ getParentIndex() {
return -1;
- },
- hasNextSibling(parentIndex, index) {
+ }
+ hasNextSibling() {
return false;
- },
- getLevel(index) {
+ }
+ getLevel() {
return 0;
- },
+ }
getCellValue(index, column) {
if (column.id == "engineShown") {
let shortcut = this._getLocalShortcut(index);
@@ -1281,17 +1277,17 @@ EngineView.prototype = {
return !this._engineStore.engines[index].originalEngine.hideOneOffButton;
}
return undefined;
- },
- toggleOpenState(index) {},
- cycleHeader(column) {},
- selectionChanged() {},
- cycleCell(row, column) {},
+ }
+ toggleOpenState() {}
+ cycleHeader() {}
+ selectionChanged() {}
+ cycleCell() {}
isEditable(index, column) {
return (
column.id != "engineName" &&
(column.id == "engineShown" || !this._getLocalShortcut(index))
);
- },
+ }
setCellValue(index, column, value) {
if (column.id == "engineShown") {
let shortcut = this._getLocalShortcut(index);
@@ -1302,18 +1298,153 @@ EngineView.prototype = {
}
this._engineStore.engines[index].originalEngine.hideOneOffButton =
value != "true";
- gEngineView.invalidate();
+ this.invalidate();
}
- },
+ }
setCellText(index, column, value) {
if (column.id == "engineKeyword") {
- gSearchPane
- .editKeyword(this._engineStore.engines[index], value)
- .then(valid => {
+ this.#changeKeyword(this._engineStore.engines[index], value).then(
+ valid => {
if (!valid) {
- gSearchPane.startEditingAlias(index);
+ this.#startEditingAlias(index);
}
- });
+ }
+ );
}
- },
-};
+ }
+
+ /**
+ * Handles changing the keyword for an engine. This will check for potentially
+ * duplicate keywords and prompt the user if necessary.
+ *
+ * @param {object} aEngine
+ * The engine to change.
+ * @param {string} aNewKeyword
+ * The new keyword.
+ * @returns {Promise<boolean>}
+ * Resolves to true if the keyword was changed.
+ */
+ async #changeKeyword(aEngine, aNewKeyword) {
+ let keyword = aNewKeyword.trim();
+ if (keyword) {
+ let eduplicate = false;
+ let dupName = "";
+
+ // Check for duplicates in Places keywords.
+ let bduplicate = !!(await PlacesUtils.keywords.fetch(keyword));
+
+ // Check for duplicates in changes we haven't committed yet
+ let engines = this._engineStore.engines;
+ let lc_keyword = keyword.toLocaleLowerCase();
+ for (let engine of engines) {
+ if (
+ engine.alias &&
+ engine.alias.toLocaleLowerCase() == lc_keyword &&
+ engine.name != aEngine.name
+ ) {
+ eduplicate = true;
+ dupName = engine.name;
+ break;
+ }
+ }
+
+ // Notify the user if they have chosen an existing engine/bookmark keyword
+ if (eduplicate || bduplicate) {
+ let msgids = [{ id: "search-keyword-warning-title" }];
+ if (eduplicate) {
+ msgids.push({
+ id: "search-keyword-warning-engine",
+ args: { name: dupName },
+ });
+ } else {
+ msgids.push({ id: "search-keyword-warning-bookmark" });
+ }
+
+ let [dtitle, msg] = await document.l10n.formatValues(msgids);
+
+ Services.prompt.alert(window, dtitle, msg);
+ return false;
+ }
+ }
+
+ this._engineStore.changeEngine(aEngine, "alias", keyword);
+ this.invalidate();
+ return true;
+ }
+}
+
+/**
+ * Manages the default engine dropdown buttons in the search pane of preferences.
+ */
+class DefaultEngineDropDown {
+ #element = null;
+ #type = null;
+
+ constructor(type, engineStore) {
+ this.#type = type;
+ this.#element = document.getElementById(
+ type == "private" ? "defaultPrivateEngine" : "defaultEngine"
+ );
+
+ engineStore.addListener(this);
+ }
+
+ rowCountChanged(index, count, enginesList) {
+ // Simply rebuild the menulist, rather than trying to update the changed row.
+ this.rebuild(enginesList);
+ }
+
+ defaultEngineChanged(type, engine, enginesList) {
+ if (type != this.#type) {
+ return;
+ }
+ // If the user is going through the drop down using up/down keys, the
+ // dropdown may still be open (eg. on Windows) when engine-default is
+ // fired, so rebuilding the list unconditionally would get in the way.
+ let selectedEngineName = this.#element.selectedItem?.engine?.name;
+ if (selectedEngineName != engine.name) {
+ this.rebuild(enginesList);
+ }
+ }
+
+ engineIconUpdated(index, enginesList) {
+ let item = this.#element.getItemAtIndex(index);
+ // Check this is the right item.
+ if (item?.label == enginesList[index].name) {
+ item.setAttribute("image", enginesList[index].iconURL);
+ }
+ }
+
+ async rebuild(enginesList) {
+ if (
+ this.#type == "private" &&
+ !gSearchPane._separatePrivateDefaultPref.value
+ ) {
+ return;
+ }
+ let defaultEngine = await Services.search[
+ this.#type == "normal" ? "getDefault" : "getDefaultPrivate"
+ ]();
+
+ this.#element.removeAllItems();
+ for (let engine of enginesList) {
+ let item = this.#element.appendItem(engine.name);
+ item.setAttribute(
+ "class",
+ "menuitem-iconic searchengine-menuitem menuitem-with-favicon"
+ );
+ if (engine.iconURL) {
+ item.setAttribute("image", engine.iconURL);
+ }
+ item.engine = engine;
+ if (engine.name == defaultEngine.name) {
+ this.#element.selectedItem = item;
+ }
+ }
+ // This should never happen, but try and make sure we have at least one
+ // selected item.
+ if (!this.#element.selectedItem) {
+ this.#element.selectedIndex = 0;
+ }
+ }
+}
diff --git a/browser/components/preferences/sync.js b/browser/components/preferences/sync.js
index 11a6a42e2e..fa3f333e8b 100644
--- a/browser/components/preferences/sync.js
+++ b/browser/components/preferences/sync.js
@@ -69,7 +69,7 @@ var gSyncPane = {
xps.ensureLoaded();
},
- _showLoadPage(xps) {
+ _showLoadPage() {
let maybeAcct = false;
let username = Services.prefs.getCharPref("services.sync.username", "");
if (username) {
diff --git a/browser/components/preferences/tests/browser.toml b/browser/components/preferences/tests/browser.toml
index fe523bde94..9e619ce4be 100644
--- a/browser/components/preferences/tests/browser.toml
+++ b/browser/components/preferences/tests/browser.toml
@@ -11,6 +11,8 @@ support-files = [
"addons/set_newtab.xpi",
]
+["browser_about_settings.js"]
+
["browser_advanced_update.js"]
skip-if = ["!updater"]
@@ -82,6 +84,8 @@ skip-if = ["socketprocess_networking"]
["browser_defaultbrowser_alwayscheck.js"]
+["browser_dns_over_https_exceptions_subdialog.js"]
+
["browser_engines.js"]
fail-if = ["a11y_checks"] # Bug 1854636 clicked treechildren#engineChildren may not be focusable
diff --git a/browser/components/preferences/tests/browser_about_settings.js b/browser/components/preferences/tests/browser_about_settings.js
new file mode 100644
index 0000000000..3ffd75eeef
--- /dev/null
+++ b/browser/components/preferences/tests/browser_about_settings.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+add_task(async function test_openPreferences_aboutSettings() {
+ await BrowserTestUtils.withNewTab(
+ {
+ gBrowser,
+ url: "about:settings",
+ },
+ async () => {
+ is(
+ gBrowser.currentURI.spec,
+ "about:settings",
+ "about:settings should open normally"
+ );
+
+ // using `openPreferencesViaOpenPreferencesAPI` would introduce an extra about:blank tab we need to take care of
+ await openPreferences("paneGeneral");
+
+ is(
+ gBrowser.currentURI.spec,
+ "about:settings#general",
+ "openPreferences should keep about:settings"
+ );
+ }
+ );
+});
diff --git a/browser/components/preferences/tests/browser_basic_rebuild_fonts_test.js b/browser/components/preferences/tests/browser_basic_rebuild_fonts_test.js
index 51998db5a9..4491373c75 100644
--- a/browser/components/preferences/tests/browser_basic_rebuild_fonts_test.js
+++ b/browser/components/preferences/tests/browser_basic_rebuild_fonts_test.js
@@ -109,7 +109,7 @@ add_task(async function () {
win.FontBuilder._enumerator = {
_list: ["MockedFont1", "MockedFont2", "MockedFont3"],
_defaultFont: null,
- EnumerateFontsAsync(lang, type) {
+ EnumerateFontsAsync() {
return Promise.resolve(this._list);
},
EnumerateAllFontsAsync() {
diff --git a/browser/components/preferences/tests/browser_browser_languages_subdialog.js b/browser/components/preferences/tests/browser_browser_languages_subdialog.js
index 1941fb3502..9faa6d2969 100644
--- a/browser/components/preferences/tests/browser_browser_languages_subdialog.js
+++ b/browser/components/preferences/tests/browser_browser_languages_subdialog.js
@@ -194,7 +194,7 @@ function assertTelemetryRecorded(events) {
// Only look at the related events after stripping the timestamp and category.
let relatedEvents = snapshot.parent
- .filter(([timestamp, category]) => category == TELEMETRY_CATEGORY)
+ .filter(([, category]) => category == TELEMETRY_CATEGORY)
.map(relatedEvent => relatedEvent.slice(2, 6));
// Events are now an array of: method, object[, value[, extra]] as expected.
@@ -297,7 +297,7 @@ add_task(async function testDisabledBrowserLanguages() {
// Search for more languages.
available.menupopup.lastElementChild.doCommand();
available.menupopup.hidePopup();
- await waitForMutation(available.menupopup, { childList: true }, target =>
+ await waitForMutation(available.menupopup, { childList: true }, () =>
Array.from(available.menupopup.children).some(
locale => locale.value == "pl"
)
@@ -352,7 +352,7 @@ add_task(async function testReorderingBrowserLanguages() {
// Install all the available langpacks.
let langpacks = await createTestLangpacks();
let addons = await Promise.all(
- langpacks.map(async ([locale, file]) => {
+ langpacks.map(async ([, file]) => {
let install = await AddonTestUtils.promiseInstallFile(file);
return install.addon;
})
@@ -458,7 +458,7 @@ add_task(async function testAddAndRemoveSelectedLanguages() {
let langpacks = await createTestLangpacks();
let addons = await Promise.all(
- langpacks.map(async ([locale, file]) => {
+ langpacks.map(async ([, file]) => {
let install = await AddonTestUtils.promiseInstallFile(file);
return install.addon;
})
@@ -603,7 +603,7 @@ add_task(async function testInstallFromAMO() {
await waitForMutation(
available.menupopup,
{ childList: true },
- target => available.itemCount > 1
+ () => available.itemCount > 1
);
}
@@ -685,7 +685,7 @@ add_task(async function testInstallFromAMO() {
await waitForMutation(
available.menupopup,
{ childList: true },
- target => available.itemCount > 1
+ () => available.itemCount > 1
);
}
assertLocaleOrder(selected, "en-US");
@@ -793,7 +793,7 @@ add_task(async function testReorderMainPane() {
let langpacks = await createTestLangpacks();
let addons = await Promise.all(
- langpacks.map(async ([locale, file]) => {
+ langpacks.map(async ([, file]) => {
let install = await AddonTestUtils.promiseInstallFile(file);
return install.addon;
})
@@ -860,7 +860,7 @@ add_task(async function testLiveLanguageReloading() {
let langpacks = await createTestLangpacks();
let addons = await Promise.all(
- langpacks.map(async ([locale, file]) => {
+ langpacks.map(async ([, file]) => {
let install = await AddonTestUtils.promiseInstallFile(file);
return install.addon;
})
@@ -928,7 +928,7 @@ add_task(async function testLiveLanguageReloadingBidiOff() {
let langpacks = await createTestLangpacks();
let addons = await Promise.all(
- langpacks.map(async ([locale, file]) => {
+ langpacks.map(async ([, file]) => {
let install = await AddonTestUtils.promiseInstallFile(file);
return install.addon;
})
@@ -1006,7 +1006,7 @@ add_task(async function testLiveLanguageReloadingBidiOn() {
let langpacks = await createTestLangpacks();
let addons = await Promise.all(
- langpacks.map(async ([locale, file]) => {
+ langpacks.map(async ([, file]) => {
let install = await AddonTestUtils.promiseInstallFile(file);
return install.addon;
})
diff --git a/browser/components/preferences/tests/browser_cert_export.js b/browser/components/preferences/tests/browser_cert_export.js
index 48769f84e6..f37cdec767 100644
--- a/browser/components/preferences/tests/browser_cert_export.js
+++ b/browser/components/preferences/tests/browser_cert_export.js
@@ -78,7 +78,7 @@ async function checkCertExportWorks(
) {
MockFilePicker.displayDirectory = destDir;
var destFile = destDir.clone();
- MockFilePicker.init(window);
+ MockFilePicker.init(window.browsingContext);
MockFilePicker.filterIndex = exportType;
MockFilePicker.showCallback = function (fp) {
info("showCallback");
diff --git a/browser/components/preferences/tests/browser_connection.js b/browser/components/preferences/tests/browser_connection.js
index 01cdf571f2..896361b16b 100644
--- a/browser/components/preferences/tests/browser_connection.js
+++ b/browser/components/preferences/tests/browser_connection.js
@@ -26,7 +26,7 @@ function test() {
so it has to be opened as a sub dialog of the main pref tab.
Open the main tab here.
*/
- open_preferences(async function tabOpened(aContentWindow) {
+ open_preferences(async function tabOpened() {
is(
gBrowser.currentURI.spec,
"about:preferences",
diff --git a/browser/components/preferences/tests/browser_connection_bug388287.js b/browser/components/preferences/tests/browser_connection_bug388287.js
index d6f0c3c9d0..87d41a22c1 100644
--- a/browser/components/preferences/tests/browser_connection_bug388287.js
+++ b/browser/components/preferences/tests/browser_connection_bug388287.js
@@ -37,7 +37,7 @@ function test() {
so it has to be opened as a sub dialog of the main pref tab.
Open the main tab here.
*/
- open_preferences(async function tabOpened(aContentWindow) {
+ open_preferences(async function tabOpened() {
let dialog, dialogClosingPromise, dialogElement;
let proxyTypePref, sharePref, httpPref, httpPortPref;
diff --git a/browser/components/preferences/tests/browser_cookies_exceptions.js b/browser/components/preferences/tests/browser_cookies_exceptions.js
index d2d538a48a..03e29d0b4c 100644
--- a/browser/components/preferences/tests/browser_cookies_exceptions.js
+++ b/browser/components/preferences/tests/browser_cookies_exceptions.js
@@ -19,7 +19,7 @@ add_task(async function testAllow() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -52,7 +52,7 @@ add_task(async function testBlock() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -85,7 +85,7 @@ add_task(async function testAllowAgain() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -152,7 +152,7 @@ add_task(async function testAdd() {
PermissionTestUtils.remove(uri, "popup");
},
- params => {
+ () => {
return [
{
type: "popup",
@@ -178,7 +178,7 @@ add_task(async function testAllowHTTPSWithPort() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -204,7 +204,7 @@ add_task(async function testBlockHTTPSWithPort() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -230,7 +230,7 @@ add_task(async function testAllowAgainHTTPSWithPort() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -288,7 +288,7 @@ add_task(async function testAllowPort() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -321,7 +321,7 @@ add_task(async function testBlockPort() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -354,7 +354,7 @@ add_task(async function testAllowAgainPort() {
apply();
await observeAllPromise;
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -450,7 +450,7 @@ add_task(async function testSort() {
PermissionTestUtils.remove(uri, "cookie");
}
},
- params => {
+ () => {
return [
{
type: "cookie",
@@ -477,7 +477,7 @@ add_task(async function testSort() {
add_task(async function testPrivateBrowsingSessionPermissionsAreHidden() {
await runTest(
- async (params, observeAllPromise, apply) => {
+ async params => {
assertListContents(params, []);
let uri = Services.io.newURI("http://test.com");
@@ -498,7 +498,7 @@ add_task(async function testPrivateBrowsingSessionPermissionsAreHidden() {
PermissionTestUtils.remove(uri, "cookie");
},
- params => {
+ () => {
return [];
}
);
diff --git a/browser/components/preferences/tests/browser_dns_over_https_exceptions_subdialog.js b/browser/components/preferences/tests/browser_dns_over_https_exceptions_subdialog.js
new file mode 100644
index 0000000000..c24c13e9e8
--- /dev/null
+++ b/browser/components/preferences/tests/browser_dns_over_https_exceptions_subdialog.js
@@ -0,0 +1,185 @@
+async function dohExceptionsSubdialogOpened(dialogOverlay) {
+ const promiseSubDialogLoaded = promiseLoadSubDialog(
+ "chrome://browser/content/preferences/dialogs/dohExceptions.xhtml"
+ );
+ const contentDocument = gBrowser.contentDocument;
+ contentDocument.getElementById("dohExceptionsButton").click();
+ const win = await promiseSubDialogLoaded;
+ dialogOverlay = content.gSubDialog._topDialog._overlay;
+ ok(!BrowserTestUtils.isHidden(dialogOverlay), "The dialog is visible.");
+ return win;
+}
+
+function acceptDoHExceptionsSubdialog(win) {
+ const button = win.document.querySelector("dialog").getButton("accept");
+ button.doCommand();
+}
+
+function cancelDoHExceptionsSubdialog(win) {
+ const button = win.document.querySelector("dialog").getButton("cancel");
+ button.doCommand();
+}
+
+function addNewException(domain, dialog) {
+ let url = dialog.document.getElementById("url");
+ let addButton = dialog.document.getElementById("btnAddException");
+
+ ok(
+ addButton.disabled,
+ "The Add button is disabled when domain's input box is empty"
+ );
+
+ url.focus();
+ EventUtils.sendString(domain);
+
+ ok(
+ !addButton.disabled,
+ "The Add button is enabled when some text is on domain's input box"
+ );
+
+ addButton.click();
+
+ is(
+ url.value,
+ "",
+ "Domain input box is empty after adding a new domain to the list"
+ );
+ ok(
+ addButton.disabled,
+ "The Add button is disabled after exception has been added to the list"
+ );
+}
+
+add_task(async function () {
+ Services.prefs.lockPref("network.trr.excluded-domains");
+
+ await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
+ leaveOpen: true,
+ });
+ let dialogOverlay = content.gSubDialog._preloadDialog._overlay;
+ let win = await dohExceptionsSubdialogOpened(dialogOverlay);
+
+ ok(
+ win.document.getElementById("btnAddException").disabled,
+ "The Add button is disabled when preference is locked"
+ );
+ ok(
+ win.document.getElementById("url").disabled,
+ "The url input box is disabled when preference is locked"
+ );
+
+ cancelDoHExceptionsSubdialog(win);
+ Services.prefs.unlockPref("network.trr.excluded-domains");
+ win = await dohExceptionsSubdialogOpened(dialogOverlay);
+
+ ok(
+ win.document.getElementById("btnAddException").disabled,
+ "The Add button is disabled when preference is not locked"
+ );
+ ok(
+ !win.document.getElementById("url").disabled,
+ "The url input box is enabled when preference is not locked"
+ );
+
+ cancelDoHExceptionsSubdialog(win);
+ gBrowser.removeCurrentTab();
+});
+
+add_task(async function () {
+ await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
+ leaveOpen: true,
+ });
+ let dialogOverlay = content.gSubDialog._preloadDialog._overlay;
+
+ ok(BrowserTestUtils.isHidden(dialogOverlay), "The dialog is invisible.");
+ let win = await dohExceptionsSubdialogOpened(dialogOverlay);
+ acceptDoHExceptionsSubdialog(win);
+ ok(BrowserTestUtils.isHidden(dialogOverlay), "The dialog is invisible.");
+
+ win = await dohExceptionsSubdialogOpened(dialogOverlay);
+ Assert.equal(
+ win.document.getElementById("permissionsBox").itemCount,
+ 0,
+ "There are no exceptions set."
+ );
+ ok(
+ win.document.getElementById("removeException").disabled,
+ "The Remove button is disabled when there are no exceptions on the list"
+ );
+ ok(
+ win.document.getElementById("removeAllExceptions").disabled,
+ "The Remove All button is disabled when there are no exceptions on the list"
+ );
+ ok(
+ win.document.getElementById("btnAddException").disabled,
+ "The Add button is disabled when dialog box has just been opened"
+ );
+
+ addNewException("test1.com", win);
+ Assert.equal(
+ win.document.getElementById("permissionsBox").itemCount,
+ 1,
+ "List shows 1 new item"
+ );
+ let activeExceptions = win.document.getElementById("permissionsBox").children;
+ is(
+ activeExceptions[0].getAttribute("domain"),
+ "test1.com",
+ "test1.com added to the list"
+ );
+ ok(
+ !win.document.getElementById("removeAllExceptions").disabled,
+ "The Remove All button is enabled when there is one exception on the list"
+ );
+ addNewException("test2.com", win);
+ addNewException("test3.com", win);
+ Assert.equal(
+ win.document.getElementById("permissionsBox").itemCount,
+ 3,
+ "List shows 3 domain items"
+ );
+ ok(
+ win.document.getElementById("removeException").disabled,
+ "The Remove button is disabled when no exception has been selected"
+ );
+ win.document.getElementById("permissionsBox").selectedIndex = 1;
+ ok(
+ !win.document.getElementById("removeException").disabled,
+ "The Remove button is enabled when an exception has been selected"
+ );
+ win.document.getElementById("removeException").doCommand();
+ Assert.equal(
+ win.document.getElementById("permissionsBox").itemCount,
+ 2,
+ "List shows 2 domain items after removing one of the three"
+ );
+ activeExceptions = win.document.getElementById("permissionsBox").children;
+ ok(
+ win.document.getElementById("permissionsBox").itemCount == 2 &&
+ activeExceptions[0].getAttribute("domain") == "test1.com" &&
+ activeExceptions[1].getAttribute("domain") == "test3.com",
+ "test1.com and test3.com are the only items left on the list"
+ );
+ is(
+ win.document.getElementById("permissionsBox").selectedIndex,
+ -1,
+ "There is no selected item after removal"
+ );
+ addNewException("test2.com", win);
+ activeExceptions = win.document.getElementById("permissionsBox").children;
+ ok(
+ win.document.getElementById("permissionsBox").itemCount == 3 &&
+ activeExceptions[1].getAttribute("domain") == "test2.com",
+ "test2.com has been added as the second item"
+ );
+ win.document.getElementById("removeAllExceptions").doCommand();
+ is(
+ win.document.getElementById("permissionsBox").itemCount,
+ 0,
+ "There are no elements on the list after clicking Remove All"
+ );
+
+ acceptDoHExceptionsSubdialog(win);
+
+ gBrowser.removeCurrentTab();
+});
diff --git a/browser/components/preferences/tests/browser_fluent.js b/browser/components/preferences/tests/browser_fluent.js
index db2daecc4f..ae83abecf0 100644
--- a/browser/components/preferences/tests/browser_fluent.js
+++ b/browser/components/preferences/tests/browser_fluent.js
@@ -1,7 +1,7 @@
function whenMainPaneLoadedFinished() {
- return new Promise(function (resolve, reject) {
+ return new Promise(function (resolve) {
const topic = "main-pane-loaded";
- Services.obs.addObserver(function observer(aSubject) {
+ Services.obs.addObserver(function observer() {
Services.obs.removeObserver(observer, topic);
resolve();
}, topic);
diff --git a/browser/components/preferences/tests/browser_localSearchShortcuts.js b/browser/components/preferences/tests/browser_localSearchShortcuts.js
index 0b8e170cc1..7f0f4869b7 100644
--- a/browser/components/preferences/tests/browser_localSearchShortcuts.js
+++ b/browser/components/preferences/tests/browser_localSearchShortcuts.js
@@ -36,7 +36,7 @@ add_setup(async function () {
// The rows should be visible and checked by default.
add_task(async function visible() {
await checkRowVisibility(true);
- await forEachLocalShortcutRow(async (row, shortcut) => {
+ await forEachLocalShortcutRow(async row => {
Assert.equal(
gTree.view.getCellValue(row, gTree.columns.getNamedColumn("engineShown")),
"true",
@@ -136,7 +136,7 @@ add_task(async function syncToPrefs_click() {
// The keyword column should not be editable according to isEditable().
add_task(async function keywordNotEditable_isEditable() {
- await forEachLocalShortcutRow(async (row, shortcut) => {
+ await forEachLocalShortcutRow(async row => {
Assert.ok(
!gTree.view.isEditable(
row,
diff --git a/browser/components/preferences/tests/browser_permissions_urlFieldHidden.js b/browser/components/preferences/tests/browser_permissions_urlFieldHidden.js
index 537ee3db72..dea9762861 100644
--- a/browser/components/preferences/tests/browser_permissions_urlFieldHidden.js
+++ b/browser/components/preferences/tests/browser_permissions_urlFieldHidden.js
@@ -3,7 +3,7 @@
const PERMISSIONS_URL =
"chrome://browser/content/preferences/dialogs/permissions.xhtml";
-add_task(async function urlFieldVisibleForPopupPermissions(finish) {
+add_task(async function urlFieldVisibleForPopupPermissions() {
await openPreferencesViaOpenPreferencesAPI("panePrivacy", {
leaveOpen: true,
});
diff --git a/browser/components/preferences/tests/browser_proxy_backup.js b/browser/components/preferences/tests/browser_proxy_backup.js
index fc05e19ada..e4ce5a99bd 100644
--- a/browser/components/preferences/tests/browser_proxy_backup.js
+++ b/browser/components/preferences/tests/browser_proxy_backup.js
@@ -47,7 +47,7 @@ function test() {
so it has to be opened as a sub dialog of the main pref tab.
Open the main tab here.
*/
- open_preferences(async function tabOpened(aContentWindow) {
+ open_preferences(async function tabOpened() {
is(
gBrowser.currentURI.spec,
"about:preferences",
diff --git a/browser/components/preferences/tests/browser_searchChangedEngine.js b/browser/components/preferences/tests/browser_searchChangedEngine.js
index 0882c9775e..22baba8dd6 100644
--- a/browser/components/preferences/tests/browser_searchChangedEngine.js
+++ b/browser/components/preferences/tests/browser_searchChangedEngine.js
@@ -46,6 +46,10 @@ add_task(async function test_change_engine() {
let row = findRow(tree, "Example");
Assert.notEqual(row, -1, "Should have found the entry");
+ await TestUtils.waitForCondition(
+ () => tree.view.getImageSrc(row, tree.columns.getNamedColumn("engineName")),
+ "Should have go an image URL"
+ );
Assert.ok(
tree.view
.getImageSrc(row, tree.columns.getNamedColumn("engineName"))
@@ -74,6 +78,13 @@ add_task(async function test_change_engine() {
row = findRow(tree, "Example 2");
Assert.notEqual(row, -1, "Should have found the updated entry");
+ await TestUtils.waitForCondition(
+ () =>
+ tree.view
+ .getImageSrc(row, tree.columns.getNamedColumn("engineName"))
+ ?.includes("img456.png"),
+ "Should have updated the image URL"
+ );
Assert.ok(
tree.view
.getImageSrc(row, tree.columns.getNamedColumn("engineName"))
diff --git a/browser/components/preferences/tests/browser_search_within_preferences_2.js b/browser/components/preferences/tests/browser_search_within_preferences_2.js
index 6de068fbe4..5fcb445adc 100644
--- a/browser/components/preferences/tests/browser_search_within_preferences_2.js
+++ b/browser/components/preferences/tests/browser_search_within_preferences_2.js
@@ -178,3 +178,87 @@ add_task(async function () {
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
+
+/**
+ * Test that search works as expected for custom elements that utilize both
+ * slots and shadow DOM. We should be able to find text the shadow DOM.
+ */
+add_task(async function testSearchShadowDOM() {
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ // Create the toggle.
+ let { toggle, SHADOW_DOM_TEXT } = createToggle(gBrowser);
+
+ ok(
+ !BrowserTestUtils.isVisible(toggle),
+ "Toggle is not visible prior to search."
+ );
+
+ // Perform search with text found in moz-toggle's shadow DOM.
+ let query = SHADOW_DOM_TEXT;
+ let searchCompletedPromise = BrowserTestUtils.waitForEvent(
+ gBrowser.contentWindow,
+ "PreferencesSearchCompleted",
+ evt => evt.detail == query
+ );
+ EventUtils.sendString(query);
+ await searchCompletedPromise;
+ ok(
+ BrowserTestUtils.isVisible(toggle),
+ "Toggle is visible after searching for string in the shadow DOM."
+ );
+
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+/**
+ * Test that search works as expected for custom elements that utilize both
+ * slots and shadow DOM. We should be able to find text the light DOM.
+ */
+add_task(async function testSearchLightDOM() {
+ await openPreferencesViaOpenPreferencesAPI("paneGeneral", {
+ leaveOpen: true,
+ });
+
+ // Create the toggle.
+ let { toggle, LIGHT_DOM_TEXT } = createToggle(gBrowser);
+
+ // Perform search with text found in moz-toggle's slotted content.
+ let query = LIGHT_DOM_TEXT;
+ let searchCompletedPromise = BrowserTestUtils.waitForEvent(
+ gBrowser.contentWindow,
+ "PreferencesSearchCompleted",
+ evt => evt.detail == query
+ );
+ EventUtils.sendString(query);
+ await searchCompletedPromise;
+ ok(
+ BrowserTestUtils.isVisible(toggle),
+ "Toggle is visible again after searching for text found in slotted content."
+ );
+
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
+
+// Create a toggle with a slotted link element.
+function createToggle(gBrowser) {
+ const SHADOW_DOM_TEXT = "This text lives in the shadow DOM";
+ const LIGHT_DOM_TEXT = "This text lives in the light DOM";
+
+ let doc = gBrowser.contentDocument;
+ let toggle = doc.createElement("moz-toggle");
+ toggle.label = SHADOW_DOM_TEXT;
+
+ let link = doc.createElement("a");
+ link.href = "https://mozilla.org/";
+ link.textContent = LIGHT_DOM_TEXT;
+ toggle.append(link);
+ link.slot = "support-link";
+
+ let protectionsGroup = doc.getElementById("trackingGroup");
+ protectionsGroup.append(toggle);
+
+ return { SHADOW_DOM_TEXT, LIGHT_DOM_TEXT, toggle };
+}
diff --git a/browser/components/preferences/tests/browser_sync_chooseWhatToSync.js b/browser/components/preferences/tests/browser_sync_chooseWhatToSync.js
index b36d9ecea3..3ff65a0d93 100644
--- a/browser/components/preferences/tests/browser_sync_chooseWhatToSync.js
+++ b/browser/components/preferences/tests/browser_sync_chooseWhatToSync.js
@@ -167,7 +167,7 @@ add_task(async function testDialogLaunchFromURI() {
);
await BrowserTestUtils.withNewTab(
"about:preferences?action=choose-what-to-sync#sync",
- async browser => {
+ async () => {
let dialogEvent = await dialogEventPromise;
Assert.equal(
dialogEvent.detail.dialog._frame.contentWindow.location,
diff --git a/browser/components/preferences/tests/browser_sync_pairing.js b/browser/components/preferences/tests/browser_sync_pairing.js
index 6491007a38..39f7b547d8 100644
--- a/browser/components/preferences/tests/browser_sync_pairing.js
+++ b/browser/components/preferences/tests/browser_sync_pairing.js
@@ -29,7 +29,7 @@ add_setup(async function () {
};
const origStart = FxAccountsPairingFlow.start;
- FxAccountsPairingFlow.start = ({ emitter: e }) => {
+ FxAccountsPairingFlow.start = () => {
return `https://foo.bar/${flowCounter++}`;
};
diff --git a/browser/components/preferences/tests/browser_trendingsuggestions.js b/browser/components/preferences/tests/browser_trendingsuggestions.js
index 1cfae387cf..81285b7f6f 100644
--- a/browser/components/preferences/tests/browser_trendingsuggestions.js
+++ b/browser/components/preferences/tests/browser_trendingsuggestions.js
@@ -78,3 +78,20 @@ add_task(async function testNonTrendingEngine() {
);
gBrowser.removeCurrentTab();
});
+
+add_task(async function testEnabledTrendingEngine() {
+ const engine1 = Services.search.getEngineByName("Google");
+ Services.search.setDefault(
+ engine1,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+ await openPreferencesViaOpenPreferencesAPI("search", { leaveOpen: true });
+ let doc = gBrowser.selectedBrowser.contentDocument;
+ let trendingCheckbox = doc.getElementById(TRENDING_CHECKBOX_ID);
+
+ Assert.ok(
+ !trendingCheckbox.disabled,
+ "Checkbox should not be disabled when an engine that supports trending suggestions is default"
+ );
+ gBrowser.removeCurrentTab();
+});
diff --git a/browser/components/preferences/tests/head.js b/browser/components/preferences/tests/head.js
index 1861c040e5..f9e5b10c09 100644
--- a/browser/components/preferences/tests/head.js
+++ b/browser/components/preferences/tests/head.js
@@ -45,7 +45,7 @@ function openAndLoadSubDialog(
}
function promiseLoadSubDialog(aURL) {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
content.gSubDialog._dialogStack.addEventListener(
"dialogopen",
function dialogopen(aEvent) {
diff --git a/browser/components/preferences/tests/siteData/browser_clearSiteData.js b/browser/components/preferences/tests/siteData/browser_clearSiteData.js
index ad1d27bfe2..7ae1fda453 100644
--- a/browser/components/preferences/tests/siteData/browser_clearSiteData.js
+++ b/browser/components/preferences/tests/siteData/browser_clearSiteData.js
@@ -137,7 +137,7 @@ async function testClearData(clearSiteData, clearCache) {
let clearButton = dialogWin.document
.querySelector("dialog")
.getButton("accept");
- if (!clearSiteData && !clearCache) {
+ if (!clearSiteData && !clearCache && useOldClearHistoryDialog) {
// Simulate user input on one of the checkboxes to trigger the event listener for
// disabling the clearButton.
clearCacheCheckbox.doCommand();
diff --git a/browser/components/preferences/tests/siteData/head.js b/browser/components/preferences/tests/siteData/head.js
index 2b8a9984a6..6385013a52 100644
--- a/browser/components/preferences/tests/siteData/head.js
+++ b/browser/components/preferences/tests/siteData/head.js
@@ -52,7 +52,7 @@ function is_element_hidden(aElement, aMsg) {
}
function promiseLoadSubDialog(aURL) {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
content.gSubDialog._dialogStack.addEventListener(
"dialogopen",
function dialogopen(aEvent) {
diff --git a/browser/components/preferences/tests/siteData/service_worker_test.html b/browser/components/preferences/tests/siteData/service_worker_test.html
index 56f5173481..710b61090f 100644
--- a/browser/components/preferences/tests/siteData/service_worker_test.html
+++ b/browser/components/preferences/tests/siteData/service_worker_test.html
@@ -13,7 +13,7 @@
<h1>Service Worker Test</h1>
<script type="text/javascript">
navigator.serviceWorker.register("service_worker_test.js")
- .then(regis => document.body.setAttribute("data-test-service-worker-registered", "true"));
+ .then(() => document.body.setAttribute("data-test-service-worker-registered", "true"));
</script>
</body>
</html>
diff --git a/browser/components/preferences/translations.inc.xhtml b/browser/components/preferences/translations.inc.xhtml
index 5fed03da9b..9463fde707 100644
--- a/browser/components/preferences/translations.inc.xhtml
+++ b/browser/components/preferences/translations.inc.xhtml
@@ -4,9 +4,12 @@
<script src="chrome://browser/content/preferences/translations.js"/>
-<div xmlns="http://www.w3.org/1999/xhtml"
+<div id="translations-settings-page"
+ xmlns="http://www.w3.org/1999/xhtml"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- data-category="paneTranslations">
+ data-category="paneTranslations"
+ data-hidden-from-search="true"
+ hidden="true">
<button id="translations-settings-back-button" class="back-button"
data-l10n-id="translations-settings-back-button"/>