--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -980,16 +980,20 @@ pref("browser.zoom.full", true);
pref("browser.zoom.siteSpecific", true);
// Whether or not to update background tabs to the current zoom level.
pref("browser.zoom.updateBackgroundTabs", true);
// The breakpad report server to link to in about:crashes
pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/");
+// URL for "Learn More" for DataCollection
+pref("toolkit.datacollection.infoURL",
+ "https://www.mozilla.org/legal/privacy/firefox.html");
+
// URL for "Learn More" for Crash Reporter
pref("toolkit.crashreporter.infoURL",
"https://www.mozilla.org/legal/privacy/firefox.html#crash-reporter");
// base URL for web-based support pages
pref("app.support.baseURL", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/");
// a11y conflicts with e10s support page
--- a/browser/base/content/aboutDialog-appUpdater.js
+++ b/browser/base/content/aboutDialog-appUpdater.js
@@ -181,24 +181,19 @@ appUpdater.prototype =
let year = buildID.slice(0, 4);
let month = buildID.slice(4, 6);
let day = buildID.slice(6, 8);
updateVersion += ` (${year}-${month}-${day})`;
}
button.label = this.bundle.formatStringFromName("update.downloadAndInstallButton.label", [updateVersion], 1);
button.accessKey = this.bundle.GetStringFromName("update.downloadAndInstallButton.accesskey");
}
- this.updateDeck.selectedPanel = panel;
- if (!document.commandDispatcher.focusedElement || // don't steal the focus
- document.commandDispatcher.focusedElement.localName == "button") // except from the other buttons
- button.focus();
+ }
- } else {
- this.updateDeck.selectedPanel = panel;
- }
+ this.updateDeck.selectedPanel = panel;
},
/**
* Check for updates
*/
checkForUpdates() {
// Clear prefs that could prevent a user from discovering available updates.
if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CANCELATIONS_OSX)) {
--- a/browser/components/preferences/applicationManager.js
+++ b/browser/components/preferences/applicationManager.js
@@ -7,41 +7,51 @@
var Cc = Components.classes;
var Ci = Components.interfaces;
var gAppManagerDialog = {
_removed: [],
init: function appManager_init() {
this.handlerInfo = window.arguments[0];
-
+ // The applicationManager will be used
+ // in in-content's gApplicationsPane and in-content-new's gMainPane.
+ // Remove this once we use the in-content-new preferences page.
+ var pane;
+ if (Services.prefs.getBoolPref("browser.preferences.useOldOrganization")) {
+ Services.scriptloader.loadSubScript("chrome://browser/content/preferences/in-content/applications.js");
+ pane = gApplicationsPane;
+ } else {
+ Services.scriptloader.loadSubScript("chrome://browser/content/preferences/in-content-new/main.js");
+ pane = gMainPane;
+ }
var bundle = document.getElementById("appManagerBundle");
var contentText;
if (this.handlerInfo.type == TYPE_MAYBE_FEED)
contentText = bundle.getString("handleWebFeeds");
else {
- var description = gApplicationsPane._describeType(this.handlerInfo);
+ var description = pane._describeType(this.handlerInfo);
var key =
(this.handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) ? "handleFile"
: "handleProtocol";
contentText = bundle.getFormattedString(key, [description]);
}
contentText = bundle.getFormattedString("descriptionApplications", [contentText]);
document.getElementById("appDescription").textContent = contentText;
var list = document.getElementById("appList");
var apps = this.handlerInfo.possibleApplicationHandlers.enumerate();
while (apps.hasMoreElements()) {
let app = apps.getNext();
- if (!gApplicationsPane.isValidHandlerApp(app))
+ if (!pane.isValidHandlerApp(app))
continue;
app.QueryInterface(Ci.nsIHandlerApp);
var item = list.appendItem(app.name);
- item.setAttribute("image", gApplicationsPane._getIconURLForHandlerApp(app));
+ item.setAttribute("image", pane._getIconURLForHandlerApp(app));
item.className = "listitem-iconic";
item.app = app;
}
list.selectedIndex = 0;
},
onOK: function appManager_onOK() {
--- a/browser/components/preferences/applicationManager.xul
+++ b/browser/components/preferences/applicationManager.xul
@@ -16,18 +16,16 @@
title="&appManager.title;"
style="&appManager.style;"
persist="screenX screenY">
<script type="application/javascript"
src="chrome://browser/content/utilityOverlay.js"/>
<script type="application/javascript"
src="chrome://browser/content/preferences/applicationManager.js"/>
- <script type="application/javascript"
- src="chrome://browser/content/preferences/in-content-new/applications.js"/>
<commandset id="appManagerCommandSet">
<command id="cmd_remove"
oncommand="gAppManagerDialog.remove();"
disabled="true"/>
</commandset>
<keyset id="appManagerKeyset">
--- a/browser/components/preferences/handlers.xml
+++ b/browser/components/preferences/handlers.xml
@@ -51,26 +51,32 @@
<xul:hbox flex="1" align="center" xbl:inherits="tooltiptext=typeDescription">
<xul:image src="moz-icon://goat?size=16" class="typeIcon"
xbl:inherits="src=typeIcon" height="16" width="16"/>
<xul:label flex="1" crop="end" xbl:inherits="value=typeDescription"/>
</xul:hbox>
<xul:hbox flex="1">
<xul:menulist class="actionsMenu" flex="1" crop="end" selectedIndex="1"
xbl:inherits="tooltiptext=actionDescription"
- oncommand="gApplicationsPane.onSelectAction(event.originalTarget)">
+ oncommand="Services.prefs.getBoolPref('browser.preferences.useOldOrganization') ?
+ gApplicationsPane.onSelectAction(event.originalTarget) :
+ gMainPane.onSelectAction(event.originalTarget)">
<xul:menupopup/>
</xul:menulist>
</xul:hbox>
</xul:hbox>
</content>
<implementation>
<constructor>
- gApplicationsPane.rebuildActionsMenu();
+ if (Services.prefs.getBoolPref("browser.preferences.useOldOrganization")) {
+ gApplicationsPane.rebuildActionsMenu();
+ } else {
+ gMainPane.rebuildActionsMenu();
+ }
</constructor>
</implementation>
</binding>
<binding id="container">
<content>
<xul:hbox flex="1" equalsize="always">
deleted file mode 100644
--- a/browser/components/preferences/in-content-new/advanced.js
+++ /dev/null
@@ -1,202 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* import-globals-from preferences.js */
-/* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
-
-// Load DownloadUtils module for convertByteUnits
-Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
-Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
-Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-var gAdvancedPane = {
- _inited: false,
-
- init() {
- function setEventListener(aId, aEventType, aCallback) {
- document.getElementById(aId)
- .addEventListener(aEventType, aCallback.bind(gAdvancedPane));
- }
-
- this._inited = true;
-
- let version = AppConstants.MOZ_APP_VERSION_DISPLAY;
-
- // Include the build ID if this is an "a#" (nightly) build
- if (/a\d+$/.test(version)) {
- let buildID = Services.appinfo.appBuildID;
- let year = buildID.slice(0, 4);
- let month = buildID.slice(4, 6);
- let day = buildID.slice(6, 8);
- version += ` (${year}-${month}-${day})`;
- }
-
- // Append "(32-bit)" or "(64-bit)" build architecture to the version number:
- let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
- let archResource = Services.appinfo.is64Bit
- ? "aboutDialog.architecture.sixtyFourBit"
- : "aboutDialog.architecture.thirtyTwoBit";
- let arch = bundle.GetStringFromName(archResource);
- version += ` (${arch})`;
-
- document.getElementById("version").textContent = version;
-
- // Show a release notes link if we have a URL.
- let relNotesLink = document.getElementById("releasenotes");
- let relNotesPrefType = Services.prefs.getPrefType("app.releaseNotesURL");
- if (relNotesPrefType != Services.prefs.PREF_INVALID) {
- let relNotesURL = Services.urlFormatter.formatURLPref("app.releaseNotesURL");
- if (relNotesURL != "about:blank") {
- relNotesLink.href = relNotesURL;
- relNotesLink.hidden = false;
- }
- }
-
- let distroId = Services.prefs.getCharPref("distribution.id", "");
- if (distroId) {
- let distroVersion = Services.prefs.getCharPref("distribution.version");
-
- let distroIdField = document.getElementById("distributionId");
- distroIdField.value = distroId + " - " + distroVersion;
- distroIdField.hidden = false;
-
- let distroAbout = Services.prefs.getStringPref("distribution.about", "");
- if (distroAbout) {
- let distroField = document.getElementById("distribution");
- distroField.value = distroAbout;
- distroField.hidden = false;
- }
- }
-
- if (AppConstants.MOZ_UPDATER) {
- gAppUpdater = new appUpdater();
- let onUnload = () => {
- window.removeEventListener("unload", onUnload);
- Services.prefs.removeObserver("app.update.", this);
- };
- window.addEventListener("unload", onUnload);
- Services.prefs.addObserver("app.update.", this);
- this.updateReadPrefs();
- setEventListener("updateRadioGroup", "command",
- gAdvancedPane.updateWritePrefs);
- setEventListener("showUpdateHistory", "command",
- gAdvancedPane.showUpdates);
- }
- },
-
- /*
- * Preferences:
- *
- * app.update.enabled
- * - true if updates to the application are enabled, false otherwise
- * app.update.auto
- * - true if updates should be automatically downloaded and installed and
- * false if the user should be asked what he wants to do when an update is
- * available
- * extensions.update.enabled
- * - true if updates to extensions and themes are enabled, false otherwise
- * browser.search.update
- * - true if updates to search engines are enabled, false otherwise
- */
-
- /**
- * Selects the item of the radiogroup based on the pref values and locked
- * states.
- *
- * UI state matrix for update preference conditions
- *
- * UI Components: Preferences
- * Radiogroup i = app.update.enabled
- * ii = app.update.auto
- *
- * Disabled states:
- * Element pref value locked disabled
- * radiogroup i t/f f false
- * i t/f *t* *true*
- * ii t/f f false
- * ii t/f *t* *true*
- */
- updateReadPrefs() {
- if (AppConstants.MOZ_UPDATER) {
- var enabledPref = document.getElementById("app.update.enabled");
- var autoPref = document.getElementById("app.update.auto");
- var radiogroup = document.getElementById("updateRadioGroup");
-
- if (!enabledPref.value) // Don't care for autoPref.value in this case.
- radiogroup.value = "manual"; // 3. Never check for updates.
- else if (autoPref.value) // enabledPref.value && autoPref.value
- radiogroup.value = "auto"; // 1. Automatically install updates
- else // enabledPref.value && !autoPref.value
- radiogroup.value = "checkOnly"; // 2. Check, but let me choose
-
- var canCheck = Components.classes["@mozilla.org/updates/update-service;1"].
- getService(Components.interfaces.nsIApplicationUpdateService).
- canCheckForUpdates;
- // canCheck is false if the enabledPref is false and locked,
- // or the binary platform or OS version is not known.
- // A locked pref is sufficient to disable the radiogroup.
- radiogroup.disabled = !canCheck || enabledPref.locked || autoPref.locked;
-
- if (AppConstants.MOZ_MAINTENANCE_SERVICE) {
- // Check to see if the maintenance service is installed.
- // If it is don't show the preference at all.
- var installed;
- try {
- var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
- .createInstance(Components.interfaces.nsIWindowsRegKey);
- wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
- "SOFTWARE\\Mozilla\\MaintenanceService",
- wrk.ACCESS_READ | wrk.WOW64_64);
- installed = wrk.readIntValue("Installed");
- wrk.close();
- } catch (e) {
- }
- if (installed != 1) {
- document.getElementById("useService").hidden = true;
- }
- }
- }
- },
-
- /**
- * Sets the pref values based on the selected item of the radiogroup.
- */
- updateWritePrefs() {
- if (AppConstants.MOZ_UPDATER) {
- var enabledPref = document.getElementById("app.update.enabled");
- var autoPref = document.getElementById("app.update.auto");
- var radiogroup = document.getElementById("updateRadioGroup");
- switch (radiogroup.value) {
- case "auto": // 1. Automatically install updates for Desktop only
- enabledPref.value = true;
- autoPref.value = true;
- break;
- case "checkOnly": // 2. Check, but let me choose
- enabledPref.value = true;
- autoPref.value = false;
- break;
- case "manual": // 3. Never check for updates.
- enabledPref.value = false;
- autoPref.value = false;
- }
- }
- },
-
- /**
- * Displays the history of installed updates.
- */
- showUpdates() {
- gSubDialog.open("chrome://mozapps/content/update/history.xul");
- },
-
- observe(aSubject, aTopic, aData) {
- if (AppConstants.MOZ_UPDATER) {
- switch (aTopic) {
- case "nsPref:changed":
- this.updateReadPrefs();
- break;
- }
- }
- },
-};
deleted file mode 100644
--- a/browser/components/preferences/in-content-new/advanced.xul
+++ /dev/null
@@ -1,195 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-<!-- Advanced panel -->
-
-#ifdef MOZ_UPDATER
- <script type="application/javascript" src="chrome://browser/content/aboutDialog-appUpdater.js"/>
-#endif
-
-<script type="application/javascript"
- src="chrome://browser/content/preferences/in-content-new/advanced.js"/>
-
-<preferences id="advancedPreferences" hidden="true" data-category="paneAdvanced">
- <preference id="browser.preferences.advanced.selectedTabIndex"
- name="browser.preferences.advanced.selectedTabIndex"
- type="int"/>
-
-<!-- Update tab -->
-#ifdef MOZ_UPDATER
- <preference id="app.update.enabled"
- name="app.update.enabled"
- type="bool"/>
- <preference id="app.update.auto"
- name="app.update.auto"
- type="bool"/>
-
- <preference id="app.update.disable_button.showUpdateHistory"
- name="app.update.disable_button.showUpdateHistory"
- type="bool"/>
-
-#ifdef MOZ_MAINTENANCE_SERVICE
- <preference id="app.update.service.enabled"
- name="app.update.service.enabled"
- type="bool"/>
-#endif
-#endif
-
- <preference id="browser.search.update"
- name="browser.search.update"
- type="bool"/>
-</preferences>
-
-#ifdef HAVE_SHELL_SERVICE
- <stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
- <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
-#endif
-
-<hbox id="header-advanced"
- class="header"
- hidden="true"
- data-category="paneAdvanced">
- <label class="header-name" flex="1">&paneUpdates.title;</label>
-</hbox>
-
-<!-- Update -->
-<groupbox id="updateApp" data-category="paneAdvanced" hidden="true">
- <caption><label>&updateApplication.label;</label></caption>
- <hbox align="start">
- <vbox flex="1">
- <description>
- &updateApplication.version.pre;<label id="version"/>&updateApplication.version.post;
- <label id="releasenotes" class="learnMore text-link" hidden="true">&releaseNotes.link;</label>
- </description>
- <description id="distribution" class="text-blurb" hidden="true"/>
- <description id="distributionId" class="text-blurb" hidden="true"/>
- </vbox>
-#ifdef MOZ_UPDATER
- <spacer flex="1"/>
- <vbox>
- <button id="showUpdateHistory"
- class="accessory-button"
- label="&updateHistory2.label;"
- accesskey="&updateHistory2.accesskey;"
- preference="app.update.disable_button.showUpdateHistory"
- searchkeywords="&history.title; &history.intro;"/>
- </vbox>
-#endif
- </hbox>
-#ifdef MOZ_UPDATER
- <vbox id="updateBox">
- <deck id="updateDeck" orient="vertical">
- <hbox id="checkForUpdates" align="center">
- <spacer flex="1"/>
- <button id="checkForUpdatesButton"
- label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- oncommand="gAppUpdater.checkForUpdates();"/>
- </hbox>
- <hbox id="downloadAndInstall" align="center">
- <spacer flex="1"/>
- <button id="downloadAndInstallButton"
- oncommand="gAppUpdater.startDownload();"/>
- <!-- label and accesskey will be filled by JS -->
- </hbox>
- <hbox id="apply" align="center">
- <spacer flex="1"/>
- <button id="updateButton"
- label="&update.updateButton.label3;"
- accesskey="&update.updateButton.accesskey;"
- oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
- </hbox>
- <hbox id="checkingForUpdates" align="center">
- <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
- <spacer flex="1"/>
- <button label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- disabled="true"/>
- </hbox>
- <hbox id="downloading" align="center">
- <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
- </hbox>
- <hbox id="applying" align="center">
- <image class="update-throbber"/><label>&update.applying;</label>
- </hbox>
- <hbox id="downloadFailed" align="center">
- <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
- <spacer flex="1"/>
- <button label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- oncommand="gAppUpdater.checkForUpdates();"/>
- </hbox>
- <hbox id="adminDisabled" align="center">
- <label>&update.adminDisabled;</label>
- <spacer flex="1"/>
- <button label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- disabled="true"/>
- </hbox>
- <hbox id="noUpdatesFound" align="center">
- <label>&update.noUpdatesFound;</label>
- <spacer flex="1"/>
- <button label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- oncommand="gAppUpdater.checkForUpdates();"/>
- </hbox>
- <hbox id="otherInstanceHandlingUpdates" align="center">
- <label>&update.otherInstanceHandlingUpdates;</label>
- <spacer flex="1"/>
- <button label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- disabled="true"/>
- </hbox>
- <hbox id="manualUpdate" align="center">
- <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
- <spacer flex="1"/>
- <button label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- disabled="true"/>
- </hbox>
- <hbox id="unsupportedSystem" align="center">
- <label>&update.unsupported.start;</label><label id="unsupportedLink" class="text-link">&update.unsupported.linkText;</label><label>&update.unsupported.end;</label>
- <spacer flex="1"/>
- <button label="&update.checkForUpdatesButton.label;"
- accesskey="&update.checkForUpdatesButton.accesskey;"
- disabled="true"/>
- </hbox>
- <hbox id="restarting" align="center">
- <image class="update-throbber"/><label>&update.restarting;</label>
- <spacer flex="1"/>
- <button label="&update.updateButton.label3;"
- accesskey="&update.updateButton.accesskey;"
- disabled="true"/>
- </hbox>
- </deck>
- </vbox>
-#endif
-
- <separator/>
-#ifdef MOZ_UPDATER
- <description>&updateApplication.description;</description>
- <radiogroup id="updateRadioGroup">
- <radio id="autoDesktop"
- value="auto"
- label="&updateAuto2.label;"
- accesskey="&updateAuto2.accesskey;"/>
- <radio value="checkOnly"
- label="&updateCheckChoose2.label;"
- accesskey="&updateCheckChoose2.accesskey;"/>
- <radio value="manual"
- label="&updateManual2.label;"
- accesskey="&updateManual2.accesskey;"/>
- </radiogroup>
-#ifdef MOZ_MAINTENANCE_SERVICE
- <checkbox id="useService"
- label="&useService.label;"
- accesskey="&useService.accesskey;"
- preference="app.update.service.enabled"/>
-#endif
-#endif
- <checkbox id="enableSearchUpdate"
- label="&enableSearchUpdate2.label;"
- accesskey="&enableSearchUpdate2.accesskey;"
- preference="browser.search.update"/>
-</groupbox>
deleted file mode 100644
--- a/browser/components/preferences/in-content-new/applications.js
+++ /dev/null
@@ -1,2101 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/* import-globals-from preferences.js */
-
-"use strict";
-
-// Constants & Enumeration Values
-
-Components.utils.import("resource://gre/modules/Services.jsm");
-Components.utils.import("resource://gre/modules/AppConstants.jsm");
-
-const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
-const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
-const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
-const TYPE_PDF = "application/pdf";
-
-const PREF_PDFJS_DISABLED = "pdfjs.disabled";
-const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
-
-const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types";
-
-// Preferences that affect which entries to show in the list.
-const PREF_SHOW_PLUGINS_IN_LIST = "browser.download.show_plugins_in_list";
-const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
- "browser.download.hide_plugins_without_extensions";
-
-/*
- * Preferences where we store handling information about the feed type.
- *
- * browser.feeds.handler
- * - "bookmarks", "reader" (clarified further using the .default preference),
- * or "ask" -- indicates the default handler being used to process feeds;
- * "bookmarks" is obsolete; to specify that the handler is bookmarks,
- * set browser.feeds.handler.default to "bookmarks";
- *
- * browser.feeds.handler.default
- * - "bookmarks", "client" or "web" -- indicates the chosen feed reader used
- * to display feeds, either transiently (i.e., when the "use as default"
- * checkbox is unchecked, corresponds to when browser.feeds.handler=="ask")
- * or more permanently (i.e., the item displayed in the dropdown in Feeds
- * preferences)
- *
- * browser.feeds.handler.webservice
- * - the URL of the currently selected web service used to read feeds
- *
- * browser.feeds.handlers.application
- * - nsILocalFile, stores the current client-side feed reading app if one has
- * been chosen
- */
-const PREF_FEED_SELECTED_APP = "browser.feeds.handlers.application";
-const PREF_FEED_SELECTED_WEB = "browser.feeds.handlers.webservice";
-const PREF_FEED_SELECTED_ACTION = "browser.feeds.handler";
-const PREF_FEED_SELECTED_READER = "browser.feeds.handler.default";
-
-const PREF_VIDEO_FEED_SELECTED_APP = "browser.videoFeeds.handlers.application";
-const PREF_VIDEO_FEED_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
-const PREF_VIDEO_FEED_SELECTED_ACTION = "browser.videoFeeds.handler";
-const PREF_VIDEO_FEED_SELECTED_READER = "browser.videoFeeds.handler.default";
-
-const PREF_AUDIO_FEED_SELECTED_APP = "browser.audioFeeds.handlers.application";
-const PREF_AUDIO_FEED_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
-const PREF_AUDIO_FEED_SELECTED_ACTION = "browser.audioFeeds.handler";
-const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
-
-// The nsHandlerInfoAction enumeration values in nsIHandlerInfo identify
-// the actions the application can take with content of various types.
-// But since nsIHandlerInfo doesn't support plugins, there's no value
-// identifying the "use plugin" action, so we use this constant instead.
-const kActionUsePlugin = 5;
-
-const ICON_URL_APP = AppConstants.platform == "linux" ?
- "moz-icon://dummy.exe?size=16" :
- "chrome://browser/skin/preferences/application.png";
-
-// For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
-// was set by us to a custom handler icon and CSS should not try to override it.
-const APP_ICON_ATTR_NAME = "appHandlerIcon";
-
-// Utilities
-
-function getFileDisplayName(file) {
- if (AppConstants.platform == "win") {
- if (file instanceof Ci.nsILocalFileWin) {
- try {
- return file.getVersionInfoField("FileDescription");
- } catch (e) {}
- }
- }
- if (AppConstants.platform == "macosx") {
- if (file instanceof Ci.nsILocalFileMac) {
- try {
- return file.bundleDisplayName;
- } catch (e) {}
- }
- }
- return file.leafName;
-}
-
-function getLocalHandlerApp(aFile) {
- var localHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
- createInstance(Ci.nsILocalHandlerApp);
- localHandlerApp.name = getFileDisplayName(aFile);
- localHandlerApp.executable = aFile;
-
- return localHandlerApp;
-}
-
-/**
- * An enumeration of items in a JS array.
- *
- * FIXME: use ArrayConverter once it lands (bug 380839).
- *
- * @constructor
- */
-function ArrayEnumerator(aItems) {
- this._index = 0;
- this._contents = aItems;
-}
-
-ArrayEnumerator.prototype = {
- _index: 0,
-
- hasMoreElements() {
- return this._index < this._contents.length;
- },
-
- getNext() {
- return this._contents[this._index++];
- }
-};
-
-function isFeedType(t) {
- return t == TYPE_MAYBE_FEED || t == TYPE_MAYBE_VIDEO_FEED || t == TYPE_MAYBE_AUDIO_FEED;
-}
-
-// HandlerInfoWrapper
-
-/**
- * This object wraps nsIHandlerInfo with some additional functionality
- * the Applications prefpane needs to display and allow modification of
- * the list of handled types.
- *
- * We create an instance of this wrapper for each entry we might display
- * in the prefpane, and we compose the instances from various sources,
- * including plugins and the handler service.
- *
- * We don't implement all the original nsIHandlerInfo functionality,
- * just the stuff that the prefpane needs.
- *
- * In theory, all of the custom functionality in this wrapper should get
- * pushed down into nsIHandlerInfo eventually.
- */
-function HandlerInfoWrapper(aType, aHandlerInfo) {
- this._type = aType;
- this.wrappedHandlerInfo = aHandlerInfo;
-}
-
-HandlerInfoWrapper.prototype = {
- // The wrapped nsIHandlerInfo object. In general, this object is private,
- // but there are a couple cases where callers access it directly for things
- // we haven't (yet?) implemented, so we make it a public property.
- wrappedHandlerInfo: null,
-
-
- // Convenience Utils
-
- _handlerSvc: Cc["@mozilla.org/uriloader/handler-service;1"].
- getService(Ci.nsIHandlerService),
-
- _prefSvc: Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch),
-
- _categoryMgr: Cc["@mozilla.org/categorymanager;1"].
- getService(Ci.nsICategoryManager),
-
- element(aID) {
- return document.getElementById(aID);
- },
-
-
- // nsIHandlerInfo
-
- // The MIME type or protocol scheme.
- _type: null,
- get type() {
- return this._type;
- },
-
- get description() {
- if (this.wrappedHandlerInfo.description)
- return this.wrappedHandlerInfo.description;
-
- if (this.primaryExtension) {
- var extension = this.primaryExtension.toUpperCase();
- return this.element("bundlePreferences").getFormattedString("fileEnding",
- [extension]);
- }
-
- return this.type;
- },
-
- get preferredApplicationHandler() {
- return this.wrappedHandlerInfo.preferredApplicationHandler;
- },
-
- set preferredApplicationHandler(aNewValue) {
- this.wrappedHandlerInfo.preferredApplicationHandler = aNewValue;
-
- // Make sure the preferred handler is in the set of possible handlers.
- if (aNewValue)
- this.addPossibleApplicationHandler(aNewValue)
- },
-
- get possibleApplicationHandlers() {
- return this.wrappedHandlerInfo.possibleApplicationHandlers;
- },
-
- addPossibleApplicationHandler(aNewHandler) {
- var possibleApps = this.possibleApplicationHandlers.enumerate();
- while (possibleApps.hasMoreElements()) {
- if (possibleApps.getNext().equals(aNewHandler))
- return;
- }
- this.possibleApplicationHandlers.appendElement(aNewHandler);
- },
-
- removePossibleApplicationHandler(aHandler) {
- var defaultApp = this.preferredApplicationHandler;
- if (defaultApp && aHandler.equals(defaultApp)) {
- // If the app we remove was the default app, we must make sure
- // it won't be used anymore
- this.alwaysAskBeforeHandling = true;
- this.preferredApplicationHandler = null;
- }
-
- var handlers = this.possibleApplicationHandlers;
- for (var i = 0; i < handlers.length; ++i) {
- var handler = handlers.queryElementAt(i, Ci.nsIHandlerApp);
- if (handler.equals(aHandler)) {
- handlers.removeElementAt(i);
- break;
- }
- }
- },
-
- get hasDefaultHandler() {
- return this.wrappedHandlerInfo.hasDefaultHandler;
- },
-
- get defaultDescription() {
- return this.wrappedHandlerInfo.defaultDescription;
- },
-
- // What to do with content of this type.
- get preferredAction() {
- // If we have an enabled plugin, then the action is to use that plugin.
- if (this.pluginName && !this.isDisabledPluginType)
- return kActionUsePlugin;
-
- // If the action is to use a helper app, but we don't have a preferred
- // handler app, then switch to using the system default, if any; otherwise
- // fall back to saving to disk, which is the default action in nsMIMEInfo.
- // Note: "save to disk" is an invalid value for protocol info objects,
- // but the alwaysAskBeforeHandling getter will detect that situation
- // and always return true in that case to override this invalid value.
- if (this.wrappedHandlerInfo.preferredAction == Ci.nsIHandlerInfo.useHelperApp &&
- !gApplicationsPane.isValidHandlerApp(this.preferredApplicationHandler)) {
- if (this.wrappedHandlerInfo.hasDefaultHandler)
- return Ci.nsIHandlerInfo.useSystemDefault;
- return Ci.nsIHandlerInfo.saveToDisk;
- }
-
- return this.wrappedHandlerInfo.preferredAction;
- },
-
- set preferredAction(aNewValue) {
- // If the action is to use the plugin,
- // we must set the preferred action to "save to disk".
- // But only if it's not currently the preferred action.
- if ((aNewValue == kActionUsePlugin) &&
- (this.preferredAction != Ci.nsIHandlerInfo.saveToDisk)) {
- aNewValue = Ci.nsIHandlerInfo.saveToDisk;
- }
-
- // We don't modify the preferred action if the new action is to use a plugin
- // because handler info objects don't understand our custom "use plugin"
- // value. Also, leaving it untouched means that we can automatically revert
- // to the old setting if the user ever removes the plugin.
-
- if (aNewValue != kActionUsePlugin)
- this.wrappedHandlerInfo.preferredAction = aNewValue;
- },
-
- get alwaysAskBeforeHandling() {
- // If this type is handled only by a plugin, we can't trust the value
- // in the handler info object, since it'll be a default based on the absence
- // of any user configuration, and the default in that case is to always ask,
- // even though we never ask for content handled by a plugin, so special case
- // plugin-handled types by returning false here.
- if (this.pluginName && this.handledOnlyByPlugin)
- return false;
-
- // If this is a protocol type and the preferred action is "save to disk",
- // which is invalid for such types, then return true here to override that
- // action. This could happen when the preferred action is to use a helper
- // app, but the preferredApplicationHandler is invalid, and there isn't
- // a default handler, so the preferredAction getter returns save to disk
- // instead.
- if (!(this.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) &&
- this.preferredAction == Ci.nsIHandlerInfo.saveToDisk)
- return true;
-
- return this.wrappedHandlerInfo.alwaysAskBeforeHandling;
- },
-
- set alwaysAskBeforeHandling(aNewValue) {
- this.wrappedHandlerInfo.alwaysAskBeforeHandling = aNewValue;
- },
-
-
- // nsIMIMEInfo
-
- // The primary file extension associated with this type, if any.
- //
- // XXX Plugin objects contain an array of MimeType objects with "suffixes"
- // properties; if this object has an associated plugin, shouldn't we check
- // those properties for an extension?
- get primaryExtension() {
- try {
- if (this.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
- this.wrappedHandlerInfo.primaryExtension)
- return this.wrappedHandlerInfo.primaryExtension
- } catch (ex) {}
-
- return null;
- },
-
-
- // Plugin Handling
-
- // A plugin that can handle this type, if any.
- //
- // Note: just because we have one doesn't mean it *will* handle the type.
- // That depends on whether or not the type is in the list of types for which
- // plugin handling is disabled.
- plugin: null,
-
- // Whether or not this type is only handled by a plugin or is also handled
- // by some user-configured action as specified in the handler info object.
- //
- // Note: we can't just check if there's a handler info object for this type,
- // because OS and user configuration is mixed up in the handler info object,
- // so we always need to retrieve it for the OS info and can't tell whether
- // it represents only OS-default information or user-configured information.
- //
- // FIXME: once handler info records are broken up into OS-provided records
- // and user-configured records, stop using this boolean flag and simply
- // check for the presence of a user-configured record to determine whether
- // or not this type is only handled by a plugin. Filed as bug 395142.
- handledOnlyByPlugin: undefined,
-
- get isDisabledPluginType() {
- return this._getDisabledPluginTypes().indexOf(this.type) != -1;
- },
-
- _getDisabledPluginTypes() {
- var types = "";
-
- if (this._prefSvc.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES))
- types = this._prefSvc.getCharPref(PREF_DISABLED_PLUGIN_TYPES);
-
- // Only split if the string isn't empty so we don't end up with an array
- // containing a single empty string.
- if (types != "")
- return types.split(",");
-
- return [];
- },
-
- disablePluginType() {
- var disabledPluginTypes = this._getDisabledPluginTypes();
-
- if (disabledPluginTypes.indexOf(this.type) == -1)
- disabledPluginTypes.push(this.type);
-
- this._prefSvc.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
- disabledPluginTypes.join(","));
-
- // Update the category manager so existing browser windows update.
- this._categoryMgr.deleteCategoryEntry("Gecko-Content-Viewers",
- this.type,
- false);
- },
-
- enablePluginType() {
- var disabledPluginTypes = this._getDisabledPluginTypes();
-
- var type = this.type;
- disabledPluginTypes = disabledPluginTypes.filter(v => v != type);
-
- this._prefSvc.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
- disabledPluginTypes.join(","));
-
- // Update the category manager so existing browser windows update.
- this._categoryMgr.
- addCategoryEntry("Gecko-Content-Viewers",
- this.type,
- "@mozilla.org/content/plugin/document-loader-factory;1",
- false,
- true);
- },
-
-
- // Storage
-
- store() {
- this._handlerSvc.store(this.wrappedHandlerInfo);
- },
-
-
- // Icons
-
- get smallIcon() {
- return this._getIcon(16);
- },
-
- _getIcon(aSize) {
- if (this.primaryExtension)
- return "moz-icon://goat." + this.primaryExtension + "?size=" + aSize;
-
- if (this.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo)
- return "moz-icon://goat?size=" + aSize + "&contentType=" + this.type;
-
- // FIXME: consider returning some generic icon when we can't get a URL for
- // one (for example in the case of protocol schemes). Filed as bug 395141.
- return null;
- }
-
-};
-
-
-// Feed Handler Info
-
-/**
- * This object implements nsIHandlerInfo for the feed types. It's a separate
- * object because we currently store handling information for the feed type
- * in a set of preferences rather than the nsIHandlerService-managed datastore.
- *
- * This object inherits from HandlerInfoWrapper in order to get functionality
- * that isn't special to the feed type.
- *
- * XXX Should we inherit from HandlerInfoWrapper? After all, we override
- * most of that wrapper's properties and methods, and we have to dance around
- * the fact that the wrapper expects to have a wrappedHandlerInfo, which we
- * don't provide.
- */
-
-function FeedHandlerInfo(aMIMEType) {
- HandlerInfoWrapper.call(this, aMIMEType, null);
-}
-
-FeedHandlerInfo.prototype = {
- __proto__: HandlerInfoWrapper.prototype,
-
- // Convenience Utils
-
- _converterSvc:
- Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
- getService(Ci.nsIWebContentConverterService),
-
- _shellSvc: AppConstants.HAVE_SHELL_SERVICE ? getShellService() : null,
-
- // nsIHandlerInfo
-
- get description() {
- return this.element("bundlePreferences").getString(this._appPrefLabel);
- },
-
- get preferredApplicationHandler() {
- switch (this.element(this._prefSelectedReader).value) {
- case "client":
- var file = this.element(this._prefSelectedApp).value;
- if (file)
- return getLocalHandlerApp(file);
-
- return null;
-
- case "web":
- var uri = this.element(this._prefSelectedWeb).value;
- if (!uri)
- return null;
- return this._converterSvc.getWebContentHandlerByURI(this.type, uri);
-
- case "bookmarks":
- default:
- // When the pref is set to bookmarks, we handle feeds internally,
- // we don't forward them to a local or web handler app, so there is
- // no preferred handler.
- return null;
- }
- },
-
- set preferredApplicationHandler(aNewValue) {
- if (aNewValue instanceof Ci.nsILocalHandlerApp) {
- this.element(this._prefSelectedApp).value = aNewValue.executable;
- this.element(this._prefSelectedReader).value = "client";
- } else if (aNewValue instanceof Ci.nsIWebContentHandlerInfo) {
- this.element(this._prefSelectedWeb).value = aNewValue.uri;
- this.element(this._prefSelectedReader).value = "web";
- // Make the web handler be the new "auto handler" for feeds.
- // Note: we don't have to unregister the auto handler when the user picks
- // a non-web handler (local app, Live Bookmarks, etc.) because the service
- // only uses the "auto handler" when the selected reader is a web handler.
- // We also don't have to unregister it when the user turns on "always ask"
- // (i.e. preview in browser), since that also overrides the auto handler.
- this._converterSvc.setAutoHandler(this.type, aNewValue);
- }
- },
-
- _possibleApplicationHandlers: null,
-
- get possibleApplicationHandlers() {
- if (this._possibleApplicationHandlers)
- return this._possibleApplicationHandlers;
-
- // A minimal implementation of nsIMutableArray. It only supports the two
- // methods its callers invoke, namely appendElement and nsIArray::enumerate.
- this._possibleApplicationHandlers = {
- _inner: [],
- _removed: [],
-
- QueryInterface(aIID) {
- if (aIID.equals(Ci.nsIMutableArray) ||
- aIID.equals(Ci.nsIArray) ||
- aIID.equals(Ci.nsISupports))
- return this;
-
- throw Cr.NS_ERROR_NO_INTERFACE;
- },
-
- get length() {
- return this._inner.length;
- },
-
- enumerate() {
- return new ArrayEnumerator(this._inner);
- },
-
- appendElement(aHandlerApp, aWeak) {
- this._inner.push(aHandlerApp);
- },
-
- removeElementAt(aIndex) {
- this._removed.push(this._inner[aIndex]);
- this._inner.splice(aIndex, 1);
- },
-
- queryElementAt(aIndex, aInterface) {
- return this._inner[aIndex].QueryInterface(aInterface);
- }
- };
-
- // Add the selected local app if it's different from the OS default handler.
- // Unlike for other types, we can store only one local app at a time for the
- // feed type, since we store it in a preference that historically stores
- // only a single path. But we display all the local apps the user chooses
- // while the prefpane is open, only dropping the list when the user closes
- // the prefpane, for maximum usability and consistency with other types.
- var preferredAppFile = this.element(this._prefSelectedApp).value;
- if (preferredAppFile) {
- let preferredApp = getLocalHandlerApp(preferredAppFile);
- let defaultApp = this._defaultApplicationHandler;
- if (!defaultApp || !defaultApp.equals(preferredApp))
- this._possibleApplicationHandlers.appendElement(preferredApp);
- }
-
- // Add the registered web handlers. There can be any number of these.
- var webHandlers = this._converterSvc.getContentHandlers(this.type);
- for (let webHandler of webHandlers)
- this._possibleApplicationHandlers.appendElement(webHandler);
-
- return this._possibleApplicationHandlers;
- },
-
- __defaultApplicationHandler: undefined,
- get _defaultApplicationHandler() {
- if (typeof this.__defaultApplicationHandler != "undefined")
- return this.__defaultApplicationHandler;
-
- var defaultFeedReader = null;
- if (AppConstants.HAVE_SHELL_SERVICE) {
- try {
- defaultFeedReader = this._shellSvc.defaultFeedReader;
- } catch (ex) {
- // no default reader or _shellSvc is null
- }
- }
-
- if (defaultFeedReader) {
- let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
- createInstance(Ci.nsIHandlerApp);
- handlerApp.name = getFileDisplayName(defaultFeedReader);
- handlerApp.QueryInterface(Ci.nsILocalHandlerApp);
- handlerApp.executable = defaultFeedReader;
-
- this.__defaultApplicationHandler = handlerApp;
- } else {
- this.__defaultApplicationHandler = null;
- }
-
- return this.__defaultApplicationHandler;
- },
-
- get hasDefaultHandler() {
- if (AppConstants.HAVE_SHELL_SERVICE) {
- try {
- if (this._shellSvc.defaultFeedReader)
- return true;
- } catch (ex) {
- // no default reader or _shellSvc is null
- }
- }
-
- return false;
- },
-
- get defaultDescription() {
- if (this.hasDefaultHandler)
- return this._defaultApplicationHandler.name;
-
- // Should we instead return null?
- return "";
- },
-
- // What to do with content of this type.
- get preferredAction() {
- switch (this.element(this._prefSelectedAction).value) {
-
- case "bookmarks":
- return Ci.nsIHandlerInfo.handleInternally;
-
- case "reader": {
- let preferredApp = this.preferredApplicationHandler;
- let defaultApp = this._defaultApplicationHandler;
-
- // If we have a valid preferred app, return useSystemDefault if it's
- // the default app; otherwise return useHelperApp.
- if (gApplicationsPane.isValidHandlerApp(preferredApp)) {
- if (defaultApp && defaultApp.equals(preferredApp))
- return Ci.nsIHandlerInfo.useSystemDefault;
-
- return Ci.nsIHandlerInfo.useHelperApp;
- }
-
- // The pref is set to "reader", but we don't have a valid preferred app.
- // What do we do now? Not sure this is the best option (perhaps we
- // should direct the user to the default app, if any), but for now let's
- // direct the user to live bookmarks.
- return Ci.nsIHandlerInfo.handleInternally;
- }
-
- // If the action is "ask", then alwaysAskBeforeHandling will override
- // the action, so it doesn't matter what we say it is, it just has to be
- // something that doesn't cause the controller to hide the type.
- case "ask":
- default:
- return Ci.nsIHandlerInfo.handleInternally;
- }
- },
-
- set preferredAction(aNewValue) {
- switch (aNewValue) {
-
- case Ci.nsIHandlerInfo.handleInternally:
- this.element(this._prefSelectedReader).value = "bookmarks";
- break;
-
- case Ci.nsIHandlerInfo.useHelperApp:
- this.element(this._prefSelectedAction).value = "reader";
- // The controller has already set preferredApplicationHandler
- // to the new helper app.
- break;
-
- case Ci.nsIHandlerInfo.useSystemDefault:
- this.element(this._prefSelectedAction).value = "reader";
- this.preferredApplicationHandler = this._defaultApplicationHandler;
- break;
- }
- },
-
- get alwaysAskBeforeHandling() {
- return this.element(this._prefSelectedAction).value == "ask";
- },
-
- set alwaysAskBeforeHandling(aNewValue) {
- if (aNewValue == true)
- this.element(this._prefSelectedAction).value = "ask";
- else
- this.element(this._prefSelectedAction).value = "reader";
- },
-
- // Whether or not we are currently storing the action selected by the user.
- // We use this to suppress notification-triggered updates to the list when
- // we make changes that may spawn such updates, specifically when we change
- // the action for the feed type, which results in feed preference updates,
- // which spawn "pref changed" notifications that would otherwise cause us
- // to rebuild the view unnecessarily.
- _storingAction: false,
-
-
- // nsIMIMEInfo
-
- get primaryExtension() {
- return "xml";
- },
-
-
- // Storage
-
- // Changes to the preferred action and handler take effect immediately
- // (we write them out to the preferences right as they happen),
- // so we when the controller calls store() after modifying the handlers,
- // the only thing we need to store is the removal of possible handlers
- // XXX Should we hold off on making the changes until this method gets called?
- store() {
- for (let app of this._possibleApplicationHandlers._removed) {
- if (app instanceof Ci.nsILocalHandlerApp) {
- let pref = this.element(PREF_FEED_SELECTED_APP);
- var preferredAppFile = pref.value;
- if (preferredAppFile) {
- let preferredApp = getLocalHandlerApp(preferredAppFile);
- if (app.equals(preferredApp))
- pref.reset();
- }
- } else {
- app.QueryInterface(Ci.nsIWebContentHandlerInfo);
- this._converterSvc.removeContentHandler(app.contentType, app.uri);
- }
- }
- this._possibleApplicationHandlers._removed = [];
- },
-
-
- // Icons
-
- get smallIcon() {
- return this._smallIcon;
- }
-
-};
-
-var feedHandlerInfo = {
- __proto__: new FeedHandlerInfo(TYPE_MAYBE_FEED),
- _prefSelectedApp: PREF_FEED_SELECTED_APP,
- _prefSelectedWeb: PREF_FEED_SELECTED_WEB,
- _prefSelectedAction: PREF_FEED_SELECTED_ACTION,
- _prefSelectedReader: PREF_FEED_SELECTED_READER,
- _smallIcon: "chrome://browser/skin/feeds/feedIcon16.png",
- _appPrefLabel: "webFeed"
-}
-
-var videoFeedHandlerInfo = {
- __proto__: new FeedHandlerInfo(TYPE_MAYBE_VIDEO_FEED),
- _prefSelectedApp: PREF_VIDEO_FEED_SELECTED_APP,
- _prefSelectedWeb: PREF_VIDEO_FEED_SELECTED_WEB,
- _prefSelectedAction: PREF_VIDEO_FEED_SELECTED_ACTION,
- _prefSelectedReader: PREF_VIDEO_FEED_SELECTED_READER,
- _smallIcon: "chrome://browser/skin/feeds/videoFeedIcon16.png",
- _appPrefLabel: "videoPodcastFeed"
-}
-
-var audioFeedHandlerInfo = {
- __proto__: new FeedHandlerInfo(TYPE_MAYBE_AUDIO_FEED),
- _prefSelectedApp: PREF_AUDIO_FEED_SELECTED_APP,
- _prefSelectedWeb: PREF_AUDIO_FEED_SELECTED_WEB,
- _prefSelectedAction: PREF_AUDIO_FEED_SELECTED_ACTION,
- _prefSelectedReader: PREF_AUDIO_FEED_SELECTED_READER,
- _smallIcon: "chrome://browser/skin/feeds/audioFeedIcon16.png",
- _appPrefLabel: "audioPodcastFeed"
-}
-
-/**
- * InternalHandlerInfoWrapper provides a basic mechanism to create an internal
- * mime type handler that can be enabled/disabled in the applications preference
- * menu.
- */
-function InternalHandlerInfoWrapper(aMIMEType) {
- var mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
- var handlerInfo = mimeSvc.getFromTypeAndExtension(aMIMEType, null);
-
- HandlerInfoWrapper.call(this, aMIMEType, handlerInfo);
-}
-
-InternalHandlerInfoWrapper.prototype = {
- __proto__: HandlerInfoWrapper.prototype,
-
- // Override store so we so we can notify any code listening for registration
- // or unregistration of this handler.
- store() {
- HandlerInfoWrapper.prototype.store.call(this);
- Services.obs.notifyObservers(null, this._handlerChanged);
- },
-
- get enabled() {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- get description() {
- return this.element("bundlePreferences").getString(this._appPrefLabel);
- }
-};
-
-var pdfHandlerInfo = {
- __proto__: new InternalHandlerInfoWrapper(TYPE_PDF),
- _handlerChanged: TOPIC_PDFJS_HANDLER_CHANGED,
- _appPrefLabel: "portableDocumentFormat",
- get enabled() {
- return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED);
- },
-};
-
-
-// Prefpane Controller
-
-var gApplicationsPane = {
- // The set of types the app knows how to handle. A hash of HandlerInfoWrapper
- // objects, indexed by type.
- _handledTypes: {},
-
- // The list of types we can show, sorted by the sort column/direction.
- // An array of HandlerInfoWrapper objects. We build this list when we first
- // load the data and then rebuild it when users change a pref that affects
- // what types we can show or change the sort column/direction.
- // Note: this isn't necessarily the list of types we *will* show; if the user
- // provides a filter string, we'll only show the subset of types in this list
- // that match that string.
- _visibleTypes: [],
-
- // A count of the number of times each visible type description appears.
- // We use these counts to determine whether or not to annotate descriptions
- // with their types to distinguish duplicate descriptions from each other.
- // A hash of integer counts, indexed by string description.
- _visibleTypeDescriptionCount: {},
-
-
- // Convenience & Performance Shortcuts
-
- // These get defined by init().
- _brandShortName: null,
- _prefsBundle: null,
- _list: null,
- _filter: null,
-
- _prefSvc: Cc["@mozilla.org/preferences-service;1"].
- getService(Ci.nsIPrefBranch),
-
- _mimeSvc: Cc["@mozilla.org/mime;1"].
- getService(Ci.nsIMIMEService),
-
- _helperAppSvc: Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
- getService(Ci.nsIExternalHelperAppService),
-
- _handlerSvc: Cc["@mozilla.org/uriloader/handler-service;1"].
- getService(Ci.nsIHandlerService),
-
- _ioSvc: Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService),
-
-
- // Initialization & Destruction
-
- init() {
- function setEventListener(aId, aEventType, aCallback) {
- document.getElementById(aId)
- .addEventListener(aEventType, aCallback.bind(gApplicationsPane));
- }
-
- // Initialize shortcuts to some commonly accessed elements & values.
- this._brandShortName =
- document.getElementById("bundleBrand").getString("brandShortName");
- this._prefsBundle = document.getElementById("bundlePreferences");
- this._list = document.getElementById("handlersView");
- this._filter = document.getElementById("filter");
-
- // Observe preferences that influence what we display so we can rebuild
- // the view when they change.
- this._prefSvc.addObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
- this._prefSvc.addObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
- this._prefSvc.addObserver(PREF_FEED_SELECTED_APP, this);
- this._prefSvc.addObserver(PREF_FEED_SELECTED_WEB, this);
- this._prefSvc.addObserver(PREF_FEED_SELECTED_ACTION, this);
- this._prefSvc.addObserver(PREF_FEED_SELECTED_READER, this);
-
- this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
- this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_WEB, this);
- this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
- this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
-
- this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
- this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
- this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
- this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
-
-
- setEventListener("focusSearch1", "command", gApplicationsPane.focusFilterBox);
- setEventListener("focusSearch2", "command", gApplicationsPane.focusFilterBox);
- setEventListener("filter", "command", gApplicationsPane.filter);
- setEventListener("handlersView", "select",
- gApplicationsPane.onSelectionChanged);
- setEventListener("typeColumn", "click", gApplicationsPane.sort);
- setEventListener("actionColumn", "click", gApplicationsPane.sort);
- setEventListener("chooseFolder", "command", gApplicationsPane.chooseFolder);
- setEventListener("browser.download.dir", "change", gApplicationsPane.displayDownloadDirPref);
-
- // Listen for window unload so we can remove our preference observers.
- window.addEventListener("unload", this);
-
- // Figure out how we should be sorting the list. We persist sort settings
- // across sessions, so we can't assume the default sort column/direction.
- // XXX should we be using the XUL sort service instead?
- if (document.getElementById("actionColumn").hasAttribute("sortDirection")) {
- this._sortColumn = document.getElementById("actionColumn");
- // The typeColumn element always has a sortDirection attribute,
- // either because it was persisted or because the default value
- // from the xul file was used. If we are sorting on the other
- // column, we should remove it.
- document.getElementById("typeColumn").removeAttribute("sortDirection");
- } else
- this._sortColumn = document.getElementById("typeColumn");
-
- // Load the data and build the list of handlers.
- // By doing this in a timeout, we let the preferences dialog resize itself
- // to an appropriate size before we add a bunch of items to the list.
- // Otherwise, if there are many items, and the Applications prefpane
- // is the one that gets displayed when the user first opens the dialog,
- // the dialog might stretch too much in an attempt to fit them all in.
- // XXX Shouldn't we perhaps just set a max-height on the richlistbox?
- var _delayedPaneLoad = function(self) {
- self._loadData();
- self._rebuildVisibleTypes();
- self._sortVisibleTypes();
- self._rebuildView();
-
- // Notify observers that the UI is now ready
- Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).
- notifyObservers(window, "app-handler-pane-loaded");
- }
- setTimeout(_delayedPaneLoad, 0, this);
- },
-
- destroy() {
- window.removeEventListener("unload", this);
- this._prefSvc.removeObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
- this._prefSvc.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
- this._prefSvc.removeObserver(PREF_FEED_SELECTED_APP, this);
- this._prefSvc.removeObserver(PREF_FEED_SELECTED_WEB, this);
- this._prefSvc.removeObserver(PREF_FEED_SELECTED_ACTION, this);
- this._prefSvc.removeObserver(PREF_FEED_SELECTED_READER, this);
-
- this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
- this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_WEB, this);
- this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
- this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
-
- this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
- this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
- this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
- this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
- },
-
-
- // nsISupports
-
- QueryInterface(aIID) {
- if (aIID.equals(Ci.nsIObserver) ||
- aIID.equals(Ci.nsIDOMEventListener ||
- aIID.equals(Ci.nsISupports)))
- return this;
-
- throw Cr.NS_ERROR_NO_INTERFACE;
- },
-
-
- // nsIObserver
-
- observe(aSubject, aTopic, aData) {
- // Rebuild the list when there are changes to preferences that influence
- // whether or not to show certain entries in the list.
- if (aTopic == "nsPref:changed" && !this._storingAction) {
- // These two prefs alter the list of visible types, so we have to rebuild
- // that list when they change.
- if (aData == PREF_SHOW_PLUGINS_IN_LIST ||
- aData == PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS) {
- this._rebuildVisibleTypes();
- this._sortVisibleTypes();
- }
-
- // All the prefs we observe can affect what we display, so we rebuild
- // the view when any of them changes.
- this._rebuildView();
- }
- },
-
-
- // nsIDOMEventListener
-
- handleEvent(aEvent) {
- if (aEvent.type == "unload") {
- this.destroy();
- }
- },
-
-
- // Composed Model Construction
-
- _loadData() {
- this._loadFeedHandler();
- this._loadInternalHandlers();
- this._loadPluginHandlers();
- this._loadApplicationHandlers();
- },
-
- _loadFeedHandler() {
- this._handledTypes[TYPE_MAYBE_FEED] = feedHandlerInfo;
- feedHandlerInfo.handledOnlyByPlugin = false;
-
- this._handledTypes[TYPE_MAYBE_VIDEO_FEED] = videoFeedHandlerInfo;
- videoFeedHandlerInfo.handledOnlyByPlugin = false;
-
- this._handledTypes[TYPE_MAYBE_AUDIO_FEED] = audioFeedHandlerInfo;
- audioFeedHandlerInfo.handledOnlyByPlugin = false;
- },
-
- /**
- * Load higher level internal handlers so they can be turned on/off in the
- * applications menu.
- */
- _loadInternalHandlers() {
- var internalHandlers = [pdfHandlerInfo];
- for (let internalHandler of internalHandlers) {
- if (internalHandler.enabled) {
- this._handledTypes[internalHandler.type] = internalHandler;
- }
- }
- },
-
- /**
- * Load the set of handlers defined by plugins.
- *
- * Note: if there's more than one plugin for a given MIME type, we assume
- * the last one is the one that the application will use. That may not be
- * correct, but it's how we've been doing it for years.
- *
- * Perhaps we should instead query navigator.mimeTypes for the set of types
- * supported by the application and then get the plugin from each MIME type's
- * enabledPlugin property. But if there's a plugin for a type, we need
- * to know about it even if it isn't enabled, since we're going to give
- * the user an option to enable it.
- *
- * Also note that enabledPlugin does not get updated when
- * plugin.disable_full_page_plugin_for_types changes, so even if we could use
- * enabledPlugin to get the plugin that would be used, we'd still need to
- * check the pref ourselves to find out if it's enabled.
- */
- _loadPluginHandlers() {
- "use strict";
-
- let mimeTypes = navigator.mimeTypes;
-
- for (let mimeType of mimeTypes) {
- let handlerInfoWrapper;
- if (mimeType.type in this._handledTypes) {
- handlerInfoWrapper = this._handledTypes[mimeType.type];
- } else {
- let wrappedHandlerInfo =
- this._mimeSvc.getFromTypeAndExtension(mimeType.type, null);
- handlerInfoWrapper = new HandlerInfoWrapper(mimeType.type, wrappedHandlerInfo);
- handlerInfoWrapper.handledOnlyByPlugin = true;
- this._handledTypes[mimeType.type] = handlerInfoWrapper;
- }
- handlerInfoWrapper.pluginName = mimeType.enabledPlugin.name;
- }
- },
-
- /**
- * Load the set of handlers defined by the application datastore.
- */
- _loadApplicationHandlers() {
- var wrappedHandlerInfos = this._handlerSvc.enumerate();
- while (wrappedHandlerInfos.hasMoreElements()) {
- let wrappedHandlerInfo =
- wrappedHandlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
- let type = wrappedHandlerInfo.type;
-
- let handlerInfoWrapper;
- if (type in this._handledTypes)
- handlerInfoWrapper = this._handledTypes[type];
- else {
- handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
- this._handledTypes[type] = handlerInfoWrapper;
- }
-
- handlerInfoWrapper.handledOnlyByPlugin = false;
- }
- },
-
-
- // View Construction
-
- _rebuildVisibleTypes() {
- // Reset the list of visible types and the visible type description counts.
- this._visibleTypes = [];
- this._visibleTypeDescriptionCount = {};
-
- // Get the preferences that help determine what types to show.
- var showPlugins = this._prefSvc.getBoolPref(PREF_SHOW_PLUGINS_IN_LIST);
- var hidePluginsWithoutExtensions =
- this._prefSvc.getBoolPref(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS);
-
- for (let type in this._handledTypes) {
- let handlerInfo = this._handledTypes[type];
-
- // Hide plugins without associated extensions if so prefed so we don't
- // show a whole bunch of obscure types handled by plugins on Mac.
- // Note: though protocol types don't have extensions, we still show them;
- // the pref is only meant to be applied to MIME types, since plugins are
- // only associated with MIME types.
- // FIXME: should we also check the "suffixes" property of the plugin?
- // Filed as bug 395135.
- if (hidePluginsWithoutExtensions && handlerInfo.handledOnlyByPlugin &&
- handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
- !handlerInfo.primaryExtension)
- continue;
-
- // Hide types handled only by plugins if so prefed.
- if (handlerInfo.handledOnlyByPlugin && !showPlugins)
- continue;
-
- // We couldn't find any reason to exclude the type, so include it.
- this._visibleTypes.push(handlerInfo);
-
- if (handlerInfo.description in this._visibleTypeDescriptionCount)
- this._visibleTypeDescriptionCount[handlerInfo.description]++;
- else
- this._visibleTypeDescriptionCount[handlerInfo.description] = 1;
- }
- },
-
- _rebuildView() {
- // Clear the list of entries.
- while (this._list.childNodes.length > 1)
- this._list.removeChild(this._list.lastChild);
-
- var visibleTypes = this._visibleTypes;
-
- // If the user is filtering the list, then only show matching types.
- if (this._filter.value)
- visibleTypes = visibleTypes.filter(this._matchesFilter, this);
-
- for (let visibleType of visibleTypes) {
- let item = document.createElement("richlistitem");
- item.setAttribute("type", visibleType.type);
- item.setAttribute("typeDescription", this._describeType(visibleType));
- if (visibleType.smallIcon)
- item.setAttribute("typeIcon", visibleType.smallIcon);
- item.setAttribute("actionDescription",
- this._describePreferredAction(visibleType));
-
- if (!this._setIconClassForPreferredAction(visibleType, item)) {
- item.setAttribute("actionIcon",
- this._getIconURLForPreferredAction(visibleType));
- }
-
- this._list.appendChild(item);
- }
-
- this._selectLastSelectedType();
- },
-
- _matchesFilter(aType) {
- var filterValue = this._filter.value.toLowerCase();
- return this._describeType(aType).toLowerCase().indexOf(filterValue) != -1 ||
- this._describePreferredAction(aType).toLowerCase().indexOf(filterValue) != -1;
- },
-
- /**
- * Describe, in a human-readable fashion, the type represented by the given
- * handler info object. Normally this is just the description provided by
- * the info object, but if more than one object presents the same description,
- * then we annotate the duplicate descriptions with the type itself to help
- * users distinguish between those types.
- *
- * @param aHandlerInfo {nsIHandlerInfo} the type being described
- * @returns {string} a description of the type
- */
- _describeType(aHandlerInfo) {
- if (this._visibleTypeDescriptionCount[aHandlerInfo.description] > 1)
- return this._prefsBundle.getFormattedString("typeDescriptionWithType",
- [aHandlerInfo.description,
- aHandlerInfo.type]);
-
- return aHandlerInfo.description;
- },
-
- /**
- * Describe, in a human-readable fashion, the preferred action to take on
- * the type represented by the given handler info object.
- *
- * XXX Should this be part of the HandlerInfoWrapper interface? It would
- * violate the separation of model and view, but it might make more sense
- * nonetheless (f.e. it would make sortTypes easier).
- *
- * @param aHandlerInfo {nsIHandlerInfo} the type whose preferred action
- * is being described
- * @returns {string} a description of the action
- */
- _describePreferredAction(aHandlerInfo) {
- // alwaysAskBeforeHandling overrides the preferred action, so if that flag
- // is set, then describe that behavior instead. For most types, this is
- // the "alwaysAsk" string, but for the feed type we show something special.
- if (aHandlerInfo.alwaysAskBeforeHandling) {
- if (isFeedType(aHandlerInfo.type))
- return this._prefsBundle.getFormattedString("previewInApp",
- [this._brandShortName]);
- return this._prefsBundle.getString("alwaysAsk");
- }
-
- switch (aHandlerInfo.preferredAction) {
- case Ci.nsIHandlerInfo.saveToDisk:
- return this._prefsBundle.getString("saveFile");
-
- case Ci.nsIHandlerInfo.useHelperApp:
- var preferredApp = aHandlerInfo.preferredApplicationHandler;
- var name;
- if (preferredApp instanceof Ci.nsILocalHandlerApp)
- name = getFileDisplayName(preferredApp.executable);
- else
- name = preferredApp.name;
- return this._prefsBundle.getFormattedString("useApp", [name]);
-
- case Ci.nsIHandlerInfo.handleInternally:
- // For the feed type, handleInternally means live bookmarks.
- if (isFeedType(aHandlerInfo.type)) {
- return this._prefsBundle.getFormattedString("addLiveBookmarksInApp",
- [this._brandShortName]);
- }
-
- if (aHandlerInfo instanceof InternalHandlerInfoWrapper) {
- return this._prefsBundle.getFormattedString("previewInApp",
- [this._brandShortName]);
- }
-
- // For other types, handleInternally looks like either useHelperApp
- // or useSystemDefault depending on whether or not there's a preferred
- // handler app.
- if (this.isValidHandlerApp(aHandlerInfo.preferredApplicationHandler))
- return aHandlerInfo.preferredApplicationHandler.name;
-
- return aHandlerInfo.defaultDescription;
-
- // XXX Why don't we say the app will handle the type internally?
- // Is it because the app can't actually do that? But if that's true,
- // then why would a preferredAction ever get set to this value
- // in the first place?
-
- case Ci.nsIHandlerInfo.useSystemDefault:
- return this._prefsBundle.getFormattedString("useDefault",
- [aHandlerInfo.defaultDescription]);
-
- case kActionUsePlugin:
- return this._prefsBundle.getFormattedString("usePluginIn",
- [aHandlerInfo.pluginName,
- this._brandShortName]);
- default:
- throw new Error(`Unexpected preferredAction: ${aHandlerInfo.preferredAction}`);
- }
- },
-
- _selectLastSelectedType() {
- // If the list is disabled by the pref.downloads.disable_button.edit_actions
- // preference being locked, then don't select the type, as that would cause
- // it to appear selected, with a different background and an actions menu
- // that makes it seem like you can choose an action for the type.
- if (this._list.disabled)
- return;
-
- var lastSelectedType = this._list.getAttribute("lastSelectedType");
- if (!lastSelectedType)
- return;
-
- var item = this._list.getElementsByAttribute("type", lastSelectedType)[0];
- if (!item)
- return;
-
- this._list.selectedItem = item;
- },
-
- /**
- * Whether or not the given handler app is valid.
- *
- * @param aHandlerApp {nsIHandlerApp} the handler app in question
- *
- * @returns {boolean} whether or not it's valid
- */
- isValidHandlerApp(aHandlerApp) {
- if (!aHandlerApp)
- return false;
-
- if (aHandlerApp instanceof Ci.nsILocalHandlerApp)
- return this._isValidHandlerExecutable(aHandlerApp.executable);
-
- if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
- return aHandlerApp.uriTemplate;
-
- if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
- return aHandlerApp.uri;
-
- return false;
- },
-
- _isValidHandlerExecutable(aExecutable) {
- let leafName;
- if (AppConstants.platform == "win") {
- leafName = `${AppConstants.MOZ_APP_NAME}.exe`;
- } else if (AppConstants.platform == "macosx") {
- leafName = AppConstants.MOZ_MACBUNDLE_NAME;
- } else {
- leafName = `${AppConstants.MOZ_APP_NAME}-bin`;
- }
- return aExecutable &&
- aExecutable.exists() &&
- aExecutable.isExecutable() &&
-// XXXben - we need to compare this with the running instance executable
-// just don't know how to do that via script...
-// XXXmano TBD: can probably add this to nsIShellService
- aExecutable.leafName != leafName;
- },
-
- /**
- * Rebuild the actions menu for the selected entry. Gets called by
- * the richlistitem constructor when an entry in the list gets selected.
- */
- rebuildActionsMenu() {
- var typeItem = this._list.selectedItem;
- var handlerInfo = this._handledTypes[typeItem.type];
- var menu =
- document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
- var menuPopup = menu.menupopup;
-
- // Clear out existing items.
- while (menuPopup.hasChildNodes())
- menuPopup.removeChild(menuPopup.lastChild);
-
- let internalMenuItem;
- // Add the "Preview in Firefox" option for optional internal handlers.
- if (handlerInfo instanceof InternalHandlerInfoWrapper) {
- internalMenuItem = document.createElement("menuitem");
- internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
- let label = this._prefsBundle.getFormattedString("previewInApp",
- [this._brandShortName]);
- internalMenuItem.setAttribute("label", label);
- internalMenuItem.setAttribute("tooltiptext", label);
- internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask");
- menuPopup.appendChild(internalMenuItem);
- }
-
- {
- var askMenuItem = document.createElement("menuitem");
- askMenuItem.setAttribute("action", Ci.nsIHandlerInfo.alwaysAsk);
- let label;
- if (isFeedType(handlerInfo.type))
- label = this._prefsBundle.getFormattedString("previewInApp",
- [this._brandShortName]);
- else
- label = this._prefsBundle.getString("alwaysAsk");
- askMenuItem.setAttribute("label", label);
- askMenuItem.setAttribute("tooltiptext", label);
- askMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask");
- menuPopup.appendChild(askMenuItem);
- }
-
- // Create a menu item for saving to disk.
- // Note: this option isn't available to protocol types, since we don't know
- // what it means to save a URL having a certain scheme to disk, nor is it
- // available to feeds, since the feed code doesn't implement the capability.
- if ((handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) &&
- !isFeedType(handlerInfo.type)) {
- var saveMenuItem = document.createElement("menuitem");
- saveMenuItem.setAttribute("action", Ci.nsIHandlerInfo.saveToDisk);
- let label = this._prefsBundle.getString("saveFile");
- saveMenuItem.setAttribute("label", label);
- saveMenuItem.setAttribute("tooltiptext", label);
- saveMenuItem.setAttribute(APP_ICON_ATTR_NAME, "save");
- menuPopup.appendChild(saveMenuItem);
- }
-
- // If this is the feed type, add a Live Bookmarks item.
- if (isFeedType(handlerInfo.type)) {
- internalMenuItem = document.createElement("menuitem");
- internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
- let label = this._prefsBundle.getFormattedString("addLiveBookmarksInApp",
- [this._brandShortName]);
- internalMenuItem.setAttribute("label", label);
- internalMenuItem.setAttribute("tooltiptext", label);
- internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "feed");
- menuPopup.appendChild(internalMenuItem);
- }
-
- // Add a separator to distinguish these items from the helper app items
- // that follow them.
- let menuseparator = document.createElement("menuseparator");
- menuPopup.appendChild(menuseparator);
-
- // Create a menu item for the OS default application, if any.
- if (handlerInfo.hasDefaultHandler) {
- var defaultMenuItem = document.createElement("menuitem");
- defaultMenuItem.setAttribute("action", Ci.nsIHandlerInfo.useSystemDefault);
- let label = this._prefsBundle.getFormattedString("useDefault",
- [handlerInfo.defaultDescription]);
- defaultMenuItem.setAttribute("label", label);
- defaultMenuItem.setAttribute("tooltiptext", handlerInfo.defaultDescription);
- defaultMenuItem.setAttribute("image", this._getIconURLForSystemDefault(handlerInfo));
-
- menuPopup.appendChild(defaultMenuItem);
- }
-
- // Create menu items for possible handlers.
- let preferredApp = handlerInfo.preferredApplicationHandler;
- let possibleApps = handlerInfo.possibleApplicationHandlers.enumerate();
- var possibleAppMenuItems = [];
- while (possibleApps.hasMoreElements()) {
- let possibleApp = possibleApps.getNext();
- if (!this.isValidHandlerApp(possibleApp))
- continue;
-
- let menuItem = document.createElement("menuitem");
- menuItem.setAttribute("action", Ci.nsIHandlerInfo.useHelperApp);
- let label;
- if (possibleApp instanceof Ci.nsILocalHandlerApp)
- label = getFileDisplayName(possibleApp.executable);
- else
- label = possibleApp.name;
- label = this._prefsBundle.getFormattedString("useApp", [label]);
- menuItem.setAttribute("label", label);
- menuItem.setAttribute("tooltiptext", label);
- menuItem.setAttribute("image", this._getIconURLForHandlerApp(possibleApp));
-
- // Attach the handler app object to the menu item so we can use it
- // to make changes to the datastore when the user selects the item.
- menuItem.handlerApp = possibleApp;
-
- menuPopup.appendChild(menuItem);
- possibleAppMenuItems.push(menuItem);
- }
-
- // Create a menu item for the plugin.
- if (handlerInfo.pluginName) {
- var pluginMenuItem = document.createElement("menuitem");
- pluginMenuItem.setAttribute("action", kActionUsePlugin);
- let label = this._prefsBundle.getFormattedString("usePluginIn",
- [handlerInfo.pluginName,
- this._brandShortName]);
- pluginMenuItem.setAttribute("label", label);
- pluginMenuItem.setAttribute("tooltiptext", label);
- pluginMenuItem.setAttribute(APP_ICON_ATTR_NAME, "plugin");
- menuPopup.appendChild(pluginMenuItem);
- }
-
- // Create a menu item for selecting a local application.
- let canOpenWithOtherApp = true;
- if (AppConstants.platform == "win") {
- // On Windows, selecting an application to open another application
- // would be meaningless so we special case executables.
- let executableType = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService)
- .getTypeFromExtension("exe");
- canOpenWithOtherApp = handlerInfo.type != executableType;
- }
- if (canOpenWithOtherApp) {
- let menuItem = document.createElement("menuitem");
- menuItem.className = "choose-app-item";
- menuItem.addEventListener("command", function(e) {
- gApplicationsPane.chooseApp(e);
- });
- let label = this._prefsBundle.getString("useOtherApp");
- menuItem.setAttribute("label", label);
- menuItem.setAttribute("tooltiptext", label);
- menuPopup.appendChild(menuItem);
- }
-
- // Create a menu item for managing applications.
- if (possibleAppMenuItems.length) {
- let menuItem = document.createElement("menuseparator");
- menuPopup.appendChild(menuItem);
- menuItem = document.createElement("menuitem");
- menuItem.className = "manage-app-item";
- menuItem.addEventListener("command", function(e) {
- gApplicationsPane.manageApp(e);
- });
- menuItem.setAttribute("label", this._prefsBundle.getString("manageApp"));
- menuPopup.appendChild(menuItem);
- }
-
- // Select the item corresponding to the preferred action. If the always
- // ask flag is set, it overrides the preferred action. Otherwise we pick
- // the item identified by the preferred action (when the preferred action
- // is to use a helper app, we have to pick the specific helper app item).
- if (handlerInfo.alwaysAskBeforeHandling)
- menu.selectedItem = askMenuItem;
- else switch (handlerInfo.preferredAction) {
- case Ci.nsIHandlerInfo.handleInternally:
- if (internalMenuItem) {
- menu.selectedItem = internalMenuItem;
- } else {
- Cu.reportError("No menu item defined to set!")
- }
- break;
- case Ci.nsIHandlerInfo.useSystemDefault:
- menu.selectedItem = defaultMenuItem;
- break;
- case Ci.nsIHandlerInfo.useHelperApp:
- if (preferredApp)
- menu.selectedItem =
- possibleAppMenuItems.filter(v => v.handlerApp.equals(preferredApp))[0];
- break;
- case kActionUsePlugin:
- menu.selectedItem = pluginMenuItem;
- break;
- case Ci.nsIHandlerInfo.saveToDisk:
- menu.selectedItem = saveMenuItem;
- break;
- }
- },
-
-
- // Sorting & Filtering
-
- _sortColumn: null,
-
- /**
- * Sort the list when the user clicks on a column header.
- */
- sort(event) {
- var column = event.target;
-
- // If the user clicked on a new sort column, remove the direction indicator
- // from the old column.
- if (this._sortColumn && this._sortColumn != column)
- this._sortColumn.removeAttribute("sortDirection");
-
- this._sortColumn = column;
-
- // Set (or switch) the sort direction indicator.
- if (column.getAttribute("sortDirection") == "ascending")
- column.setAttribute("sortDirection", "descending");
- else
- column.setAttribute("sortDirection", "ascending");
-
- this._sortVisibleTypes();
- this._rebuildView();
- },
-
- /**
- * Sort the list of visible types by the current sort column/direction.
- */
- _sortVisibleTypes() {
- if (!this._sortColumn)
- return;
-
- var t = this;
-
- function sortByType(a, b) {
- return t._describeType(a).toLowerCase().
- localeCompare(t._describeType(b).toLowerCase());
- }
-
- function sortByAction(a, b) {
- return t._describePreferredAction(a).toLowerCase().
- localeCompare(t._describePreferredAction(b).toLowerCase());
- }
-
- switch (this._sortColumn.getAttribute("value")) {
- case "type":
- this._visibleTypes.sort(sortByType);
- break;
- case "action":
- this._visibleTypes.sort(sortByAction);
- break;
- }
-
- if (this._sortColumn.getAttribute("sortDirection") == "descending")
- this._visibleTypes.reverse();
- },
-
- /**
- * Filter the list when the user enters a filter term into the filter field.
- */
- filter() {
- this._rebuildView();
- },
-
- focusFilterBox() {
- this._filter.focus();
- this._filter.select();
- },
-
-
- // Changes
-
- onSelectAction(aActionItem) {
- this._storingAction = true;
-
- try {
- this._storeAction(aActionItem);
- } finally {
- this._storingAction = false;
- }
- },
-
- _storeAction(aActionItem) {
- var typeItem = this._list.selectedItem;
- var handlerInfo = this._handledTypes[typeItem.type];
-
- let action = parseInt(aActionItem.getAttribute("action"));
-
- // Set the plugin state if we're enabling or disabling a plugin.
- if (action == kActionUsePlugin)
- handlerInfo.enablePluginType();
- else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
- handlerInfo.disablePluginType();
-
- // Set the preferred application handler.
- // We leave the existing preferred app in the list when we set
- // the preferred action to something other than useHelperApp so that
- // legacy datastores that don't have the preferred app in the list
- // of possible apps still include the preferred app in the list of apps
- // the user can choose to handle the type.
- if (action == Ci.nsIHandlerInfo.useHelperApp)
- handlerInfo.preferredApplicationHandler = aActionItem.handlerApp;
-
- // Set the "always ask" flag.
- if (action == Ci.nsIHandlerInfo.alwaysAsk)
- handlerInfo.alwaysAskBeforeHandling = true;
- else
- handlerInfo.alwaysAskBeforeHandling = false;
-
- // Set the preferred action.
- handlerInfo.preferredAction = action;
-
- handlerInfo.store();
-
- // Make sure the handler info object is flagged to indicate that there is
- // now some user configuration for the type.
- handlerInfo.handledOnlyByPlugin = false;
-
- // Update the action label and image to reflect the new preferred action.
- typeItem.setAttribute("actionDescription",
- this._describePreferredAction(handlerInfo));
- if (!this._setIconClassForPreferredAction(handlerInfo, typeItem)) {
- typeItem.setAttribute("actionIcon",
- this._getIconURLForPreferredAction(handlerInfo));
- }
- },
-
- manageApp(aEvent) {
- // Don't let the normal "on select action" handler get this event,
- // as we handle it specially ourselves.
- aEvent.stopPropagation();
-
- var typeItem = this._list.selectedItem;
- var handlerInfo = this._handledTypes[typeItem.type];
-
- let onComplete = () => {
- // Rebuild the actions menu so that we revert to the previous selection,
- // or "Always ask" if the previous default application has been removed
- this.rebuildActionsMenu();
-
- // update the richlistitem too. Will be visible when selecting another row
- typeItem.setAttribute("actionDescription",
- this._describePreferredAction(handlerInfo));
- if (!this._setIconClassForPreferredAction(handlerInfo, typeItem)) {
- typeItem.setAttribute("actionIcon",
- this._getIconURLForPreferredAction(handlerInfo));
- }
- };
-
- gSubDialog.open("chrome://browser/content/preferences/applicationManager.xul",
- "resizable=no", handlerInfo, onComplete);
-
- },
-
- chooseApp(aEvent) {
- // Don't let the normal "on select action" handler get this event,
- // as we handle it specially ourselves.
- aEvent.stopPropagation();
-
- var handlerApp;
- let chooseAppCallback = aHandlerApp => {
- // Rebuild the actions menu whether the user picked an app or canceled.
- // If they picked an app, we want to add the app to the menu and select it.
- // If they canceled, we want to go back to their previous selection.
- this.rebuildActionsMenu();
-
- // If the user picked a new app from the menu, select it.
- if (aHandlerApp) {
- let typeItem = this._list.selectedItem;
- let actionsMenu =
- document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
- let menuItems = actionsMenu.menupopup.childNodes;
- for (let i = 0; i < menuItems.length; i++) {
- let menuItem = menuItems[i];
- if (menuItem.handlerApp && menuItem.handlerApp.equals(aHandlerApp)) {
- actionsMenu.selectedIndex = i;
- this.onSelectAction(menuItem);
- break;
- }
- }
- }
- };
-
- if (AppConstants.platform == "win") {
- var params = {};
- var handlerInfo = this._handledTypes[this._list.selectedItem.type];
-
- if (isFeedType(handlerInfo.type)) {
- // MIME info will be null, create a temp object.
- params.mimeInfo = this._mimeSvc.getFromTypeAndExtension(handlerInfo.type,
- handlerInfo.primaryExtension);
- } else {
- params.mimeInfo = handlerInfo.wrappedHandlerInfo;
- }
-
- params.title = this._prefsBundle.getString("fpTitleChooseApp");
- params.description = handlerInfo.description;
- params.filename = null;
- params.handlerApp = null;
-
- let onAppSelected = () => {
- if (this.isValidHandlerApp(params.handlerApp)) {
- handlerApp = params.handlerApp;
-
- // Add the app to the type's list of possible handlers.
- handlerInfo.addPossibleApplicationHandler(handlerApp);
- }
-
- chooseAppCallback(handlerApp);
- };
-
- gSubDialog.open("chrome://global/content/appPicker.xul",
- null, params, onAppSelected);
- } else {
- let winTitle = this._prefsBundle.getString("fpTitleChooseApp");
- let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
- let fpCallback = aResult => {
- if (aResult == Ci.nsIFilePicker.returnOK && fp.file &&
- this._isValidHandlerExecutable(fp.file)) {
- handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
- createInstance(Ci.nsILocalHandlerApp);
- handlerApp.name = getFileDisplayName(fp.file);
- handlerApp.executable = fp.file;
-
- // Add the app to the type's list of possible handlers.
- let handler = this._handledTypes[this._list.selectedItem.type];
- handler.addPossibleApplicationHandler(handlerApp);
-
- chooseAppCallback(handlerApp);
- }
- };
-
- // 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.appendFilters(Ci.nsIFilePicker.filterApps);
- fp.open(fpCallback);
- }
- },
-
- // Mark which item in the list was last selected so we can reselect it
- // when we rebuild the list or when the user returns to the prefpane.
- onSelectionChanged() {
- if (this._list.selectedItem)
- this._list.setAttribute("lastSelectedType",
- this._list.selectedItem.getAttribute("type"));
- },
-
- _setIconClassForPreferredAction(aHandlerInfo, aElement) {
- // If this returns true, the attribute that CSS sniffs for was set to something
- // so you shouldn't manually set an icon URI.
- // This removes the existing actionIcon attribute if any, even if returning false.
- aElement.removeAttribute("actionIcon");
-
- if (aHandlerInfo.alwaysAskBeforeHandling) {
- aElement.setAttribute(APP_ICON_ATTR_NAME, "ask");
- return true;
- }
-
- switch (aHandlerInfo.preferredAction) {
- case Ci.nsIHandlerInfo.saveToDisk:
- aElement.setAttribute(APP_ICON_ATTR_NAME, "save");
- return true;
-
- case Ci.nsIHandlerInfo.handleInternally:
- if (isFeedType(aHandlerInfo.type)) {
- aElement.setAttribute(APP_ICON_ATTR_NAME, "feed");
- return true;
- } else if (aHandlerInfo instanceof InternalHandlerInfoWrapper) {
- aElement.setAttribute(APP_ICON_ATTR_NAME, "ask");
- return true;
- }
- break;
-
- case kActionUsePlugin:
- aElement.setAttribute(APP_ICON_ATTR_NAME, "plugin");
- return true;
- }
- aElement.removeAttribute(APP_ICON_ATTR_NAME);
- return false;
- },
-
- _getIconURLForPreferredAction(aHandlerInfo) {
- switch (aHandlerInfo.preferredAction) {
- case Ci.nsIHandlerInfo.useSystemDefault:
- return this._getIconURLForSystemDefault(aHandlerInfo);
-
- case Ci.nsIHandlerInfo.useHelperApp:
- let preferredApp = aHandlerInfo.preferredApplicationHandler;
- if (this.isValidHandlerApp(preferredApp))
- return this._getIconURLForHandlerApp(preferredApp);
- // Explicit fall-through
-
- // This should never happen, but if preferredAction is set to some weird
- // value, then fall back to the generic application icon.
- default:
- return ICON_URL_APP;
- }
- },
-
- _getIconURLForHandlerApp(aHandlerApp) {
- if (aHandlerApp instanceof Ci.nsILocalHandlerApp)
- return this._getIconURLForFile(aHandlerApp.executable);
-
- if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
- return this._getIconURLForWebApp(aHandlerApp.uriTemplate);
-
- if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
- return this._getIconURLForWebApp(aHandlerApp.uri)
-
- // We know nothing about other kinds of handler apps.
- return "";
- },
-
- _getIconURLForFile(aFile) {
- var fph = this._ioSvc.getProtocolHandler("file").
- QueryInterface(Ci.nsIFileProtocolHandler);
- var urlSpec = fph.getURLSpecFromFile(aFile);
-
- return "moz-icon://" + urlSpec + "?size=16";
- },
-
- _getIconURLForWebApp(aWebAppURITemplate) {
- var uri = this._ioSvc.newURI(aWebAppURITemplate);
-
- // Unfortunately we can't use the favicon service to get the favicon,
- // because the service looks in the annotations table for a record with
- // the exact URL we give it, and users won't have such records for URLs
- // they don't visit, and users won't visit the web app's URL template,
- // they'll only visit URLs derived from that template (i.e. with %s
- // in the template replaced by the URL of the content being handled).
-
- if (/^https?$/.test(uri.scheme) && this._prefSvc.getBoolPref("browser.chrome.favicons"))
- return uri.prePath + "/favicon.ico";
-
- return "";
- },
-
- _getIconURLForSystemDefault(aHandlerInfo) {
- // Handler info objects for MIME types on some OSes implement a property bag
- // interface from which we can get an icon for the default app, so if we're
- // dealing with a MIME type on one of those OSes, then try to get the icon.
- if ("wrappedHandlerInfo" in aHandlerInfo) {
- let wrappedHandlerInfo = aHandlerInfo.wrappedHandlerInfo;
-
- if (wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
- wrappedHandlerInfo instanceof Ci.nsIPropertyBag) {
- try {
- let url = wrappedHandlerInfo.getProperty("defaultApplicationIconURL");
- if (url)
- return url + "?size=16";
- } catch (ex) {}
- }
- }
-
- // If this isn't a MIME type object on an OS that supports retrieving
- // the icon, or if we couldn't retrieve the icon for some other reason,
- // then use a generic icon.
- return ICON_URL_APP;
- },
-
- // DOWNLOADS
-
- /*
- * Preferences:
- *
- * browser.download.useDownloadDir - bool
- * True - Save files directly to the folder configured via the
- * browser.download.folderList preference.
- * False - Always ask the user where to save a file and default to
- * browser.download.lastDir when displaying a folder picker dialog.
- * browser.download.dir - local file handle
- * A local folder the user may have selected for downloaded files to be
- * saved. Migration of other browser settings may also set this path.
- * This folder is enabled when folderList equals 2.
- * browser.download.lastDir - local file handle
- * May contain the last folder path accessed when the user browsed
- * via the file save-as dialog. (see contentAreaUtils.js)
- * browser.download.folderList - int
- * Indicates the location users wish to save downloaded files too.
- * It is also used to display special file labels when the default
- * download location is either the Desktop or the Downloads folder.
- * Values:
- * 0 - The desktop is the default download location.
- * 1 - The system's downloads folder is the default download location.
- * 2 - The default download location is elsewhere as specified in
- * browser.download.dir.
- * browser.download.downloadDir
- * deprecated.
- * browser.download.defaultFolder
- * deprecated.
- */
-
- /**
- * Enables/disables the folder field and Browse button based on whether a
- * default download directory is being used.
- */
- readUseDownloadDir() {
- var downloadFolder = document.getElementById("downloadFolder");
- var chooseFolder = document.getElementById("chooseFolder");
- var preference = document.getElementById("browser.download.useDownloadDir");
- downloadFolder.disabled = !preference.value || preference.locked;
- chooseFolder.disabled = !preference.value || preference.locked;
-
- // don't override the preference's value in UI
- return undefined;
- },
-
- /**
- * Displays a file picker in which the user can choose the location where
- * downloads are automatically saved, updating preferences and UI in
- * response to the choice, if one is made.
- */
- chooseFolder() {
- return this.chooseFolderTask().catch(Components.utils.reportError);
- },
- async chooseFolderTask() {
- let bundlePreferences = document.getElementById("bundlePreferences");
- let title = bundlePreferences.getString("chooseDownloadFolderTitle");
- let folderListPref = document.getElementById("browser.download.folderList");
- let currentDirPref = await this._indexToFolder(folderListPref.value);
- let defDownloads = await this._indexToFolder(1);
- let fp = Components.classes["@mozilla.org/filepicker;1"].
- createInstance(Components.interfaces.nsIFilePicker);
-
- fp.init(window, title, Components.interfaces.nsIFilePicker.modeGetFolder);
- fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
- // First try to open what's currently configured
- if (currentDirPref && currentDirPref.exists()) {
- fp.displayDirectory = currentDirPref;
- } else if (defDownloads && defDownloads.exists()) {
- // Try the system's download dir
- fp.displayDirectory = defDownloads;
- } else {
- // Fall back to Desktop
- fp.displayDirectory = await this._indexToFolder(0);
- }
-
- let result = await new Promise(resolve => fp.open(resolve));
- if (result != Components.interfaces.nsIFilePicker.returnOK) {
- return;
- }
-
- let downloadDirPref = document.getElementById("browser.download.dir");
- downloadDirPref.value = fp.file;
- folderListPref.value = await this._folderToIndex(fp.file);
- // Note, the real prefs will not be updated yet, so dnld manager's
- // userDownloadsDirectory may not return the right folder after
- // this code executes. displayDownloadDirPref will be called on
- // the assignment above to update the UI.
- },
-
- /**
- * Initializes the download folder display settings based on the user's
- * preferences.
- */
- displayDownloadDirPref() {
- this.displayDownloadDirPrefTask().catch(Components.utils.reportError);
-
- // don't override the preference's value in UI
- return undefined;
- },
-
- async displayDownloadDirPrefTask() {
- var folderListPref = document.getElementById("browser.download.folderList");
- var bundlePreferences = document.getElementById("bundlePreferences");
- var downloadFolder = document.getElementById("downloadFolder");
- var currentDirPref = document.getElementById("browser.download.dir");
-
- // Used in defining the correct path to the folder icon.
- var ios = Components.classes["@mozilla.org/network/io-service;1"]
- .getService(Components.interfaces.nsIIOService);
- var fph = ios.getProtocolHandler("file")
- .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
- var iconUrlSpec;
-
- // Display a 'pretty' label or the path in the UI.
- if (folderListPref.value == 2) {
- // Custom path selected and is configured
- downloadFolder.label = this._getDisplayNameOfFile(currentDirPref.value);
- iconUrlSpec = fph.getURLSpecFromFile(currentDirPref.value);
- } else if (folderListPref.value == 1) {
- // 'Downloads'
- downloadFolder.label = bundlePreferences.getString("downloadsFolderName");
- iconUrlSpec = fph.getURLSpecFromFile(await this._indexToFolder(1));
- } else {
- // 'Desktop'
- downloadFolder.label = bundlePreferences.getString("desktopFolderName");
- iconUrlSpec = fph.getURLSpecFromFile(await this._getDownloadsFolder("Desktop"));
- }
- downloadFolder.image = "moz-icon://" + iconUrlSpec + "?size=16";
- },
-
- /**
- * Returns the textual path of a folder in readable form.
- */
- _getDisplayNameOfFile(aFolder) {
- // TODO: would like to add support for 'Downloads on Macintosh HD'
- // for OS X users.
- return aFolder ? aFolder.path : "";
- },
-
- /**
- * Returns the Downloads folder. If aFolder is "Desktop", then the Downloads
- * folder returned is the desktop folder; otherwise, it is a folder whose name
- * indicates that it is a download folder and whose path is as determined by
- * the XPCOM directory service via the download manager's attribute
- * defaultDownloadsDirectory.
- *
- * @throws if aFolder is not "Desktop" or "Downloads"
- */
- async _getDownloadsFolder(aFolder) {
- switch (aFolder) {
- case "Desktop":
- var fileLoc = Components.classes["@mozilla.org/file/directory_service;1"]
- .getService(Components.interfaces.nsIProperties);
- return fileLoc.get("Desk", Components.interfaces.nsILocalFile);
- case "Downloads":
- let downloadsDir = await Downloads.getSystemDownloadsDirectory();
- return new FileUtils.File(downloadsDir);
- }
- throw "ASSERTION FAILED: folder type should be 'Desktop' or 'Downloads'";
- },
-
- /**
- * Determines the type of the given folder.
- *
- * @param aFolder
- * the folder whose type is to be determined
- * @returns integer
- * 0 if aFolder is the Desktop or is unspecified,
- * 1 if aFolder is the Downloads folder,
- * 2 otherwise
- */
- async _folderToIndex(aFolder) {
- if (!aFolder || aFolder.equals(await this._getDownloadsFolder("Desktop")))
- return 0;
- else if (aFolder.equals(await this._getDownloadsFolder("Downloads")))
- return 1;
- return 2;
- },
-
- /**
- * Converts an integer into the corresponding folder.
- *
- * @param aIndex
- * an integer
- * @returns the Desktop folder if aIndex == 0,
- * the Downloads folder if aIndex == 1,
- * the folder stored in browser.download.dir
- */
- async _indexToFolder(aIndex) {
- switch (aIndex) {
- case 0:
- return await this._getDownloadsFolder("Desktop");
- case 1:
- return await this._getDownloadsFolder("Downloads");
- }
- var currentDirPref = document.getElementById("browser.download.dir");
- return currentDirPref.value;
- }
-
-};
deleted file mode 100644
--- a/browser/components/preferences/in-content-new/applications.xul
+++ /dev/null
@@ -1,131 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-<!-- Applications panel -->
-
-<script type="application/javascript"
- src="chrome://browser/content/preferences/in-content-new/applications.js"/>
-
-<preferences id="feedsPreferences" hidden="true" data-category="paneApplications">
- <preference id="browser.feeds.handler"
- name="browser.feeds.handler"
- type="string"/>
- <preference id="browser.feeds.handler.default"
- name="browser.feeds.handler.default"
- type="string"/>
- <preference id="browser.feeds.handlers.application"
- name="browser.feeds.handlers.application"
- type="file"/>
- <preference id="browser.feeds.handlers.webservice"
- name="browser.feeds.handlers.webservice"
- type="string"/>
-
- <preference id="browser.videoFeeds.handler"
- name="browser.videoFeeds.handler"
- type="string"/>
- <preference id="browser.videoFeeds.handler.default"
- name="browser.videoFeeds.handler.default"
- type="string"/>
- <preference id="browser.videoFeeds.handlers.application"
- name="browser.videoFeeds.handlers.application"
- type="file"/>
- <preference id="browser.videoFeeds.handlers.webservice"
- name="browser.videoFeeds.handlers.webservice"
- type="string"/>
-
- <preference id="browser.audioFeeds.handler"
- name="browser.audioFeeds.handler"
- type="string"/>
- <preference id="browser.audioFeeds.handler.default"
- name="browser.audioFeeds.handler.default"
- type="string"/>
- <preference id="browser.audioFeeds.handlers.application"
- name="browser.audioFeeds.handlers.application"
- type="file"/>
- <preference id="browser.audioFeeds.handlers.webservice"
- name="browser.audioFeeds.handlers.webservice"
- type="string"/>
-
- <preference id="pref.downloads.disable_button.edit_actions"
- name="pref.downloads.disable_button.edit_actions"
- type="bool"/>
-</preferences>
-
-<keyset data-category="paneApplications">
- <!-- Ctrl+f/k focus the search box in the Applications pane.
- These <key>s have oncommand attributes because of bug 371900. -->
- <key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand=";"/>
- <key key="&focusSearch2.key;" modifiers="accel" id="focusSearch2" oncommand=";"/>
-</keyset>
-
-<hbox id="header-applications"
- class="header"
- hidden="true"
- data-category="paneApplications">
- <label class="header-name" flex="1">&paneFilesApplications.title;</label>
-</hbox>
-
-<vbox id="applicationsContent"
- data-category="paneApplications"
- hidden="true"
- flex="1">
-
- <!--Downloads-->
- <groupbox id="downloadsGroup">
- <caption><label>&downloads.label;</label></caption>
-
- <radiogroup id="saveWhere"
- preference="browser.download.useDownloadDir"
- onsyncfrompreference="return gApplicationsPane.readUseDownloadDir();">
- <hbox id="saveToRow">
- <radio id="saveTo"
- value="true"
- label="&saveTo.label;"
- accesskey="&saveTo.accesskey;"
- aria-labelledby="saveTo downloadFolder"/>
- <filefield id="downloadFolder"
- flex="1"
- preference="browser.download.folderList"
- preference-editable="true"
- aria-labelledby="saveTo"
- onsyncfrompreference="return gApplicationsPane.displayDownloadDirPref();"/>
- <button id="chooseFolder"
-#ifdef XP_MACOSX
- accesskey="&chooseFolderMac.accesskey;"
- label="&chooseFolderMac.label;"
-#else
- accesskey="&chooseFolderWin.accesskey;"
- label="&chooseFolderWin.label;"
-#endif
- />
- </hbox>
- <radio id="alwaysAsk"
- value="false"
- label="&alwaysAskWhere.label;"
- accesskey="&alwaysAskWhere.accesskey;"/>
- </radiogroup>
- </groupbox>
-
- <groupbox id="applicationsGroup">
- <caption><label>&applications.label;</label></caption>
- <description>&applications.description;</description>
- <textbox id="filter" flex="1"
- type="search"
- placeholder="&filter2.emptytext;"
- aria-controls="handlersView"/>
-
- <richlistbox id="handlersView" orient="vertical" persist="lastSelectedType"
- preference="pref.downloads.disable_button.edit_actions"
- flex="1">
- <listheader equalsize="always">
- <treecol id="typeColumn" label="&typeColumn.label;" value="type"
- accesskey="&typeColumn.accesskey;" persist="sortDirection"
- flex="1" sortDirection="ascending"/>
- <treecol id="actionColumn" label="&actionColumn2.label;" value="action"
- accesskey="&actionColumn2.accesskey;" persist="sortDirection"
- flex="1"/>
- </listheader>
- </richlistbox>
- </groupbox>
-</vbox>
--- a/browser/components/preferences/in-content-new/containers.js
+++ b/browser/components/preferences/in-content-new/containers.js
@@ -13,17 +13,17 @@ const defaultContainerIcon = "fingerprin
const defaultContainerColor = "blue";
let gContainersPane = {
init() {
this._list = document.getElementById("containersView");
document.getElementById("backContainersLink").addEventListener("click", function() {
- gotoPref("privacy");
+ gotoPref("general");
});
this._rebuildView();
},
_rebuildView() {
const containers = ContextualIdentityService.getPublicIdentities();
while (this._list.firstChild) {
--- a/browser/components/preferences/in-content-new/containers.xul
+++ b/browser/components/preferences/in-content-new/containers.xul
@@ -13,17 +13,17 @@
name="privacy.userContext.enabled"
type="bool"/>
</preferences>
<hbox hidden="true"
class="container-header-links"
data-category="paneContainers">
- <label class="text-link" id="backContainersLink">&backLink.label;</label>
+ <label class="text-link" id="backContainersLink">&backLink2.label;</label>
</hbox>
<hbox id="header-containers"
class="header"
hidden="true"
data-category="paneContainers">
<label class="header-name" flex="1">&paneContainers.title;</label>
</hbox>
--- a/browser/components/preferences/in-content-new/findInPage.js
+++ b/browser/components/preferences/in-content-new/findInPage.js
@@ -27,16 +27,20 @@ var gSearchResultsPane = {
this.listSearchTooltips.forEach((anchorNode) => {
this.calculateTooltipPosition(anchorNode);
});
callbackId = null;
});
}
});
}
+ let strings = this.strings;
+ this.searchInput.placeholder = AppConstants.platform == "win" ?
+ strings.getString("searchInput.labelWin") :
+ strings.getString("searchInput.labelUnix");
},
handleEvent(event) {
if (event.type === "command") {
this.searchFunction(event);
} else if (event.type === "focus") {
this.initializeCategories();
}
--- a/browser/components/preferences/in-content-new/jar.mn
+++ b/browser/components/preferences/in-content-new/jar.mn
@@ -3,14 +3,13 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
content/browser/preferences/in-content-new/preferences.js
* content/browser/preferences/in-content-new/preferences.xul
content/browser/preferences/in-content-new/subdialogs.js
content/browser/preferences/in-content-new/main.js
+ content/browser/preferences/in-content-new/search.js
content/browser/preferences/in-content-new/privacy.js
content/browser/preferences/in-content-new/containers.js
- content/browser/preferences/in-content-new/advanced.js
- content/browser/preferences/in-content-new/applications.js
content/browser/preferences/in-content-new/sync.js
content/browser/preferences/in-content-new/findInPage.js
--- a/browser/components/preferences/in-content-new/main.js
+++ b/browser/components/preferences/in-content-new/main.js
@@ -1,48 +1,147 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* import-globals-from preferences.js */
/* import-globals-from ../../../../toolkit/mozapps/preferences/fontbuilder.js */
+/* import-globals-from ../../../base/content/aboutDialog-appUpdater.js */
Components.utils.import("resource://gre/modules/Downloads.jsm");
Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource:///modules/ShellService.jsm");
Components.utils.import("resource:///modules/TransientPrefs.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/AppConstants.jsm");
+
+// Constants & Enumeration Values
+const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
+const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
+const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
+const TYPE_PDF = "application/pdf";
+
+const PREF_PDFJS_DISABLED = "pdfjs.disabled";
+const TOPIC_PDFJS_HANDLER_CHANGED = "pdfjs:handlerChanged";
+
+const PREF_DISABLED_PLUGIN_TYPES = "plugin.disable_full_page_plugin_for_types";
+
+// Preferences that affect which entries to show in the list.
+const PREF_SHOW_PLUGINS_IN_LIST = "browser.download.show_plugins_in_list";
+const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
+ "browser.download.hide_plugins_without_extensions";
+
+/*
+ * Preferences where we store handling information about the feed type.
+ *
+ * browser.feeds.handler
+ * - "bookmarks", "reader" (clarified further using the .default preference),
+ * or "ask" -- indicates the default handler being used to process feeds;
+ * "bookmarks" is obsolete; to specify that the handler is bookmarks,
+ * set browser.feeds.handler.default to "bookmarks";
+ *
+ * browser.feeds.handler.default
+ * - "bookmarks", "client" or "web" -- indicates the chosen feed reader used
+ * to display feeds, either transiently (i.e., when the "use as default"
+ * checkbox is unchecked, corresponds to when browser.feeds.handler=="ask")
+ * or more permanently (i.e., the item displayed in the dropdown in Feeds
+ * preferences)
+ *
+ * browser.feeds.handler.webservice
+ * - the URL of the currently selected web service used to read feeds
+ *
+ * browser.feeds.handlers.application
+ * - nsILocalFile, stores the current client-side feed reading app if one has
+ * been chosen
+ */
+const PREF_FEED_SELECTED_APP = "browser.feeds.handlers.application";
+const PREF_FEED_SELECTED_WEB = "browser.feeds.handlers.webservice";
+const PREF_FEED_SELECTED_ACTION = "browser.feeds.handler";
+const PREF_FEED_SELECTED_READER = "browser.feeds.handler.default";
+
+const PREF_VIDEO_FEED_SELECTED_APP = "browser.videoFeeds.handlers.application";
+const PREF_VIDEO_FEED_SELECTED_WEB = "browser.videoFeeds.handlers.webservice";
+const PREF_VIDEO_FEED_SELECTED_ACTION = "browser.videoFeeds.handler";
+const PREF_VIDEO_FEED_SELECTED_READER = "browser.videoFeeds.handler.default";
+
+const PREF_AUDIO_FEED_SELECTED_APP = "browser.audioFeeds.handlers.application";
+const PREF_AUDIO_FEED_SELECTED_WEB = "browser.audioFeeds.handlers.webservice";
+const PREF_AUDIO_FEED_SELECTED_ACTION = "browser.audioFeeds.handler";
+const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
+
+// The nsHandlerInfoAction enumeration values in nsIHandlerInfo identify
+// the actions the application can take with content of various types.
+// But since nsIHandlerInfo doesn't support plugins, there's no value
+// identifying the "use plugin" action, so we use this constant instead.
+const kActionUsePlugin = 5;
+
+const ICON_URL_APP = AppConstants.platform == "linux" ?
+ "moz-icon://dummy.exe?size=16" :
+ "chrome://browser/skin/preferences/application.png";
+
+// For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
+// was set by us to a custom handler icon and CSS should not try to override it.
+const APP_ICON_ATTR_NAME = "appHandlerIcon";
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
if (AppConstants.E10S_TESTING_ONLY) {
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
}
-XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
- "resource://gre/modules/PlacesUtils.jsm");
-
if (AppConstants.MOZ_DEV_EDITION) {
XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
"resource://gre/modules/FxAccounts.jsm");
}
-const ENGINE_FLAVOR = "text/x-moz-search-engine";
-
-var gEngineView = null;
-
var gMainPane = {
- /**
- * Initialize autocomplete to ensure prefs are in sync.
- */
- _initAutocomplete() {
- Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
- .getService(Components.interfaces.mozIPlacesAutoComplete);
- },
+ // The set of types the app knows how to handle. A hash of HandlerInfoWrapper
+ // objects, indexed by type.
+ _handledTypes: {},
+
+ // The list of types we can show, sorted by the sort column/direction.
+ // An array of HandlerInfoWrapper objects. We build this list when we first
+ // load the data and then rebuild it when users change a pref that affects
+ // what types we can show or change the sort column/direction.
+ // Note: this isn't necessarily the list of types we *will* show; if the user
+ // provides a filter string, we'll only show the subset of types in this list
+ // that match that string.
+ _visibleTypes: [],
+
+ // A count of the number of times each visible type description appears.
+ // We use these counts to determine whether or not to annotate descriptions
+ // with their types to distinguish duplicate descriptions from each other.
+ // A hash of integer counts, indexed by string description.
+ _visibleTypeDescriptionCount: {},
+
+
+ // Convenience & Performance Shortcuts
+
+ // These get defined by init().
+ _brandShortName: null,
+ _prefsBundle: null,
+ _list: null,
+ _filter: null,
+
+ _prefSvc: Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch),
+
+ _mimeSvc: Cc["@mozilla.org/mime;1"].
+ getService(Ci.nsIMIMEService),
+
+ _helperAppSvc: Cc["@mozilla.org/uriloader/external-helper-app-service;1"].
+ getService(Ci.nsIExternalHelperAppService),
+
+ _handlerSvc: Cc["@mozilla.org/uriloader/handler-service;1"].
+ getService(Ci.nsIHandlerService),
+
+ _ioSvc: Cc["@mozilla.org/network/io-service;1"].
+ getService(Ci.nsIIOService),
/**
* Initialization of this.
*/
init() {
function setEventListener(aId, aEventType, aCallback) {
document.getElementById(aId)
.addEventListener(aEventType, aCallback.bind(gMainPane));
@@ -55,52 +154,23 @@ var gMainPane = {
// way to get all file type association prefs. So we don't know
// when the user will select the default. We refresh here periodically
// in case the default changes. On other Windows OS's defaults can also
// be set while the prefs are open.
window.setInterval(this.updateSetDefaultBrowser.bind(this), 1000);
}
}
- gEngineView = new EngineView(new EngineStore());
- document.getElementById("engineList").view = gEngineView;
- this.buildDefaultEngineDropDown();
-
+ this.initBrowserContainers();
this.buildContentProcessCountMenuList();
- let addEnginesLink = document.getElementById("addEngines");
- let searchEnginesURL = Services.wm.getMostRecentWindow("navigator:browser")
- .BrowserSearch.searchEnginesURL;
- addEnginesLink.setAttribute("href", searchEnginesURL);
-
let performanceSettingsLink = document.getElementById("performanceSettingsLearnMore");
let performanceSettingsUrl = Services.urlFormatter.formatURLPref("app.support.baseURL") + "performance";
performanceSettingsLink.setAttribute("href", performanceSettingsUrl);
- window.addEventListener("click", this);
- window.addEventListener("command", this);
- window.addEventListener("dragstart", this);
- window.addEventListener("keypress", this);
- window.addEventListener("select", this);
- window.addEventListener("blur", this, true);
-
- Services.obs.addObserver(this, "browser-search-engine-modified");
- window.addEventListener("unload", () => {
- Services.obs.removeObserver(this, "browser-search-engine-modified");
- });
-
- this._initAutocomplete();
-
- let suggestsPref =
- document.getElementById("browser.search.suggest.enabled");
- suggestsPref.addEventListener("change", () => {
- this.updateSuggestsCheckbox();
- });
- this.updateSuggestsCheckbox();
-
this.updateDefaultPerformanceSettingsPref();
let defaultPerformancePref =
document.getElementById("browser.preferences.defaultPerformanceSettings.enabled");
defaultPerformancePref.addEventListener("change", () => {
this.updatePerformanceSettingsBox();
});
this.updatePerformanceSettingsBox();
@@ -152,16 +222,22 @@ var gMainPane = {
setEventListener("font.language.group", "change",
gMainPane._rebuildFonts);
setEventListener("advancedFonts", "command",
gMainPane.configureFonts);
setEventListener("colors", "command",
gMainPane.configureColors);
setEventListener("layers.acceleration.disabled", "change",
gMainPane.updateHardwareAcceleration);
+ setEventListener("connectionSettings", "command",
+ gMainPane.showConnections);
+ setEventListener("browserContainersCheckbox", "command",
+ gMainPane.checkBrowserContainers);
+ setEventListener("browserContainersSettings", "command",
+ gMainPane.showContainerSettings);
// Initializes the fonts dropdowns displayed in this pane.
this._rebuildFonts();
this.updateOnScreenKeyboardVisibility();
// Show translation preferences if we may:
const prefName = "browser.translation.ui.show";
@@ -207,22 +283,183 @@ var gMainPane = {
() => separateProfileModeCheckbox.checked = true);
fxAccounts.getSignedInUser().then(data => {
document.getElementById("getStarted").selectedIndex = data ? 1 : 0;
})
.catch(Cu.reportError);
}
+ // Initialize the Firefox Updates section.
+ let version = AppConstants.MOZ_APP_VERSION_DISPLAY;
+
+ // Include the build ID if this is an "a#" (nightly) build
+ if (/a\d+$/.test(version)) {
+ let buildID = Services.appinfo.appBuildID;
+ let year = buildID.slice(0, 4);
+ let month = buildID.slice(4, 6);
+ let day = buildID.slice(6, 8);
+ version += ` (${year}-${month}-${day})`;
+ }
+
+ // Append "(32-bit)" or "(64-bit)" build architecture to the version number:
+ let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+ let archResource = Services.appinfo.is64Bit
+ ? "aboutDialog.architecture.sixtyFourBit"
+ : "aboutDialog.architecture.thirtyTwoBit";
+ let arch = bundle.GetStringFromName(archResource);
+ version += ` (${arch})`;
+
+ document.getElementById("version").textContent = version;
+
+ // Show a release notes link if we have a URL.
+ let relNotesLink = document.getElementById("releasenotes");
+ let relNotesPrefType = Services.prefs.getPrefType("app.releaseNotesURL");
+ if (relNotesPrefType != Services.prefs.PREF_INVALID) {
+ let relNotesURL = Services.urlFormatter.formatURLPref("app.releaseNotesURL");
+ if (relNotesURL != "about:blank") {
+ relNotesLink.href = relNotesURL;
+ relNotesLink.hidden = false;
+ }
+ }
+
+ let distroId = Services.prefs.getCharPref("distribution.id", "");
+ if (distroId) {
+ let distroVersion = Services.prefs.getCharPref("distribution.version");
+
+ let distroIdField = document.getElementById("distributionId");
+ distroIdField.value = distroId + " - " + distroVersion;
+ distroIdField.hidden = false;
+
+ let distroAbout = Services.prefs.getStringPref("distribution.about", "");
+ if (distroAbout) {
+ let distroField = document.getElementById("distribution");
+ distroField.value = distroAbout;
+ distroField.hidden = false;
+ }
+ }
+
+ if (AppConstants.MOZ_UPDATER) {
+ gAppUpdater = new appUpdater();
+ let onUnload = () => {
+ window.removeEventListener("unload", onUnload);
+ Services.prefs.removeObserver("app.update.", this);
+ };
+ window.addEventListener("unload", onUnload);
+ Services.prefs.addObserver("app.update.", this);
+ this.updateReadPrefs();
+ setEventListener("updateRadioGroup", "command",
+ gMainPane.updateWritePrefs);
+ setEventListener("showUpdateHistory", "command",
+ gMainPane.showUpdates);
+ }
+
+ // Initilize Application section.
+ // Initialize shortcuts to some commonly accessed elements & values.
+ this._brandShortName =
+ document.getElementById("bundleBrand").getString("brandShortName");
+ this._prefsBundle = document.getElementById("bundlePreferences");
+ this._list = document.getElementById("handlersView");
+ this._filter = document.getElementById("filter");
+
+ // Observe preferences that influence what we display so we can rebuild
+ // the view when they change.
+ this._prefSvc.addObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
+ this._prefSvc.addObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
+ this._prefSvc.addObserver(PREF_FEED_SELECTED_APP, this);
+ this._prefSvc.addObserver(PREF_FEED_SELECTED_WEB, this);
+ this._prefSvc.addObserver(PREF_FEED_SELECTED_ACTION, this);
+ this._prefSvc.addObserver(PREF_FEED_SELECTED_READER, this);
+
+ this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
+ this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_WEB, this);
+ this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
+ this._prefSvc.addObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
+
+ this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
+ this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
+ this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
+ this._prefSvc.addObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
+
+ setEventListener("focusSearch1", "command", gMainPane.focusFilterBox);
+ setEventListener("focusSearch2", "command", gMainPane.focusFilterBox);
+ setEventListener("filter", "command", gMainPane.filter);
+ setEventListener("handlersView", "select",
+ gMainPane.onSelectionChanged);
+ setEventListener("typeColumn", "click", gMainPane.sort);
+ setEventListener("actionColumn", "click", gMainPane.sort);
+ setEventListener("chooseFolder", "command", gMainPane.chooseFolder);
+ setEventListener("browser.download.dir", "change", gMainPane.displayDownloadDirPref);
+
+ // Listen for window unload so we can remove our preference observers.
+ window.addEventListener("unload", this);
+
+ // Figure out how we should be sorting the list. We persist sort settings
+ // across sessions, so we can't assume the default sort column/direction.
+ // XXX should we be using the XUL sort service instead?
+ if (document.getElementById("actionColumn").hasAttribute("sortDirection")) {
+ this._sortColumn = document.getElementById("actionColumn");
+ // The typeColumn element always has a sortDirection attribute,
+ // either because it was persisted or because the default value
+ // from the xul file was used. If we are sorting on the other
+ // column, we should remove it.
+ document.getElementById("typeColumn").removeAttribute("sortDirection");
+ } else
+ this._sortColumn = document.getElementById("typeColumn");
+
+ // Load the data and build the list of handlers.
+ // By doing this in a timeout, we let the preferences dialog resize itself
+ // to an appropriate size before we add a bunch of items to the list.
+ // Otherwise, if there are many items, and the Applications prefpane
+ // is the one that gets displayed when the user first opens the dialog,
+ // the dialog might stretch too much in an attempt to fit them all in.
+ // XXX Shouldn't we perhaps just set a max-height on the richlistbox?
+ var _delayedPaneLoad = function(self) {
+ self._loadData();
+ self._rebuildVisibleTypes();
+ self._sortVisibleTypes();
+ self._rebuildView();
+ }
+ setTimeout(_delayedPaneLoad, 0, this);
+
+ let browserBundle = document.getElementById("browserBundle");
+ appendSearchKeywords("browserContainersSettings", [
+ browserBundle.getString("userContextPersonal.label"),
+ browserBundle.getString("userContextWork.label"),
+ browserBundle.getString("userContextBanking.label"),
+ browserBundle.getString("userContextShopping.label"),
+ ]);
+
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded");
},
+ /**
+ * Show the Containers UI depending on the privacy.userContext.ui.enabled pref.
+ */
+ initBrowserContainers() {
+ if (!Services.prefs.getBoolPref("privacy.userContext.ui.enabled")) {
+ // The browserContainersGroup element has its own internal padding that
+ // is visible even if the browserContainersbox is visible, so hide the whole
+ // groupbox if the feature is disabled to prevent a gap in the preferences.
+ document.getElementById("browserContainersbox").setAttribute("data-hidden-from-search", "true");
+ return;
+ }
+
+ let link = document.getElementById("browserContainersLearnMore");
+ link.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "containers";
+
+ document.getElementById("browserContainersbox").hidden = false;
+
+ document.getElementById("browserContainersCheckbox").checked =
+ Services.prefs.getBoolPref("privacy.userContext.enabled");
+ },
+
isE10SEnabled() {
let e10sEnabled;
try {
let e10sStatus = Components.classes["@mozilla.org/supports-PRUint64;1"]
.createInstance(Ci.nsISupportsPRUint64);
let appinfo = Services.appinfo.QueryInterface(Ci.nsIObserver);
appinfo.observe(e10sStatus, "getE10SBlocked", "");
e10sEnabled = e10sStatus.data < 2;
@@ -648,16 +885,67 @@ var gMainPane = {
/**
* Displays the colors dialog, where default web page/link/etc. colors can be
* configured.
*/
configureColors() {
gSubDialog.open("chrome://browser/content/preferences/colors.xul", "resizable=no");
},
+ // NETWORK
+ /**
+ * Displays a dialog in which proxy settings may be changed.
+ */
+ showConnections() {
+ gSubDialog.open("chrome://browser/content/preferences/connection.xul");
+ },
+
+ checkBrowserContainers(event) {
+ let checkbox = document.getElementById("browserContainersCheckbox");
+ if (checkbox.checked) {
+ Services.prefs.setBoolPref("privacy.userContext.enabled", true);
+ return;
+ }
+
+ let count = ContextualIdentityService.countContainerTabs();
+ if (count == 0) {
+ Services.prefs.setBoolPref("privacy.userContext.enabled", false);
+ return;
+ }
+
+ let bundlePreferences = document.getElementById("bundlePreferences");
+
+ let title = bundlePreferences.getString("disableContainersAlertTitle");
+ let message = PluralForm.get(count, bundlePreferences.getString("disableContainersMsg"))
+ .replace("#S", count)
+ let okButton = PluralForm.get(count, bundlePreferences.getString("disableContainersOkButton"))
+ .replace("#S", count)
+ let cancelButton = bundlePreferences.getString("disableContainersButton2");
+
+ let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
+ (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1);
+
+ let rv = Services.prompt.confirmEx(window, title, message, buttonFlags,
+ okButton, cancelButton, null, null, {});
+ if (rv == 0) {
+ ContextualIdentityService.closeContainerTabs();
+ Services.prefs.setBoolPref("privacy.userContext.enabled", false);
+ return;
+ }
+
+ checkbox.checked = true;
+ },
+
+ /**
+ * Displays container panel for customising and adding containers.
+ */
+ showContainerSettings() {
+ gotoPref("containers");
+ },
+
/**
* ui.osk.enabled
* - when set to true, subject to other conditions, we may sometimes invoke
* an on-screen keyboard when a text input is focused.
* (Currently Windows-only, and depending on prefs, may be Windows-8-only)
*/
updateOnScreenKeyboardVisibility() {
if (AppConstants.platform == "win") {
@@ -788,36 +1076,16 @@ var gMainPane = {
if (this._storedSpellCheck == 2) {
return 2;
}
return 1;
}
return 0;
},
- updateSuggestsCheckbox() {
- let suggestsPref =
- document.getElementById("browser.search.suggest.enabled");
- let permanentPB =
- Services.prefs.getBoolPref("browser.privatebrowsing.autostart");
- let urlbarSuggests = document.getElementById("urlBarSuggestion");
- urlbarSuggests.disabled = !suggestsPref.value || permanentPB;
-
- let urlbarSuggestsPref =
- document.getElementById("browser.urlbar.suggest.searches");
- urlbarSuggests.checked = urlbarSuggestsPref.value;
- if (urlbarSuggests.disabled) {
- urlbarSuggests.checked = false;
- }
-
- let permanentPBLabel =
- document.getElementById("urlBarSuggestionPermanentPBLabel");
- permanentPBLabel.hidden = urlbarSuggests.hidden || !permanentPB;
- },
-
updateDefaultPerformanceSettingsPref() {
let defaultPerformancePref =
document.getElementById("browser.preferences.defaultPerformanceSettings.enabled");
let processCountPref = document.getElementById("dom.ipc.processCount");
let accelerationPref = document.getElementById("layers.acceleration.disabled");
if (processCountPref.value != processCountPref.defaultValue ||
accelerationPref.value != accelerationPref.defaultValue) {
defaultPerformancePref.value = false;
@@ -857,536 +1125,2009 @@ var gMainPane = {
} else {
document.getElementById("limitContentProcess").disabled = true;
document.getElementById("contentProcessCount").disabled = true;
document.getElementById("contentProcessCountEnabledDescription").hidden = true;
document.getElementById("contentProcessCountDisabledDescription").hidden = false;
}
},
- buildDefaultEngineDropDown() {
- // This is called each time something affects the list of engines.
- let list = document.getElementById("defaultEngine");
- // Set selection to the current default engine.
- let currentEngine = Services.search.currentEngine.name;
-
- // If the current engine isn't in the list any more, select the first item.
- let engines = gEngineView._engineStore._engines;
- 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.iconURI) {
- item.setAttribute("image", e.iconURI.spec);
+ /*
+ * Preferences:
+ *
+ * app.update.enabled
+ * - true if updates to the application are enabled, false otherwise
+ * app.update.auto
+ * - true if updates should be automatically downloaded and installed and
+ * false if the user should be asked what he wants to do when an update is
+ * available
+ * extensions.update.enabled
+ * - true if updates to extensions and themes are enabled, false otherwise
+ * browser.search.update
+ * - true if updates to search engines are enabled, false otherwise
+ */
+
+ /**
+ * Selects the item of the radiogroup based on the pref values and locked
+ * states.
+ *
+ * UI state matrix for update preference conditions
+ *
+ * UI Components: Preferences
+ * Radiogroup i = app.update.enabled
+ * ii = app.update.auto
+ *
+ * Disabled states:
+ * Element pref value locked disabled
+ * radiogroup i t/f f false
+ * i t/f *t* *true*
+ * ii t/f f false
+ * ii t/f *t* *true*
+ */
+ updateReadPrefs() {
+ if (AppConstants.MOZ_UPDATER) {
+ var enabledPref = document.getElementById("app.update.enabled");
+ var autoPref = document.getElementById("app.update.auto");
+ var radiogroup = document.getElementById("updateRadioGroup");
+
+ if (!enabledPref.value) // Don't care for autoPref.value in this case.
+ radiogroup.value = "manual"; // 3. Never check for updates.
+ else if (autoPref.value) // enabledPref.value && autoPref.value
+ radiogroup.value = "auto"; // 1. Automatically install updates
+ else // enabledPref.value && !autoPref.value
+ radiogroup.value = "checkOnly"; // 2. Check, but let me choose
+
+ var canCheck = Components.classes["@mozilla.org/updates/update-service;1"].
+ getService(Components.interfaces.nsIApplicationUpdateService).
+ canCheckForUpdates;
+ // canCheck is false if the enabledPref is false and locked,
+ // or the binary platform or OS version is not known.
+ // A locked pref is sufficient to disable the radiogroup.
+ radiogroup.disabled = !canCheck || enabledPref.locked || autoPref.locked;
+
+ if (AppConstants.MOZ_MAINTENANCE_SERVICE) {
+ // Check to see if the maintenance service is installed.
+ // If it is don't show the preference at all.
+ var installed;
+ try {
+ var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
+ .createInstance(Components.interfaces.nsIWindowsRegKey);
+ wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
+ "SOFTWARE\\Mozilla\\MaintenanceService",
+ wrk.ACCESS_READ | wrk.WOW64_64);
+ installed = wrk.readIntValue("Installed");
+ wrk.close();
+ } catch (e) {
+ }
+ if (installed != 1) {
+ document.getElementById("useService").hidden = true;
+ }
}
- item.engine = e;
- if (e.name == currentEngine)
- list.selectedItem = item;
- });
+ }
+ },
+
+ /**
+ * Sets the pref values based on the selected item of the radiogroup.
+ */
+ updateWritePrefs() {
+ if (AppConstants.MOZ_UPDATER) {
+ var enabledPref = document.getElementById("app.update.enabled");
+ var autoPref = document.getElementById("app.update.auto");
+ var radiogroup = document.getElementById("updateRadioGroup");
+ switch (radiogroup.value) {
+ case "auto": // 1. Automatically install updates for Desktop only
+ enabledPref.value = true;
+ autoPref.value = true;
+ break;
+ case "checkOnly": // 2. Check, but let me choose
+ enabledPref.value = true;
+ autoPref.value = false;
+ break;
+ case "manual": // 3. Never check for updates.
+ enabledPref.value = false;
+ autoPref.value = false;
+ }
+ }
+ },
+
+ /**
+ * Displays the history of installed updates.
+ */
+ showUpdates() {
+ gSubDialog.open("chrome://mozapps/content/update/history.xul");
},
+ destroy() {
+ window.removeEventListener("unload", this);
+ this._prefSvc.removeObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
+ this._prefSvc.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
+ this._prefSvc.removeObserver(PREF_FEED_SELECTED_APP, this);
+ this._prefSvc.removeObserver(PREF_FEED_SELECTED_WEB, this);
+ this._prefSvc.removeObserver(PREF_FEED_SELECTED_ACTION, this);
+ this._prefSvc.removeObserver(PREF_FEED_SELECTED_READER, this);
+
+ this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
+ this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_WEB, this);
+ this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
+ this._prefSvc.removeObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
+
+ this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
+ this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
+ this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
+ this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
+ },
+
+
+ // nsISupports
+
+ QueryInterface(aIID) {
+ if (aIID.equals(Ci.nsIObserver) ||
+ aIID.equals(Ci.nsIDOMEventListener ||
+ aIID.equals(Ci.nsISupports)))
+ return this;
+
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ },
+
+
+ // nsIObserver
+
+ observe(aSubject, aTopic, aData) {
+ if (aTopic == "nsPref:changed") {
+ // Rebuild the list when there are changes to preferences that influence
+ // whether or not to show certain entries in the list.
+ if (!this._storingAction) {
+ // These two prefs alter the list of visible types, so we have to rebuild
+ // that list when they change.
+ if (aData == PREF_SHOW_PLUGINS_IN_LIST ||
+ aData == PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS) {
+ this._rebuildVisibleTypes();
+ this._sortVisibleTypes();
+ }
+
+ // All the prefs we observe can affect what we display, so we rebuild
+ // the view when any of them changes.
+ this._rebuildView();
+ }
+ if (AppConstants.MOZ_UPDATER) {
+ this.updateReadPrefs();
+ }
+ }
+ },
+
+
+ // nsIDOMEventListener
+
handleEvent(aEvent) {
- switch (aEvent.type) {
- 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();
- }
+ if (aEvent.type == "unload") {
+ this.destroy();
+ }
+ },
+
+
+ // Composed Model Construction
+
+ _loadData() {
+ this._loadFeedHandler();
+ this._loadInternalHandlers();
+ this._loadPluginHandlers();
+ this._loadApplicationHandlers();
+ },
+
+ _loadFeedHandler() {
+ this._handledTypes[TYPE_MAYBE_FEED] = feedHandlerInfo;
+ feedHandlerInfo.handledOnlyByPlugin = false;
+
+ this._handledTypes[TYPE_MAYBE_VIDEO_FEED] = videoFeedHandlerInfo;
+ videoFeedHandlerInfo.handledOnlyByPlugin = false;
+
+ this._handledTypes[TYPE_MAYBE_AUDIO_FEED] = audioFeedHandlerInfo;
+ audioFeedHandlerInfo.handledOnlyByPlugin = false;
+ },
+
+ /**
+ * Load higher level internal handlers so they can be turned on/off in the
+ * applications menu.
+ */
+ _loadInternalHandlers() {
+ var internalHandlers = [pdfHandlerInfo];
+ for (let internalHandler of internalHandlers) {
+ if (internalHandler.enabled) {
+ this._handledTypes[internalHandler.type] = internalHandler;
+ }
+ }
+ },
+
+ /**
+ * Load the set of handlers defined by plugins.
+ *
+ * Note: if there's more than one plugin for a given MIME type, we assume
+ * the last one is the one that the application will use. That may not be
+ * correct, but it's how we've been doing it for years.
+ *
+ * Perhaps we should instead query navigator.mimeTypes for the set of types
+ * supported by the application and then get the plugin from each MIME type's
+ * enabledPlugin property. But if there's a plugin for a type, we need
+ * to know about it even if it isn't enabled, since we're going to give
+ * the user an option to enable it.
+ *
+ * Also note that enabledPlugin does not get updated when
+ * plugin.disable_full_page_plugin_for_types changes, so even if we could use
+ * enabledPlugin to get the plugin that would be used, we'd still need to
+ * check the pref ourselves to find out if it's enabled.
+ */
+ _loadPluginHandlers() {
+ "use strict";
+
+ let mimeTypes = navigator.mimeTypes;
+
+ for (let mimeType of mimeTypes) {
+ let handlerInfoWrapper;
+ if (mimeType.type in this._handledTypes) {
+ handlerInfoWrapper = this._handledTypes[mimeType.type];
+ } else {
+ let wrappedHandlerInfo =
+ this._mimeSvc.getFromTypeAndExtension(mimeType.type, null);
+ handlerInfoWrapper = new HandlerInfoWrapper(mimeType.type, wrappedHandlerInfo);
+ handlerInfoWrapper.handledOnlyByPlugin = true;
+ this._handledTypes[mimeType.type] = handlerInfoWrapper;
+ }
+ handlerInfoWrapper.pluginName = mimeType.enabledPlugin.name;
+ }
+ },
+
+ /**
+ * Load the set of handlers defined by the application datastore.
+ */
+ _loadApplicationHandlers() {
+ var wrappedHandlerInfos = this._handlerSvc.enumerate();
+ while (wrappedHandlerInfos.hasMoreElements()) {
+ let wrappedHandlerInfo =
+ wrappedHandlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
+ let type = wrappedHandlerInfo.type;
+
+ let handlerInfoWrapper;
+ if (type in this._handledTypes)
+ handlerInfoWrapper = this._handledTypes[type];
+ else {
+ handlerInfoWrapper = new HandlerInfoWrapper(type, wrappedHandlerInfo);
+ this._handledTypes[type] = handlerInfoWrapper;
+ }
+
+ handlerInfoWrapper.handledOnlyByPlugin = false;
+ }
+ },
+
+
+ // View Construction
+
+ _rebuildVisibleTypes() {
+ // Reset the list of visible types and the visible type description counts.
+ this._visibleTypes = [];
+ this._visibleTypeDescriptionCount = {};
+
+ // Get the preferences that help determine what types to show.
+ var showPlugins = this._prefSvc.getBoolPref(PREF_SHOW_PLUGINS_IN_LIST);
+ var hidePluginsWithoutExtensions =
+ this._prefSvc.getBoolPref(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS);
+
+ for (let type in this._handledTypes) {
+ let handlerInfo = this._handledTypes[type];
+
+ // Hide plugins without associated extensions if so prefed so we don't
+ // show a whole bunch of obscure types handled by plugins on Mac.
+ // Note: though protocol types don't have extensions, we still show them;
+ // the pref is only meant to be applied to MIME types, since plugins are
+ // only associated with MIME types.
+ // FIXME: should we also check the "suffixes" property of the plugin?
+ // Filed as bug 395135.
+ if (hidePluginsWithoutExtensions && handlerInfo.handledOnlyByPlugin &&
+ handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
+ !handlerInfo.primaryExtension)
+ continue;
+
+ // Hide types handled only by plugins if so prefed.
+ if (handlerInfo.handledOnlyByPlugin && !showPlugins)
+ continue;
+
+ // We couldn't find any reason to exclude the type, so include it.
+ this._visibleTypes.push(handlerInfo);
+
+ if (handlerInfo.description in this._visibleTypeDescriptionCount)
+ this._visibleTypeDescriptionCount[handlerInfo.description]++;
+ else
+ this._visibleTypeDescriptionCount[handlerInfo.description] = 1;
+ }
+ },
+
+ _rebuildView() {
+ // Clear the list of entries.
+ while (this._list.childNodes.length > 1)
+ this._list.removeChild(this._list.lastChild);
+
+ var visibleTypes = this._visibleTypes;
+
+ // If the user is filtering the list, then only show matching types.
+ if (this._filter.value)
+ visibleTypes = visibleTypes.filter(this._matchesFilter, this);
+
+ for (let visibleType of visibleTypes) {
+ let item = document.createElement("richlistitem");
+ item.setAttribute("type", visibleType.type);
+ item.setAttribute("typeDescription", this._describeType(visibleType));
+ if (visibleType.smallIcon)
+ item.setAttribute("typeIcon", visibleType.smallIcon);
+ item.setAttribute("actionDescription",
+ this._describePreferredAction(visibleType));
+
+ if (!this._setIconClassForPreferredAction(visibleType, item)) {
+ item.setAttribute("actionIcon",
+ this._getIconURLForPreferredAction(visibleType));
+ }
+
+ this._list.appendChild(item);
+ }
+
+ this._selectLastSelectedType();
+ },
+
+ _matchesFilter(aType) {
+ var filterValue = this._filter.value.toLowerCase();
+ return this._describeType(aType).toLowerCase().indexOf(filterValue) != -1 ||
+ this._describePreferredAction(aType).toLowerCase().indexOf(filterValue) != -1;
+ },
+
+ /**
+ * Describe, in a human-readable fashion, the type represented by the given
+ * handler info object. Normally this is just the description provided by
+ * the info object, but if more than one object presents the same description,
+ * then we annotate the duplicate descriptions with the type itself to help
+ * users distinguish between those types.
+ *
+ * @param aHandlerInfo {nsIHandlerInfo} the type being described
+ * @returns {string} a description of the type
+ */
+ _describeType(aHandlerInfo) {
+ if (this._visibleTypeDescriptionCount[aHandlerInfo.description] > 1)
+ return this._prefsBundle.getFormattedString("typeDescriptionWithType",
+ [aHandlerInfo.description,
+ aHandlerInfo.type]);
+
+ return aHandlerInfo.description;
+ },
+
+ /**
+ * Describe, in a human-readable fashion, the preferred action to take on
+ * the type represented by the given handler info object.
+ *
+ * XXX Should this be part of the HandlerInfoWrapper interface? It would
+ * violate the separation of model and view, but it might make more sense
+ * nonetheless (f.e. it would make sortTypes easier).
+ *
+ * @param aHandlerInfo {nsIHandlerInfo} the type whose preferred action
+ * is being described
+ * @returns {string} a description of the action
+ */
+ _describePreferredAction(aHandlerInfo) {
+ // alwaysAskBeforeHandling overrides the preferred action, so if that flag
+ // is set, then describe that behavior instead. For most types, this is
+ // the "alwaysAsk" string, but for the feed type we show something special.
+ if (aHandlerInfo.alwaysAskBeforeHandling) {
+ if (isFeedType(aHandlerInfo.type))
+ return this._prefsBundle.getFormattedString("previewInApp",
+ [this._brandShortName]);
+ return this._prefsBundle.getString("alwaysAsk");
+ }
+
+ switch (aHandlerInfo.preferredAction) {
+ case Ci.nsIHandlerInfo.saveToDisk:
+ return this._prefsBundle.getString("saveFile");
+
+ case Ci.nsIHandlerInfo.useHelperApp:
+ var preferredApp = aHandlerInfo.preferredApplicationHandler;
+ var name;
+ if (preferredApp instanceof Ci.nsILocalHandlerApp)
+ name = getFileDisplayName(preferredApp.executable);
+ else
+ name = preferredApp.name;
+ return this._prefsBundle.getFormattedString("useApp", [name]);
+
+ case Ci.nsIHandlerInfo.handleInternally:
+ // For the feed type, handleInternally means live bookmarks.
+ if (isFeedType(aHandlerInfo.type)) {
+ return this._prefsBundle.getFormattedString("addLiveBookmarksInApp",
+ [this._brandShortName]);
+ }
+
+ if (aHandlerInfo instanceof InternalHandlerInfoWrapper) {
+ return this._prefsBundle.getFormattedString("previewInApp",
+ [this._brandShortName]);
+ }
+
+ // For other types, handleInternally looks like either useHelperApp
+ // or useSystemDefault depending on whether or not there's a preferred
+ // handler app.
+ if (this.isValidHandlerApp(aHandlerInfo.preferredApplicationHandler))
+ return aHandlerInfo.preferredApplicationHandler.name;
+
+ return aHandlerInfo.defaultDescription;
+
+ // XXX Why don't we say the app will handle the type internally?
+ // Is it because the app can't actually do that? But if that's true,
+ // then why would a preferredAction ever get set to this value
+ // in the first place?
+
+ case Ci.nsIHandlerInfo.useSystemDefault:
+ return this._prefsBundle.getFormattedString("useDefault",
+ [aHandlerInfo.defaultDescription]);
+
+ case kActionUsePlugin:
+ return this._prefsBundle.getFormattedString("usePluginIn",
+ [aHandlerInfo.pluginName,
+ this._brandShortName]);
+ default:
+ throw new Error(`Unexpected preferredAction: ${aHandlerInfo.preferredAction}`);
+ }
+ },
+
+ _selectLastSelectedType() {
+ // If the list is disabled by the pref.downloads.disable_button.edit_actions
+ // preference being locked, then don't select the type, as that would cause
+ // it to appear selected, with a different background and an actions menu
+ // that makes it seem like you can choose an action for the type.
+ if (this._list.disabled)
+ return;
+
+ var lastSelectedType = this._list.getAttribute("lastSelectedType");
+ if (!lastSelectedType)
+ return;
+
+ var item = this._list.getElementsByAttribute("type", lastSelectedType)[0];
+ if (!item)
+ return;
+
+ this._list.selectedItem = item;
+ },
+
+ /**
+ * Whether or not the given handler app is valid.
+ *
+ * @param aHandlerApp {nsIHandlerApp} the handler app in question
+ *
+ * @returns {boolean} whether or not it's valid
+ */
+ isValidHandlerApp(aHandlerApp) {
+ if (!aHandlerApp)
+ return false;
+
+ if (aHandlerApp instanceof Ci.nsILocalHandlerApp)
+ return this._isValidHandlerExecutable(aHandlerApp.executable);
+
+ if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
+ return aHandlerApp.uriTemplate;
+
+ if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
+ return aHandlerApp.uri;
+
+ return false;
+ },
+
+ _isValidHandlerExecutable(aExecutable) {
+ let leafName;
+ if (AppConstants.platform == "win") {
+ leafName = `${AppConstants.MOZ_APP_NAME}.exe`;
+ } else if (AppConstants.platform == "macosx") {
+ leafName = AppConstants.MOZ_MACBUNDLE_NAME;
+ } else {
+ leafName = `${AppConstants.MOZ_APP_NAME}-bin`;
+ }
+ return aExecutable &&
+ aExecutable.exists() &&
+ aExecutable.isExecutable() &&
+// XXXben - we need to compare this with the running instance executable
+// just don't know how to do that via script...
+// XXXmano TBD: can probably add this to nsIShellService
+ aExecutable.leafName != leafName;
+ },
+
+ /**
+ * Rebuild the actions menu for the selected entry. Gets called by
+ * the richlistitem constructor when an entry in the list gets selected.
+ */
+ rebuildActionsMenu() {
+ var typeItem = this._list.selectedItem;
+ var handlerInfo = this._handledTypes[typeItem.type];
+ var menu =
+ document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
+ var menuPopup = menu.menupopup;
+
+ // Clear out existing items.
+ while (menuPopup.hasChildNodes())
+ menuPopup.removeChild(menuPopup.lastChild);
+
+ let internalMenuItem;
+ // Add the "Preview in Firefox" option for optional internal handlers.
+ if (handlerInfo instanceof InternalHandlerInfoWrapper) {
+ internalMenuItem = document.createElement("menuitem");
+ internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
+ let label = this._prefsBundle.getFormattedString("previewInApp",
+ [this._brandShortName]);
+ internalMenuItem.setAttribute("label", label);
+ internalMenuItem.setAttribute("tooltiptext", label);
+ internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask");
+ menuPopup.appendChild(internalMenuItem);
+ }
+
+ {
+ var askMenuItem = document.createElement("menuitem");
+ askMenuItem.setAttribute("action", Ci.nsIHandlerInfo.alwaysAsk);
+ let label;
+ if (isFeedType(handlerInfo.type))
+ label = this._prefsBundle.getFormattedString("previewInApp",
+ [this._brandShortName]);
+ else
+ label = this._prefsBundle.getString("alwaysAsk");
+ askMenuItem.setAttribute("label", label);
+ askMenuItem.setAttribute("tooltiptext", label);
+ askMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask");
+ menuPopup.appendChild(askMenuItem);
+ }
+
+ // Create a menu item for saving to disk.
+ // Note: this option isn't available to protocol types, since we don't know
+ // what it means to save a URL having a certain scheme to disk, nor is it
+ // available to feeds, since the feed code doesn't implement the capability.
+ if ((handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) &&
+ !isFeedType(handlerInfo.type)) {
+ var saveMenuItem = document.createElement("menuitem");
+ saveMenuItem.setAttribute("action", Ci.nsIHandlerInfo.saveToDisk);
+ let label = this._prefsBundle.getString("saveFile");
+ saveMenuItem.setAttribute("label", label);
+ saveMenuItem.setAttribute("tooltiptext", label);
+ saveMenuItem.setAttribute(APP_ICON_ATTR_NAME, "save");
+ menuPopup.appendChild(saveMenuItem);
+ }
+
+ // If this is the feed type, add a Live Bookmarks item.
+ if (isFeedType(handlerInfo.type)) {
+ internalMenuItem = document.createElement("menuitem");
+ internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
+ let label = this._prefsBundle.getFormattedString("addLiveBookmarksInApp",
+ [this._brandShortName]);
+ internalMenuItem.setAttribute("label", label);
+ internalMenuItem.setAttribute("tooltiptext", label);
+ internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "feed");
+ menuPopup.appendChild(internalMenuItem);
+ }
+
+ // Add a separator to distinguish these items from the helper app items
+ // that follow them.
+ let menuseparator = document.createElement("menuseparator");
+ menuPopup.appendChild(menuseparator);
+
+ // Create a menu item for the OS default application, if any.
+ if (handlerInfo.hasDefaultHandler) {
+ var defaultMenuItem = document.createElement("menuitem");
+ defaultMenuItem.setAttribute("action", Ci.nsIHandlerInfo.useSystemDefault);
+ let label = this._prefsBundle.getFormattedString("useDefault",
+ [handlerInfo.defaultDescription]);
+ defaultMenuItem.setAttribute("label", label);
+ defaultMenuItem.setAttribute("tooltiptext", handlerInfo.defaultDescription);
+ defaultMenuItem.setAttribute("image", this._getIconURLForSystemDefault(handlerInfo));
+
+ menuPopup.appendChild(defaultMenuItem);
+ }
+
+ // Create menu items for possible handlers.
+ let preferredApp = handlerInfo.preferredApplicationHandler;
+ let possibleApps = handlerInfo.possibleApplicationHandlers.enumerate();
+ var possibleAppMenuItems = [];
+ while (possibleApps.hasMoreElements()) {
+ let possibleApp = possibleApps.getNext();
+ if (!this.isValidHandlerApp(possibleApp))
+ continue;
+
+ let menuItem = document.createElement("menuitem");
+ menuItem.setAttribute("action", Ci.nsIHandlerInfo.useHelperApp);
+ let label;
+ if (possibleApp instanceof Ci.nsILocalHandlerApp)
+ label = getFileDisplayName(possibleApp.executable);
+ else
+ label = possibleApp.name;
+ label = this._prefsBundle.getFormattedString("useApp", [label]);
+ menuItem.setAttribute("label", label);
+ menuItem.setAttribute("tooltiptext", label);
+ menuItem.setAttribute("image", this._getIconURLForHandlerApp(possibleApp));
+
+ // Attach the handler app object to the menu item so we can use it
+ // to make changes to the datastore when the user selects the item.
+ menuItem.handlerApp = possibleApp;
+
+ menuPopup.appendChild(menuItem);
+ possibleAppMenuItems.push(menuItem);
+ }
+
+ // Create a menu item for the plugin.
+ if (handlerInfo.pluginName) {
+ var pluginMenuItem = document.createElement("menuitem");
+ pluginMenuItem.setAttribute("action", kActionUsePlugin);
+ let label = this._prefsBundle.getFormattedString("usePluginIn",
+ [handlerInfo.pluginName,
+ this._brandShortName]);
+ pluginMenuItem.setAttribute("label", label);
+ pluginMenuItem.setAttribute("tooltiptext", label);
+ pluginMenuItem.setAttribute(APP_ICON_ATTR_NAME, "plugin");
+ menuPopup.appendChild(pluginMenuItem);
+ }
+
+ // Create a menu item for selecting a local application.
+ let canOpenWithOtherApp = true;
+ if (AppConstants.platform == "win") {
+ // On Windows, selecting an application to open another application
+ // would be meaningless so we special case executables.
+ let executableType = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService)
+ .getTypeFromExtension("exe");
+ canOpenWithOtherApp = handlerInfo.type != executableType;
+ }
+ if (canOpenWithOtherApp) {
+ let menuItem = document.createElement("menuitem");
+ menuItem.className = "choose-app-item";
+ menuItem.addEventListener("command", function(e) {
+ gMainPane.chooseApp(e);
+ });
+ let label = this._prefsBundle.getString("useOtherApp");
+ menuItem.setAttribute("label", label);
+ menuItem.setAttribute("tooltiptext", label);
+ menuPopup.appendChild(menuItem);
+ }
+
+ // Create a menu item for managing applications.
+ if (possibleAppMenuItems.length) {
+ let menuItem = document.createElement("menuseparator");
+ menuPopup.appendChild(menuItem);
+ menuItem = document.createElement("menuitem");
+ menuItem.className = "manage-app-item";
+ menuItem.addEventListener("command", function(e) {
+ gMainPane.manageApp(e);
+ });
+ menuItem.setAttribute("label", this._prefsBundle.getString("manageApp"));
+ menuPopup.appendChild(menuItem);
+ }
+
+ // Select the item corresponding to the preferred action. If the always
+ // ask flag is set, it overrides the preferred action. Otherwise we pick
+ // the item identified by the preferred action (when the preferred action
+ // is to use a helper app, we have to pick the specific helper app item).
+ if (handlerInfo.alwaysAskBeforeHandling)
+ menu.selectedItem = askMenuItem;
+ else switch (handlerInfo.preferredAction) {
+ case Ci.nsIHandlerInfo.handleInternally:
+ if (internalMenuItem) {
+ menu.selectedItem = internalMenuItem;
+ } else {
+ Cu.reportError("No menu item defined to set!")
}
break;
- case "command":
- switch (aEvent.target.id) {
- case "":
- if (aEvent.target.parentNode &&
- aEvent.target.parentNode.parentNode &&
- aEvent.target.parentNode.parentNode.id == "defaultEngine") {
- gMainPane.setDefaultEngine();
- }
- break;
- case "restoreDefaultSearchEngines":
- gMainPane.onRestoreDefaults();
- break;
- case "removeEngineButton":
- Services.search.removeEngine(gEngineView.selectedEngine.originalEngine);
- break;
- }
+ case Ci.nsIHandlerInfo.useSystemDefault:
+ menu.selectedItem = defaultMenuItem;
break;
- case "dragstart":
- if (aEvent.target.id == "engineChildren") {
- onDragEngineStart(aEvent);
- }
- break;
- case "keypress":
- if (aEvent.target.id == "engineList") {
- gMainPane.onTreeKeyPress(aEvent);
- }
+ case Ci.nsIHandlerInfo.useHelperApp:
+ if (preferredApp)
+ menu.selectedItem =
+ possibleAppMenuItems.filter(v => v.handlerApp.equals(preferredApp))[0];
break;
- case "select":
- if (aEvent.target.id == "engineList") {
- gMainPane.onTreeSelect();
- }
+ case kActionUsePlugin:
+ menu.selectedItem = pluginMenuItem;
break;
- case "blur":
- if (aEvent.target.id == "engineList" &&
- aEvent.target.inputField == document.getBindingParent(aEvent.originalTarget)) {
- gMainPane.onInputBlur();
- }
+ case Ci.nsIHandlerInfo.saveToDisk:
+ menu.selectedItem = saveMenuItem;
break;
}
},
- observe(aEngine, aTopic, aVerb) {
- if (aTopic == "browser-search-engine-modified") {
- aEngine.QueryInterface(Components.interfaces.nsISearchEngine);
- switch (aVerb) {
- case "engine-added":
- gEngineView._engineStore.addEngine(aEngine);
- gEngineView.rowCountChanged(gEngineView.lastIndex, 1);
- gMainPane.buildDefaultEngineDropDown();
+
+ // Sorting & Filtering
+
+ _sortColumn: null,
+
+ /**
+ * Sort the list when the user clicks on a column header.
+ */
+ sort(event) {
+ var column = event.target;
+
+ // If the user clicked on a new sort column, remove the direction indicator
+ // from the old column.
+ if (this._sortColumn && this._sortColumn != column)
+ this._sortColumn.removeAttribute("sortDirection");
+
+ this._sortColumn = column;
+
+ // Set (or switch) the sort direction indicator.
+ if (column.getAttribute("sortDirection") == "ascending")
+ column.setAttribute("sortDirection", "descending");
+ else
+ column.setAttribute("sortDirection", "ascending");
+
+ this._sortVisibleTypes();
+ this._rebuildView();
+ },
+
+ /**
+ * Sort the list of visible types by the current sort column/direction.
+ */
+ _sortVisibleTypes() {
+ if (!this._sortColumn)
+ return;
+
+ var t = this;
+
+ function sortByType(a, b) {
+ return t._describeType(a).toLowerCase().
+ localeCompare(t._describeType(b).toLowerCase());
+ }
+
+ function sortByAction(a, b) {
+ return t._describePreferredAction(a).toLowerCase().
+ localeCompare(t._describePreferredAction(b).toLowerCase());
+ }
+
+ switch (this._sortColumn.getAttribute("value")) {
+ case "type":
+ this._visibleTypes.sort(sortByType);
+ break;
+ case "action":
+ this._visibleTypes.sort(sortByAction);
break;
- case "engine-changed":
- gEngineView._engineStore.reloadIcons();
- gEngineView.invalidate();
+ }
+
+ if (this._sortColumn.getAttribute("sortDirection") == "descending")
+ this._visibleTypes.reverse();
+ },
+
+ /**
+ * Filter the list when the user enters a filter term into the filter field.
+ */
+ filter() {
+ this._rebuildView();
+ },
+
+ focusFilterBox() {
+ this._filter.focus();
+ this._filter.select();
+ },
+
+
+ // Changes
+
+ onSelectAction(aActionItem) {
+ this._storingAction = true;
+
+ try {
+ this._storeAction(aActionItem);
+ } finally {
+ this._storingAction = false;
+ }
+ },
+
+ _storeAction(aActionItem) {
+ var typeItem = this._list.selectedItem;
+ var handlerInfo = this._handledTypes[typeItem.type];
+
+ let action = parseInt(aActionItem.getAttribute("action"));
+
+ // Set the plugin state if we're enabling or disabling a plugin.
+ if (action == kActionUsePlugin)
+ handlerInfo.enablePluginType();
+ else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
+ handlerInfo.disablePluginType();
+
+ // Set the preferred application handler.
+ // We leave the existing preferred app in the list when we set
+ // the preferred action to something other than useHelperApp so that
+ // legacy datastores that don't have the preferred app in the list
+ // of possible apps still include the preferred app in the list of apps
+ // the user can choose to handle the type.
+ if (action == Ci.nsIHandlerInfo.useHelperApp)
+ handlerInfo.preferredApplicationHandler = aActionItem.handlerApp;
+
+ // Set the "always ask" flag.
+ if (action == Ci.nsIHandlerInfo.alwaysAsk)
+ handlerInfo.alwaysAskBeforeHandling = true;
+ else
+ handlerInfo.alwaysAskBeforeHandling = false;
+
+ // Set the preferred action.
+ handlerInfo.preferredAction = action;
+
+ handlerInfo.store();
+
+ // Make sure the handler info object is flagged to indicate that there is
+ // now some user configuration for the type.
+ handlerInfo.handledOnlyByPlugin = false;
+
+ // Update the action label and image to reflect the new preferred action.
+ typeItem.setAttribute("actionDescription",
+ this._describePreferredAction(handlerInfo));
+ if (!this._setIconClassForPreferredAction(handlerInfo, typeItem)) {
+ typeItem.setAttribute("actionIcon",
+ this._getIconURLForPreferredAction(handlerInfo));
+ }
+ },
+
+ manageApp(aEvent) {
+ // Don't let the normal "on select action" handler get this event,
+ // as we handle it specially ourselves.
+ aEvent.stopPropagation();
+
+ var typeItem = this._list.selectedItem;
+ var handlerInfo = this._handledTypes[typeItem.type];
+
+ let onComplete = () => {
+ // Rebuild the actions menu so that we revert to the previous selection,
+ // or "Always ask" if the previous default application has been removed
+ this.rebuildActionsMenu();
+
+ // update the richlistitem too. Will be visible when selecting another row
+ typeItem.setAttribute("actionDescription",
+ this._describePreferredAction(handlerInfo));
+ if (!this._setIconClassForPreferredAction(handlerInfo, typeItem)) {
+ typeItem.setAttribute("actionIcon",
+ this._getIconURLForPreferredAction(handlerInfo));
+ }
+ };
+
+ gSubDialog.open("chrome://browser/content/preferences/applicationManager.xul",
+ "resizable=no", handlerInfo, onComplete);
+
+ },
+
+ chooseApp(aEvent) {
+ // Don't let the normal "on select action" handler get this event,
+ // as we handle it specially ourselves.
+ aEvent.stopPropagation();
+
+ var handlerApp;
+ let chooseAppCallback = aHandlerApp => {
+ // Rebuild the actions menu whether the user picked an app or canceled.
+ // If they picked an app, we want to add the app to the menu and select it.
+ // If they canceled, we want to go back to their previous selection.
+ this.rebuildActionsMenu();
+
+ // If the user picked a new app from the menu, select it.
+ if (aHandlerApp) {
+ let typeItem = this._list.selectedItem;
+ let actionsMenu =
+ document.getAnonymousElementByAttribute(typeItem, "class", "actionsMenu");
+ let menuItems = actionsMenu.menupopup.childNodes;
+ for (let i = 0; i < menuItems.length; i++) {
+ let menuItem = menuItems[i];
+ if (menuItem.handlerApp && menuItem.handlerApp.equals(aHandlerApp)) {
+ actionsMenu.selectedIndex = i;
+ this.onSelectAction(menuItem);
+ break;
+ }
+ }
+ }
+ };
+
+ if (AppConstants.platform == "win") {
+ var params = {};
+ var handlerInfo = this._handledTypes[this._list.selectedItem.type];
+
+ if (isFeedType(handlerInfo.type)) {
+ // MIME info will be null, create a temp object.
+ params.mimeInfo = this._mimeSvc.getFromTypeAndExtension(handlerInfo.type,
+ handlerInfo.primaryExtension);
+ } else {
+ params.mimeInfo = handlerInfo.wrappedHandlerInfo;
+ }
+
+ params.title = this._prefsBundle.getString("fpTitleChooseApp");
+ params.description = handlerInfo.description;
+ params.filename = null;
+ params.handlerApp = null;
+
+ let onAppSelected = () => {
+ if (this.isValidHandlerApp(params.handlerApp)) {
+ handlerApp = params.handlerApp;
+
+ // Add the app to the type's list of possible handlers.
+ handlerInfo.addPossibleApplicationHandler(handlerApp);
+ }
+
+ chooseAppCallback(handlerApp);
+ };
+
+ gSubDialog.open("chrome://global/content/appPicker.xul",
+ null, params, onAppSelected);
+ } else {
+ let winTitle = this._prefsBundle.getString("fpTitleChooseApp");
+ let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
+ let fpCallback = aResult => {
+ if (aResult == Ci.nsIFilePicker.returnOK && fp.file &&
+ this._isValidHandlerExecutable(fp.file)) {
+ handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+ createInstance(Ci.nsILocalHandlerApp);
+ handlerApp.name = getFileDisplayName(fp.file);
+ handlerApp.executable = fp.file;
+
+ // Add the app to the type's list of possible handlers.
+ let handler = this._handledTypes[this._list.selectedItem.type];
+ handler.addPossibleApplicationHandler(handlerApp);
+
+ chooseAppCallback(handlerApp);
+ }
+ };
+
+ // 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.appendFilters(Ci.nsIFilePicker.filterApps);
+ fp.open(fpCallback);
+ }
+ },
+
+ // Mark which item in the list was last selected so we can reselect it
+ // when we rebuild the list or when the user returns to the prefpane.
+ onSelectionChanged() {
+ if (this._list.selectedItem)
+ this._list.setAttribute("lastSelectedType",
+ this._list.selectedItem.getAttribute("type"));
+ },
+
+ _setIconClassForPreferredAction(aHandlerInfo, aElement) {
+ // If this returns true, the attribute that CSS sniffs for was set to something
+ // so you shouldn't manually set an icon URI.
+ // This removes the existing actionIcon attribute if any, even if returning false.
+ aElement.removeAttribute("actionIcon");
+
+ if (aHandlerInfo.alwaysAskBeforeHandling) {
+ aElement.setAttribute(APP_ICON_ATTR_NAME, "ask");
+ return true;
+ }
+
+ switch (aHandlerInfo.preferredAction) {
+ case Ci.nsIHandlerInfo.saveToDisk:
+ aElement.setAttribute(APP_ICON_ATTR_NAME, "save");
+ return true;
+
+ case Ci.nsIHandlerInfo.handleInternally:
+ if (isFeedType(aHandlerInfo.type)) {
+ aElement.setAttribute(APP_ICON_ATTR_NAME, "feed");
+ return true;
+ } else if (aHandlerInfo instanceof InternalHandlerInfoWrapper) {
+ aElement.setAttribute(APP_ICON_ATTR_NAME, "ask");
+ return true;
+ }
break;
- case "engine-removed":
- gMainPane.remove(aEngine);
- break;
- case "engine-current":
- // If the user is going through the drop down using up/down keys, the
- // dropdown may still be open (eg. on Windows) when engine-current is
- // fired, so rebuilding the list unconditionally would get in the way.
- let selectedEngine =
- document.getElementById("defaultEngine").selectedItem.engine;
- if (selectedEngine.name != aEngine.name)
- gMainPane.buildDefaultEngineDropDown();
- break;
- case "engine-default":
- // Not relevant
+
+ case kActionUsePlugin:
+ aElement.setAttribute(APP_ICON_ATTR_NAME, "plugin");
+ return true;
+ }
+ aElement.removeAttribute(APP_ICON_ATTR_NAME);
+ return false;
+ },
+
+ _getIconURLForPreferredAction(aHandlerInfo) {
+ switch (aHandlerInfo.preferredAction) {
+ case Ci.nsIHandlerInfo.useSystemDefault:
+ return this._getIconURLForSystemDefault(aHandlerInfo);
+
+ case Ci.nsIHandlerInfo.useHelperApp:
+ let preferredApp = aHandlerInfo.preferredApplicationHandler;
+ if (this.isValidHandlerApp(preferredApp))
+ return this._getIconURLForHandlerApp(preferredApp);
+ // Explicit fall-through
+
+ // This should never happen, but if preferredAction is set to some weird
+ // value, then fall back to the generic application icon.
+ default:
+ return ICON_URL_APP;
+ }
+ },
+
+ _getIconURLForHandlerApp(aHandlerApp) {
+ if (aHandlerApp instanceof Ci.nsILocalHandlerApp)
+ return this._getIconURLForFile(aHandlerApp.executable);
+
+ if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
+ return this._getIconURLForWebApp(aHandlerApp.uriTemplate);
+
+ if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
+ return this._getIconURLForWebApp(aHandlerApp.uri)
+
+ // We know nothing about other kinds of handler apps.
+ return "";
+ },
+
+ _getIconURLForFile(aFile) {
+ var fph = this._ioSvc.getProtocolHandler("file").
+ QueryInterface(Ci.nsIFileProtocolHandler);
+ var urlSpec = fph.getURLSpecFromFile(aFile);
+
+ return "moz-icon://" + urlSpec + "?size=16";
+ },
+
+ _getIconURLForWebApp(aWebAppURITemplate) {
+ var uri = this._ioSvc.newURI(aWebAppURITemplate);
+
+ // Unfortunately we can't use the favicon service to get the favicon,
+ // because the service looks in the annotations table for a record with
+ // the exact URL we give it, and users won't have such records for URLs
+ // they don't visit, and users won't visit the web app's URL template,
+ // they'll only visit URLs derived from that template (i.e. with %s
+ // in the template replaced by the URL of the content being handled).
+
+ if (/^https?$/.test(uri.scheme) && this._prefSvc.getBoolPref("browser.chrome.favicons"))
+ return uri.prePath + "/favicon.ico";
+
+ return "";
+ },
+
+ _getIconURLForSystemDefault(aHandlerInfo) {
+ // Handler info objects for MIME types on some OSes implement a property bag
+ // interface from which we can get an icon for the default app, so if we're
+ // dealing with a MIME type on one of those OSes, then try to get the icon.
+ if ("wrappedHandlerInfo" in aHandlerInfo) {
+ let wrappedHandlerInfo = aHandlerInfo.wrappedHandlerInfo;
+
+ if (wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
+ wrappedHandlerInfo instanceof Ci.nsIPropertyBag) {
+ try {
+ let url = wrappedHandlerInfo.getProperty("defaultApplicationIconURL");
+ if (url)
+ return url + "?size=16";
+ } catch (ex) {}
+ }
+ }
+
+ // If this isn't a MIME type object on an OS that supports retrieving
+ // the icon, or if we couldn't retrieve the icon for some other reason,
+ // then use a generic icon.
+ return ICON_URL_APP;
+ },
+
+ // DOWNLOADS
+
+ /*
+ * Preferences:
+ *
+ * browser.download.useDownloadDir - bool
+ * True - Save files directly to the folder configured via the
+ * browser.download.folderList preference.
+ * False - Always ask the user where to save a file and default to
+ * browser.download.lastDir when displaying a folder picker dialog.
+ * browser.download.dir - local file handle
+ * A local folder the user may have selected for downloaded files to be
+ * saved. Migration of other browser settings may also set this path.
+ * This folder is enabled when folderList equals 2.
+ * browser.download.lastDir - local file handle
+ * May contain the last folder path accessed when the user browsed
+ * via the file save-as dialog. (see contentAreaUtils.js)
+ * browser.download.folderList - int
+ * Indicates the location users wish to save downloaded files too.
+ * It is also used to display special file labels when the default
+ * download location is either the Desktop or the Downloads folder.
+ * Values:
+ * 0 - The desktop is the default download location.
+ * 1 - The system's downloads folder is the default download location.
+ * 2 - The default download location is elsewhere as specified in
+ * browser.download.dir.
+ * browser.download.downloadDir
+ * deprecated.
+ * browser.download.defaultFolder
+ * deprecated.
+ */
+
+ /**
+ * Enables/disables the folder field and Browse button based on whether a
+ * default download directory is being used.
+ */
+ readUseDownloadDir() {
+ var downloadFolder = document.getElementById("downloadFolder");
+ var chooseFolder = document.getElementById("chooseFolder");
+ var preference = document.getElementById("browser.download.useDownloadDir");
+ downloadFolder.disabled = !preference.value || preference.locked;
+ chooseFolder.disabled = !preference.value || preference.locked;
+
+ // don't override the preference's value in UI
+ return undefined;
+ },
+
+ /**
+ * Displays a file picker in which the user can choose the location where
+ * downloads are automatically saved, updating preferences and UI in
+ * response to the choice, if one is made.
+ */
+ chooseFolder() {
+ return this.chooseFolderTask().catch(Components.utils.reportError);
+ },
+ async chooseFolderTask() {
+ let bundlePreferences = document.getElementById("bundlePreferences");
+ let title = bundlePreferences.getString("chooseDownloadFolderTitle");
+ let folderListPref = document.getElementById("browser.download.folderList");
+ let currentDirPref = await this._indexToFolder(folderListPref.value);
+ let defDownloads = await this._indexToFolder(1);
+ let fp = Components.classes["@mozilla.org/filepicker;1"].
+ createInstance(Components.interfaces.nsIFilePicker);
+
+ fp.init(window, title, Components.interfaces.nsIFilePicker.modeGetFolder);
+ fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
+ // First try to open what's currently configured
+ if (currentDirPref && currentDirPref.exists()) {
+ fp.displayDirectory = currentDirPref;
+ } else if (defDownloads && defDownloads.exists()) {
+ // Try the system's download dir
+ fp.displayDirectory = defDownloads;
+ } else {
+ // Fall back to Desktop
+ fp.displayDirectory = await this._indexToFolder(0);
+ }
+
+ let result = await new Promise(resolve => fp.open(resolve));
+ if (result != Components.interfaces.nsIFilePicker.returnOK) {
+ return;
+ }
+
+ let downloadDirPref = document.getElementById("browser.download.dir");
+ downloadDirPref.value = fp.file;
+ folderListPref.value = await this._folderToIndex(fp.file);
+ // Note, the real prefs will not be updated yet, so dnld manager's
+ // userDownloadsDirectory may not return the right folder after
+ // this code executes. displayDownloadDirPref will be called on
+ // the assignment above to update the UI.
+ },
+
+ /**
+ * Initializes the download folder display settings based on the user's
+ * preferences.
+ */
+ displayDownloadDirPref() {
+ this.displayDownloadDirPrefTask().catch(Components.utils.reportError);
+
+ // don't override the preference's value in UI
+ return undefined;
+ },
+
+ async displayDownloadDirPrefTask() {
+ var folderListPref = document.getElementById("browser.download.folderList");
+ var bundlePreferences = document.getElementById("bundlePreferences");
+ var downloadFolder = document.getElementById("downloadFolder");
+ var currentDirPref = document.getElementById("browser.download.dir");
+
+ // Used in defining the correct path to the folder icon.
+ var ios = Components.classes["@mozilla.org/network/io-service;1"]
+ .getService(Components.interfaces.nsIIOService);
+ var fph = ios.getProtocolHandler("file")
+ .QueryInterface(Components.interfaces.nsIFileProtocolHandler);
+ var iconUrlSpec;
+
+ // Display a 'pretty' label or the path in the UI.
+ if (folderListPref.value == 2) {
+ // Custom path selected and is configured
+ downloadFolder.label = this._getDisplayNameOfFile(currentDirPref.value);
+ iconUrlSpec = fph.getURLSpecFromFile(currentDirPref.value);
+ } else if (folderListPref.value == 1) {
+ // 'Downloads'
+ downloadFolder.label = bundlePreferences.getString("downloadsFolderName");
+ iconUrlSpec = fph.getURLSpecFromFile(await this._indexToFolder(1));
+ } else {
+ // 'Desktop'
+ downloadFolder.label = bundlePreferences.getString("desktopFolderName");
+ iconUrlSpec = fph.getURLSpecFromFile(await this._getDownloadsFolder("Desktop"));
+ }
+ downloadFolder.image = "moz-icon://" + iconUrlSpec + "?size=16";
+ },
+
+ /**
+ * Returns the textual path of a folder in readable form.
+ */
+ _getDisplayNameOfFile(aFolder) {
+ // TODO: would like to add support for 'Downloads on Macintosh HD'
+ // for OS X users.
+ return aFolder ? aFolder.path : "";
+ },
+
+ /**
+ * Returns the Downloads folder. If aFolder is "Desktop", then the Downloads
+ * folder returned is the desktop folder; otherwise, it is a folder whose name
+ * indicates that it is a download folder and whose path is as determined by
+ * the XPCOM directory service via the download manager's attribute
+ * defaultDownloadsDirectory.
+ *
+ * @throws if aFolder is not "Desktop" or "Downloads"
+ */
+ async _getDownloadsFolder(aFolder) {
+ switch (aFolder) {
+ case "Desktop":
+ var fileLoc = Components.classes["@mozilla.org/file/directory_service;1"]
+ .getService(Components.interfaces.nsIProperties);
+ return fileLoc.get("Desk", Components.interfaces.nsILocalFile);
+ case "Downloads":
+ let downloadsDir = await Downloads.getSystemDownloadsDirectory();
+ return new FileUtils.File(downloadsDir);
+ }
+ throw "ASSERTION FAILED: folder type should be 'Desktop' or 'Downloads'";
+ },
+
+ /**
+ * Determines the type of the given folder.
+ *
+ * @param aFolder
+ * the folder whose type is to be determined
+ * @returns integer
+ * 0 if aFolder is the Desktop or is unspecified,
+ * 1 if aFolder is the Downloads folder,
+ * 2 otherwise
+ */
+ async _folderToIndex(aFolder) {
+ if (!aFolder || aFolder.equals(await this._getDownloadsFolder("Desktop")))
+ return 0;
+ else if (aFolder.equals(await this._getDownloadsFolder("Downloads")))
+ return 1;
+ return 2;
+ },
+
+ /**
+ * Converts an integer into the corresponding folder.
+ *
+ * @param aIndex
+ * an integer
+ * @returns the Desktop folder if aIndex == 0,
+ * the Downloads folder if aIndex == 1,
+ * the folder stored in browser.download.dir
+ */
+ async _indexToFolder(aIndex) {
+ switch (aIndex) {
+ case 0:
+ return await this._getDownloadsFolder("Desktop");
+ case 1:
+ return await this._getDownloadsFolder("Downloads");
+ }
+ var currentDirPref = document.getElementById("browser.download.dir");
+ return currentDirPref.value;
+ }
+};
+
+// Utilities
+
+function getFileDisplayName(file) {
+ if (AppConstants.platform == "win") {
+ if (file instanceof Ci.nsILocalFileWin) {
+ try {
+ return file.getVersionInfoField("FileDescription");
+ } catch (e) {}
+ }
+ }
+ if (AppConstants.platform == "macosx") {
+ if (file instanceof Ci.nsILocalFileMac) {
+ try {
+ return file.bundleDisplayName;
+ } catch (e) {}
+ }
+ }
+ return file.leafName;
+}
+
+function getLocalHandlerApp(aFile) {
+ var localHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+ createInstance(Ci.nsILocalHandlerApp);
+ localHandlerApp.name = getFileDisplayName(aFile);
+ localHandlerApp.executable = aFile;
+
+ return localHandlerApp;
+}
+
+/**
+ * An enumeration of items in a JS array.
+ *
+ * FIXME: use ArrayConverter once it lands (bug 380839).
+ *
+ * @constructor
+ */
+function ArrayEnumerator(aItems) {
+ this._index = 0;
+ this._contents = aItems;
+}
+
+ArrayEnumerator.prototype = {
+ _index: 0,
+
+ hasMoreElements() {
+ return this._index < this._contents.length;
+ },
+
+ getNext() {
+ return this._contents[this._index++];
+ }
+};
+
+function isFeedType(t) {
+ return t == TYPE_MAYBE_FEED || t == TYPE_MAYBE_VIDEO_FEED || t == TYPE_MAYBE_AUDIO_FEED;
+}
+
+// HandlerInfoWrapper
+
+/**
+ * This object wraps nsIHandlerInfo with some additional functionality
+ * the Applications prefpane needs to display and allow modification of
+ * the list of handled types.
+ *
+ * We create an instance of this wrapper for each entry we might display
+ * in the prefpane, and we compose the instances from various sources,
+ * including plugins and the handler service.
+ *
+ * We don't implement all the original nsIHandlerInfo functionality,
+ * just the stuff that the prefpane needs.
+ *
+ * In theory, all of the custom functionality in this wrapper should get
+ * pushed down into nsIHandlerInfo eventually.
+ */
+function HandlerInfoWrapper(aType, aHandlerInfo) {
+ this._type = aType;
+ this.wrappedHandlerInfo = aHandlerInfo;
+}
+
+HandlerInfoWrapper.prototype = {
+ // The wrapped nsIHandlerInfo object. In general, this object is private,
+ // but there are a couple cases where callers access it directly for things
+ // we haven't (yet?) implemented, so we make it a public property.
+ wrappedHandlerInfo: null,
+
+
+ // Convenience Utils
+
+ _handlerSvc: Cc["@mozilla.org/uriloader/handler-service;1"].
+ getService(Ci.nsIHandlerService),
+
+ _prefSvc: Cc["@mozilla.org/preferences-service;1"].
+ getService(Ci.nsIPrefBranch),
+
+ _categoryMgr: Cc["@mozilla.org/categorymanager;1"].
+ getService(Ci.nsICategoryManager),
+
+ element(aID) {
+ return document.getElementById(aID);
+ },
+
+
+ // nsIHandlerInfo
+
+ // The MIME type or protocol scheme.
+ _type: null,
+ get type() {
+ return this._type;
+ },
+
+ get description() {
+ if (this.wrappedHandlerInfo.description)
+ return this.wrappedHandlerInfo.description;
+
+ if (this.primaryExtension) {
+ var extension = this.primaryExtension.toUpperCase();
+ return this.element("bundlePreferences").getFormattedString("fileEnding",
+ [extension]);
+ }
+
+ return this.type;
+ },
+
+ get preferredApplicationHandler() {
+ return this.wrappedHandlerInfo.preferredApplicationHandler;
+ },
+
+ set preferredApplicationHandler(aNewValue) {
+ this.wrappedHandlerInfo.preferredApplicationHandler = aNewValue;
+
+ // Make sure the preferred handler is in the set of possible handlers.
+ if (aNewValue)
+ this.addPossibleApplicationHandler(aNewValue)
+ },
+
+ get possibleApplicationHandlers() {
+ return this.wrappedHandlerInfo.possibleApplicationHandlers;
+ },
+
+ addPossibleApplicationHandler(aNewHandler) {
+ var possibleApps = this.possibleApplicationHandlers.enumerate();
+ while (possibleApps.hasMoreElements()) {
+ if (possibleApps.getNext().equals(aNewHandler))
+ return;
+ }
+ this.possibleApplicationHandlers.appendElement(aNewHandler);
+ },
+
+ removePossibleApplicationHandler(aHandler) {
+ var defaultApp = this.preferredApplicationHandler;
+ if (defaultApp && aHandler.equals(defaultApp)) {
+ // If the app we remove was the default app, we must make sure
+ // it won't be used anymore
+ this.alwaysAskBeforeHandling = true;
+ this.preferredApplicationHandler = null;
+ }
+
+ var handlers = this.possibleApplicationHandlers;
+ for (var i = 0; i < handlers.length; ++i) {
+ var handler = handlers.queryElementAt(i, Ci.nsIHandlerApp);
+ if (handler.equals(aHandler)) {
+ handlers.removeElementAt(i);
break;
}
}
},
- onInputBlur(aEvent) {
- let tree = document.getElementById("engineList");
- if (!tree.hasAttribute("editing"))
- return;
-
- // Accept input unless discarded.
- let accept = aEvent.charCode != KeyEvent.DOM_VK_ESCAPE;
- tree.stopEditing(accept);
+ get hasDefaultHandler() {
+ return this.wrappedHandlerInfo.hasDefaultHandler;
+ },
+
+ get defaultDescription() {
+ return this.wrappedHandlerInfo.defaultDescription;
+ },
+
+ // What to do with content of this type.
+ get preferredAction() {
+ // If we have an enabled plugin, then the action is to use that plugin.
+ if (this.pluginName && !this.isDisabledPluginType)
+ return kActionUsePlugin;
+
+ // If the action is to use a helper app, but we don't have a preferred
+ // handler app, then switch to using the system default, if any; otherwise
+ // fall back to saving to disk, which is the default action in nsMIMEInfo.
+ // Note: "save to disk" is an invalid value for protocol info objects,
+ // but the alwaysAskBeforeHandling getter will detect that situation
+ // and always return true in that case to override this invalid value.
+ if (this.wrappedHandlerInfo.preferredAction == Ci.nsIHandlerInfo.useHelperApp &&
+ !gMainPane.isValidHandlerApp(this.preferredApplicationHandler)) {
+ if (this.wrappedHandlerInfo.hasDefaultHandler)
+ return Ci.nsIHandlerInfo.useSystemDefault;
+ return Ci.nsIHandlerInfo.saveToDisk;
+ }
+
+ return this.wrappedHandlerInfo.preferredAction;
+ },
+
+ set preferredAction(aNewValue) {
+ // If the action is to use the plugin,
+ // we must set the preferred action to "save to disk".
+ // But only if it's not currently the preferred action.
+ if ((aNewValue == kActionUsePlugin) &&
+ (this.preferredAction != Ci.nsIHandlerInfo.saveToDisk)) {
+ aNewValue = Ci.nsIHandlerInfo.saveToDisk;
+ }
+
+ // We don't modify the preferred action if the new action is to use a plugin
+ // because handler info objects don't understand our custom "use plugin"
+ // value. Also, leaving it untouched means that we can automatically revert
+ // to the old setting if the user ever removes the plugin.
+
+ if (aNewValue != kActionUsePlugin)
+ this.wrappedHandlerInfo.preferredAction = aNewValue;
},
- onTreeSelect() {
- document.getElementById("removeEngineButton").disabled =
- !gEngineView.isEngineSelectedAndRemovable();
+ get alwaysAskBeforeHandling() {
+ // If this type is handled only by a plugin, we can't trust the value
+ // in the handler info object, since it'll be a default based on the absence
+ // of any user configuration, and the default in that case is to always ask,
+ // even though we never ask for content handled by a plugin, so special case
+ // plugin-handled types by returning false here.
+ if (this.pluginName && this.handledOnlyByPlugin)
+ return false;
+
+ // If this is a protocol type and the preferred action is "save to disk",
+ // which is invalid for such types, then return true here to override that
+ // action. This could happen when the preferred action is to use a helper
+ // app, but the preferredApplicationHandler is invalid, and there isn't
+ // a default handler, so the preferredAction getter returns save to disk
+ // instead.
+ if (!(this.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) &&
+ this.preferredAction == Ci.nsIHandlerInfo.saveToDisk)
+ return true;
+
+ return this.wrappedHandlerInfo.alwaysAskBeforeHandling;
+ },
+
+ set alwaysAskBeforeHandling(aNewValue) {
+ this.wrappedHandlerInfo.alwaysAskBeforeHandling = aNewValue;
+ },
+
+
+ // nsIMIMEInfo
+
+ // The primary file extension associated with this type, if any.
+ //
+ // XXX Plugin objects contain an array of MimeType objects with "suffixes"
+ // properties; if this object has an associated plugin, shouldn't we check
+ // those properties for an extension?
+ get primaryExtension() {
+ try {
+ if (this.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo &&
+ this.wrappedHandlerInfo.primaryExtension)
+ return this.wrappedHandlerInfo.primaryExtension
+ } catch (ex) {}
+
+ return null;
+ },
+
+
+ // Plugin Handling
+
+ // A plugin that can handle this type, if any.
+ //
+ // Note: just because we have one doesn't mean it *will* handle the type.
+ // That depends on whether or not the type is in the list of types for which
+ // plugin handling is disabled.
+ plugin: null,
+
+ // Whether or not this type is only handled by a plugin or is also handled
+ // by some user-configured action as specified in the handler info object.
+ //
+ // Note: we can't just check if there's a handler info object for this type,
+ // because OS and user configuration is mixed up in the handler info object,
+ // so we always need to retrieve it for the OS info and can't tell whether
+ // it represents only OS-default information or user-configured information.
+ //
+ // FIXME: once handler info records are broken up into OS-provided records
+ // and user-configured records, stop using this boolean flag and simply
+ // check for the presence of a user-configured record to determine whether
+ // or not this type is only handled by a plugin. Filed as bug 395142.
+ handledOnlyByPlugin: undefined,
+
+ get isDisabledPluginType() {
+ return this._getDisabledPluginTypes().indexOf(this.type) != -1;
+ },
+
+ _getDisabledPluginTypes() {
+ var types = "";
+
+ if (this._prefSvc.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES))
+ types = this._prefSvc.getCharPref(PREF_DISABLED_PLUGIN_TYPES);
+
+ // Only split if the string isn't empty so we don't end up with an array
+ // containing a single empty string.
+ if (types != "")
+ return types.split(",");
+
+ return [];
},
- 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._engineStore.engines[index].shown;
- 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)) {
- tree.startEditing(index, tree.columns.getLastColumn());
- } 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);
- }
+ disablePluginType() {
+ var disabledPluginTypes = this._getDisabledPluginTypes();
+
+ if (disabledPluginTypes.indexOf(this.type) == -1)
+ disabledPluginTypes.push(this.type);
+
+ this._prefSvc.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
+ disabledPluginTypes.join(","));
+
+ // Update the category manager so existing browser windows update.
+ this._categoryMgr.deleteCategoryEntry("Gecko-Content-Viewers",
+ this.type,
+ false);
+ },
+
+ enablePluginType() {
+ var disabledPluginTypes = this._getDisabledPluginTypes();
+
+ var type = this.type;
+ disabledPluginTypes = disabledPluginTypes.filter(v => v != type);
+
+ this._prefSvc.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
+ disabledPluginTypes.join(","));
+
+ // Update the category manager so existing browser windows update.
+ this._categoryMgr.
+ addCategoryEntry("Gecko-Content-Viewers",
+ this.type,
+ "@mozilla.org/content/plugin/document-loader-factory;1",
+ false,
+ true);
+ },
+
+
+ // Storage
+
+ store() {
+ this._handlerSvc.store(this.wrappedHandlerInfo);
+ },
+
+
+ // Icons
+
+ get smallIcon() {
+ return this._getIcon(16);
+ },
+
+ _getIcon(aSize) {
+ if (this.primaryExtension)
+ return "moz-icon://goat." + this.primaryExtension + "?size=" + aSize;
+
+ if (this.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo)
+ return "moz-icon://goat?size=" + aSize + "&contentType=" + this.type;
+
+ // FIXME: consider returning some generic icon when we can't get a URL for
+ // one (for example in the case of protocol schemes). Filed as bug 395141.
+ return null;
+ }
+
+};
+
+
+// Feed Handler Info
+
+/**
+ * This object implements nsIHandlerInfo for the feed types. It's a separate
+ * object because we currently store handling information for the feed type
+ * in a set of preferences rather than the nsIHandlerService-managed datastore.
+ *
+ * This object inherits from HandlerInfoWrapper in order to get functionality
+ * that isn't special to the feed type.
+ *
+ * XXX Should we inherit from HandlerInfoWrapper? After all, we override
+ * most of that wrapper's properties and methods, and we have to dance around
+ * the fact that the wrapper expects to have a wrappedHandlerInfo, which we
+ * don't provide.
+ */
+
+function FeedHandlerInfo(aMIMEType) {
+ HandlerInfoWrapper.call(this, aMIMEType, null);
+}
+
+FeedHandlerInfo.prototype = {
+ __proto__: HandlerInfoWrapper.prototype,
+
+ // Convenience Utils
+
+ _converterSvc:
+ Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
+ getService(Ci.nsIWebContentConverterService),
+
+ _shellSvc: AppConstants.HAVE_SHELL_SERVICE ? getShellService() : null,
+
+ // nsIHandlerInfo
+
+ get description() {
+ return this.element("bundlePreferences").getString(this._appPrefLabel);
+ },
+
+ get preferredApplicationHandler() {
+ switch (this.element(this._prefSelectedReader).value) {
+ case "client":
+ var file = this.element(this._prefSelectedApp).value;
+ if (file)
+ return getLocalHandlerApp(file);
+
+ return null;
+
+ case "web":
+ var uri = this.element(this._prefSelectedWeb).value;
+ if (!uri)
+ return null;
+ return this._converterSvc.getWebContentHandlerByURI(this.type, uri);
+
+ case "bookmarks":
+ default:
+ // When the pref is set to bookmarks, we handle feeds internally,
+ // we don't forward them to a local or web handler app, so there is
+ // no preferred handler.
+ return null;
+ }
+ },
+
+ set preferredApplicationHandler(aNewValue) {
+ if (aNewValue instanceof Ci.nsILocalHandlerApp) {
+ this.element(this._prefSelectedApp).value = aNewValue.executable;
+ this.element(this._prefSelectedReader).value = "client";
+ } else if (aNewValue instanceof Ci.nsIWebContentHandlerInfo) {
+ this.element(this._prefSelectedWeb).value = aNewValue.uri;
+ this.element(this._prefSelectedReader).value = "web";
+ // Make the web handler be the new "auto handler" for feeds.
+ // Note: we don't have to unregister the auto handler when the user picks
+ // a non-web handler (local app, Live Bookmarks, etc.) because the service
+ // only uses the "auto handler" when the selected reader is a web handler.
+ // We also don't have to unregister it when the user turns on "always ask"
+ // (i.e. preview in browser), since that also overrides the auto handler.
+ this._converterSvc.setAutoHandler(this.type, aNewValue);
}
},
- onRestoreDefaults() {
- let num = gEngineView._engineStore.restoreDefaultEngines();
- gEngineView.rowCountChanged(0, num);
- gEngineView.invalidate();
- },
-
- showRestoreDefaults(aEnable) {
- document.getElementById("restoreDefaultSearchEngines").disabled = !aEnable;
- },
-
- remove(aEngine) {
- let index = gEngineView._engineStore.removeEngine(aEngine);
- gEngineView.rowCountChanged(index, -1);
- gEngineView.invalidate();
- gEngineView.selection.select(Math.min(index, gEngineView.lastIndex));
- gEngineView.ensureRowIsVisible(gEngineView.currentIndex);
- document.getElementById("engineList").focus();
+ _possibleApplicationHandlers: null,
+
+ get possibleApplicationHandlers() {
+ if (this._possibleApplicationHandlers)
+ return this._possibleApplicationHandlers;
+
+ // A minimal implementation of nsIMutableArray. It only supports the two
+ // methods its callers invoke, namely appendElement and nsIArray::enumerate.
+ this._possibleApplicationHandlers = {
+ _inner: [],
+ _removed: [],
+
+ QueryInterface(aIID) {
+ if (aIID.equals(Ci.nsIMutableArray) ||
+ aIID.equals(Ci.nsIArray) ||
+ aIID.equals(Ci.nsISupports))
+ return this;
+
+ throw Cr.NS_ERROR_NO_INTERFACE;
+ },
+
+ get length() {
+ return this._inner.length;
+ },
+
+ enumerate() {
+ return new ArrayEnumerator(this._inner);
+ },
+
+ appendElement(aHandlerApp, aWeak) {
+ this._inner.push(aHandlerApp);
+ },
+
+ removeElementAt(aIndex) {
+ this._removed.push(this._inner[aIndex]);
+ this._inner.splice(aIndex, 1);
+ },
+
+ queryElementAt(aIndex, aInterface) {
+ return this._inner[aIndex].QueryInterface(aInterface);
+ }
+ };
+
+ // Add the selected local app if it's different from the OS default handler.
+ // Unlike for other types, we can store only one local app at a time for the
+ // feed type, since we store it in a preference that historically stores
+ // only a single path. But we display all the local apps the user chooses
+ // while the prefpane is open, only dropping the list when the user closes
+ // the prefpane, for maximum usability and consistency with other types.
+ var preferredAppFile = this.element(this._prefSelectedApp).value;
+ if (preferredAppFile) {
+ let preferredApp = getLocalHandlerApp(preferredAppFile);
+ let defaultApp = this._defaultApplicationHandler;
+ if (!defaultApp || !defaultApp.equals(preferredApp))
+ this._possibleApplicationHandlers.appendElement(preferredApp);
+ }
+
+ // Add the registered web handlers. There can be any number of these.
+ var webHandlers = this._converterSvc.getContentHandlers(this.type);
+ for (let webHandler of webHandlers)
+ this._possibleApplicationHandlers.appendElement(webHandler);
+
+ return this._possibleApplicationHandlers;
},
- 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;
- }
+ __defaultApplicationHandler: undefined,
+ get _defaultApplicationHandler() {
+ if (typeof this.__defaultApplicationHandler != "undefined")
+ return this.__defaultApplicationHandler;
+
+ var defaultFeedReader = null;
+ if (AppConstants.HAVE_SHELL_SERVICE) {
+ try {
+ defaultFeedReader = this._shellSvc.defaultFeedReader;
+ } catch (ex) {
+ // no default reader or _shellSvc is null
}
-
- // Notify the user if they have chosen an existing engine/bookmark keyword
- if (eduplicate || bduplicate) {
- let strings = document.getElementById("engineManagerBundle");
- let dtitle = strings.getString("duplicateTitle");
- let bmsg = strings.getString("duplicateBookmarkMsg");
- let emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
-
- Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
- return false;
+ }
+
+ if (defaultFeedReader) {
+ let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+ createInstance(Ci.nsIHandlerApp);
+ handlerApp.name = getFileDisplayName(defaultFeedReader);
+ handlerApp.QueryInterface(Ci.nsILocalHandlerApp);
+ handlerApp.executable = defaultFeedReader;
+
+ this.__defaultApplicationHandler = handlerApp;
+ } else {
+ this.__defaultApplicationHandler = null;
+ }
+
+ return this.__defaultApplicationHandler;
+ },
+
+ get hasDefaultHandler() {
+ if (AppConstants.HAVE_SHELL_SERVICE) {
+ try {
+ if (this._shellSvc.defaultFeedReader)
+ return true;
+ } catch (ex) {
+ // no default reader or _shellSvc is null
}
}
- gEngineView._engineStore.changeEngine(aEngine, "alias", keyword);
- gEngineView.invalidate();
- return true;
+ return false;
+ },
+
+ get defaultDescription() {
+ if (this.hasDefaultHandler)
+ return this._defaultApplicationHandler.name;
+
+ // Should we instead return null?
+ return "";
+ },
+
+ // What to do with content of this type.
+ get preferredAction() {
+ switch (this.element(this._prefSelectedAction).value) {
+
+ case "bookmarks":
+ return Ci.nsIHandlerInfo.handleInternally;
+
+ case "reader": {
+ let preferredApp = this.preferredApplicationHandler;
+ let defaultApp = this._defaultApplicationHandler;
+
+ // If we have a valid preferred app, return useSystemDefault if it's
+ // the default app; otherwise return useHelperApp.
+ if (gMainPane.isValidHandlerApp(preferredApp)) {
+ if (defaultApp && defaultApp.equals(preferredApp))
+ return Ci.nsIHandlerInfo.useSystemDefault;
+
+ return Ci.nsIHandlerInfo.useHelperApp;
+ }
+
+ // The pref is set to "reader", but we don't have a valid preferred app.
+ // What do we do now? Not sure this is the best option (perhaps we
+ // should direct the user to the default app, if any), but for now let's
+ // direct the user to live bookmarks.
+ return Ci.nsIHandlerInfo.handleInternally;
+ }
+
+ // If the action is "ask", then alwaysAskBeforeHandling will override
+ // the action, so it doesn't matter what we say it is, it just has to be
+ // something that doesn't cause the controller to hide the type.
+ case "ask":
+ default:
+ return Ci.nsIHandlerInfo.handleInternally;
+ }
+ },
+
+ set preferredAction(aNewValue) {
+ switch (aNewValue) {
+
+ case Ci.nsIHandlerInfo.handleInternally:
+ this.element(this._prefSelectedReader).value = "bookmarks";
+ break;
+
+ case Ci.nsIHandlerInfo.useHelperApp:
+ this.element(this._prefSelectedAction).value = "reader";
+ // The controller has already set preferredApplicationHandler
+ // to the new helper app.
+ break;
+
+ case Ci.nsIHandlerInfo.useSystemDefault:
+ this.element(this._prefSelectedAction).value = "reader";
+ this.preferredApplicationHandler = this._defaultApplicationHandler;
+ break;
+ }
+ },
+
+ get alwaysAskBeforeHandling() {
+ return this.element(this._prefSelectedAction).value == "ask";
+ },
+
+ set alwaysAskBeforeHandling(aNewValue) {
+ if (aNewValue == true)
+ this.element(this._prefSelectedAction).value = "ask";
+ else
+ this.element(this._prefSelectedAction).value = "reader";
+ },
+
+ // Whether or not we are currently storing the action selected by the user.
+ // We use this to suppress notification-triggered updates to the list when
+ // we make changes that may spawn such updates, specifically when we change
+ // the action for the feed type, which results in feed preference updates,
+ // which spawn "pref changed" notifications that would otherwise cause us
+ // to rebuild the view unnecessarily.
+ _storingAction: false,
+
+
+ // nsIMIMEInfo
+
+ get primaryExtension() {
+ return "xml";
},
- saveOneClickEnginesList() {
- let hiddenList = [];
- for (let engine of gEngineView._engineStore.engines) {
- if (!engine.shown)
- hiddenList.push(engine.name);
+
+ // Storage
+
+ // Changes to the preferred action and handler take effect immediately
+ // (we write them out to the preferences right as they happen),
+ // so we when the controller calls store() after modifying the handlers,
+ // the only thing we need to store is the removal of possible handlers
+ // XXX Should we hold off on making the changes until this method gets called?
+ store() {
+ for (let app of this._possibleApplicationHandlers._removed) {
+ if (app instanceof Ci.nsILocalHandlerApp) {
+ let pref = this.element(PREF_FEED_SELECTED_APP);
+ var preferredAppFile = pref.value;
+ if (preferredAppFile) {
+ let preferredApp = getLocalHandlerApp(preferredAppFile);
+ if (app.equals(preferredApp))
+ pref.reset();
+ }
+ } else {
+ app.QueryInterface(Ci.nsIWebContentHandlerInfo);
+ this._converterSvc.removeContentHandler(app.contentType, app.uri);
+ }
}
- document.getElementById("browser.search.hiddenOneOffs").value =
- hiddenList.join(",");
+ this._possibleApplicationHandlers._removed = [];
},
- setDefaultEngine() {
- Services.search.currentEngine =
- document.getElementById("defaultEngine").selectedItem.engine;
+
+ // Icons
+
+ get smallIcon() {
+ return this._smallIcon;
+ }
+
+};
+
+var feedHandlerInfo = {
+ __proto__: new FeedHandlerInfo(TYPE_MAYBE_FEED),
+ _prefSelectedApp: PREF_FEED_SELECTED_APP,
+ _prefSelectedWeb: PREF_FEED_SELECTED_WEB,
+ _prefSelectedAction: PREF_FEED_SELECTED_ACTION,
+ _prefSelectedReader: PREF_FEED_SELECTED_READER,
+ _smallIcon: "chrome://browser/skin/feeds/feedIcon16.png",
+ _appPrefLabel: "webFeed"
+}
+
+var videoFeedHandlerInfo = {
+ __proto__: new FeedHandlerInfo(TYPE_MAYBE_VIDEO_FEED),
+ _prefSelectedApp: PREF_VIDEO_FEED_SELECTED_APP,
+ _prefSelectedWeb: PREF_VIDEO_FEED_SELECTED_WEB,
+ _prefSelectedAction: PREF_VIDEO_FEED_SELECTED_ACTION,
+ _prefSelectedReader: PREF_VIDEO_FEED_SELECTED_READER,
+ _smallIcon: "chrome://browser/skin/feeds/videoFeedIcon16.png",
+ _appPrefLabel: "videoPodcastFeed"
+}
+
+var audioFeedHandlerInfo = {
+ __proto__: new FeedHandlerInfo(TYPE_MAYBE_AUDIO_FEED),
+ _prefSelectedApp: PREF_AUDIO_FEED_SELECTED_APP,
+ _prefSelectedWeb: PREF_AUDIO_FEED_SELECTED_WEB,
+ _prefSelectedAction: PREF_AUDIO_FEED_SELECTED_ACTION,
+ _prefSelectedReader: PREF_AUDIO_FEED_SELECTED_READER,
+ _smallIcon: "chrome://browser/skin/feeds/audioFeedIcon16.png",
+ _appPrefLabel: "audioPodcastFeed"
+}
+
+/**
+ * InternalHandlerInfoWrapper provides a basic mechanism to create an internal
+ * mime type handler that can be enabled/disabled in the applications preference
+ * menu.
+ */
+function InternalHandlerInfoWrapper(aMIMEType) {
+ var mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+ var handlerInfo = mimeSvc.getFromTypeAndExtension(aMIMEType, null);
+
+ HandlerInfoWrapper.call(this, aMIMEType, handlerInfo);
+}
+
+InternalHandlerInfoWrapper.prototype = {
+ __proto__: HandlerInfoWrapper.prototype,
+
+ // Override store so we so we can notify any code listening for registration
+ // or unregistration of this handler.
+ store() {
+ HandlerInfoWrapper.prototype.store.call(this);
+ Services.obs.notifyObservers(null, this._handlerChanged);
+ },
+
+ get enabled() {
+ throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+ },
+
+ get description() {
+ return this.element("bundlePreferences").getString(this._appPrefLabel);
}
};
-function onDragEngineStart(event) {
- var selectedIndex = gEngineView.selectedIndex;
- var tree = document.getElementById("engineList");
- var row = { }, col = { }, child = { };
- tree.treeBoxObject.getCellAt(event.clientX, event.clientY, row, col, child);
- if (selectedIndex >= 0 && !gEngineView.isCheckBox(row.value, col.value)) {
- event.dataTransfer.setData(ENGINE_FLAVOR, selectedIndex.toString());
- event.dataTransfer.effectAllowed = "move";
- }
-}
-
-
-function EngineStore() {
- let pref = document.getElementById("browser.search.hiddenOneOffs").value;
- this.hiddenList = pref ? pref.split(",") : [];
-
- this._engines = Services.search.getVisibleEngines().map(this._cloneEngine, this);
- this._defaultEngines = Services.search.getDefaultEngines().map(this._cloneEngine, this);
-
- // check if we need to disable the restore defaults button
- var someHidden = this._defaultEngines.some(e => e.hidden);
- gMainPane.showRestoreDefaults(someHidden);
-}
-EngineStore.prototype = {
- _engines: null,
- _defaultEngines: null,
-
- get engines() {
- return this._engines;
- },
- set engines(val) {
- this._engines = val;
- return val;
- },
-
- _getIndexForEngine(aEngine) {
- return this._engines.indexOf(aEngine);
- },
-
- _getEngineByName(aName) {
- return this._engines.find(engine => engine.name == aName);
- },
-
- _cloneEngine(aEngine) {
- var clonedObj = {};
- for (var i in aEngine)
- clonedObj[i] = aEngine[i];
- clonedObj.originalEngine = aEngine;
- clonedObj.shown = this.hiddenList.indexOf(clonedObj.name) == -1;
- return clonedObj;
- },
-
- // Callback for Array's some(). A thisObj must be passed to some()
- _isSameEngine(aEngineClone) {
- return aEngineClone.originalEngine == this.originalEngine;
- },
-
- addEngine(aEngine) {
- this._engines.push(this._cloneEngine(aEngine));
+var pdfHandlerInfo = {
+ __proto__: new InternalHandlerInfoWrapper(TYPE_PDF),
+ _handlerChanged: TOPIC_PDFJS_HANDLER_CHANGED,
+ _appPrefLabel: "portableDocumentFormat",
+ get enabled() {
+ return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED);
},
-
- moveEngine(aEngine, aNewIndex) {
- if (aNewIndex < 0 || aNewIndex > this._engines.length - 1)
- throw new Error("ES_moveEngine: invalid aNewIndex!");
- var index = this._getIndexForEngine(aEngine);
- if (index == -1)
- throw new Error("ES_moveEngine: invalid engine?");
-
- if (index == aNewIndex)
- return; // nothing to do
-
- // Move the engine in our internal store
- var removedEngine = this._engines.splice(index, 1)[0];
- this._engines.splice(aNewIndex, 0, removedEngine);
-
- Services.search.moveEngine(aEngine.originalEngine, aNewIndex);
- },
-
- removeEngine(aEngine) {
- 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);
-
- if (index == -1)
- throw new Error("invalid engine?");
-
- let removedEngine = this._engines.splice(index, 1)[0];
-
- if (this._defaultEngines.some(this._isSameEngine, removedEngine))
- gMainPane.showRestoreDefaults(true);
- gMainPane.buildDefaultEngineDropDown();
- return index;
- },
-
- restoreDefaultEngines() {
- var added = 0;
-
- for (var i = 0; i < this._defaultEngines.length; ++i) {
- var e = this._defaultEngines[i];
-
- // If the engine is already in the list, just move it.
- if (this._engines.some(this._isSameEngine, e)) {
- this.moveEngine(this._getEngineByName(e.name), i);
- } else {
- // Otherwise, add it back to our internal store
-
- // The search service removes the alias when an engine is hidden,
- // so clear any alias we may have cached before unhiding the engine.
- e.alias = "";
-
- this._engines.splice(i, 0, e);
- let engine = e.originalEngine;
- engine.hidden = false;
- Services.search.moveEngine(engine, i);
- added++;
- }
- }
- Services.search.resetToOriginalDefaultEngine();
- gMainPane.showRestoreDefaults(false);
- gMainPane.buildDefaultEngineDropDown();
- return added;
- },
-
- changeEngine(aEngine, aProp, aNewValue) {
- var index = this._getIndexForEngine(aEngine);
- if (index == -1)
- throw new Error("invalid engine?");
-
- this._engines[index][aProp] = aNewValue;
- aEngine.originalEngine[aProp] = aNewValue;
- },
-
- reloadIcons() {
- this._engines.forEach(function(e) {
- e.uri = e.originalEngine.uri;
- });
- }
};
-
-function EngineView(aEngineStore) {
- this._engineStore = aEngineStore;
-}
-EngineView.prototype = {
- _engineStore: null,
- tree: null,
-
- get lastIndex() {
- return this.rowCount - 1;
- },
- get selectedIndex() {
- var seln = this.selection;
- if (seln.getRangeCount() > 0) {
- var min = {};
- seln.getRangeAt(0, min, {});
- return min.value;
- }
- return -1;
- },
- get selectedEngine() {
- return this._engineStore.engines[this.selectedIndex];
- },
-
- // Helpers
- rowCountChanged(index, count) {
- this.tree.rowCountChanged(index, count);
- },
-
- 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() {
- return this.selectedIndex != -1 && this.lastIndex != 0;
- },
-
- // nsITreeView
- get rowCount() {
- return this._engineStore.engines.length;
- },
-
- getImageSrc(index, column) {
- if (column.id == "engineName") {
- if (this._engineStore.engines[index].iconURI)
- return this._engineStore.engines[index].iconURI.spec;
-
- if (window.devicePixelRatio > 1)
- return "chrome://browser/skin/search-engine-placeholder@2x.png";
- return "chrome://browser/skin/search-engine-placeholder.png";
- }
-
- return "";
- },
-
- getCellText(index, column) {
- if (column.id == "engineName")
- return this._engineStore.engines[index].name;
- else if (column.id == "engineKeyword")
- return this._engineStore.engines[index].alias;
- return "";
- },
-
- setTree(tree) {
- this.tree = tree;
- },
-
- canDrop(targetIndex, orientation, dataTransfer) {
- var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
- return (sourceIndex != -1 &&
- sourceIndex != targetIndex &&
- sourceIndex != targetIndex + orientation);
- },
-
- drop(dropIndex, orientation, dataTransfer) {
- var sourceIndex = this.getSourceIndexFromDrag(dataTransfer);
- var sourceEngine = this._engineStore.engines[sourceIndex];
-
- const nsITreeView = Components.interfaces.nsITreeView;
- if (dropIndex > sourceIndex) {
- if (orientation == nsITreeView.DROP_BEFORE)
- dropIndex--;
- } else if (orientation == nsITreeView.DROP_AFTER) {
- dropIndex++;
- }
-
- this._engineStore.moveEngine(sourceEngine, dropIndex);
- gMainPane.showRestoreDefaults(true);
- gMainPane.buildDefaultEngineDropDown();
-
- // Redraw, and adjust selection
- this.invalidate();
- this.selection.select(dropIndex);
- },
-
- selection: null,
- getRowProperties(index) { return ""; },
- getCellProperties(index, column) { return ""; },
- getColumnProperties(column) { return ""; },
- isContainer(index) { return false; },
- isContainerOpen(index) { return false; },
- isContainerEmpty(index) { return false; },
- isSeparator(index) { return false; },
- isSorted(index) { return false; },
- getParentIndex(index) { return -1; },
- hasNextSibling(parentIndex, index) { return false; },
- getLevel(index) { return 0; },
- getProgressMode(index, column) { },
- getCellValue(index, column) {
- if (column.id == "engineShown")
- return this._engineStore.engines[index].shown;
- return undefined;
- },
- toggleOpenState(index) { },
- cycleHeader(column) { },
- selectionChanged() { },
- cycleCell(row, column) { },
- isEditable(index, column) { return column.id != "engineName"; },
- isSelectable(index, column) { return false; },
- setCellValue(index, column, value) {
- if (column.id == "engineShown") {
- this._engineStore.engines[index].shown = value == "true";
- gEngineView.invalidate();
- gMainPane.saveOneClickEnginesList();
- }
- },
- setCellText(index, column, value) {
- if (column.id == "engineKeyword") {
- gMainPane.editKeyword(this._engineStore.engines[index], value)
- .then(valid => {
- if (!valid)
- document.getElementById("engineList").startEditing(index, column);
- });
- }
- },
- performAction(action) { },
- performActionOnRow(action, index) { },
- performActionOnCell(action, index, column) { }
-};
--- a/browser/components/preferences/in-content-new/main.xul
+++ b/browser/components/preferences/in-content-new/main.xul
@@ -2,21 +2,23 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<!-- General panel -->
<script type="application/javascript"
src="chrome://browser/content/preferences/in-content-new/main.js"/>
+#ifdef MOZ_UPDATER
+ <script type="application/javascript" src="chrome://browser/content/aboutDialog-appUpdater.js"/>
+#endif
+
<script type="application/javascript"
src="chrome://mozapps/content/preferences/fontbuilder.js"/>
-<stringbundle id="engineManagerBundle" src="chrome://browser/locale/engineManager.properties"/>
-
<stringbundle id="bundlePreferences" src="chrome://browser/locale/preferences.properties"/>
<preferences id="mainPreferences" hidden="true" data-category="paneGeneral">
#ifdef E10S_TESTING_ONLY
<preference id="browser.tabs.remote.autostart"
name="browser.tabs.remote.autostart"
type="bool"/>
@@ -55,29 +57,16 @@
<preference id="pref.browser.homepage.disable_button.restore_default"
name="pref.browser.homepage.disable_button.restore_default"
type="bool"/>
<preference id="browser.privatebrowsing.autostart"
name="browser.privatebrowsing.autostart"
type="bool"/>
- <!-- Search Engine -->
- <preference id="browser.search.suggest.enabled"
- name="browser.search.suggest.enabled"
- type="bool"/>
-
- <preference id="browser.urlbar.suggest.searches"
- name="browser.urlbar.suggest.searches"
- type="bool"/>
-
- <preference id="browser.search.hiddenOneOffs"
- name="browser.search.hiddenOneOffs"
- type="unichar"/>
-
<!-- Downloads -->
<preference id="browser.download.useDownloadDir"
name="browser.download.useDownloadDir"
type="bool"/>
<preference id="browser.download.folderList"
name="browser.download.folderList"
type="int"/>
@@ -194,16 +183,93 @@
<preference id="dom.ipc.processCount"
name="dom.ipc.processCount"
type="int"/>
<preference id="layers.acceleration.disabled"
name="layers.acceleration.disabled"
type="bool"
inverted="true"/>
+
+ <!-- Files and Applications -->
+ <preference id="browser.feeds.handler"
+ name="browser.feeds.handler"
+ type="string"/>
+ <preference id="browser.feeds.handler.default"
+ name="browser.feeds.handler.default"
+ type="string"/>
+ <preference id="browser.feeds.handlers.application"
+ name="browser.feeds.handlers.application"
+ type="file"/>
+ <preference id="browser.feeds.handlers.webservice"
+ name="browser.feeds.handlers.webservice"
+ type="string"/>
+
+ <preference id="browser.videoFeeds.handler"
+ name="browser.videoFeeds.handler"
+ type="string"/>
+ <preference id="browser.videoFeeds.handler.default"
+ name="browser.videoFeeds.handler.default"
+ type="string"/>
+ <preference id="browser.videoFeeds.handlers.application"
+ name="browser.videoFeeds.handlers.application"
+ type="file"/>
+ <preference id="browser.videoFeeds.handlers.webservice"
+ name="browser.videoFeeds.handlers.webservice"
+ type="string"/>
+
+ <preference id="browser.audioFeeds.handler"
+ name="browser.audioFeeds.handler"
+ type="string"/>
+ <preference id="browser.audioFeeds.handler.default"
+ name="browser.audioFeeds.handler.default"
+ type="string"/>
+ <preference id="browser.audioFeeds.handlers.application"
+ name="browser.audioFeeds.handlers.application"
+ type="file"/>
+ <preference id="browser.audioFeeds.handlers.webservice"
+ name="browser.audioFeeds.handlers.webservice"
+ type="string"/>
+
+ <preference id="pref.downloads.disable_button.edit_actions"
+ name="pref.downloads.disable_button.edit_actions"
+ type="bool"/>
+
+ <!-- DRM content -->
+ <preference id="media.eme.enabled"
+ name="media.eme.enabled"
+ type="bool"/>
+
+ <!-- Update -->
+ <preference id="browser.preferences.advanced.selectedTabIndex"
+ name="browser.preferences.advanced.selectedTabIndex"
+ type="int"/>
+
+#ifdef MOZ_UPDATER
+ <preference id="app.update.enabled"
+ name="app.update.enabled"
+ type="bool"/>
+ <preference id="app.update.auto"
+ name="app.update.auto"
+ type="bool"/>
+
+ <preference id="app.update.disable_button.showUpdateHistory"
+ name="app.update.disable_button.showUpdateHistory"
+ type="bool"/>
+
+#ifdef MOZ_MAINTENANCE_SERVICE
+ <preference id="app.update.service.enabled"
+ name="app.update.service.enabled"
+ type="bool"/>
+#endif
+#endif
+
+ <preference id="browser.search.update"
+ name="browser.search.update"
+ type="bool"/>
</preferences>
<hbox id="header-general"
class="header"
hidden="true"
data-category="paneGeneral">
<label class="header-name" flex="1">&paneGeneral.title;</label>
</hbox>
@@ -237,17 +303,17 @@
<vbox id="defaultBrowserBox">
<checkbox id="alwaysCheckDefault" preference="browser.shell.checkDefaultBrowser"
label="&alwaysCheckDefault2.label;" accesskey="&alwaysCheckDefault2.accesskey;"/>
<deck id="setDefaultPane">
<hbox align="center" class="indent">
<label id="isNotDefaultLabel" flex="1">&isNotDefault.label;</label>
<button id="setDefaultButton"
class="accessory-button"
- label="&setAsMyDefaultBrowser2.label;" accesskey="&setAsMyDefaultBrowser2.accesskey;"
+ label="&setAsMyDefaultBrowser3.label;" accesskey="&setAsMyDefaultBrowser3.accesskey;"
preference="pref.general.disable_button.default_browser"/>
</hbox>
<hbox align="center" class="indent">
<label id="isDefaultLabel" flex="1">&isDefault.label;</label>
</hbox>
</deck>
<separator class="thin"/>
</vbox>
@@ -314,74 +380,18 @@
label="&restoreDefault.label;"
accesskey="&restoreDefault.accesskey;"
preference="pref.browser.homepage.disable_button.restore_default"/>
</html:td>
</html:tr>
</html:table>
</groupbox>
-<!-- Default Search Engine -->
-<groupbox id="defaultEngineGroup" data-category="paneGeneral" data-subcategory="search">
<caption><label>&defaultSearchEngine.label;</label></caption>
- <label>&chooseYourDefaultSearchEngine.label;</label>
- <box align="start">
- <menulist id="defaultEngine">
- <menupopup/>
- </menulist>
- </box>
- <checkbox id="suggestionsInSearchFieldsCheckbox"
- label="&provideSearchSuggestions.label;"
- accesskey="&provideSearchSuggestions.accesskey;"
- preference="browser.search.suggest.enabled"/>
- <vbox class="indent">
- <checkbox id="urlBarSuggestion" label="&showURLBarSuggestions.label;"
- accesskey="&showURLBarSuggestions.accesskey;"
- preference="browser.urlbar.suggest.searches"/>
- <hbox id="urlBarSuggestionPermanentPBLabel"
- align="center" class="indent">
- <label flex="1">&urlBarSuggestionsPermanentPB.label;</label>
- </hbox>
- </vbox>
-</groupbox>
-
-<groupbox id="oneClickSearchProvidersGroup" data-category="paneGeneral" data-subcategory="search">
<caption><label>&oneClickSearchEngines.label;</label></caption>
- <label>&chooseWhichOneToDisplay.label;</label>
-
- <tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
- seltype="single" allowunderflowscroll="true">
- <treechildren id="engineChildren" flex="1"/>
- <treecols>
- <treecol id="engineShown" type="checkbox" editable="true" sortable="false"/>
- <treecol id="engineName" flex="4" label="&engineNameColumn.label;" sortable="false"/>
- <treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"
- sortable="false"/>
- </treecols>
- </tree>
-
- <hbox>
- <button id="restoreDefaultSearchEngines"
- label="&restoreDefaultSearchEngines.label;"
- accesskey="&restoreDefaultSearchEngines.accesskey;"/>
- <spacer flex="1"/>
- <button id="removeEngineButton"
- class="searchEngineAction accessory-button"
- label="&removeEngine.label;"
- accesskey="&removeEngine.accesskey;"
- disabled="true"/>
- </hbox>
-
- <separator class="thin"/>
-
- <hbox id="addEnginesBox" pack="start">
- <label id="addEngines" class="text-link">&addMoreSearchEngines2.label;</label>
- </hbox>
-</groupbox>
-
<!-- Tab preferences -->
<groupbox data-category="paneGeneral"
hidden="true">
<caption><label>&tabsGroup.label;</label></caption>
<checkbox id="ctrlTabRecentlyUsedOrder" label="&ctrlTabRecentlyUsedOrder.label;"
accesskey="&ctrlTabRecentlyUsedOrder.accesskey;"
preference="browser.ctrlTab.previews"/>
@@ -404,91 +414,37 @@
accesskey="&switchLinksToNewTabs.accesskey;"
preference="browser.tabs.loadInBackground"/>
#ifdef XP_WIN
<checkbox id="showTabsInTaskbar" label="&showTabsInTaskbar.label;"
accesskey="&showTabsInTaskbar.accesskey;"
preference="browser.taskbar.previews.enable"/>
#endif
-</groupbox>
-<!-- Accessibility -->
-<groupbox data-category="paneGeneral" id="accessibilityGroup">
- <caption><label>&accessibility.label;</label></caption>
-
-#ifdef XP_WIN
- <checkbox id="useOnScreenKeyboard"
- hidden="true"
- label="&useOnScreenKeyboard.label;"
- accesskey="&useOnScreenKeyboard.accesskey;"
- preference="ui.osk.enabled"/>
-#endif
- <checkbox id="useCursorNavigation"
- label="&useCursorNavigation.label;"
- accesskey="&useCursorNavigation.accesskey;"
- preference="accessibility.browsewithcaret"/>
- <checkbox id="searchStartTyping"
- label="&searchOnStartTyping.label;"
- accesskey="&searchOnStartTyping.accesskey;"
- preference="accessibility.typeaheadfind"/>
- <checkbox id="blockAutoRefresh"
- label="&blockAutoReload.label;"
- accesskey="&blockAutoReload.accesskey;"
- preference="accessibility.blockautorefresh"/>
+ <hbox id="browserContainersbox" hidden="true" align="center">
+ <checkbox id="browserContainersCheckbox"
+ label="&browserContainersEnabled.label;"
+ accesskey="&browserContainersEnabled.accesskey;"
+ preference="privacy.userContext.enabled"
+ onsyncfrompreference="return gPrivacyPane.readBrowserContainersCheckbox();"/>
+ <label id="browserContainersLearnMore" class="learnMore text-link">
+ &browserContainersLearnMore.label;
+ </label>
+ <spacer flex="1"/>
+ <button id="browserContainersSettings"
+ class="accessory-button"
+ label="&browserContainersSettings.label;"
+ accesskey="&browserContainersSettings.accesskey;"
+ searchkeywords="&addButton.label;
+ &preferencesButton.label;
+ &removeButton.label;"/>
+ </hbox>
</groupbox>
-<!-- Languages -->
-<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true">
- <caption><label>&languages.label;</label></caption>
-
- <hbox id="languagesBox" align="center">
- <description flex="1" control="chooseLanguage">&chooseLanguage.label;</description>
- <button id="chooseLanguage"
- class="accessory-button"
- label="&chooseButton.label;"
- accesskey="&chooseButton.accesskey;"
- searchkeywords="&languages.customize.Header;
- &languages.customize.description;
- &languages.customize.moveUp.label;
- &languages.customize.moveDown.label;
- &languages.customize.deleteButton.label;
- &languages.customize.selectLanguage.label;
- &languages.customize.addButton.label;"/>
- </hbox>
-
- <hbox id="translationBox" hidden="true">
- <hbox align="center" flex="1">
- <checkbox id="translate" preference="browser.translation.detectLanguage"
- label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
- onsyncfrompreference="return gMainPane.updateButtons('translateButton',
- 'browser.translation.detectLanguage');"/>
- <hbox id="bingAttribution" hidden="true">
- <label>&translation.options.attribution.beforeLogo;</label>
- <separator orient="vertical" class="thin"/>
- <image id="translationAttributionImage" aria-label="Microsoft Translator"
- src="chrome://browser/content/microsoft-translator-attribution.png"/>
- <separator orient="vertical" class="thin"/>
- <label>&translation.options.attribution.afterLogo;</label>
- </hbox>
- </hbox>
- <button id="translateButton"
- class="accessory-button"
- label="&translateExceptions.label;"
- accesskey="&translateExceptions.accesskey;"/>
- </hbox>
- <checkbox id="checkSpelling"
- label="&checkUserSpelling.label;"
- accesskey="&checkUserSpelling.accesskey;"
- onsyncfrompreference="return gMainPane.readCheckSpelling();"
- onsynctopreference="return gMainPane.writeCheckSpelling();"
- preference="layout.spellcheckDefault"/>
-</groupbox>
-
-
<!-- Fonts and Colors -->
<groupbox id="fontsGroup" data-category="paneGeneral" hidden="true">
<caption><label>&fontsAndColors.label;</label></caption>
<vbox>
<hbox id="fontSettings">
<hbox align="center">
<label control="defaultFont" accesskey="&defaultFont2.accesskey;">&defaultFont2.label;</label>
@@ -605,28 +561,296 @@
&useSystemColors.label;
&underlineLinks.label;
&linkColor.label;
&visitedLinkColor.label;"/>
</hbox>
</vbox>
</groupbox>
-<!-- Browsing -->
-<groupbox id="browsingGroup" data-category="paneGeneral">
- <caption><label>&browsing.label;</label></caption>
+<!-- Languages -->
+<groupbox id="languagesGroup" data-category="paneGeneral" hidden="true">
+ <caption><label>&language2.label;</label></caption>
+
+ <hbox id="languagesBox" align="center">
+ <description flex="1" control="chooseLanguage">&chooseLanguage.label;</description>
+ <button id="chooseLanguage"
+ class="accessory-button"
+ label="&chooseButton.label;"
+ accesskey="&chooseButton.accesskey;"
+ searchkeywords="&languages.customize.Header;
+ &languages.customize.description;
+ &languages.customize.moveUp.label;
+ &languages.customize.moveDown.label;
+ &languages.customize.deleteButton.label;
+ &languages.customize.selectLanguage.label;
+ &languages.customize.addButton.label;"/>
+ </hbox>
+
+ <hbox id="translationBox" hidden="true">
+ <hbox align="center" flex="1">
+ <checkbox id="translate" preference="browser.translation.detectLanguage"
+ label="&translateWebPages.label;." accesskey="&translateWebPages.accesskey;"
+ onsyncfrompreference="return gMainPane.updateButtons('translateButton',
+ 'browser.translation.detectLanguage');"/>
+ <hbox id="bingAttribution" hidden="true">
+ <label>&translation.options.attribution.beforeLogo;</label>
+ <separator orient="vertical" class="thin"/>
+ <image id="translationAttributionImage" aria-label="Microsoft Translator"
+ src="chrome://browser/content/microsoft-translator-attribution.png"/>
+ <separator orient="vertical" class="thin"/>
+ <label>&translation.options.attribution.afterLogo;</label>
+ </hbox>
+ </hbox>
+ <button id="translateButton"
+ class="accessory-button"
+ label="&translateExceptions.label;"
+ accesskey="&translateExceptions.accesskey;"/>
+ </hbox>
+ <checkbox id="checkSpelling"
+ label="&checkUserSpelling.label;"
+ accesskey="&checkUserSpelling.accesskey;"
+ onsyncfrompreference="return gMainPane.readCheckSpelling();"
+ onsynctopreference="return gMainPane.writeCheckSpelling();"
+ preference="layout.spellcheckDefault"/>
+</groupbox>
+
+<!-- Files and Applications -->
+<keyset data-category="paneGeneral">
+ <!-- Ctrl+f/k focus the search box in the Applications pane.
+ These <key>s have oncommand attributes because of bug 371900. -->
+ <key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand=";"/>
+ <key key="&focusSearch2.key;" modifiers="accel" id="focusSearch2" oncommand=";"/>
+</keyset>
+
+<!--Downloads-->
+<groupbox id="downloadsGroup" data-category="paneGeneral" hidden="true">
+ <caption><label>&downloads.label;</label></caption>
+
+ <radiogroup id="saveWhere"
+ preference="browser.download.useDownloadDir"
+ onsyncfrompreference="return gMainPane.readUseDownloadDir();">
+ <hbox id="saveToRow">
+ <radio id="saveTo"
+ value="true"
+ label="&saveTo.label;"
+ accesskey="&saveTo.accesskey;"
+ aria-labelledby="saveTo downloadFolder"/>
+ <filefield id="downloadFolder"
+ flex="1"
+ preference="browser.download.folderList"
+ preference-editable="true"
+ aria-labelledby="saveTo"
+ onsyncfrompreference="return gMainPane.displayDownloadDirPref();"/>
+ <button id="chooseFolder"
+#ifdef XP_MACOSX
+ accesskey="&chooseFolderMac.accesskey;"
+ label="&chooseFolderMac.label;"
+#else
+ accesskey="&chooseFolderWin.accesskey;"
+ label="&chooseFolderWin.label;"
+#endif
+ />
+ </hbox>
+ <radio id="alwaysAsk"
+ value="false"
+ label="&alwaysAskWhere.label;"
+ accesskey="&alwaysAskWhere.accesskey;"/>
+ </radiogroup>
+</groupbox>
+
+<groupbox id="applicationsGroup" data-category="paneGeneral" hidden="true">
+ <caption><label>&applications.label;</label></caption>
+ <description>&applications.description;</description>
+ <textbox id="filter" flex="1"
+ type="search"
+ placeholder="&filter2.emptytext;"
+ aria-controls="handlersView"/>
+
+ <richlistbox id="handlersView" orient="vertical" persist="lastSelectedType"
+ preference="pref.downloads.disable_button.edit_actions"
+ flex="1">
+ <listheader equalsize="always">
+ <treecol id="typeColumn" label="&typeColumn.label;" value="type"
+ accesskey="&typeColumn.accesskey;" persist="sortDirection"
+ flex="1" sortDirection="ascending"/>
+ <treecol id="actionColumn" label="&actionColumn2.label;" value="action"
+ accesskey="&actionColumn2.accesskey;" persist="sortDirection"
+ flex="1"/>
+ </listheader>
+ </richlistbox>
+</groupbox>
+
+
+<!-- DRM Content -->
+<groupbox id="drmGroup" data-category="paneGeneral" hidden="true">
+ <caption><label>&drmContent2.label;</label></caption>
+ <grid id="contentGrid2">
+ <columns>
+ <column flex="1"/>
+ <column/>
+ </columns>
+ <rows id="contentRows-2">
+ <row id="playDRMContentRow">
+ <hbox align="center">
+ <checkbox id="playDRMContent" preference="media.eme.enabled"
+ label="&playDRMContent2.label;" accesskey="&playDRMContent2.accesskey;"/>
+ <label id="playDRMContentLink" class="learnMore text-link">
+ &playDRMContent.learnMore.label;
+ </label>
+ </hbox>
+ </row>
+ </rows>
+ </grid>
+</groupbox>
- <checkbox id="useAutoScroll"
- label="&useAutoScroll.label;"
- accesskey="&useAutoScroll.accesskey;"
- preference="general.autoScroll"/>
- <checkbox id="useSmoothScrolling"
- label="&useSmoothScrolling.label;"
- accesskey="&useSmoothScrolling.accesskey;"
- preference="general.smoothScroll"/>
+#ifdef HAVE_SHELL_SERVICE
+ <stringbundle id="bundleShell" src="chrome://browser/locale/shellservice.properties"/>
+ <stringbundle id="bundleBrand" src="chrome://branding/locale/brand.properties"/>
+#endif
+
+<!-- Update -->
+<groupbox id="updateApp" data-category="paneGeneral" hidden="true">
+ <caption><label>&updateApplication.label;</label></caption>
+ <hbox align="start">
+ <vbox flex="1">
+ <description>
+ &updateApplication.version.pre;<label id="version"/>&updateApplication.version.post;
+ <label id="releasenotes" class="learnMore text-link" hidden="true">&releaseNotes.link;</label>
+ </description>
+ <description id="distribution" class="text-blurb" hidden="true"/>
+ <description id="distributionId" class="text-blurb" hidden="true"/>
+ </vbox>
+#ifdef MOZ_UPDATER
+ <spacer flex="1"/>
+ <vbox>
+ <button id="showUpdateHistory"
+ class="accessory-button"
+ label="&updateHistory2.label;"
+ accesskey="&updateHistory2.accesskey;"
+ preference="app.update.disable_button.showUpdateHistory"
+ searchkeywords="&history.title; &history.intro;"/>
+ </vbox>
+#endif
+ </hbox>
+#ifdef MOZ_UPDATER
+ <vbox id="updateBox">
+ <deck id="updateDeck" orient="vertical">
+ <hbox id="checkForUpdates" align="center">
+ <spacer flex="1"/>
+ <button id="checkForUpdatesButton"
+ label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ oncommand="gAppUpdater.checkForUpdates();"/>
+ </hbox>
+ <hbox id="downloadAndInstall" align="center">
+ <spacer flex="1"/>
+ <button id="downloadAndInstallButton"
+ oncommand="gAppUpdater.startDownload();"/>
+ <!-- label and accesskey will be filled by JS -->
+ </hbox>
+ <hbox id="apply" align="center">
+ <spacer flex="1"/>
+ <button id="updateButton"
+ label="&update.updateButton.label3;"
+ accesskey="&update.updateButton.accesskey;"
+ oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
+ </hbox>
+ <hbox id="checkingForUpdates" align="center">
+ <image class="update-throbber"/><label>&update.checkingForUpdates;</label>
+ <spacer flex="1"/>
+ <button label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ disabled="true"/>
+ </hbox>
+ <hbox id="downloading" align="center">
+ <image class="update-throbber"/><label>&update.downloading.start;</label><label id="downloadStatus"/><label>&update.downloading.end;</label>
+ </hbox>
+ <hbox id="applying" align="center">
+ <image class="update-throbber"/><label>&update.applying;</label>
+ </hbox>
+ <hbox id="downloadFailed" align="center">
+ <label>&update.failed.start;</label><label id="failedLink" class="text-link">&update.failed.linkText;</label><label>&update.failed.end;</label>
+ <spacer flex="1"/>
+ <button label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ oncommand="gAppUpdater.checkForUpdates();"/>
+ </hbox>
+ <hbox id="adminDisabled" align="center">
+ <label>&update.adminDisabled;</label>
+ <spacer flex="1"/>
+ <button label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ disabled="true"/>
+ </hbox>
+ <hbox id="noUpdatesFound" align="center">
+ <label>&update.noUpdatesFound;</label>
+ <spacer flex="1"/>
+ <button label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ oncommand="gAppUpdater.checkForUpdates();"/>
+ </hbox>
+ <hbox id="otherInstanceHandlingUpdates" align="center">
+ <label>&update.otherInstanceHandlingUpdates;</label>
+ <spacer flex="1"/>
+ <button label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ disabled="true"/>
+ </hbox>
+ <hbox id="manualUpdate" align="center">
+ <label>&update.manual.start;</label><label id="manualLink" class="text-link"/><label>&update.manual.end;</label>
+ <spacer flex="1"/>
+ <button label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ disabled="true"/>
+ </hbox>
+ <hbox id="unsupportedSystem" align="center">
+ <label>&update.unsupported.start;</label><label id="unsupportedLink" class="text-link">&update.unsupported.linkText;</label><label>&update.unsupported.end;</label>
+ <spacer flex="1"/>
+ <button label="&update.checkForUpdatesButton.label;"
+ accesskey="&update.checkForUpdatesButton.accesskey;"
+ disabled="true"/>
+ </hbox>
+ <hbox id="restarting" align="center">
+ <image class="update-throbber"/><label>&update.restarting;</label>
+ <spacer flex="1"/>
+ <button label="&update.updateButton.label3;"
+ accesskey="&update.updateButton.accesskey;"
+ disabled="true"/>
+ </hbox>
+ </deck>
+ </vbox>
+#endif
+
+ <separator/>
+#ifdef MOZ_UPDATER
+ <description>&updateApplication.description;</description>
+ <radiogroup id="updateRadioGroup">
+ <radio id="autoDesktop"
+ value="auto"
+ label="&updateAuto2.label;"
+ accesskey="&updateAuto2.accesskey;"/>
+ <radio value="checkOnly"
+ label="&updateCheckChoose2.label;"
+ accesskey="&updateCheckChoose2.accesskey;"/>
+ <radio value="manual"
+ label="&updateManual2.label;"
+ accesskey="&updateManual2.accesskey;"/>
+ </radiogroup>
+#ifdef MOZ_MAINTENANCE_SERVICE
+ <checkbox id="useService"
+ label="&useService.label;"
+ accesskey="&useService.accesskey;"
+ preference="app.update.service.enabled"/>
+#endif
+#endif
+ <checkbox id="enableSearchUpdate"
+ label="&enableSearchUpdate2.label;"
+ accesskey="&enableSearchUpdate2.accesskey;"
+ preference="browser.search.update"/>
</groupbox>
<!-- Performance -->
<groupbox id="performanceGroup" data-category="paneGeneral" hidden="true">
<caption><label>&performance.label;</label></caption>
<hbox align="center">
<checkbox id="useRecommendedPerformanceSettings"
@@ -655,8 +879,70 @@
<menuitem label="7" value="7"/>
</menupopup>
</menulist>
</hbox>
<description id="contentProcessCountEnabledDescription">&limitContentProcessOption.description;</description>
<description id="contentProcessCountDisabledDescription">&limitContentProcessOption.disabledDescription;<label class="text-link" href="https://wiki.mozilla.org/Electrolysis">&limitContentProcessOption.disabledDescriptionLink;</label></description>
</vbox>
</groupbox>
+
+<!-- Browsing -->
+<groupbox id="browsingGroup" data-category="paneGeneral" hidden="true">
+ <caption><label>&browsing.label;</label></caption>
+
+ <checkbox id="useAutoScroll"
+ label="&useAutoScroll.label;"
+ accesskey="&useAutoScroll.accesskey;"
+ preference="general.autoScroll"/>
+ <checkbox id="useSmoothScrolling"
+ label="&useSmoothScrolling.label;"
+ accesskey="&useSmoothScrolling.accesskey;"
+ preference="general.smoothScroll"/>
+
+#ifdef XP_WIN
+ <checkbox id="useOnScreenKeyboard"
+ hidden="true"
+ label="&useOnScreenKeyboard.label;"
+ accesskey="&useOnScreenKeyboard.accesskey;"
+ preference="ui.osk.enabled"/>
+#endif
+ <checkbox id="useCursorNavigation"
+ label="&useCursorNavigation.label;"
+ accesskey="&useCursorNavigation.accesskey;"
+ preference="accessibility.browsewithcaret"/>
+ <checkbox id="searchStartTyping"
+ label="&searchOnStartTyping.label;"
+ accesskey="&searchOnStartTyping.accesskey;"
+ preference="accessibility.typeaheadfind"/>
+</groupbox>
+
+<!-- Network Proxy-->
+<groupbox id="connectionGroup" data-category="paneGeneral" hidden="true">
+ <caption><label>&networkProxy.label;</label></caption>
+
+ <hbox align="center">
+ <description flex="1" control="connectionSettings">&connectionDesc.label;</description>
+ <button id="connectionSettings"
+ class="accessory-button"
+ icon="network"
+ label="&connectionSettings.label;"
+ accesskey="&connectionSettings.accesskey;"
+ searchkeywords="&connectionsDialog.title;
+ &noProxyTypeRadio.label;
+ &WPADTypeRadio.label;
+ &systemTypeRadio.label;
+ &manualTypeRadio.label;
+ &http.label;
+ &ssl.label;
+ &ftp.label;
+ &socks.label;
+ &socks4.label;
+ &socks5.label;
+ &noproxy.label;
+ &noproxyExplain.label;
+ &shareproxy.label;
+ &autoTypeRadio.label;
+ &reload.label;
+ &autologinproxy.label;
+ &socksRemoteDNS.label2;"/>
+ </hbox>
+</groupbox>
--- a/browser/components/preferences/in-content-new/preferences.js
+++ b/browser/components/preferences/in-content-new/preferences.js
@@ -1,19 +1,18 @@
/* - This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this file,
- You can obtain one at http://mozilla.org/MPL/2.0/. */
// Import globals from the files imported by the .xul files.
/* import-globals-from subdialogs.js */
-/* import-globals-from advanced.js */
/* import-globals-from main.js */
+/* import-globals-from search.js */
/* import-globals-from containers.js */
/* import-globals-from privacy.js */
-/* import-globals-from applications.js */
/* import-globals-from sync.js */
/* import-globals-from findInPage.js */
/* import-globals-from ../../../base/content/utilityOverlay.js */
"use strict";
var Cc = Components.classes;
var Ci = Components.interfaces;
@@ -50,20 +49,19 @@ function register_module(categoryName, c
document.addEventListener("DOMContentLoaded", init_all, {once: true});
function init_all() {
document.documentElement.instantApply = true;
gSubDialog.init();
register_module("paneGeneral", gMainPane);
+ register_module("paneSearch", gSearchPane);
register_module("panePrivacy", gPrivacyPane);
register_module("paneContainers", gContainersPane);
- register_module("paneAdvanced", gAdvancedPane);
- register_module("paneApplications", gApplicationsPane);
register_module("paneSync", gSyncPane);
register_module("paneSearchResults", gSearchResultsPane);
gSearchResultsPane.init();
let categories = document.getElementById("categories");
categories.addEventListener("select", event => gotoPref(event.target.value));
document.documentElement.addEventListener("keydown", function(event) {
@@ -339,8 +337,19 @@ function confirmRestartPrompt(aRestartTo
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
"restart");
if (cancelQuit.data) {
buttonIndex = CONFIRM_RESTART_PROMPT_CANCEL;
}
}
return buttonIndex;
}
+
+// This function is used to append search keywords found
+// in the related subdialog to the button that will activate the subdialog.
+function appendSearchKeywords(aId, keywords) {
+ let element = document.getElementById(aId);
+ let searchKeywords = element.getAttribute("searchkeywords");
+ if (searchKeywords) {
+ keywords.push(searchKeywords);
+ }
+ element.setAttribute("searchkeywords", keywords.join(" "));
+}
--- a/browser/components/preferences/in-content-new/preferences.xul
+++ b/browser/components/preferences/in-content-new/preferences.xul
@@ -139,84 +139,72 @@
value="paneGeneral"
helpTopic="prefs-main"
tooltiptext="&paneGeneral.title;"
align="center">
<image class="category-icon"/>
<label class="category-name" flex="1">&paneGeneral.title;</label>
</richlistitem>
- <richlistitem id="category-application"
+ <richlistitem id="category-search"
class="category"
- value="paneApplications"
- helpTopic="prefs-applications"
- tooltiptext="&paneFilesApplications.title;"
+ value="paneSearch"
+ helpTopic="prefs-search"
+ tooltiptext="&paneSearch.title;"
align="center">
<image class="category-icon"/>
- <label class="category-name" flex="1">&paneFilesApplications.title;</label>
+ <label class="category-name" flex="1">&paneSearch.title;</label>
</richlistitem>
<richlistitem id="category-containers"
class="category"
value="paneContainers"
helpTopic="prefs-containers"
hidden="true"/>
- <richlistitem id="category-sync"
- class="category"
- value="paneSync"
- helpTopic="prefs-weave"
- tooltiptext="&paneSync1.title;"
- align="center">
- <image class="category-icon"/>
- <label class="category-name" flex="1">&paneSync1.title;</label>
- </richlistitem>
-
<richlistitem id="category-privacy"
class="category"
value="panePrivacy"
helpTopic="prefs-privacy"
tooltiptext="&panePrivacySecurity.title;"
align="center">
<image class="category-icon"/>
<label class="category-name" flex="1">&panePrivacySecurity.title;</label>
</richlistitem>
- <richlistitem id="category-advanced"
+ <richlistitem id="category-sync"
class="category"
- value="paneAdvanced"
- helpTopic="prefs-advanced-general"
- tooltiptext="&paneUpdates.title;"
+ value="paneSync"
+ helpTopic="prefs-weave"
+ tooltiptext="&paneSync1.title;"
align="center">
<image class="category-icon"/>
- <label class="category-name" flex="1">&paneUpdates.title;</label>
+ <label class="category-name" flex="1">&paneSync1.title;</label>
</richlistitem>
</richlistbox>
<keyset>
<!-- Disable the findbar because it doesn't work properly.
Remove this keyset once bug 1094240 ("disablefastfind" attribute
broken in e10s mode) is fixed. -->
<key key="&focusSearch1.key;" modifiers="accel" id="focusSearch1" oncommand=";"/>
</keyset>
<html:a class="help-button" target="_blank" aria-label="&helpButton2.label;">&helpButton2.label;</html:a>
<vbox class="main-content" flex="1">
<hbox pack="end">
- <textbox type="search" id="searchInput" placeholder="&searchInput.label;" hidden="true"
- clickSelectsAll="true"/>
+ <textbox type="search" id="searchInput" hidden="true" clickSelectsAll="true"/>
</hbox>
<prefpane id="mainPrefPane">
#include searchResults.xul
#include main.xul
+#include search.xul
#include privacy.xul
#include containers.xul
-#include advanced.xul
-#include applications.xul
#include sync.xul
</prefpane>
</vbox>
</hbox>
<stack id="dialogStack" hidden="true"/>
<vbox id="dialogTemplate" class="dialogOverlay" align="center" pack="center" topmost="true" hidden="true">
<groupbox class="dialogBox"
--- a/browser/components/preferences/in-content-new/privacy.js
+++ b/browser/components/preferences/in-content-new/privacy.js
@@ -1,16 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/* import-globals-from preferences.js */
Components.utils.import("resource://gre/modules/AppConstants.jsm");
Components.utils.import("resource://gre/modules/PluralForm.jsm");
+Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
+Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
"resource://gre/modules/ContextualIdentityService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
"resource://gre/modules/LoginHelper.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SiteDataManager",
@@ -80,98 +82,33 @@ var gPrivacyPane = {
* Initialize autocomplete to ensure prefs are in sync.
*/
_initAutocomplete() {
Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
.getService(Components.interfaces.mozIPlacesAutoComplete);
},
/**
- * Show the Containers UI depending on the privacy.userContext.ui.enabled pref.
- */
- _initBrowserContainers() {
- if (!Services.prefs.getBoolPref("privacy.userContext.ui.enabled")) {
- // The browserContainersGroup element has its own internal padding that
- // is visible even if the browserContainersbox is visible, so hide the whole
- // groupbox if the feature is disabled to prevent a gap in the preferences.
- document.getElementById("browserContainersGroup").setAttribute("data-hidden-from-search", "true");
- return;
- }
-
- let link = document.getElementById("browserContainersLearnMore");
- link.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "containers";
-
- document.getElementById("browserContainersbox").hidden = false;
-
- document.getElementById("browserContainersCheckbox").checked =
- Services.prefs.getBoolPref("privacy.userContext.enabled");
- },
-
- _checkBrowserContainers(event) {
- let checkbox = document.getElementById("browserContainersCheckbox");
- if (checkbox.checked) {
- Services.prefs.setBoolPref("privacy.userContext.enabled", true);
- return;
- }
-
- let count = ContextualIdentityService.countContainerTabs();
- if (count == 0) {
- Services.prefs.setBoolPref("privacy.userContext.enabled", false);
- return;
- }
-
- let bundlePreferences = document.getElementById("bundlePreferences");
-
- let title = bundlePreferences.getString("disableContainersAlertTitle");
- let message = PluralForm.get(count, bundlePreferences.getString("disableContainersMsg"))
- .replace("#S", count)
- let okButton = PluralForm.get(count, bundlePreferences.getString("disableContainersOkButton"))
- .replace("#S", count)
- let cancelButton = bundlePreferences.getString("disableContainersButton2");
-
- let buttonFlags = (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
- (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1);
-
- let rv = Services.prompt.confirmEx(window, title, message, buttonFlags,
- okButton, cancelButton, null, null, {});
- if (rv == 0) {
- ContextualIdentityService.closeContainerTabs();
- Services.prefs.setBoolPref("privacy.userContext.enabled", false);
- return;
- }
-
- checkbox.checked = true;
- },
-
- /**
* Sets up the UI for the number of days of history to keep, and updates the
* label of the "Clear Now..." button.
*/
init() {
function setEventListener(aId, aEventType, aCallback) {
document.getElementById(aId)
.addEventListener(aEventType, aCallback.bind(gPrivacyPane));
}
- function appendSearchKeywords(aId, keywords) {
- let element = document.getElementById(aId);
- let searchKeywords = element.getAttribute("searchkeywords");
- searchKeywords && keywords.push(searchKeywords);
- element.setAttribute("searchkeywords", keywords.join(" "));
- }
-
this._updateSanitizeSettingsButton();
this.initializeHistoryMode();
this.updateHistoryModePane();
this.updatePrivacyMicroControls();
this.initAutoStartPrivateBrowsingReverter();
this._initTrackingProtection();
this._initTrackingProtectionPBM();
this._initAutocomplete();
- this._initBrowserContainers();
setEventListener("privacy.sanitize.sanitizeOnShutdown", "change",
gPrivacyPane._updateSanitizeSettingsButton);
setEventListener("browser.privatebrowsing.autostart", "change",
gPrivacyPane.updatePrivacyMicroControls);
setEventListener("historyMode", "command", function() {
gPrivacyPane.updateHistoryModePane();
gPrivacyPane.updateHistoryModePrefs();
@@ -199,36 +136,30 @@ var gPrivacyPane = {
setEventListener("clearDataSettings", "command",
gPrivacyPane.showClearPrivateDataSettings);
setEventListener("trackingProtectionRadioGroup", "command",
gPrivacyPane.trackingProtectionWritePrefs);
setEventListener("trackingProtectionExceptions", "command",
gPrivacyPane.showTrackingProtectionExceptions);
setEventListener("changeBlockList", "command",
gPrivacyPane.showBlockLists);
- setEventListener("browserContainersCheckbox", "command",
- gPrivacyPane._checkBrowserContainers);
- setEventListener("browserContainersSettings", "command",
- gPrivacyPane.showContainerSettings);
setEventListener("passwordExceptions", "command",
gPrivacyPane.showPasswordExceptions);
setEventListener("useMasterPassword", "command",
gPrivacyPane.updateMasterPasswordButton);
setEventListener("changeMasterPassword", "command",
gPrivacyPane.changeMasterPassword);
setEventListener("showPasswords", "command",
gPrivacyPane.showPasswords);
setEventListener("addonExceptions", "command",
gPrivacyPane.showAddonExceptions);
setEventListener("viewCertificatesButton", "command",
gPrivacyPane.showCertificates);
setEventListener("viewSecurityDevicesButton", "command",
gPrivacyPane.showSecurityDevices);
- setEventListener("connectionSettings", "command",
- gPrivacyPane.showConnections);
setEventListener("clearCacheButton", "command",
gPrivacyPane.clearCache);
this._pane = document.getElementById("panePrivacy");
this._initMasterPasswordUI();
this._initSafeBrowsing();
this.updateCacheSizeInputField();
this.updateActualCacheSize();
@@ -305,29 +236,28 @@ var gPrivacyPane = {
emeUIEnabled = emeUIEnabled && parseFloat(Services.sysinfo.get("version")) >= 6;
}
if (!emeUIEnabled) {
// Don't want to rely on .hidden for the toplevel groupbox because
// of the pane hiding/showing code potentially interfering:
document.getElementById("drmGroup").setAttribute("style", "display: none !important");
}
+ this.initDataCollection();
if (AppConstants.MOZ_CRASHREPORTER) {
this.initSubmitCrashes();
}
this.initTelemetry();
this.initSubmitHealthReport();
setEventListener("submitHealthReportBox", "command",
gPrivacyPane.updateSubmitHealthReport);
- // Append search keywords into the elements could open subdialogs.
let bundlePrefs = document.getElementById("bundlePreferences");
let signonBundle = document.getElementById("signonBundle");
let pkiBundle = document.getElementById("pkiBundle");
- let browserBundle = document.getElementById("browserBundle");
appendSearchKeywords("passwordExceptions", [
bundlePrefs.getString("savedLoginsExceptions_title"),
bundlePrefs.getString("savedLoginsExceptions_desc"),
]);
appendSearchKeywords("showPasswords", [
signonBundle.getString("loginsDescriptionAll"),
]);
appendSearchKeywords("trackingProtectionExceptions", [
@@ -348,22 +278,16 @@ var gPrivacyPane = {
]);
appendSearchKeywords("addonExceptions", [
bundlePrefs.getString("addons_permissions_title"),
bundlePrefs.getString("addonspermissionstext"),
]);
appendSearchKeywords("viewSecurityDevicesButton", [
pkiBundle.getString("enable_fips"),
]);
- appendSearchKeywords("browserContainersSettings", [
- browserBundle.getString("userContextPersonal.label"),
- browserBundle.getString("userContextWork.label"),
- browserBundle.getString("userContextBanking.label"),
- browserBundle.getString("userContextShopping.label"),
- ]);
appendSearchKeywords("siteDataSettings", [
bundlePrefs.getString("siteDataSettings.description"),
bundlePrefs.getString("removeAllCookies.label"),
bundlePrefs.getString("removeSelectedCookies.label"),
]);
},
// TRACKING PROTECTION MODE
@@ -652,23 +576,16 @@ var gPrivacyPane = {
windowTitle: bundlePreferences.getString("trackingprotectionpermissionstitle"),
introText: bundlePreferences.getString("trackingprotectionpermissionstext"),
};
gSubDialog.open("chrome://browser/content/preferences/permissions.xul",
null, params);
},
/**
- * Displays container panel for customising and adding containers.
- */
- showContainerSettings() {
- gotoPref("containers");
- },
-
- /**
* Displays the available block lists for tracking protection.
*/
showBlockLists() {
var bundlePreferences = document.getElementById("bundlePreferences");
let brandName = document.getElementById("bundleBrand")
.getString("brandShortName");
var params = { brandShortName: brandName,
windowTitle: bundlePreferences.getString("blockliststitle"),
@@ -1227,24 +1144,16 @@ var gPrivacyPane = {
/**
* Displays a dialog from which the user can manage his security devices.
*/
showSecurityDevices() {
gSubDialog.open("chrome://pippki/content/device_manager.xul");
},
- // NETWORK
- /**
- * Displays a dialog in which proxy settings may be changed.
- */
- showConnections() {
- gSubDialog.open("chrome://browser/content/preferences/connection.xul");
- },
-
/**
* Clears the cache.
*/
clearCache() {
try {
var cache = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
.getService(Components.interfaces.nsICacheStorageService);
cache.clear();
@@ -1389,31 +1298,34 @@ var gPrivacyPane = {
let result = Services.prompt.confirmEx(
window, title, text, flags, btn0Label, null, null, null, {});
if (result == 0) {
SiteDataManager.removeAll();
}
},
+ initDataCollection() {
+ this._setupLearnMoreLink("toolkit.datacollection.infoURL",
+ "dataCollectionLearnMore");
+ },
+
initSubmitCrashes() {
this._setupLearnMoreLink("toolkit.crashreporter.infoURL",
"crashReporterLearnMore");
},
/**
* The preference/checkbox is configured in XUL.
*
* In all cases, set up the Learn More link sanely.
*/
initTelemetry() {
- this._setupLearnMoreLink("toolkit.telemetry.infoURL", "telemetryLearnMore");
- // If we're not sending any Telemetry, disable the telemetry upload checkbox as well.
- if (!AppConstants.MOZ_TELEMETRY_REPORTING) {
- document.getElementById("submitTelemetryBox").setAttribute("disabled", "true");
+ if (AppConstants.MOZ_TELEMETRY_REPORTING) {
+ this._setupLearnMoreLink("toolkit.telemetry.infoURL", "telemetryLearnMore");
}
},
/**
* Set up or hide the Learn More links for various data collection options
*/
_setupLearnMoreLink(pref, element) {
// set up the Learn More link with the correct URL
--- a/browser/components/preferences/in-content-new/privacy.xul
+++ b/browser/components/preferences/in-content-new/privacy.xul
@@ -75,21 +75,16 @@
<!-- Private Browsing -->
<preference id="browser.privatebrowsing.autostart"
name="browser.privatebrowsing.autostart"
type="bool"/>
<!-- Do not track -->
<preference id="privacy.donottrackheader.enabled"
name="privacy.donottrackheader.enabled"
type="bool"/>
- <!-- DRM content -->
- <preference id="media.eme.enabled"
- name="media.eme.enabled"
- type="bool"/>
-
<!-- Popups -->
<preference id="dom.disable_open_during_load"
name="dom.disable_open_during_load"
type="bool"/>
<!-- Passwords -->
<preference id="signon.rememberSignons" name="signon.rememberSignons" type="bool"/>
<!-- XXX buttons -->
@@ -178,49 +173,51 @@
<hbox id="header-privacy"
class="header"
hidden="true"
data-category="panePrivacy">
<label class="header-name" flex="1">&panePrivacySecurity.title;</label>
</hbox>
-<!-- Permissions -->
-<groupbox id="permissionsGroup" data-category="panePrivacy" hidden="true">
- <caption><label>&permissions.label;</label></caption>
- <separator class="thin"/>
- <hbox align="start">
- <checkbox id="popupPolicy" preference="dom.disable_open_during_load"
- label="&blockPopups.label;" accesskey="&blockPopups.accesskey;"
- onsyncfrompreference="return gPrivacyPane.updateButtons('popupPolicyButton',
- 'dom.disable_open_during_load');"
- flex="1" />
- <button id="popupPolicyButton"
+<!-- Passwords -->
+<groupbox id="passwordsGroup" orient="vertical" data-category="panePrivacy" hidden="true">
+ <caption><label>&formsAndPasswords.label;</label></caption>
+
+ <vbox id="passwordSettings">
+ <hbox id="savePasswordsBox">
+ <checkbox id="savePasswords"
+ label="&rememberLogins1.label;" accesskey="&rememberLogins1.accesskey;"
+ preference="signon.rememberSignons"
+ onsyncfrompreference="return gPrivacyPane.readSavePasswords();"
+ flex="1" />
+ <button id="passwordExceptions"
+ class="accessory-button"
+ label="&passwordExceptions.label;"
+ accesskey="&passwordExceptions.accesskey;"
+ preference="pref.privacy.disable_button.view_passwords_exceptions"
+ searchkeywords="&address.label;"/>
+ </hbox>
+ <hbox id="showPasswordBox" pack="end">
+ <button id="showPasswords"
+ class="accessory-button"
+ label="&savedLogins.label;" accesskey="&savedLogins.accesskey;"
+ preference="pref.privacy.disable_button.view_passwords"
+ searchkeywords="&savedLogins.title;"/>
+ </hbox>
+ </vbox>
+ <hbox id="masterPasswordRow">
+ <checkbox id="useMasterPassword"
+ label="&useMasterPassword.label;"
+ accesskey="&useMasterPassword.accesskey;"
+ flex="1"/>
+ <button id="changeMasterPassword"
class="accessory-button"
- label="&popupExceptions.label;"
- accesskey="&popupExceptions.accesskey;"
- searchkeywords="&address.label; &button.cancel.label; &button.ok.label;"/>
- </hbox>
- <hbox id="addonInstallBox">
- <checkbox id="warnAddonInstall"
- label="&warnOnAddonInstall.label;"
- accesskey="&warnOnAddonInstall.accesskey;"
- preference="xpinstall.whitelist.required"
- onsyncfrompreference="return gPrivacyPane.readWarnAddonInstall();"
- flex="1" />
- <button id="addonExceptions"
- class="accessory-button"
- label="&addonExceptions.label;"
- accesskey="&addonExceptions.accesskey;"
- searchkeywords="&address.label;
- &allow.label;
- &removepermission.label;
- &removeallpermissions.label;
- &button.cancel.label;
- &button.ok.label;"/>
+ label="&changeMasterPassword.label;"
+ accesskey="&changeMasterPassword.accesskey;"/>
</hbox>
</groupbox>
<!-- History -->
<groupbox id="historyGroup" data-category="panePrivacy" hidden="true">
<caption><label>&history.label;</label></caption>
<hbox align="center">
<label id="historyModeLabel"
@@ -358,52 +355,86 @@
accesskey="&clearOnCloseSettings.accesskey;"/>
</hbox>
</vbox>
</vbox>
</vbox>
</deck>
</groupbox>
-<!-- Passwords -->
-<groupbox id="passwordsGroup" orient="vertical" data-category="panePrivacy" hidden="true">
- <caption><label>&formsAndPasswords.label;</label></caption>
+<!-- Address Bar -->
+<groupbox id="locationBarGroup"
+ data-category="panePrivacy"
+ hidden="true">
+ <caption><label>&addressBar.label;</label></caption>
+ <label id="locationBarSuggestionLabel">&addressBar.suggest.label;</label>
+ <checkbox id="historySuggestion" label="&locbar.history.label;"
+ accesskey="&locbar.history.accesskey;"
+ preference="browser.urlbar.suggest.history"/>
+ <checkbox id="bookmarkSuggestion" label="&locbar.bookmarks.label;"
+ accesskey="&locbar.bookmarks.accesskey;"
+ preference="browser.urlbar.suggest.bookmark"/>
+ <checkbox id="openpageSuggestion" label="&locbar.openpage.label;"
+ accesskey="&locbar.openpage.accesskey;"
+ preference="browser.urlbar.suggest.openpage"/>
+ <label class="text-link" onclick="gotoPref('general')">
+ &suggestionSettings2.label;
+ </label>
+</groupbox>
+
+<!-- Cache -->
+<groupbox id="cacheGroup" data-category="panePrivacy" hidden="true">
+ <caption><label>&httpCache.label;</label></caption>
- <vbox id="passwordSettings">
- <hbox id="savePasswordsBox">
- <checkbox id="savePasswords"
- label="&rememberLogins1.label;" accesskey="&rememberLogins1.accesskey;"
- preference="signon.rememberSignons"
- onsyncfrompreference="return gPrivacyPane.readSavePasswords();"
- flex="1" />
- <button id="passwordExceptions"
- class="accessory-button"
- label="&passwordExceptions.label;"
- accesskey="&passwordExceptions.accesskey;"
- preference="pref.privacy.disable_button.view_passwords_exceptions"
- searchkeywords="&address.label;"/>
- </hbox>
- <hbox id="showPasswordBox" pack="end">
- <button id="showPasswords"
- class="accessory-button"
- label="&savedLogins.label;" accesskey="&savedLogins.accesskey;"
- preference="pref.privacy.disable_button.view_passwords"
- searchkeywords="&savedLogins.title;"/>
- </hbox>
+ <hbox align="center">
+ <label id="actualDiskCacheSize" flex="1"/>
+ <button id="clearCacheButton"
+ class="accessory-button"
+ icon="clear"
+ label="&clearCacheNow.label;" accesskey="&clearCacheNow.accesskey;"/>
+ </hbox>
+ <checkbox preference="browser.cache.disk.smart_size.enabled"
+ id="allowSmartSize"
+ onsyncfrompreference="return gPrivacyPane.readSmartSizeEnabled();"
+ label="&overrideSmartCacheSize.label;"
+ accesskey="&overrideSmartCacheSize.accesskey;"/>
+ <hbox align="center" class="indent">
+ <label id="useCacheBefore" control="cacheSize"
+ accesskey="&limitCacheSizeBefore.accesskey;">
+ &limitCacheSizeBefore.label;
+ </label>
+ <textbox id="cacheSize" type="number" size="4" max="1024"
+ aria-labelledby="useCacheBefore cacheSize useCacheAfter"/>
+ <label id="useCacheAfter" flex="1">&limitCacheSizeAfter.label;</label>
+ </hbox>
+</groupbox>
+
+<!-- Site Data -->
+<groupbox id="siteDataGroup" hidden="true" data-category="panePrivacy" data-hidden-from-search="true">
+ <caption><label>&siteData.label;</label></caption>
+
+ <hbox align="baseline">
+ <label id="totalSiteDataSize"></label>
+ <label id="siteDataLearnMoreLink" class="learnMore text-link" value="&siteDataLearnMoreLink.label;"></label>
+ <spacer flex="1" />
+ <button id="clearSiteDataButton"
+ class="accessory-button"
+ icon="clear"
+ label="&clearSiteData.label;" accesskey="&clearSiteData.accesskey;"/>
+ </hbox>
+ <vbox align="end">
+ <button id="siteDataSettings"
+ class="accessory-button"
+ label="&siteDataSettings.label;"
+ accesskey="&siteDataSettings.accesskey;"
+ searchkeywords="&window.title;
+ &hostCol.label;
+ &statusCol.label;
+ &usageCol.label;"/>
</vbox>
- <hbox id="masterPasswordRow">
- <checkbox id="useMasterPassword"
- label="&useMasterPassword.label;"
- accesskey="&useMasterPassword.accesskey;"
- flex="1"/>
- <button id="changeMasterPassword"
- class="accessory-button"
- label="&changeMasterPassword.label;"
- accesskey="&changeMasterPassword.accesskey;"/>
- </hbox>
</groupbox>
<!-- Tracking -->
<groupbox id="trackingGroup" data-category="panePrivacy" hidden="true">
<caption><label>&trackingProtectionHeader2.label;</label></caption>
<vbox>
<hbox align="start">
<vbox flex="1">
@@ -468,19 +499,18 @@
<radiogroup id="doNotTrackRadioGroup" aria-labelledby="doNotTrackDesc" preference="privacy.donottrackheader.enabled">
<radio value="false" label="&doNotTrack.default.label;"/>
<radio value="true" label="&doNotTrack.always.label;"/>
</radiogroup>
</vbox>
</vbox>
</groupbox>
-<!-- Notifications -->
-<groupbox id="notificationsGroup" data-category="panePrivacy" hidden="true">
- <caption><label>¬ificationsPolicy.label;</label></caption>
+<!-- Permissions -->
+<groupbox id="permissionsGroup" data-category="panePrivacy" hidden="true">
<grid>
<columns>
<column flex="1"/>
<column/>
</columns>
<rows>
<row id="notificationsPolicyRow" align="center">
<hbox flex="1">
@@ -502,41 +532,95 @@
</rows>
</grid>
<vbox id="notificationsDoNotDisturbBox" hidden="true">
<checkbox id="notificationsDoNotDisturb" label="¬ificationsDoNotDisturb.label;"
accesskey="¬ificationsDoNotDisturb.accesskey;"/>
<label id="notificationsDoNotDisturbDetails"
class="indent">¬ificationsDoNotDisturbDetails.value;</label>
</vbox>
+
+ <hbox align="start">
+ <checkbox id="popupPolicy" preference="dom.disable_open_during_load"
+ label="&blockPopups.label;" accesskey="&blockPopups.accesskey;"
+ onsyncfrompreference="return gPrivacyPane.updateButtons('popupPolicyButton',
+ 'dom.disable_open_during_load');"
+ flex="1" />
+ <button id="popupPolicyButton"
+ class="accessory-button"
+ label="&popupExceptions.label;"
+ accesskey="&popupExceptions.accesskey;"
+ searchkeywords="&address.label; &button.cancel.label; &button.ok.label;"/>
+ </hbox>
+
+ <hbox id="addonInstallBox">
+ <checkbox id="warnAddonInstall"
+ label="&warnOnAddonInstall.label;"
+ accesskey="&warnOnAddonInstall.accesskey;"
+ preference="xpinstall.whitelist.required"
+ onsyncfrompreference="return gPrivacyPane.readWarnAddonInstall();"
+ flex="1" />
+ <button id="addonExceptions"
+ class="accessory-button"
+ label="&addonExceptions.label;"
+ accesskey="&addonExceptions.accesskey;"
+ searchkeywords="&address.label;
+ &allow.label;
+ &removepermission.label;
+ &removeallpermissions.label;
+ &button.cancel.label;
+ &button.ok.label;"/>
+ </hbox>
</groupbox>
-<!-- Location Bar -->
-<groupbox id="locationBarGroup"
- data-category="panePrivacy"
- hidden="true">
- <caption><label>&locationBar.label;</label></caption>
- <label id="locationBarSuggestionLabel">&locbar.suggest2.label;</label>
- <checkbox id="historySuggestion" label="&locbar.history.label;"
- accesskey="&locbar.history.accesskey;"
- preference="browser.urlbar.suggest.history"/>
- <checkbox id="bookmarkSuggestion" label="&locbar.bookmarks.label;"
- accesskey="&locbar.bookmarks.accesskey;"
- preference="browser.urlbar.suggest.bookmark"/>
- <checkbox id="openpageSuggestion" label="&locbar.openpage.label;"
- accesskey="&locbar.openpage.accesskey;"
- preference="browser.urlbar.suggest.openpage"/>
- <label class="text-link" onclick="gotoPref('general')">
- &suggestionSettings2.label;
- </label>
+<!-- Firefox Data Collection and Use -->
+#ifdef MOZ_DATA_REPORTING
+<groupbox id="dataCollectionGroup" data-category="panePrivacy" data-subcategory="reports" hidden="true">
+ <caption><label>&dataCollection.label;</label></caption>
+ <description>
+ &dataCollectionDesc.label;<label id="dataCollectionLearnMore" class="learnMore text-link">&dataCollectionLearnMore.label;</label>
+ </description>
+#ifndef MOZ_TELEMETRY_REPORTING
+ <description id="TelemetryDisabledDesc" control="telemetryGroup">&healthReportingDisabled.label;</description>
+#endif
+
+ <hbox align="center">
+ <checkbox id="submitHealthReportBox" label="&enableHealthReport.label;"
+ accesskey="&enableHealthReport.accesskey;"/>
+ <label id="FHRLearnMore"
+ class="learnMore text-link">&healthReportLearnMore.label;</label>
+ </hbox>
+ <description class="indent">&healthReportDesc.label;</description>
+ <vbox class="indent">
+ <hbox align="center">
+ <checkbox id="submitTelemetryBox" preference="toolkit.telemetry.enabled"
+ label="&enableTelemetryData.label;"
+ accesskey="&enableTelemetryData.accesskey;"/>
+ <label id="telemetryLearnMore"
+ class="learnMore text-link">&telemetryLearnMore.label;</label>
+ </hbox>
+ <description id="telemetryDataDesc"
+ class="indent">&telemetryDesc.label;</description>
+ </vbox>
+#ifdef MOZ_CRASHREPORTER
+ <hbox align="center">
+ <checkbox id="automaticallySubmitCrashesBox"
+ preference="browser.crashReports.unsubmittedCheck.autoSubmit"
+ label="&alwaysSubmitCrashReports.label;"
+ accesskey="&alwaysSubmitCrashReports.accesskey;"/>
+ <label id="crashReporterLearnMore"
+ class="learnMore text-link">&crashReporterLearnMore.label;</label>
+ </hbox>
+#endif
</groupbox>
+#endif
-<!-- Forgery (phishing) UI Security -->
-<groupbox id="phishingGroup" data-category="panePrivacy" hidden="true">
- <caption><label>&security.label;</label></caption>
+<!-- addons, forgery (phishing) UI Security -->
+<groupbox id="addonsPhishingGroup" data-category="panePrivacy" hidden="true">
+ <caption><label>&phishingProtection.label;</label></caption>
<checkbox id="enableSafeBrowsing"
label="&enableSafeBrowsing.label;"
accesskey="&enableSafeBrowsing.accesskey;" />
<vbox class="indent">
<checkbox id="blockDownloads"
label="&blockDownloads.label;"
accesskey="&blockDownloads.accesskey;" />
<checkbox id="blockUncommonUnwanted"
@@ -608,123 +692,16 @@
&devmgr.button.logout.label;
&devmgr.button.changepw.label;
&devmgr.button.load.label;
&devmgr.button.unload.label;"/>
</vbox>
</hbox>
</groupbox>
-<!-- DRM Content -->
-<groupbox id="drmGroup" data-category="panePrivacy" hidden="true">
- <caption><label>&drmContent.label;</label></caption>
- <grid id="contentGrid2">
- <columns>
- <column flex="1"/>
- <column/>
- </columns>
- <rows id="contentRows-2">
- <row id="playDRMContentRow">
- <hbox align="center">
- <checkbox id="playDRMContent" preference="media.eme.enabled"
- label="&playDRMContent.label;" accesskey="&playDRMContent.accesskey;"/>
- <label id="playDRMContentLink" class="learnMore text-link">
- &playDRMContent.learnMore.label;
- </label>
- </hbox>
- </row>
- </rows>
- </grid>
-</groupbox>
-
-<!-- Containers -->
-<groupbox id="browserContainersGroup" data-category="panePrivacy" hidden="true">
- <vbox id="browserContainersbox" hidden="true">
- <caption><label>&browserContainersHeader.label;</label></caption>
- <hbox align="center">
- <checkbox id="browserContainersCheckbox"
- label="&browserContainersEnabled.label;"
- accesskey="&browserContainersEnabled.accesskey;"
- preference="privacy.userContext.enabled"
- onsyncfrompreference="return gPrivacyPane.readBrowserContainersCheckbox();"/>
- <label id="browserContainersLearnMore" class="learnMore text-link">
- &browserContainersLearnMore.label;
- </label>
- <spacer flex="1"/>
- <button id="browserContainersSettings"
- class="accessory-button"
- label="&browserContainersSettings.label;"
- accesskey="&browserContainersSettings.accesskey;"
- searchkeywords="&addButton.label;
- &preferencesButton.label;
- &removeButton.label;"/>
- </hbox>
- </vbox>
-</groupbox>
-
-<!-- Network -->
-<!-- Connection -->
-<groupbox id="connectionGroup" data-category="panePrivacy" hidden="true">
- <caption><label>&connection.label;</label></caption>
-
- <hbox align="center">
- <description flex="1" control="connectionSettings">&connectionDesc.label;</description>
- <button id="connectionSettings"
- class="accessory-button"
- icon="network"
- label="&connectionSettings.label;"
- accesskey="&connectionSettings.accesskey;"
- searchkeywords="&connectionsDialog.title;
- &noProxyTypeRadio.label;
- &WPADTypeRadio.label;
- &systemTypeRadio.label;
- &manualTypeRadio.label;
- &http.label;
- &ssl.label;
- &ftp.label;
- &socks.label;
- &socks4.label;
- &socks5.label;
- &noproxy.label;
- &noproxyExplain.label;
- &shareproxy.label;
- &autoTypeRadio.label;
- &reload.label;
- &autologinproxy.label;
- &socksRemoteDNS.label2;"/>
- </hbox>
-</groupbox>
-
-<!-- Cache -->
-<groupbox id="cacheGroup" data-category="panePrivacy" hidden="true">
- <caption><label>&httpCache.label;</label></caption>
-
- <hbox align="center">
- <label id="actualDiskCacheSize" flex="1"/>
- <button id="clearCacheButton"
- class="accessory-button"
- icon="clear"
- label="&clearCacheNow.label;" accesskey="&clearCacheNow.accesskey;"/>
- </hbox>
- <checkbox preference="browser.cache.disk.smart_size.enabled"
- id="allowSmartSize"
- onsyncfrompreference="return gPrivacyPane.readSmartSizeEnabled();"
- label="&overrideSmartCacheSize.label;"
- accesskey="&overrideSmartCacheSize.accesskey;"/>
- <hbox align="center" class="indent">
- <label id="useCacheBefore" control="cacheSize"
- accesskey="&limitCacheSizeBefore.accesskey;">
- &limitCacheSizeBefore.label;
- </label>
- <textbox id="cacheSize" type="number" size="4" max="1024"
- aria-labelledby="useCacheBefore cacheSize useCacheAfter"/>
- <label id="useCacheAfter" flex="1">&limitCacheSizeAfter.label;</label>
- </hbox>
-</groupbox>
-
<!-- Offline apps -->
<groupbox id="offlineGroup" data-category="panePrivacy" hidden="true" data-hidden-from-search="true">
<caption><label>&offlineStorage2.label;</label></caption>
<hbox align="center">
<label id="actualAppCacheSize" flex="1"/>
<button id="clearOfflineAppCacheButton"
class="accessory-button"
@@ -754,78 +731,8 @@
<button id="offlineAppsListRemove"
class="accessory-button"
disabled="true"
label="&offlineAppsListRemove.label;"
accesskey="&offlineAppsListRemove.accesskey;"/>
</vbox>
</hbox>
</groupbox>
-
-<!-- Site Data -->
-<groupbox id="siteDataGroup" hidden="true" data-category="panePrivacy" data-hidden-from-search="true">
- <caption><label>&siteData.label;</label></caption>
-
- <hbox align="baseline">
- <label id="totalSiteDataSize"></label>
- <label id="siteDataLearnMoreLink" class="learnMore text-link" value="&siteDataLearnMoreLink.label;"></label>
- <spacer flex="1" />
- <button id="clearSiteDataButton"
- class="accessory-button"
- icon="clear"
- label="&clearSiteData.label;" accesskey="&clearSiteData.accesskey;"/>
- </hbox>
- <vbox align="end">
- <button id="siteDataSettings"
- class="accessory-button"
- label="&siteDataSettings.label;"
- accesskey="&siteDataSettings.accesskey;"
- searchkeywords="&window.title;
- &hostCol.label;
- &statusCol.label;
- &usageCol.label;"/>
- </vbox>
-</groupbox>
-
-<!-- Data Choices -->
-#ifdef MOZ_DATA_REPORTING
-
-<groupbox id="telemetryGroup" data-category="panePrivacy" data-subcategory="reports" hidden="true">
-<caption><label>&reports.label;</label></caption>
-#ifndef MOZ_TELEMETRY_REPORTING
- <description id="TelemetryDisabledDesc" control="telemetryGroup">&healthReportingDisabled.label;</description>
-#endif
-
- <hbox align="center">
- <checkbox id="submitHealthReportBox" label="&enableHealthReport.label;"
- accesskey="&enableHealthReport.accesskey;"/>
- <label id="FHRLearnMore"
- class="learnMore text-link">&healthReportLearnMore.label;</label>
- </hbox>
- <description class="indent">&healthReportDesc.label;</description>
- <vbox class="indent">
- <hbox align="center">
- <checkbox id="submitTelemetryBox" preference="toolkit.telemetry.enabled"
- label="&enableTelemetryData.label;"
- accesskey="&enableTelemetryData.accesskey;"/>
- <label id="telemetryLearnMore"
- class="learnMore text-link">&telemetryLearnMore.label;</label>
- </hbox>
- <description id="telemetryDataDesc"
- class="indent">&telemetryDesc.label;</description>
- </vbox>
-</groupbox>
-
-#ifdef MOZ_CRASHREPORTER
-<groupbox id="crashReporterGroup" data-category="panePrivacy" data-subcategory="reports" hidden="true">
- <hbox align="center">
- <checkbox id="automaticallySubmitCrashesBox"
- preference="browser.crashReports.unsubmittedCheck.autoSubmit"
- label="&alwaysSubmitCrashReports.label;"
- accesskey="&alwaysSubmitCrashReports.accesskey;"/>
- <label id="crashReporterLearnMore"
- class="learnMore text-link">&crashReporterLearnMore.label;</label>
- </hbox>
- <description class="indent">&crashReporterDesc2.label;</description>
-</groupbox>
-
-#endif
-#endif
copy from browser/components/preferences/in-content/search.js
copy to browser/components/preferences/in-content-new/search.js
copy from browser/components/preferences/in-content/search.xul
copy to browser/components/preferences/in-content-new/search.xul
--- a/browser/components/preferences/in-content/search.xul
+++ b/browser/components/preferences/in-content-new/search.xul
@@ -10,53 +10,52 @@
<preference id="browser.search.hiddenOneOffs"
name="browser.search.hiddenOneOffs"
type="unichar"/>
</preferences>
<script type="application/javascript"
- src="chrome://browser/content/preferences/in-content/search.js"/>
+ src="chrome://browser/content/preferences/in-content-new/search.js"/>
<stringbundle id="engineManagerBundle" src="chrome://browser/locale/engineManager.properties"/>
<hbox id="header-search"
class="header"
hidden="true"
data-category="paneSearch">
<label class="header-name" flex="1">&paneSearch.title;</label>
- <html:a class="help-button" target="_blank" aria-label="&helpButton.label;"></html:a>
</hbox>
<!-- Default Search Engine -->
<groupbox id="defaultEngineGroup" align="start" data-category="paneSearch">
<caption label="&defaultSearchEngine.label;"/>
- <label>&chooseYourDefaultSearchEngine.label;</label>
+ <label>&chooseYourDefaultSearchEngine2.label;</label>
<menulist id="defaultEngine">
<menupopup/>
</menulist>
<checkbox id="suggestionsInSearchFieldsCheckbox"
label="&provideSearchSuggestions.label;"
accesskey="&provideSearchSuggestions.accesskey;"
preference="browser.search.suggest.enabled"/>
<vbox class="indent">
- <checkbox id="urlBarSuggestion" label="&showURLBarSuggestions.label;"
- accesskey="&showURLBarSuggestions.accesskey;"
+ <checkbox id="urlBarSuggestion" label="&showURLBarSuggestions2.label;"
+ accesskey="&showURLBarSuggestions2.accesskey;"
preference="browser.urlbar.suggest.searches"/>
<hbox id="urlBarSuggestionPermanentPBLabel"
align="center" class="indent">
<label flex="1">&urlBarSuggestionsPermanentPB.label;</label>
</hbox>
</vbox>
</groupbox>
<groupbox id="oneClickSearchProvidersGroup" data-category="paneSearch">
<caption label="&oneClickSearchEngines.label;"/>
- <label>&chooseWhichOneToDisplay.label;</label>
+ <label>&chooseWhichOneToDisplay2.label;</label>
<tree id="engineList" flex="1" rows="8" hidecolumnpicker="true" editable="true"
seltype="single">
<treechildren id="engineChildren" flex="1"/>
<treecols>
<treecol id="engineShown" type="checkbox" editable="true" sortable="false"/>
<treecol id="engineName" flex="4" label="&engineNameColumn.label;" sortable="false"/>
<treecol id="engineKeyword" flex="1" label="&engineKeywordColumn.label;" editable="true"
@@ -76,11 +75,11 @@
accesskey="&removeEngine.accesskey;"
disabled="true"
/>
</hbox>
<separator class="thin"/>
<hbox id="addEnginesBox" pack="start">
- <label id="addEngines" class="text-link" value="&addMoreSearchEngines.label;"/>
+ <label id="addEngines" class="text-link" value="&findMoreSearchEngines.label;"/>
</hbox>
</groupbox>
--- a/browser/installer/allowed-dupes.mn
+++ b/browser/installer/allowed-dupes.mn
@@ -16,18 +16,16 @@ browser/chrome/browser/content/browser/p
browser/chrome/browser/content/browser/preferences/in-content/containers.js
browser/chrome/browser/content/browser/preferences/in-content/content.js
browser/chrome/browser/content/browser/preferences/in-content/main.js
browser/chrome/browser/content/browser/preferences/in-content/preferences.js
browser/chrome/browser/content/browser/preferences/in-content/privacy.js
browser/chrome/browser/content/browser/preferences/in-content/search.js
browser/chrome/browser/content/browser/preferences/in-content/security.js
browser/chrome/browser/content/browser/preferences/in-content/sync.js
-browser/chrome/browser/content/browser/preferences/in-content-new/advanced.js
-browser/chrome/browser/content/browser/preferences/in-content-new/applications.js
browser/chrome/browser/content/browser/preferences/in-content-new/containers.js
browser/chrome/browser/content/browser/preferences/in-content-new/content.js
browser/chrome/browser/content/browser/preferences/in-content-new/main.js
browser/chrome/browser/content/browser/preferences/in-content-new/preferences.js
browser/chrome/browser/content/browser/preferences/in-content-new/privacy.js
browser/chrome/browser/content/browser/preferences/in-content-new/search.js
browser/chrome/browser/content/browser/preferences/in-content-new/security.js
browser/chrome/browser/content/browser/preferences/in-content-new/sync.js
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -1,24 +1,20 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!-- Note: each tab panel must contain unique accesskeys -->
<!ENTITY generalTab.label "General">
-<!ENTITY accessibility.label "Accessibility">
-
<!ENTITY useCursorNavigation.label "Always use the cursor keys to navigate within pages">
<!ENTITY useCursorNavigation.accesskey "c">
<!ENTITY searchOnStartTyping.label "Search for text when you start typing">
<!ENTITY searchOnStartTyping.accesskey "x">
-<!ENTITY blockAutoReload.label "Warn you when websites try to redirect or reload the page">
-<!ENTITY blockAutoReload.accesskey "b">
<!ENTITY useOnScreenKeyboard.label "Show a touch keyboard when necessary">
<!ENTITY useOnScreenKeyboard.accesskey "k">
<!ENTITY browsing.label "Browsing">
<!ENTITY useAutoScroll.label "Use autoscrolling">
<!ENTITY useAutoScroll.accesskey "a">
<!ENTITY useSmoothScrolling.label "Use smooth scrolling">
@@ -38,24 +34,27 @@ available. -->
<!ENTITY enableHealthReport.accesskey "R">
<!ENTITY healthReportLearnMore.label "Learn more">
<!ENTITY telemetryDesc.label "Shares performance, usage, hardware and customization data about your browser with &vendorShortName; to help us make &brandShortName; better">
<!ENTITY enableTelemetryData.label "Share Additional Data (i.e., Telemetry)">
<!ENTITY enableTelemetryData.accesskey "T">
<!ENTITY telemetryLearnMore.label "Learn more">
-<!ENTITY crashReporterDesc2.label "Crash reports help &vendorShortName; fix problems and make your browser more stable and secure">
-<!ENTITY alwaysSubmitCrashReports.label "Allow &brandShortName; to send backlogged crash reports on your behalf">
+<!ENTITY dataCollection.label "&brandShortName; Data Collection and Use">
+<!ENTITY dataCollectionDesc.label "We strive to provide you with choices and collect only what we need to provide and improve &brandShortName; for everyone. We always ask permission before receiving personal information.">
+<!ENTITY dataCollectionLearnMore.label "Learn more">
+
+<!ENTITY alwaysSubmitCrashReports.label "Allow &brandShortName; to send backlogged crash reports on your behalf">
<!ENTITY alwaysSubmitCrashReports.accesskey "c">
-<!ENTITY crashReporterLearnMore.label "Learn more">
+<!ENTITY crashReporterLearnMore.label "Learn more">
<!ENTITY networkTab.label "Network">
-<!ENTITY connection.label "Connection">
+<!ENTITY networkProxy.label "Network Proxy">
<!ENTITY connectionDesc.label "Configure how &brandShortName; connects to the Internet">
<!ENTITY connectionSettings.label "Settings…">
<!ENTITY connectionSettings.accesskey "e">
<!ENTITY httpCache.label "Cached Web Content">
<!ENTITY offlineStorage2.label "Offline Web Content and User Data">
@@ -111,18 +110,16 @@ available. -->
<!ENTITY updateHistory2.accesskey "p">
<!ENTITY useService.label "Use a background service to install updates">
<!ENTITY useService.accesskey "b">
<!ENTITY enableSearchUpdate2.label "Automatically update search engines">
<!ENTITY enableSearchUpdate2.accesskey "e">
-<!ENTITY reports.label "Reports">
-
<!ENTITY offlineStorageNotify.label "Tell you when a website asks to store data for offline use">
<!ENTITY offlineStorageNotify.accesskey "T">
<!ENTITY offlineStorageNotifyExceptions.label "Exceptions…">
<!ENTITY offlineStorageNotifyExceptions.accesskey "x">
<!ENTITY offlineAppsList2.label "The following websites are allowed to store data for offline use:">
<!ENTITY offlineAppsList.height "7em">
<!ENTITY offlineAppsListRemove.label "Remove…">
--- a/browser/locales/en-US/chrome/browser/preferences/containers.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/containers.dtd
@@ -2,17 +2,17 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY addButton.label "Add New Container">
<!ENTITY addButton.accesskey "A">
<!ENTITY preferencesButton.label "Preferences">
<!ENTITY removeButton.label "Remove">
<!-- « is « however it's not defined in XML -->
-<!ENTITY backLink.label "« Go Back to Privacy">
+<!ENTITY backLink2.label "« Go Back">
<!ENTITY window.title "Add New Container">
<!ENTITY window.width "45em">
<!ENTITY name.label "Name:">
<!ENTITY name.accesskey "N">
<!ENTITY name.placeholder "Enter a container name">
<!ENTITY icon.label "Icon:">
--- a/browser/locales/en-US/chrome/browser/preferences/content.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/content.dtd
@@ -1,17 +1,17 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!ENTITY permissions.label "Permissions">
<!ENTITY blockPopups.label "Block pop-up windows">
<!ENTITY blockPopups.accesskey "B">
-<!ENTITY notificationsPolicy.label "Notifications">
<!ENTITY notificationsPolicyLearnMore.label "Learn more">
<!ENTITY notificationsPolicyDesc3.label "Choose which sites are allowed to send you notifications">
<!ENTITY notificationsPolicyButton.accesskey "h">
<!ENTITY notificationsPolicyButton.label "Choose…">
<!ENTITY notificationsDoNotDisturb.label "Do not disturb me">
<!ENTITY notificationsDoNotDisturb.accesskey "n">
<!ENTITY notificationsDoNotDisturbDetails.value "No notification will be shown until you restart &brandShortName;">
@@ -27,17 +27,17 @@
<!ENTITY advancedFonts.label "Advanced…">
<!ENTITY advancedFonts.accesskey "A">
<!ENTITY colors.label "Colors…">
<!ENTITY colors.accesskey "C">
-<!ENTITY languages.label "Languages">
+<!ENTITY language2.label "Language">
<!ENTITY chooseLanguage.label "Choose your preferred language for displaying pages">
<!ENTITY chooseButton.label "Choose…">
<!ENTITY chooseButton.accesskey "o">
<!ENTITY translateWebPages.label "Translate web content">
<!ENTITY translateWebPages.accesskey "T">
<!ENTITY translateExceptions.label "Exceptions…">
<!ENTITY translateExceptions.accesskey "x">
@@ -47,13 +47,13 @@
- These 2 strings are displayed before and after a 'Microsoft Translator'
- logo.
- The translations for these strings should match the translations in
- browser/translation.dtd
-->
<!ENTITY translation.options.attribution.beforeLogo "Translations by">
<!ENTITY translation.options.attribution.afterLogo "">
-<!ENTITY drmContent.label "DRM Content">
+<!ENTITY drmContent2.label "Digital Rights Management (DRM) Content">
-<!ENTITY playDRMContent.label "Play DRM content">
-<!ENTITY playDRMContent.accesskey "P">
+<!ENTITY playDRMContent2.label "Play DRM-controlled content">
+<!ENTITY playDRMContent2.accesskey "P">
<!ENTITY playDRMContent.learnMore.label "Learn more">
--- a/browser/locales/en-US/chrome/browser/preferences/main.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/main.dtd
@@ -5,17 +5,17 @@
<!ENTITY startup.label "Startup">
<!ENTITY startupPage2.label "When &brandShortName; starts">
<!ENTITY startupPage2.accesskey "s">
<!ENTITY startupUserHomePage.label "Show your home page">
<!ENTITY startupBlankPage.label "Show a blank page">
<!ENTITY startupPrevSession.label "Show your windows and tabs from last time">
-<!ENTITY homepage2.label "Home Page">
+<!ENTITY homepage2.label "Home page">
<!ENTITY homepage2.accesskey "P">
<!ENTITY useCurrentPage.label "Use Current Page">
<!ENTITY useCurrentPage.accesskey "C">
<!ENTITY useMultiple.label "Use Current Pages">
<!ENTITY chooseBookmark.label "Use Bookmark…">
<!ENTITY chooseBookmark.accesskey "B">
<!ENTITY restoreDefault.label "Restore to Default">
<!ENTITY restoreDefault.accesskey "R">
@@ -28,18 +28,18 @@
<!ENTITY chooseFolderWin.accesskey "o">
<!ENTITY chooseFolderMac.label "Choose…">
<!ENTITY chooseFolderMac.accesskey "e">
<!ENTITY alwaysAskWhere.label "Always ask you where to save files">
<!ENTITY alwaysAskWhere.accesskey "A">
<!ENTITY alwaysCheckDefault2.label "Always check if &brandShortName; is your default browser">
<!ENTITY alwaysCheckDefault2.accesskey "y">
-<!ENTITY setAsMyDefaultBrowser2.label "Make Default">
-<!ENTITY setAsMyDefaultBrowser2.accesskey "D">
+<!ENTITY setAsMyDefaultBrowser3.label "Make Default…">
+<!ENTITY setAsMyDefaultBrowser3.accesskey "D">
<!ENTITY isDefault.label "&brandShortName; is currently your default browser">
<!ENTITY isNotDefault.label "&brandShortName; is not your default browser">
<!ENTITY separateProfileMode.label "Allow &brandShortName; and Firefox to run at the same time">
<!ENTITY useFirefoxSync.label "Tip: This uses separate profiles. Use Sync to share data between them.">
<!ENTITY getStarted.notloggedin.label "Sign in to &syncBrand.shortName.label;…">
<!ENTITY getStarted.configured.label "Open &syncBrand.shortName.label; preferences">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.dtd
@@ -10,19 +10,18 @@
<!-- When making changes to prefWindow.styleWin test both Windows Classic and
Luna since widget heights are different based on the OS theme -->
<!ENTITY prefWinMinSize.styleWin2 "width: 42em; min-height: 37.5em;">
<!ENTITY prefWinMinSize.styleMac "width: 47em; min-height: 40em;">
<!ENTITY prefWinMinSize.styleGNOME "width: 45.5em; min-height: 40.5em;">
<!ENTITY paneSearchResults.title "Search Results">
<!ENTITY paneGeneral.title "General">
+<!ENTITY paneSearch.title "Search">
<!ENTITY paneFilesApplications.title "Files & Applications">
<!ENTITY panePrivacySecurity.title "Privacy & Security">
<!ENTITY paneContainers.title "Container Tabs">
<!ENTITY paneUpdates.title "Updates">
<!-- LOCALIZATION NOTE (paneSync1.title): This should match syncBrand.fxAccount.label in ../syncBrand.dtd -->
<!ENTITY paneSync1.title "Firefox Account">
<!ENTITY helpButton2.label "&brandShortName; Support">
-
-<!ENTITY searchInput.label "Search">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -250,16 +250,20 @@ removeContainerAlertTitle=Remove This Co
# LOCALIZATION NOTE (removeContainerMsg): Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #S is the number of container tabs
removeContainerMsg=If you remove this Container now, #S container tab will be closed. Are you sure you want to remove this Container?;If you remove this Container now, #S container tabs will be closed. Are you sure you want to remove this Container?
removeContainerOkButton=Remove this Container
removeContainerButton2=Don’t remove this Container
+# Search Input
+searchInput.labelWin=Find in Options
+searchInput.labelUnix=Find in Preferences
+
# Search Results Pane
# LOCALIZATION NOTE %S will be replaced by the word being searched
searchResults.sorryMessageWin=Sorry! There are no results in Options for “%S”.
searchResults.sorryMessageUnix=Sorry! There are no results in Preferences for “%S”.
# LOCALIZATION NOTE (searchResults.needHelp2): %1$S is a link to SUMO, %2$S is
# the browser name
searchResults.needHelp2=Need help? Visit <html:a id="need-help-link" target="_blank" href="%1$S">%2$S Support</html:a>
--- a/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
@@ -26,19 +26,18 @@
<!ENTITY doNotTrack.description "Send websites a “Do Not Track” signal that you don’t want to be tracked">
<!ENTITY doNotTrack.learnMore.label "Learn more">
<!ENTITY doNotTrack.default.label "Only when using Tracking Protection">
<!ENTITY doNotTrack.always.label "Always">
<!ENTITY history.label "History">
<!ENTITY permissions.label "Permissions">
-<!ENTITY locationBar.label "Location Bar">
-
-<!ENTITY locbar.suggest2.label "When using the location bar, suggest">
+<!ENTITY addressBar.label "Address Bar">
+<!ENTITY addressBar.suggest.label "When using the address bar, suggest">
<!ENTITY locbar.history.label "History">
<!ENTITY locbar.history.accesskey "H">
<!ENTITY locbar.bookmarks.label "Bookmarks">
<!ENTITY locbar.bookmarks.accesskey "k">
<!ENTITY locbar.openpage.label "Open tabs">
<!ENTITY locbar.openpage.accesskey "O">
<!ENTITY locbar.searches.label "Related searches from the default search engine">
<!ENTITY locbar.searches.accesskey "d">
@@ -102,14 +101,13 @@
<!ENTITY rememberSearchForm.accesskey "f">
<!ENTITY clearOnClose.label "Clear history when &brandShortName; closes">
<!ENTITY clearOnClose.accesskey "r">
<!ENTITY clearOnCloseSettings.label "Settings…">
<!ENTITY clearOnCloseSettings.accesskey "t">
-<!ENTITY browserContainersHeader.label "Container Tabs">
<!ENTITY browserContainersLearnMore.label "Learn more">
<!ENTITY browserContainersEnabled.label "Enable Container Tabs">
<!ENTITY browserContainersEnabled.accesskey "n">
<!ENTITY browserContainersSettings.label "Settings…">
<!ENTITY browserContainersSettings.accesskey "i">
--- a/browser/locales/en-US/chrome/browser/preferences/search.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/search.dtd
@@ -1,29 +1,29 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY defaultSearchEngine.label "Default Search Engine">
-<!ENTITY chooseYourDefaultSearchEngine.label "Choose your default search engine. &brandShortName; uses it in the location bar, search bar, and start page.">
+<!ENTITY chooseYourDefaultSearchEngine2.label "Choose the default search engine to use in the address bar and search bar.">
<!ENTITY provideSearchSuggestions.label "Provide search suggestions">
<!ENTITY provideSearchSuggestions.accesskey "s">
-<!ENTITY showURLBarSuggestions.label "Show search suggestions in location bar results">
-<!ENTITY showURLBarSuggestions.accesskey "l">
+<!ENTITY showURLBarSuggestions2.label "Show search suggestions in address bar results">
+<!ENTITY showURLBarSuggestions2.accesskey "l">
<!ENTITY urlBarSuggestionsPermanentPB.label "Search suggestions will not be shown in location bar results because you have configured &brandShortName; to never remember history.">
<!ENTITY oneClickSearchEngines.label "One-Click Search Engines">
-<!ENTITY chooseWhichOneToDisplay.label "The search bar lets you search alternate engines directly. Choose which ones to display.">
+<!ENTITY chooseWhichOneToDisplay2.label "Choose the alternative search engines that appear below the address bar and search bar when you start to enter a keyword.">
<!ENTITY engineNameColumn.label "Search Engine">
<!ENTITY engineKeywordColumn.label "Keyword">
<!ENTITY restoreDefaultSearchEngines.label "Restore Default Search Engines">
<!ENTITY restoreDefaultSearchEngines.accesskey "d">
<!ENTITY removeEngine.label "Remove">
<!ENTITY removeEngine.accesskey "r">
-<!ENTITY addMoreSearchEngines2.label "Add more search engines">
+<!ENTITY findMoreSearchEngines.label "Find more search engines">
--- a/browser/locales/en-US/chrome/browser/preferences/security.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/security.dtd
@@ -1,13 +1,14 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!ENTITY security.label "Security">
+<!ENTITY phishingProtection.label "Phishing Protection">
<!ENTITY warnOnAddonInstall.label "Warn you when sites try to install add-ons">
<!ENTITY warnOnAddonInstall.accesskey "W">
<!-- LOCALIZATION NOTE (enableSafeBrowsing.label, blockDownloads.label, blockUncommonUnwanted.label):
It is important that wording follows the guidelines outlined on this page:
https://developers.google.com/safe-browsing/developers_guide_v2#AcceptableUsage
-->
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -76,16 +76,20 @@ treecol {
display: -moz-box;
visibility: collapse;
}
#category-general > .category-icon {
list-style-image: url("chrome://browser/skin/preferences/in-content-new/icons.svg#general");
}
+#category-search > .category-icon {
+ list-style-image: url("chrome://browser/skin/preferences/in-content-new/icons.svg#searchResults");
+}
+
#category-application > .category-icon {
list-style-image: url("chrome://browser/skin/preferences/in-content-new/icons.svg#content");
}
#category-privacy > .category-icon {
list-style-image: url("chrome://browser/skin/preferences/in-content-new/icons.svg#security");
}
@@ -239,20 +243,16 @@ treecol {
#doNotTrackLearnMoreBox {
margin-top: 30px
}
#trackingProtectionAdvancedSettings {
margin-inline-start: 15px;
}
-#crashReporterGroup {
- margin-top: 0;
-}
-
/* Collapse the non-active vboxes in decks to use only the height the
active vbox needs */
#historyPane:not([selectedIndex="1"]) > #historyDontRememberPane,
#historyPane:not([selectedIndex="2"]) > #historyCustomPane,
#weavePrefsDeck:not([selectedIndex="1"]) > #hasFxaAccount,
#fxaLoginStatus:not([selectedIndex="1"]) > #fxaLoginUnverified,
#fxaLoginStatus:not([selectedIndex="2"]) > #fxaLoginRejected {
visibility: collapse;