--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -1376,17 +1376,17 @@ var gMainPane = {
audioFeedHandlerInfo.handledOnlyByPlugin = false;
},
/**
* Load higher level internal handlers so they can be turned on/off in the
* applications menu.
*/
_loadInternalHandlers() {
- var internalHandlers = [pdfHandlerInfo];
+ var internalHandlers = [new PDFHandlerInfoWrapper()];
for (let internalHandler of internalHandlers) {
if (internalHandler.enabled) {
this._handledTypes[internalHandler.type] = internalHandler;
}
}
},
/**
@@ -1980,16 +1980,24 @@ var gMainPane = {
focusFilterBox() {
this._filter.focus();
this._filter.select();
},
// Changes
+ // 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,
+
onSelectAction(aActionItem) {
this._storingAction = true;
try {
this._storeAction(aActionItem);
} finally {
this._storingAction = false;
}
@@ -2609,77 +2617,60 @@ function isFeedType(t) {
* 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,
-
-
- // nsIHandlerInfo
-
- // The MIME type or protocol scheme.
- _type: null,
- get type() {
- return this._type;
- },
+class HandlerInfoWrapper {
+ constructor(type, handlerInfo) {
+ this.type = type;
+ this.wrappedHandlerInfo = handlerInfo;
+ }
get description() {
if (this.wrappedHandlerInfo.description)
return this.wrappedHandlerInfo.description;
if (this.primaryExtension) {
var extension = this.primaryExtension.toUpperCase();
return gMainPane._prefsBundle.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;
@@ -2688,25 +2679,25 @@ HandlerInfoWrapper.prototype = {
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
@@ -2718,17 +2709,17 @@ HandlerInfoWrapper.prototype = {
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;
@@ -2736,17 +2727,17 @@ HandlerInfoWrapper.prototype = {
// 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)
@@ -2758,96 +2749,92 @@ HandlerInfoWrapper.prototype = {
// 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
-
+ }
+
+ // this.pluginName
+ //
// 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,
-
+
+ // this.handledOnlyByPlugin
+ //
// 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().includes(this.type);
- },
+ }
_getDisabledPluginTypes() {
var types = "";
if (Services.prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES))
types = Services.prefs.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.includes(this.type))
disabledPluginTypes.push(this.type);
Services.prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
disabledPluginTypes.join(","));
// Update the category manager so existing browser windows update.
gCategoryManager.deleteCategoryEntry("Gecko-Content-Viewers",
this.type,
false);
- },
+ }
enablePluginType() {
var disabledPluginTypes = this._getDisabledPluginTypes();
var type = this.type;
disabledPluginTypes = disabledPluginTypes.filter(v => v != type);
Services.prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
@@ -2855,75 +2842,56 @@ HandlerInfoWrapper.prototype = {
// Update the category manager so existing browser windows update.
gCategoryManager.addCategoryEntry(
"Gecko-Content-Viewers",
this.type,
"@mozilla.org/content/plugin/document-loader-factory;1",
false,
true);
- },
-
-
- // Storage
+ }
store() {
gHandlerService.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,
-
- // nsIHandlerInfo
+class FeedHandlerInfo extends HandlerInfoWrapper {
+ constructor(aMIMEType, properties) {
+ super(aMIMEType, null);
+ Object.assign(this, properties);
+ }
get description() {
return gMainPane._prefsBundle.getString(this._appPrefLabel);
- },
+ }
get preferredApplicationHandler() {
switch (Preferences.get(this._prefSelectedReader).value) {
case "client":
var file = Preferences.get(this._prefSelectedApp).value;
if (file)
return getLocalHandlerApp(file);
@@ -2937,36 +2905,34 @@ FeedHandlerInfo.prototype = {
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) {
Preferences.get(this._prefSelectedApp).value = aNewValue.executable;
Preferences.get(this._prefSelectedReader).value = "client";
} else if (aNewValue instanceof Ci.nsIWebContentHandlerInfo) {
Preferences.get(this._prefSelectedWeb).value = aNewValue.uri;
Preferences.get(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.
gWebContentContentConverterService.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 = {
@@ -3012,19 +2978,18 @@ FeedHandlerInfo.prototype = {
}
// Add the registered web handlers. There can be any number of these.
var webHandlers = gWebContentContentConverterService.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 = getShellService().defaultFeedReader;
@@ -3041,38 +3006,38 @@ FeedHandlerInfo.prototype = {
handlerApp.executable = defaultFeedReader;
this.__defaultApplicationHandler = handlerApp;
} else {
this.__defaultApplicationHandler = null;
}
return this.__defaultApplicationHandler;
- },
+ }
get hasDefaultHandler() {
if (AppConstants.HAVE_SHELL_SERVICE) {
try {
if (getShellService().defaultFeedReader)
return true;
} catch (ex) {
// no default reader or getShellService() 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 (Preferences.get(this._prefSelectedAction).value) {
case "bookmarks":
return Ci.nsIHandlerInfo.handleInternally;
@@ -3098,17 +3063,17 @@ FeedHandlerInfo.prototype = {
// 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:
Preferences.get(this._prefSelectedReader).value = "bookmarks";
break;
@@ -3118,46 +3083,32 @@ FeedHandlerInfo.prototype = {
// to the new helper app.
break;
case Ci.nsIHandlerInfo.useSystemDefault:
Preferences.get(this._prefSelectedAction).value = "reader";
this.preferredApplicationHandler = this._defaultApplicationHandler;
break;
}
- },
+ }
get alwaysAskBeforeHandling() {
return Preferences.get(this._prefSelectedAction).value == "ask";
- },
+ }
set alwaysAskBeforeHandling(aNewValue) {
if (aNewValue)
Preferences.get(this._prefSelectedAction).value = "ask";
else
Preferences.get(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) {
@@ -3171,89 +3122,86 @@ FeedHandlerInfo.prototype = {
}
} else {
app.QueryInterface(Ci.nsIWebContentHandlerInfo);
gWebContentContentConverterService.removeContentHandler(app.contentType,
app.uri);
}
}
this._possibleApplicationHandlers._removed = [];
- },
-
-
- // Icons
+ }
get smallIcon() {
return this._smallIcon;
}
-
-};
-
-var feedHandlerInfo = {
- __proto__: new FeedHandlerInfo(TYPE_MAYBE_FEED),
+}
+
+var feedHandlerInfo = 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),
+});
+
+var videoFeedHandlerInfo = 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),
+});
+
+var audioFeedHandlerInfo = 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,
+class InternalHandlerInfoWrapper extends HandlerInfoWrapper {
+ constructor(mimeType) {
+ super(mimeType, gMIMEService.getFromTypeAndExtension(mimeType, null));
+ }
// Override store so we so we can notify any code listening for registration
// or unregistration of this handler.
store() {
- HandlerInfoWrapper.prototype.store.call(this);
+ super.store();
Services.obs.notifyObservers(null, this._handlerChanged);
- },
+ }
get enabled() {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- },
+ }
get description() {
return gMainPane._prefsBundle.getString(this._appPrefLabel);
}
-};
-
-var pdfHandlerInfo = {
- __proto__: new InternalHandlerInfoWrapper(TYPE_PDF),
- _handlerChanged: TOPIC_PDFJS_HANDLER_CHANGED,
- _appPrefLabel: "portableDocumentFormat",
+}
+
+class PDFHandlerInfoWrapper extends InternalHandlerInfoWrapper {
+ constructor() {
+ super(TYPE_PDF);
+ }
+
+ get _handlerChanged() {
+ return TOPIC_PDFJS_HANDLER_CHANGED;
+ }
+
+ get _appPrefLabel() {
+ return "portableDocumentFormat";
+ }
+
get enabled() {
return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED) &&
Services.policies.isAllowed("PDF.js");
- },
-};
+ }
+}