Bug 1109714 - Make the feed subscriber UI work in e10s r=mrbkap,jaws

This commit is contained in:
George Wright 2016-01-04 18:59:44 -05:00
parent 9af1dff99c
commit 237a81888c
21 changed files with 1070 additions and 945 deletions

View File

@ -17,12 +17,12 @@ var FeedHandler = {
* The feed list container (menupopup or subview) to be populated.
* @param isSubview
* Whether we're creating a subview (true) or menu (false/undefined)
* @returns true if the menu/subview should be shown, false if there was only
* @return true if the menu/subview should be shown, false if there was only
* one feed and the feed should be shown inline in the browser
* window (do not show the menupopup/subview).
*/
buildFeedList: function(container, isSubview) {
var feeds = gBrowser.selectedBrowser.feeds;
buildFeedList(container, isSubview) {
let feeds = gBrowser.selectedBrowser.feeds;
if (!isSubview && feeds == null) {
// XXX hack -- menu opening depends on setting of an "open"
// attribute, and the menu refuses to open if that attribute is
@ -45,11 +45,11 @@ var FeedHandler = {
return false;
// Build the menu showing the available feed choices for viewing.
var itemNodeType = isSubview ? "toolbarbutton" : "menuitem";
let itemNodeType = isSubview ? "toolbarbutton" : "menuitem";
for (let feedInfo of feeds) {
var item = document.createElement(itemNodeType);
var baseTitle = feedInfo.title || feedInfo.href;
var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
let item = document.createElement(itemNodeType);
let baseTitle = feedInfo.title || feedInfo.href;
let labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
item.setAttribute("label", labelStr);
item.setAttribute("feed", feedInfo.href);
item.setAttribute("tooltiptext", feedInfo.href);
@ -77,14 +77,14 @@ var FeedHandler = {
* The event this method is handling. Used to decide where
* to open the preview UI. (Optional, unless href is null)
*/
subscribeToFeed: function(href, event) {
subscribeToFeed(href, event) {
// Just load the feed in the content area to either subscribe or show the
// preview UI
if (!href)
href = event.target.getAttribute("feed");
urlSecurityCheck(href, gBrowser.contentPrincipal,
Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
var feedURI = makeURI(href, document.characterSet);
let feedURI = makeURI(href, document.characterSet);
// Use the feed scheme so X-Moz-Is-Feed will be set
// The value doesn't matter
if (/^https?$/.test(feedURI.scheme))
@ -92,8 +92,8 @@ var FeedHandler = {
this.loadFeed(href, event);
},
loadFeed: function(href, event) {
var feeds = gBrowser.selectedBrowser.feeds;
loadFeed(href, event) {
let feeds = gBrowser.selectedBrowser.feeds;
try {
openUILink(href, event, { ignoreAlt: true });
}
@ -118,14 +118,14 @@ var FeedHandler = {
* Update the browser UI to show whether or not feeds are available when
* a page is loaded or the user switches tabs to a page that has feeds.
*/
updateFeeds: function() {
updateFeeds() {
if (this._updateFeedTimeout)
clearTimeout(this._updateFeedTimeout);
var feeds = gBrowser.selectedBrowser.feeds;
var haveFeeds = feeds && feeds.length > 0;
let feeds = gBrowser.selectedBrowser.feeds;
let haveFeeds = feeds && feeds.length > 0;
var feedButton = document.getElementById("feed-button");
let feedButton = document.getElementById("feed-button");
if (feedButton) {
if (haveFeeds) {
feedButton.removeAttribute("disabled");
@ -152,7 +152,7 @@ var FeedHandler = {
}
},
addFeed: function(link, browserForLink) {
addFeed(link, browserForLink) {
if (!browserForLink.feeds)
browserForLink.feeds = [];
@ -169,15 +169,184 @@ var FeedHandler = {
}
},
/**
* Get the human-readable display name of a file. This could be the
* application name.
* @param file
* A nsIFile to look up the name of
* @return The display name of the application represented by the file.
*/
_getFileDisplayName(file) {
switch (AppConstants.platform) {
case "win":
if (file instanceof Ci.nsILocalFileWin) {
try {
return file.getVersionInfoField("FileDescription");
} catch (e) {}
}
break;
case "macosx":
if (file instanceof Ci.nsILocalFileMac) {
try {
return file.bundleDisplayName;
} catch (e) {}
}
break;
}
return file.leafName;
},
chooseClientApp(aTitle, aPrefName, aBrowser) {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, aTitle, Ci.nsIFilePicker.modeOpen);
fp.appendFilters(Ci.nsIFilePicker.filterApps);
fp.open((aResult) => {
if (aResult == Ci.nsIFilePicker.returnOK) {
let selectedApp = fp.file;
if (selectedApp) {
// 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
let appName = "";
switch (AppConstants.platform) {
case "win":
appName = AppConstants.MOZ_APP_NAME + ".exe";
break;
case "macosx":
appName = AppConstants.MOZ_MACBUNDLE_NAME;
break;
default:
appName = AppConstants.MOZ_APP_NAME + "-bin";
break;
}
if (fp.file.leafName != appName) {
Services.prefs.setComplexValue(aPrefName, Ci.nsILocalFile, selectedApp);
aBrowser.messageManager.sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
{ name: this._getFileDisplayName(selectedApp),
type: "SelectedAppMenuItem" });
}
}
}
});
},
executeClientApp(aSpec, aTitle, aSubtitle, aFeedHandler) {
// aFeedHandler is either "default", indicating the system default reader, or a pref-name containing
// an nsILocalFile pointing to the feed handler's executable.
let clientApp = null;
if (aFeedHandler == "default") {
clientApp = Cc["@mozilla.org/browser/shell-service;1"]
.getService(Ci.nsIShellService)
.defaultFeedReader;
} else {
clientApp = Services.prefs.getComplexValue(aFeedHandler, Ci.nsILocalFile);
}
// For the benefit of applications that might know how to deal with more
// URLs than just feeds, send feed: URLs in the following format:
//
// http urls: replace scheme with feed, e.g.
// http://foo.com/index.rdf -> feed://foo.com/index.rdf
// other urls: prepend feed: scheme, e.g.
// https://foo.com/index.rdf -> feed:https://foo.com/index.rdf
let feedURI = NetUtil.newURI(aSpec);
if (feedURI.schemeIs("http")) {
feedURI.scheme = "feed";
aSpec = feedURI.spec;
} else {
aSpec = "feed:" + aSpec;
}
// Retrieving the shell service might fail on some systems, most
// notably systems where GNOME is not installed.
try {
let ss = Cc["@mozilla.org/browser/shell-service;1"]
.getService(Ci.nsIShellService);
ss.openApplicationWithURI(clientApp, aSpec);
} catch(e) {
// If we couldn't use the shell service, fallback to using a
// nsIProcess instance
let p = Cc["@mozilla.org/process/util;1"]
.createInstance(Ci.nsIProcess);
p.init(clientApp);
p.run(false, [aSpec], 1);
}
},
init() {
window.messageManager.addMessageListener("FeedWriter:ChooseClientApp", this);
window.messageManager.addMessageListener("FeedWriter:RequestClientAppName", this);
window.messageManager.addMessageListener("FeedWriter:SetFeedCharPref", this);
window.messageManager.addMessageListener("FeedWriter:SetFeedComplexString", this);
window.messageManager.addMessageListener("FeedWriter:ShownFirstRun", this);
Services.ppmm.addMessageListener("FeedConverter:ExecuteClientApp", this);
},
uninit() {
Services.ppmm.removeMessageListener("FeedConverter:ExecuteClientApp", this);
},
receiveMessage(msg) {
switch (msg.name) {
case "FeedWriter:ChooseClientApp":
this.chooseClientApp(msg.data.title, msg.data.prefName, msg.target);
break;
case "FeedWriter:RequestClientAppName":
let selectedClientApp;
try {
selectedClientApp = Services.prefs.getComplexValue(msg.data.feedTypePref, Ci.nsILocalFile);
} catch (ex) {
// Just do nothing, then we won't bother populating
}
let defaultClientApp = null;
try {
// This can sometimes not exist
defaultClientApp = Cc["@mozilla.org/browser/shell-service;1"]
.getService(Ci.nsIShellService)
.defaultFeedReader;
} catch(ex) {
// Just do nothing, then we don't bother populating
}
if (selectedClientApp && selectedClientApp.exists()) {
if (defaultClientApp && selectedClientApp.path != defaultClientApp.path) {
// Only set the default menu item if it differs from the selected one
msg.target.messageManager
.sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
{ name: this._getFileDisplayName(defaultClientApp),
type: "DefaultAppMenuItem" });
}
msg.target.messageManager
.sendAsyncMessage("FeedWriter:SetApplicationLauncherMenuItem",
{ name: this._getFileDisplayName(selectedClientApp),
type: "SelectedAppMenuItem" });
}
break;
case "FeedWriter:ShownFirstRun":
Services.prefs.setBoolPref("browser.feeds.showFirstRunUI", false);
break;
case "FeedWriter:SetFeedCharPref":
Services.prefs.setCharPref(msg.data.pref, msg.data.value);
break;
case "FeedWriter:SetFeedComplexString": {
let supportsString = Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
supportsString.data = msg.data.value;
Services.prefs.setComplexValue(msg.data.pref, Ci.nsISupportsString, supportsString);
break;
}
case "FeedConverter:ExecuteClientApp":
this.executeClientApp(msg.data.spec, msg.data.title,
msg.data.subtitle, msg.data.feedHandler);
break;
}
},
};

View File

@ -1434,6 +1434,8 @@ var gBrowserInit = {
BrowserOnClick.uninit();
FeedHandler.uninit();
DevEdition.uninit();
TrackingProtection.uninit();

View File

@ -92,7 +92,7 @@ function getPrefReaderForType(t) {
}
function safeGetCharPref(pref, defaultValue) {
var prefs =
var prefs =
Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
try {
@ -112,7 +112,7 @@ FeedConverter.prototype = {
* This is the downloaded text data for the feed.
*/
_data: null,
/**
* This is the object listening to the conversion, which is ultimately the
* docshell for the load.
@ -127,81 +127,81 @@ FeedConverter.prototype = {
/**
* See nsIStreamConverter.idl
*/
convert: function FC_convert(sourceStream, sourceType, destinationType,
context) {
convert(sourceStream, sourceType, destinationType,
context) {
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* See nsIStreamConverter.idl
*/
asyncConvertData: function FC_asyncConvertData(sourceType, destinationType,
listener, context) {
asyncConvertData(sourceType, destinationType,
listener, context) {
this._listener = listener;
},
/**
* Whether or not the preview page is being forced.
*/
_forcePreviewPage: false,
/**
/**
* Release our references to various things once we're done using them.
*/
_releaseHandles: function FC__releaseHandles() {
_releaseHandles() {
this._listener = null;
this._request = null;
this._processor = null;
},
/**
* See nsIFeedResultListener.idl
*/
handleResult: function FC_handleResult(result) {
handleResult(result) {
// Feeds come in various content types, which our feed sniffer coerces to
// the maybe.feed type. However, feeds are used as a transport for
// the maybe.feed type. However, feeds are used as a transport for
// different data types, e.g. news/blogs (traditional feed), video/audio
// (podcasts) and photos (photocasts, photostreams). Each of these is
// (podcasts) and photos (photocasts, photostreams). Each of these is
// different in that there's a different class of application suitable for
// handling feeds of that type, but without a content-type differentiation
// it is difficult for us to disambiguate.
//
//
// The other problem is that if the user specifies an auto-action handler
// for one feed application, the fact that the content type is shared means
// that all other applications will auto-load with that handler too,
// regardless of the content-type.
// for one feed application, the fact that the content type is shared means
// that all other applications will auto-load with that handler too,
// regardless of the content-type.
//
// This means that content-type alone is not enough to determine whether
// or not a feed should be auto-handled. This means that for feeds we need
// to always use this stream converter, even when an auto-action is
// specified, not the basic one provided by WebContentConverter. This
// to always use this stream converter, even when an auto-action is
// specified, not the basic one provided by WebContentConverter. This
// converter needs to consume all of the data and parse it, and based on
// that determination make a judgment about type.
// that determination make a judgment about type.
//
// Since there are no content types for this content, and I'm not going to
// invent any, the upshot is that while a user can set an auto-handler for
// generic feed content, the system will prevent them from setting an auto-
// handler for other stream types. In those cases, the user will always see
// the preview page and have to select a handler. We can guess and show
// the preview page and have to select a handler. We can guess and show
// a client handler, but will not be able to show web handlers for those
// types.
//
// If this is just a feed, not some kind of specialized application, then
// auto-handlers can be set and we should obey them.
try {
var feedService =
let feedService =
Cc["@mozilla.org/browser/feeds/result-service;1"].
getService(Ci.nsIFeedResultService);
if (!this._forcePreviewPage && result.doc) {
var feed = result.doc.QueryInterface(Ci.nsIFeed);
var handler = safeGetCharPref(getPrefActionForType(feed.type), "ask");
let feed = result.doc.QueryInterface(Ci.nsIFeed);
let handler = safeGetCharPref(getPrefActionForType(feed.type), "ask");
if (handler != "ask") {
if (handler == "reader")
handler = safeGetCharPref(getPrefReaderForType(feed.type), "bookmarks");
switch (handler) {
case "web":
var wccr =
let wccr =
Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentConverterService);
if ((feed.type == Ci.nsIFeed.TYPE_FEED &&
@ -220,25 +220,27 @@ FeedConverter.prototype = {
// fall through -- let feed service handle error
case "bookmarks":
case "client":
case "default":
try {
var title = feed.title ? feed.title.plainText() : "";
var desc = feed.subtitle ? feed.subtitle.plainText() : "";
feedService.addToClientReader(result.uri.spec, title, desc, feed.type);
let title = feed.title ? feed.title.plainText() : "";
let desc = feed.subtitle ? feed.subtitle.plainText() : "";
let feedReader = safeGetCharPref(getPrefActionForType(feedType), "bookmarks");
feedService.addToClientReader(result.uri.spec, title, desc, feed.type, feedReader);
return;
} catch(ex) { /* fallback to preview mode */ }
}
}
}
var ios =
let ios =
Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var chromeChannel;
let chromeChannel;
// handling a redirect, hence forwarding the loadInfo from the old channel
// to the newchannel.
var oldChannel = this._request.QueryInterface(Ci.nsIChannel);
var loadInfo = oldChannel.loadInfo;
let oldChannel = this._request.QueryInterface(Ci.nsIChannel);
let loadInfo = oldChannel.loadInfo;
// If there was no automatic handler, or this was a podcast,
// photostream or some other kind of application, show the preview page
@ -250,7 +252,7 @@ FeedConverter.prototype = {
feedService.addFeedResult(result);
// Now load the actual XUL document.
var aboutFeedsURI = ios.newURI("about:feeds", null, null);
let aboutFeedsURI = ios.newURI("about:feeds", null, null);
chromeChannel = ios.newChannelFromURIWithLoadInfo(aboutFeedsURI, loadInfo);
chromeChannel.originalURI = result.uri;
chromeChannel.owner =
@ -266,27 +268,27 @@ FeedConverter.prototype = {
this._releaseHandles();
}
},
/**
* See nsIStreamListener.idl
*/
onDataAvailable: function FC_onDataAvailable(request, context, inputStream,
sourceOffset, count) {
onDataAvailable(request, context, inputStream,
sourceOffset, count) {
if (this._processor)
this._processor.onDataAvailable(request, context, inputStream,
sourceOffset, count);
},
/**
* See nsIRequestObserver.idl
*/
onStartRequest: function FC_onStartRequest(request, context) {
var channel = request.QueryInterface(Ci.nsIChannel);
onStartRequest(request, context) {
let channel = request.QueryInterface(Ci.nsIChannel);
// Check for a header that tells us there was no sniffing
// The value doesn't matter.
try {
var httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
// Make sure to check requestSucceeded before the potentially-throwing
// getResponseHeader.
if (!httpChannel.requestSucceeded) {
@ -294,17 +296,17 @@ FeedConverter.prototype = {
request.cancel(Cr.NS_BINDING_ABORTED);
return;
}
var noSniff = httpChannel.getResponseHeader("X-Moz-Is-Feed");
let noSniff = httpChannel.getResponseHeader("X-Moz-Is-Feed");
}
catch (ex) {
this._sniffed = true;
}
this._request = request;
// Save and reset the forced state bit early, in case there's some kind of
// error.
var feedService =
let feedService =
Cc["@mozilla.org/browser/feeds/result-service;1"].
getService(Ci.nsIFeedResultService);
this._forcePreviewPage = feedService.forcePreviewPage;
@ -316,22 +318,22 @@ FeedConverter.prototype = {
createInstance(Ci.nsIFeedProcessor);
this._processor.listener = this;
this._processor.parseAsync(null, channel.URI);
this._processor.onStartRequest(request, context);
},
/**
* See nsIRequestObserver.idl
*/
onStopRequest: function FC_onStopRequest(request, context, status) {
onStopRequest(request, context, status) {
if (this._processor)
this._processor.onStopRequest(request, context, status);
},
/**
* See nsISupports.idl
*/
QueryInterface: function FC_QueryInterface(iid) {
QueryInterface(iid) {
if (iid.equals(Ci.nsIFeedResultListener) ||
iid.equals(Ci.nsIStreamConverter) ||
iid.equals(Ci.nsIStreamListener) ||
@ -344,133 +346,105 @@ FeedConverter.prototype = {
/**
* Keeps parsed FeedResults around for use elsewhere in the UI after the stream
* converter completes.
* converter completes.
*/
function FeedResultService() {
}
FeedResultService.prototype = {
classID: Components.ID("{2376201c-bbc6-472f-9b62-7548040a61c6}"),
/**
* A URI spec -> [nsIFeedResult] hash. We have to keep a list as the
* value in case the same URI is requested concurrently.
*/
_results: { },
/**
* See nsIFeedResultService.idl
*/
forcePreviewPage: false,
/**
* See nsIFeedResultService.idl
*/
addToClientReader: function FRS_addToClientReader(spec, title, subtitle, feedType) {
var prefs =
Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
addToClientReader(spec, title, subtitle, feedType, feedReader) {
if (!feedReader) {
feedReader = "default";
}
var handler = safeGetCharPref(getPrefActionForType(feedType), "bookmarks");
let handler = safeGetCharPref(getPrefActionForType(feedType), "bookmarks");
if (handler == "ask" || handler == "reader")
handler = safeGetCharPref(getPrefReaderForType(feedType), "bookmarks");
handler = feedReader;
switch (handler) {
case "client":
var clientApp = prefs.getComplexValue(getPrefAppForType(feedType), Ci.nsILocalFile);
// For the benefit of applications that might know how to deal with more
// URLs than just feeds, send feed: URLs in the following format:
//
// http urls: replace scheme with feed, e.g.
// http://foo.com/index.rdf -> feed://foo.com/index.rdf
// other urls: prepend feed: scheme, e.g.
// https://foo.com/index.rdf -> feed:https://foo.com/index.rdf
var ios =
Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
var feedURI = ios.newURI(spec, null, null);
if (feedURI.schemeIs("http")) {
feedURI.scheme = "feed";
spec = feedURI.spec;
}
else
spec = "feed:" + spec;
// Retrieving the shell service might fail on some systems, most
// notably systems where GNOME is not installed.
try {
var ss =
Cc["@mozilla.org/browser/shell-service;1"].
getService(Ci.nsIShellService);
ss.openApplicationWithURI(clientApp, spec);
} catch(e) {
// If we couldn't use the shell service, fallback to using a
// nsIProcess instance
var p =
Cc["@mozilla.org/process/util;1"].
createInstance(Ci.nsIProcess);
p.init(clientApp);
p.run(false, [spec], 1);
}
Services.cpmm.sendAsyncMessage("FeedConverter:ExecuteClientApp",
{ spec,
title,
subtitle,
feedHandler: getPrefAppForType(feedType) });
break;
case "default":
// Default system feed reader
Services.cpmm.sendAsyncMessage("FeedConverter:ExecuteClientApp",
{ spec,
title,
subtitle,
feedHandler: "default" });
break;
default:
// "web" should have been handled elsewhere
LOG("unexpected handler: " + handler);
// fall through
case "bookmarks":
var wm =
Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
var topWindow = wm.getMostRecentWindow("navigator:browser");
topWindow.PlacesCommandHook.addLiveBookmark(spec, title, subtitle)
.catch(Components.utils.reportError);
Services.cpmm.sendAsyncMessage("FeedConverter:addLiveBookmark",
{ spec, title, subtitle });
break;
}
},
/**
* See nsIFeedResultService.idl
*/
addFeedResult: function FRS_addFeedResult(feedResult) {
addFeedResult(feedResult) {
NS_ASSERT(feedResult.uri != null, "null URI!");
NS_ASSERT(feedResult.uri != null, "null feedResult!");
var spec = feedResult.uri.spec;
if(!this._results[spec])
let spec = feedResult.uri.spec;
if (!this._results[spec])
this._results[spec] = [];
this._results[spec].push(feedResult);
},
/**
* See nsIFeedResultService.idl
*/
getFeedResult: function RFS_getFeedResult(uri) {
getFeedResult(uri) {
NS_ASSERT(uri != null, "null URI!");
var resultList = this._results[uri.spec];
for (var i in resultList) {
if (resultList[i].uri == uri)
return resultList[i];
let resultList = this._results[uri.spec];
for (let result of resultList) {
if (result.uri == uri)
return result;
}
return null;
},
/**
* See nsIFeedResultService.idl
*/
removeFeedResult: function FRS_removeFeedResult(uri) {
removeFeedResult(uri) {
NS_ASSERT(uri != null, "null URI!");
var resultList = this._results[uri.spec];
let resultList = this._results[uri.spec];
if (!resultList)
return;
var deletions = 0;
for (var i = 0; i < resultList.length; ++i) {
let deletions = 0;
for (let i = 0; i < resultList.length; ++i) {
if (resultList[i].uri == uri) {
delete resultList[i];
++deletions;
}
}
// send the holes to the end
resultList.sort();
// and trim the list
@ -479,13 +453,13 @@ FeedResultService.prototype = {
delete this._results[uri.spec];
},
createInstance: function FRS_createInstance(outer, iid) {
createInstance(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return this.QueryInterface(iid);
},
QueryInterface: function FRS_QueryInterface(iid) {
QueryInterface(iid) {
if (iid.equals(Ci.nsIFeedResultService) ||
iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsISupports))
@ -501,8 +475,8 @@ FeedResultService.prototype = {
function GenericProtocolHandler() {
}
GenericProtocolHandler.prototype = {
_init: function GPH_init(scheme) {
var ios =
_init(scheme) {
let ios =
Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
this._http = ios.getProtocolHandler("http");
@ -512,46 +486,46 @@ GenericProtocolHandler.prototype = {
get scheme() {
return this._scheme;
},
get protocolFlags() {
return this._http.protocolFlags;
},
get defaultPort() {
return this._http.defaultPort;
},
allowPort: function GPH_allowPort(port, scheme) {
allowPort(port, scheme) {
return this._http.allowPort(port, scheme);
},
newURI: function GPH_newURI(spec, originalCharset, baseURI) {
newURI(spec, originalCharset, baseURI) {
// Feed URIs can be either nested URIs of the form feed:realURI (in which
// case we create a nested URI for the realURI) or feed://example.com, in
// which case we create a nested URI for the real protocol which is http.
var scheme = this._scheme + ":";
let scheme = this._scheme + ":";
if (spec.substr(0, scheme.length) != scheme)
throw Cr.NS_ERROR_MALFORMED_URI;
var prefix = spec.substr(scheme.length, 2) == "//" ? "http:" : "";
var inner = Cc["@mozilla.org/network/io-service;1"].
let prefix = spec.substr(scheme.length, 2) == "//" ? "http:" : "";
let inner = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService).newURI(spec.replace(scheme, prefix),
originalCharset, baseURI);
var netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
const URI_INHERITS_SECURITY_CONTEXT = Ci.nsIProtocolHandler
.URI_INHERITS_SECURITY_CONTEXT;
if (netutil.URIChainHasFlags(inner, URI_INHERITS_SECURITY_CONTEXT))
throw Cr.NS_ERROR_MALFORMED_URI;
var uri = netutil.newSimpleNestedURI(inner);
let uri = netutil.newSimpleNestedURI(inner);
uri.spec = inner.spec.replace(prefix, scheme);
return uri;
},
newChannel2: function GPH_newChannel(aUri, aLoadInfo) {
var inner = aUri.QueryInterface(Ci.nsINestedURI).innerURI;
var channel = Cc["@mozilla.org/network/io-service;1"].
newChannel2(aUri, aLoadInfo) {
let inner = aUri.QueryInterface(Ci.nsINestedURI).innerURI;
let channel = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService).
newChannelFromURIWithLoadInfo(inner, aLoadInfo);
@ -561,14 +535,13 @@ GenericProtocolHandler.prototype = {
channel.originalURI = aUri;
return channel;
},
QueryInterface: function GPH_QueryInterface(iid) {
QueryInterface(iid) {
if (iid.equals(Ci.nsIProtocolHandler) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
};
function FeedProtocolHandler() {

File diff suppressed because it is too large Load Diff

View File

@ -40,19 +40,19 @@ const NS_ERROR_DOM_SYNTAX_ERR = NS_ERROR_MODULE_DOM + 12;
function WebContentConverter() {
}
WebContentConverter.prototype = {
convert: function WCC_convert() { },
asyncConvertData: function WCC_asyncConvertData() { },
onDataAvailable: function WCC_onDataAvailable() { },
onStopRequest: function WCC_onStopRequest() { },
onStartRequest: function WCC_onStartRequest(request, context) {
var wccr =
convert() { },
asyncConvertData() { },
onDataAvailable() { },
onStopRequest() { },
onStartRequest(request, context) {
let wccr =
Cc[WCCR_CONTRACTID].
getService(Ci.nsIWebContentConverterService);
wccr.loadPreferredHandler(request);
},
QueryInterface: function WCC_QueryInterface(iid) {
QueryInterface(iid) {
if (iid.equals(Ci.nsIStreamConverter) ||
iid.equals(Ci.nsIStreamListener) ||
iid.equals(Ci.nsISupports))
@ -61,14 +61,14 @@ WebContentConverter.prototype = {
}
};
var WebContentConverterFactory = {
createInstance: function WCCF_createInstance(outer, iid) {
let WebContentConverterFactory = {
createInstance(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return new WebContentConverter().QueryInterface(iid);
},
QueryInterface: function WCC_QueryInterface(iid) {
QueryInterface(iid) {
if (iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsISupports))
return this;
@ -88,11 +88,11 @@ ServiceInfo.prototype = {
get name() {
return this._name;
},
/**
* See nsIHandlerApp
*/
equals: function SI_equals(aHandlerApp) {
equals(aHandlerApp) {
if (!aHandlerApp)
throw Cr.NS_ERROR_NULL_POINTER;
@ -121,11 +121,11 @@ ServiceInfo.prototype = {
/**
* See nsIWebContentHandlerInfo
*/
getHandlerURI: function SI_getHandlerURI(uri) {
getHandlerURI(uri) {
return this._uri.replace(/%s/gi, encodeURIComponent(uri));
},
QueryInterface: function SI_QueryInterface(iid) {
QueryInterface(iid) {
if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
iid.equals(Ci.nsISupports))
return this;
@ -139,9 +139,10 @@ const Utils = {
},
checkAndGetURI(aURIString, aContentWindow) {
let uri;
try {
let baseURI = aContentWindow.document.baseURIObject;
var uri = this.makeURI(aURIString, null, baseURI);
uri = this.makeURI(aURIString, null, baseURI);
} catch (ex) {
throw NS_ERROR_DOM_SYNTAX_ERR;
}
@ -155,7 +156,7 @@ const Utils = {
// We also reject handlers registered from a different host (see bug 402287)
// The pref allows us to test the feature
var pb = Services.prefs;
let pb = Services.prefs;
if ((!pb.prefHasUserValue(PREF_ALLOW_DIFFERENT_HOST) ||
!pb.getBoolPref(PREF_ALLOW_DIFFERENT_HOST)) &&
aContentWindow.location.hostname != uri.host)
@ -172,7 +173,7 @@ const Utils = {
checkProtocolHandlerAllowed(aProtocol, aURIString) {
// First, check to make sure this isn't already handled internally (we don't
// want to let them take over, say "chrome").
var handler = Services.io.getProtocolHandler(aProtocol);
let handler = Services.io.getProtocolHandler(aProtocol);
if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
// This is handled internally, so we don't want them to register
// XXX this should be a "security exception" according to spec, but that
@ -181,8 +182,8 @@ const Utils = {
}
// check if it is in the black list
var pb = Services.prefs;
var allowed;
let pb = Services.prefs;
let allowed;
try {
allowed = pb.getBoolPref(PREF_HANDLER_EXTERNAL_PREFIX + "." + aProtocol);
}
@ -211,49 +212,47 @@ const Utils = {
};
function WebContentConverterRegistrar() {
this._contentTypes = { };
this._autoHandleContentTypes = { };
this._contentTypes = {};
this._autoHandleContentTypes = {};
}
WebContentConverterRegistrar.prototype = {
get stringBundle() {
var sb = Services.strings.createBundle(STRING_BUNDLE_URI);
let sb = Services.strings.createBundle(STRING_BUNDLE_URI);
delete WebContentConverterRegistrar.prototype.stringBundle;
return WebContentConverterRegistrar.prototype.stringBundle = sb;
},
_getFormattedString: function WCCR__getFormattedString(key, params) {
_getFormattedString(key, params) {
return this.stringBundle.formatStringFromName(key, params, params.length);
},
_getString: function WCCR_getString(key) {
_getString(key) {
return this.stringBundle.GetStringFromName(key);
},
/**
* See nsIWebContentConverterService
*/
getAutoHandler:
function WCCR_getAutoHandler(contentType) {
getAutoHandler(contentType) {
contentType = Utils.resolveContentType(contentType);
if (contentType in this._autoHandleContentTypes)
return this._autoHandleContentTypes[contentType];
return null;
},
/**
* See nsIWebContentConverterService
*/
setAutoHandler:
function WCCR_setAutoHandler(contentType, handler) {
setAutoHandler(contentType, handler) {
if (handler && !this._typeIsRegistered(contentType, handler.uri))
throw Cr.NS_ERROR_NOT_AVAILABLE;
contentType = Utils.resolveContentType(contentType);
this._setAutoHandler(contentType, handler);
var ps = Services.prefs;
var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
let ps = Services.prefs;
let autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
if (handler)
autoBranch.setCharPref(contentType, handler.uri);
else if (autoBranch.prefHasUserValue(contentType))
@ -261,65 +260,57 @@ WebContentConverterRegistrar.prototype = {
ps.savePrefFile(null);
},
/**
* Update the internal data structure (not persistent)
*/
_setAutoHandler:
function WCCR__setAutoHandler(contentType, handler) {
if (handler)
_setAutoHandler(contentType, handler) {
if (handler)
this._autoHandleContentTypes[contentType] = handler;
else if (contentType in this._autoHandleContentTypes)
delete this._autoHandleContentTypes[contentType];
},
/**
* See nsIWebContentConverterService
*/
getWebContentHandlerByURI:
function WCCR_getWebContentHandlerByURI(contentType, uri) {
var handlers = this.getContentHandlers(contentType, { });
for (var i = 0; i < handlers.length; ++i) {
if (handlers[i].uri == uri)
return handlers[i];
}
return null;
getWebContentHandlerByURI(contentType, uri) {
return this.getContentHandlers(contentType)
.find(e => e.uri == uri) || null;
},
/**
* See nsIWebContentConverterService
*/
loadPreferredHandler:
function WCCR_loadPreferredHandler(request) {
var channel = request.QueryInterface(Ci.nsIChannel);
var contentType = Utils.resolveContentType(channel.contentType);
var handler = this.getAutoHandler(contentType);
loadPreferredHandler(request) {
let channel = request.QueryInterface(Ci.nsIChannel);
let contentType = Utils.resolveContentType(channel.contentType);
let handler = this.getAutoHandler(contentType);
if (handler) {
request.cancel(Cr.NS_ERROR_FAILURE);
var webNavigation =
let webNavigation =
channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation);
webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec),
Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec),
Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
null, null, null);
}
}
},
/**
* See nsIWebContentConverterService
*/
removeProtocolHandler:
function WCCR_removeProtocolHandler(aProtocol, aURITemplate) {
var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
removeProtocolHandler(aProtocol, aURITemplate) {
let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
var handlers = handlerInfo.possibleApplicationHandlers;
let handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
let handlers = handlerInfo.possibleApplicationHandlers;
for (let i = 0; i < handlers.length; i++) {
try { // We only want to test web handlers
let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
if (handler.uriTemplate == aURITemplate) {
handlers.removeElementAt(i);
var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
let hs = Cc["@mozilla.org/uriloader/handler-service;1"].
getService(Ci.nsIHandlerService);
hs.store(handlerInfo);
return;
@ -327,24 +318,23 @@ WebContentConverterRegistrar.prototype = {
} catch (e) { /* it wasn't a web handler */ }
}
},
/**
* See nsIWebContentConverterService
*/
removeContentHandler:
function WCCR_removeContentHandler(contentType, uri) {
removeContentHandler(contentType, uri) {
function notURI(serviceInfo) {
return serviceInfo.uri != uri;
}
if (contentType in this._contentTypes) {
this._contentTypes[contentType] =
this._contentTypes[contentType] =
this._contentTypes[contentType].filter(notURI);
}
},
/**
* These are types for which there is a separate content converter aside
* These are types for which there is a separate content converter aside
* from our built in generic one. We should not automatically register
* a factory for creating a converter for these types.
*/
@ -361,12 +351,11 @@ WebContentConverterRegistrar.prototype = {
* The URI template that the handler uses to handle the protocol.
* @return true if it is already registered, false otherwise.
*/
_protocolHandlerRegistered:
function WCCR_protocolHandlerRegistered(aProtocol, aURITemplate) {
var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
_protocolHandlerRegistered(aProtocol, aURITemplate) {
let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
var handlers = handlerInfo.possibleApplicationHandlers;
let handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
let handlers = handlerInfo.possibleApplicationHandlers;
for (let i = 0; i < handlers.length; i++) {
try { // We only want to test web handlers
let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
@ -380,11 +369,10 @@ WebContentConverterRegistrar.prototype = {
/**
* See nsIWebContentHandlerRegistrar
*/
registerProtocolHandler:
function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
registerProtocolHandler(aProtocol, aURIString, aTitle, aBrowserOrWindow) {
LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
var haveWindow = (aBrowserOrWindow instanceof Ci.nsIDOMWindow);
var uri;
let haveWindow = (aBrowserOrWindow instanceof Ci.nsIDOMWindow);
let uri;
if (haveWindow) {
uri = Utils.checkAndGetURI(aURIString, aBrowserOrWindow);
} else {
@ -397,7 +385,7 @@ WebContentConverterRegistrar.prototype = {
return;
}
var browser;
let browser;
if (haveWindow) {
let browserWindow =
this._getBrowserWindowForContentWindow(aBrowserOrWindow);
@ -418,30 +406,29 @@ WebContentConverterRegistrar.prototype = {
Utils.checkProtocolHandlerAllowed(aProtocol, aURIString);
// Now Ask the user and provide the proper callback
var message = this._getFormattedString("addProtocolHandler",
let message = this._getFormattedString("addProtocolHandler",
[aTitle, uri.host, aProtocol]);
var notificationIcon = uri.prePath + "/favicon.ico";
var notificationValue = "Protocol Registration: " + aProtocol;
var addButton = {
let notificationIcon = uri.prePath + "/favicon.ico";
let notificationValue = "Protocol Registration: " + aProtocol;
let addButton = {
label: this._getString("addProtocolHandlerAddButton"),
accessKey: this._getString("addHandlerAddButtonAccesskey"),
protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
callback:
function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
var protocol = aButtonInfo.protocolInfo.protocol;
var uri = aButtonInfo.protocolInfo.uri;
var name = aButtonInfo.protocolInfo.name;
callback(aNotification, aButtonInfo) {
let protocol = aButtonInfo.protocolInfo.protocol;
let uri = aButtonInfo.protocolInfo.uri;
let name = aButtonInfo.protocolInfo.name;
var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
let handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
createInstance(Ci.nsIWebHandlerApp);
handler.name = name;
handler.uriTemplate = uri;
var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
let eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
getService(Ci.nsIExternalProtocolService);
var handlerInfo = eps.getProtocolHandlerInfo(protocol);
let handlerInfo = eps.getProtocolHandlerInfo(protocol);
handlerInfo.possibleApplicationHandlers.appendElement(handler, false);
// Since the user has agreed to add a new handler, chances are good
@ -450,12 +437,12 @@ WebContentConverterRegistrar.prototype = {
// use.
handlerInfo.alwaysAskBeforeHandling = true;
var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
let hs = Cc["@mozilla.org/uriloader/handler-service;1"].
getService(Ci.nsIHandlerService);
hs.store(handlerInfo);
}
};
var notificationBox = browser.getTabBrowser().getNotificationBox(browser);
let notificationBox = browser.getTabBrowser().getNotificationBox(browser);
notificationBox.appendNotification(message,
notificationValue,
notificationIcon,
@ -468,26 +455,25 @@ WebContentConverterRegistrar.prototype = {
* If a DOM window is provided, then the request came from content, so we
* prompt the user to confirm the registration.
*/
registerContentHandler:
function WCCR_registerContentHandler(aContentType, aURIString, aTitle, aWindowOrBrowser) {
registerContentHandler(aContentType, aURIString, aTitle, aWindowOrBrowser) {
LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")");
// We only support feed types at present.
// XXX this should be a "security exception" according to spec, but that
// isn't defined yet.
var contentType = Utils.resolveContentType(aContentType);
let contentType = Utils.resolveContentType(aContentType);
if (contentType != TYPE_MAYBE_FEED)
return;
if (aWindowOrBrowser) {
var haveWindow = (aWindowOrBrowser instanceof Ci.nsIDOMWindow);
var uri;
var notificationBox;
let haveWindow = (aWindowOrBrowser instanceof Ci.nsIDOMWindow);
let uri;
let notificationBox;
if (haveWindow) {
uri = Utils.checkAndGetURI(aURIString, aWindowOrBrowser);
var browserWindow = this._getBrowserWindowForContentWindow(aWindowOrBrowser);
var browserElement = this._getBrowserForContentWindow(browserWindow, aWindowOrBrowser);
let browserWindow = this._getBrowserWindowForContentWindow(aWindowOrBrowser);
let browserElement = this._getBrowserForContentWindow(browserWindow, aWindowOrBrowser);
notificationBox = browserElement.getTabBrowser().getNotificationBox(browserElement);
} else {
// uri was vetted in the content process.
@ -498,15 +484,15 @@ WebContentConverterRegistrar.prototype = {
this._appendFeedReaderNotification(uri, aTitle, notificationBox);
}
else
else {
this._registerContentHandler(contentType, aURIString, aTitle);
}
},
/**
* Returns the browser chrome window in which the content window is in
*/
_getBrowserWindowForContentWindow:
function WCCR__getBrowserWindowForContentWindow(aContentWindow) {
_getBrowserWindowForContentWindow(aContentWindow) {
return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
@ -526,15 +512,11 @@ WebContentConverterRegistrar.prototype = {
* The content window. It's possible to pass a child content window
* (i.e. the content window of a frame/iframe).
*/
_getBrowserForContentWindow:
function WCCR__getBrowserForContentWindow(aBrowserWindow, aContentWindow) {
_getBrowserForContentWindow(aBrowserWindow, aContentWindow) {
// This depends on pseudo APIs of browser.js and tabbrowser.xml
aContentWindow = aContentWindow.top;
var browsers = aBrowserWindow.gBrowser.browsers;
for (var i = 0; i < browsers.length; ++i) {
if (browsers[i].contentWindow == aContentWindow)
return browsers[i];
}
return aBrowserWindow.gBrowser.browsers.find((browser) =>
browser.contentWindow == aContentWindow);
},
/**
@ -558,35 +540,34 @@ WebContentConverterRegistrar.prototype = {
* The notification box to which a notification might be appended
* @return true if a notification has been appended, false otherwise.
*/
_appendFeedReaderNotification:
function WCCR__appendFeedReaderNotification(aURI, aName, aNotificationBox) {
var uriSpec = aURI.spec;
var notificationValue = "feed reader notification: " + uriSpec;
var notificationIcon = aURI.prePath + "/favicon.ico";
_appendFeedReaderNotification(aURI, aName, aNotificationBox) {
let uriSpec = aURI.spec;
let notificationValue = "feed reader notification: " + uriSpec;
let notificationIcon = aURI.prePath + "/favicon.ico";
// Don't append a new notification if the notificationbox
// has a notification for the given feed reader already
if (aNotificationBox.getNotificationWithValue(notificationValue))
return false;
var buttons, message;
let buttons;
let message;
if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uriSpec))
message = this._getFormattedString("handlerRegistered", [aName]);
else {
message = this._getFormattedString("addHandler", [aName, aURI.host]);
var self = this;
var addButton = {
let self = this;
let addButton = {
_outer: self,
label: self._getString("addHandlerAddButton"),
accessKey: self._getString("addHandlerAddButtonAccesskey"),
feedReaderInfo: { uri: uriSpec, name: aName },
/* static */
callback:
function WCCR__addFeedReaderButtonCallback(aNotification, aButtonInfo) {
var uri = aButtonInfo.feedReaderInfo.uri;
var name = aButtonInfo.feedReaderInfo.name;
var outer = aButtonInfo._outer;
callback(aNotification, aButtonInfo) {
let uri = aButtonInfo.feedReaderInfo.uri;
let name = aButtonInfo.feedReaderInfo.name;
let outer = aButtonInfo._outer;
// The reader could have been added from another window mean while
if (!outer.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uri))
@ -610,7 +591,7 @@ WebContentConverterRegistrar.prototype = {
},
/**
* Save Web Content Handler metadata to persistent preferences.
* Save Web Content Handler metadata to persistent preferences.
* @param contentType
* The content Type being handled
* @param uri
@ -619,18 +600,17 @@ WebContentConverterRegistrar.prototype = {
* The human readable name of the web service
*
* This data is stored under:
*
*
* browser.contentHandlers.type0 = content/type
* browser.contentHandlers.uri0 = http://www.foo.com/q=%s
* browser.contentHandlers.title0 = Foo 2.0alphr
*/
_saveContentHandlerToPrefs:
function WCCR__saveContentHandlerToPrefs(contentType, uri, title) {
var ps = Services.prefs;
var i = 0;
var typeBranch = null;
_saveContentHandlerToPrefs(contentType, uri, title) {
let ps = Services.prefs;
let i = 0;
let typeBranch = null;
while (true) {
typeBranch =
typeBranch =
ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + ".");
try {
typeBranch.getCharPref("type");
@ -643,54 +623,49 @@ WebContentConverterRegistrar.prototype = {
}
if (typeBranch) {
typeBranch.setCharPref("type", contentType);
var pls =
let pls =
Cc["@mozilla.org/pref-localizedstring;1"].
createInstance(Ci.nsIPrefLocalizedString);
pls.data = uri;
typeBranch.setComplexValue("uri", Ci.nsIPrefLocalizedString, pls);
pls.data = title;
typeBranch.setComplexValue("title", Ci.nsIPrefLocalizedString, pls);
ps.savePrefFile(null);
}
},
/**
* Determines if there is a type with a particular uri registered for the
* Determines if there is a type with a particular uri registered for the
* specified content type already.
* @param contentType
* The content type that the uri handles
* @param uri
* The uri of the
* The uri of the content type
*/
_typeIsRegistered: function WCCR__typeIsRegistered(contentType, uri) {
_typeIsRegistered(contentType, uri) {
if (!(contentType in this._contentTypes))
return false;
var services = this._contentTypes[contentType];
for (var i = 0; i < services.length; ++i) {
// This uri has already been registered
if (services[i].uri == uri)
return true;
}
return false;
return this._contentTypes[contentType]
.some(t => t.uri == uri);
},
/**
* Gets a stream converter contract id for the specified content type.
* @param contentType
* The source content type for the conversion.
* @returns A contract id to construct a converter to convert between the
* @returns A contract id to construct a converter to convert between the
* contentType and *\/*.
*/
_getConverterContractID: function WCCR__getConverterContractID(contentType) {
_getConverterContractID(contentType) {
const template = "@mozilla.org/streamconv;1?from=%s&to=*/*";
return template.replace(/%s/, contentType);
},
/**
* Register a web service handler for a content type.
*
*
* @param contentType
* the content type being handled
* @param uri
@ -698,18 +673,17 @@ WebContentConverterRegistrar.prototype = {
* @param title
* the human readable name of the web service
*/
_registerContentHandler:
function WCCR__registerContentHandler(contentType, uri, title) {
_registerContentHandler(contentType, uri, title) {
this._updateContentTypeHandlerMap(contentType, uri, title);
this._saveContentHandlerToPrefs(contentType, uri, title);
if (contentType == TYPE_MAYBE_FEED) {
// Make the new handler the last-selected reader in the preview page
// and make sure the preview page is shown the next time a feed is visited
var pb = Services.prefs.getBranch(null);
let pb = Services.prefs.getBranch(null);
pb.setCharPref(PREF_SELECTED_READER, "web");
var supportsString =
let supportsString =
Cc["@mozilla.org/supports-string;1"].
createInstance(Ci.nsISupportsString);
supportsString.data = uri;
@ -730,136 +704,133 @@ WebContentConverterRegistrar.prototype = {
* @param title
* The human readable name of the web service
*/
_updateContentTypeHandlerMap:
function WCCR__updateContentTypeHandlerMap(contentType, uri, title) {
_updateContentTypeHandlerMap(contentType, uri, title) {
if (!(contentType in this._contentTypes))
this._contentTypes[contentType] = [];
// Avoid adding duplicates
if (this._typeIsRegistered(contentType, uri))
if (this._typeIsRegistered(contentType, uri))
return;
this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
if (!(contentType in this._blockedTypes)) {
var converterContractID = this._getConverterContractID(contentType);
var cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID,
let converterContractID = this._getConverterContractID(contentType);
let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID,
WebContentConverterFactory);
}
},
/**
* See nsIWebContentConverterService
*/
getContentHandlers:
function WCCR_getContentHandlers(contentType, countRef) {
countRef.value = 0;
getContentHandlers(contentType, countRef) {
if (countRef) {
countRef.value = 0;
}
if (!(contentType in this._contentTypes))
return [];
var handlers = this._contentTypes[contentType];
countRef.value = handlers.length;
let handlers = this._contentTypes[contentType];
if (countRef) {
countRef.value = handlers.length;
}
return handlers;
},
/**
* See nsIWebContentConverterService
*/
resetHandlersForType:
function WCCR_resetHandlersForType(contentType) {
resetHandlersForType(contentType) {
// currently unused within the tree, so only useful for extensions; previous
// impl. was buggy (and even infinite-looped!), so I argue that this is a
// definite improvement
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
},
/**
* Registers a handler from the settings on a preferences branch.
*
* Since we support up to six predefined readers, we need to handle gaps
* better, since the first branch with user-added values will be .6
*
* How we deal with that is to check to see if there's no prefs in the
* branch and stop cycling once that's true. This doesn't fix the case
* where a user manually removes a reader, but that's not supported yet!
*
* @param branch
* an nsIPrefBranch containing "type", "uri", and "title" preferences
* corresponding to the content handler to be registered
*/
_registerContentHandlerWithBranch: function(branch) {
/**
* Since we support up to six predefined readers, we need to handle gaps
* better, since the first branch with user-added values will be .6
*
* How we deal with that is to check to see if there's no prefs in the
* branch and stop cycling once that's true. This doesn't fix the case
* where a user manually removes a reader, but that's not supported yet!
*/
var vals = branch.getChildList("");
_registerContentHandlerHavingBranch(branch) {
let vals = branch.getChildList("");
if (vals.length == 0)
return;
try {
var type = branch.getCharPref("type");
var uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
var title = branch.getComplexValue("title",
Ci.nsIPrefLocalizedString).data;
this._updateContentTypeHandlerMap(type, uri, title);
}
catch(ex) {
// do nothing, the next branch might have values
}
let type = branch.getCharPref("type");
let uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
let title = branch.getComplexValue("title",
Ci.nsIPrefLocalizedString).data;
this._updateContentTypeHandlerMap(type, uri, title);
},
/**
* Load the auto handler, content handler and protocol tables from
* Load the auto handler, content handler and protocol tables from
* preferences.
*/
_init: function WCCR__init() {
var ps = Services.prefs;
_init() {
let ps = Services.prefs;
var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
.getChildList("");
let children = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
.getChildList("");
// first get the numbers of the providers by getting all ###.uri prefs
var nums = [];
for (var i = 0; i < kids.length; i++) {
var match = /^(\d+)\.uri$/.exec(kids[i]);
if (!match)
continue;
else
nums.push(match[1]);
}
let nums = children.map((child) => {
let match = /^(\d+)\.uri$/.exec(child);
return match ? match[1] : "";
}).filter(child => !!child)
.sort();
// sort them, to get them back in order
nums.sort(function(a, b) {return a - b;});
// now register them
for (var i = 0; i < nums.length; i++) {
var branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + nums[i] + ".");
this._registerContentHandlerWithBranch(branch);
}
// We need to do this _after_ registering all of the available handlers,
// so that getWebContentHandlerByURI can return successfully.
try {
var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
var childPrefs = autoBranch.getChildList("");
for (var i = 0; i < childPrefs.length; ++i) {
var type = childPrefs[i];
var uri = autoBranch.getCharPref(type);
if (uri) {
var handler = this.getWebContentHandlerByURI(type, uri);
this._setAutoHandler(type, handler);
}
for (num of nums) {
let branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + num + ".");
try {
this._registerContentHandlerHavingBranch(branch);
} catch (ex) {
// do nothing, the next branch might have values
}
}
catch (e) {
// We need to do this _after_ registering all of the available handlers,
// so that getWebContentHandlerByURI can return successfully.
let autoBranch;
try {
autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
} catch (e) {
// No auto branch yet, that's fine
//LOG("WCCR.init: There is no auto branch, benign");
}
if (autoBranch) {
for (let type of autoBranch.getChildList("")) {
let uri = autoBranch.getCharPref(type);
if (uri) {
let handler = this.getWebContentHandlerByURI(type, uri);
if (handler) {
this._setAutoHandler(type, handler);
}
}
}
}
},
/**
* See nsIObserver
*/
observe: function WCCR_observe(subject, topic, data) {
var os = Services.obs;
observe(subject, topic, data) {
let os = Services.obs;
switch (topic) {
case "app-startup":
os.addObserver(this, "browser-ui-startup-complete", false);
@ -870,11 +841,11 @@ WebContentConverterRegistrar.prototype = {
break;
}
},
/**
* See nsIFactory
*/
createInstance: function WCCR_createInstance(outer, iid) {
createInstance(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return this.QueryInterface(iid);
@ -886,7 +857,7 @@ WebContentConverterRegistrar.prototype = {
* See nsISupports
*/
QueryInterface: XPCOMUtils.generateQI(
[Ci.nsIWebContentConverterService,
[Ci.nsIWebContentConverterService,
Ci.nsIWebContentHandlerRegistrar,
Ci.nsIObserver,
Ci.nsIFactory]),
@ -898,9 +869,137 @@ WebContentConverterRegistrar.prototype = {
};
function WebContentConverterRegistrarContent() {
this._contentTypes = {};
}
WebContentConverterRegistrarContent.prototype = {
/**
* Load the auto handler, content handler and protocol tables from
* preferences.
*/
_init() {
let ps = Services.prefs;
let children = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
.getChildList("");
// first get the numbers of the providers by getting all ###.uri prefs
let nums = children.map((child) => {
let match = /^(\d+)\.uri$/.exec(child);
return match ? match[1] : "";
}).filter(child => !!child)
.sort();
// now register them
for (num of nums) {
let branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + num + ".");
try {
this._registerContentHandlerHavingBranch(branch);
} catch(ex) {
// do nothing, the next branch might have values
}
}
// We need to do this _after_ registering all of the available handlers,
// so that getWebContentHandlerByURI can return successfully.
let autoBranch;
try {
autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
} catch (e) {
// No auto branch yet, that's fine
//LOG("WCCR.init: There is no auto branch, benign");
}
if (autoBranch) {
for (let type of autoBranch.getChildList("")) {
let uri = autoBranch.getCharPref(type);
if (uri) {
let handler = this.getWebContentHandlerByURI(type, uri);
if (handler) {
this._setAutoHandler(type, handler);
}
}
}
}
},
_typeIsRegistered(contentType, uri) {
return this._contentTypes[contentType]
.some(e => e.uri == uri);
},
/**
* Since we support up to six predefined readers, we need to handle gaps
* better, since the first branch with user-added values will be .6
*
* How we deal with that is to check to see if there's no prefs in the
* branch and stop cycling once that's true. This doesn't fix the case
* where a user manually removes a reader, but that's not supported yet!
*
* @param branch
* The pref branch to register the content handler under
*
*/
_registerContentHandlerHavingBranch(branch) {
let vals = branch.getChildList("");
if (vals.length == 0)
return;
let type = branch.getCharPref("type");
let uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
let title = branch.getComplexValue("title",
Ci.nsIPrefLocalizedString).data;
this._updateContentTypeHandlerMap(type, uri, title);
},
_updateContentTypeHandlerMap(contentType, uri, title) {
if (!(contentType in this._contentTypes))
this._contentTypes[contentType] = [];
// Avoid adding duplicates
if (this._typeIsRegistered(contentType, uri))
return;
this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
if (!(contentType in this._blockedTypes)) {
let converterContractID = this._getConverterContractID(contentType);
let cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID,
WebContentConverterFactory);
}
},
/**
* See nsIWebContentConverterService
*/
getContentHandlers(contentType, countRef) {
this._init();
if (countRef) {
countRef.value = 0;
}
if (!(contentType in this._contentTypes))
return [];
let handlers = this._contentTypes[contentType];
if (countRef) {
countRef.value = handlers.length;
}
return handlers;
},
setAutoHandler(contentType, handler) {
Services.cpmm.sendAsyncMessage("WCCR:setAutoHandler",
{ contentType, handler });
},
getWebContentHandlerByURI(contentType, uri) {
return this.getContentHandlers(contentType)
.find(e => e.uri == uri) || null;
},
/**
* See nsIWebContentHandlerRegistrar
*/
@ -945,7 +1044,7 @@ WebContentConverterRegistrarContent.prototype = {
/**
* See nsIFactory
*/
createInstance: function WCCR_createInstance(outer, iid) {
createInstance(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return this.QueryInterface(iid);
@ -958,6 +1057,7 @@ WebContentConverterRegistrarContent.prototype = {
*/
QueryInterface: XPCOMUtils.generateQI(
[Ci.nsIWebContentHandlerRegistrar,
Ci.nsIWebContentConverterService,
Ci.nsIFactory])
};

View File

@ -1,7 +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/. */
#feedSubscribeLine {
-moz-binding: url(subscribe.xml#feedreaderUI);
}

View File

@ -27,10 +27,6 @@
href="chrome://browser/skin/feeds/subscribe.css"
type="text/css"
media="all"/>
<link rel="stylesheet"
href="chrome://browser/content/feeds/subscribe.css"
type="text/css"
media="all"/>
<script type="application/javascript"
src="chrome://browser/content/feeds/subscribe.js"/>
</head>
@ -41,8 +37,20 @@
<p id="feedSubscriptionInfo1" />
<p id="feedSubscriptionInfo2" />
</div>
<div id="feedSubscribeLine"></div>
<div id="feedSubscribeLine">
<label id="subscribeUsingDescription">
<select id="handlersMenuList">
<option id="liveBookmarksMenuItem" selected="true">&feedLiveBookmarks;</option>
<option disabled="true">&#x2501;&#x2501;&#x2501;&#x2501;&#x2501;&#x2501;&#x2501;</option>
</select>
</label>
<label id="checkboxText">
<input type="checkbox" id="alwaysUse" class="alwaysUse" checked="false"/>
</label>
<button id="subscribeButton">&feedSubscribeNow;</button>
</div>
</div>
<div id="feedHeaderContainerSpacer"/>
</div>
<script type="application/javascript">

View File

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<!DOCTYPE bindings [
<!ENTITY % feedDTD
SYSTEM "chrome://browser/locale/feeds/subscribe.dtd">
%feedDTD;
]>
<bindings id="feedBindings"
xmlns="http://www.mozilla.org/xbl"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<binding id="feedreaderUI" bindToUntrustedContent="true">
<content>
<xul:vbox>
<xul:hbox align="center">
<xul:description anonid="subscribeUsingDescription" class="subscribeUsingDescription"/>
<xul:menulist anonid="handlersMenuList" class="handlersMenuList" aria-labelledby="subscribeUsingDescription">
<xul:menupopup anonid="handlersMenuPopup" class="handlersMenuPopup">
<xul:menuitem anonid="liveBookmarksMenuItem" label="&feedLiveBookmarks;" class="menuitem-iconic liveBookmarksMenuItem" image="chrome://browser/skin/page-livemarks.png" selected="true"/>
<xul:menuseparator/>
</xul:menupopup>
</xul:menulist>
</xul:hbox>
<xul:hbox>
<xul:checkbox anonid="alwaysUse" class="alwaysUse" checked="false"/>
</xul:hbox>
<xul:hbox align="center">
<xul:spacer flex="1"/>
<xul:button label="&feedSubscribeNow;" anonid="subscribeButton" class="subscribeButton"/>
</xul:hbox>
</xul:vbox>
</content>
<resources>
<stylesheet src="chrome://browser/skin/feeds/subscribe-ui.css"/>
</resources>
</binding>
</bindings>

View File

@ -5,5 +5,3 @@
browser.jar:
content/browser/feeds/subscribe.xhtml (content/subscribe.xhtml)
content/browser/feeds/subscribe.js (content/subscribe.js)
content/browser/feeds/subscribe.xml (content/subscribe.xml)
content/browser/feeds/subscribe.css (content/subscribe.css)

View File

@ -24,11 +24,8 @@ SOURCES += [
EXTRA_COMPONENTS += [
'BrowserFeeds.manifest',
'FeedConverter.js',
'WebContentConverter.js',
]
EXTRA_PP_COMPONENTS += [
'FeedWriter.js',
'WebContentConverter.js',
]
FINAL_LIBRARY = 'browsercomps'

View File

@ -12,7 +12,7 @@ interface nsIFeedResult;
* nsIFeedResultService provides a globally-accessible object for retrieving
* the results of feed processing.
*/
[scriptable, uuid(950a829e-c20e-4dc3-b447-f8b753ae54da)]
[scriptable, uuid(95309fd2-7b3a-47fb-97f3-5c460d9473cd)]
interface nsIFeedResultService : nsISupports
{
/**
@ -22,8 +22,8 @@ interface nsIFeedResultService : nsISupports
attribute boolean forcePreviewPage;
/**
* Adds a URI to the user's specified external feed handler, or live
* bookmarks.
* Adds a URI to the user's specified external feed handler, or live
* bookmarks.
* @param uri
* The uri of the feed to add.
* @param title
@ -32,11 +32,15 @@ interface nsIFeedResultService : nsISupports
* The subtitle of the feed to add.
* @param feedType
* The nsIFeed type of the feed. See nsIFeed.idl
* @param feedReader
* The type of feed reader we're using (client, bookmarks, default)
* If this parameter is null, the type is set to default
*/
void addToClientReader(in AUTF8String uri,
void addToClientReader(in AUTF8String uri,
in AString title,
in AString subtitle,
in unsigned long feedType);
in unsigned long feedType,
[optional] in AString feedReader);
/**
* Registers a Feed Result object with a globally accessible service

View File

@ -21,8 +21,7 @@ SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var doc = SpecialPowers.wrap($("testFrame")).contentDocument;
var daddy = doc.getElementById("feedSubscribeLine");
var popup = doc.getAnonymousElementByAttribute(daddy, "anonid", "handlersMenuPopup");
var popup = doc.getElementById("handlersMenuList");
isnot(popup, null, "Feed preview should have a handlers popup");
});
addLoadEvent(SimpleTest.finish);

View File

@ -11,6 +11,8 @@ Components.utils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUtils",
"resource://gre/modules/BrowserUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
"resource:///modules/RecentWindow.jsm");
const { interfaces: Ci, classes: Cc } = Components;
@ -18,12 +20,15 @@ this.Feeds = {
init() {
let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
mm.addMessageListener("WCCR:registerProtocolHandler", this);
Services.ppmm.addMessageListener("WCCR:setAutoHandler", this);
Services.ppmm.addMessageListener("FeedConverter:addLiveBookmark", this);
},
receiveMessage(aMessage) {
let data = aMessage.data;
switch (aMessage.name) {
case "WCCR:registerProtocolHandler": {
let data = aMessage.data;
let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentHandlerRegistrar);
registrar.registerProtocolHandler(data.protocol, data.uri, data.title,
@ -32,13 +37,26 @@ this.Feeds = {
}
case "WCCR:registerContentHandler": {
let data = aMessage.data;
let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentHandlerRegistrar);
registrar.registerContentHandler(data.contentType, data.uri, data.title,
aMessage.target);
break;
}
case "WCCR:setAutoHandler": {
let registrar = Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
getService(Ci.nsIWebContentHandlerRegistrar);
registrar.setAutoHandler(data.contentType, data.handler);
break;
}
case "FeedConverter:addLiveBookmark": {
let topWindow = RecentWindow.getMostRecentBrowserWindow();
topWindow.PlacesCommandHook.addLiveBookmark(data.spec, data.title, data.subtitle)
.catch(Components.utils.reportError);
break;
}
}
},

View File

@ -5,25 +5,3 @@
.alwaysUse {
padding: 5px;
}
.handlersMenuPopup > menuitem {
-moz-padding-start: 23px;
}
.handlersMenuPopup > menuitem.menuitem-iconic {
-moz-padding-start: 2px;
}
.handlersMenuPopup > .menuitem-iconic > .menu-iconic-left {
display: -moz-box;
min-width: 16px;
-moz-padding-end: 2px;
}
.chooseApplicationMenuItem {
list-style-image: url("moz-icon://dummy.exe?size=16");
}
#feedHeader[dir="rtl"] .handlersMenuList > menupopup {
direction: rtl;
}

View File

@ -7,6 +7,20 @@ html {
font: 3mm tahoma,arial,helvetica,sans-serif;
}
#subscribeUsingDescription,
#subscribeButton {
display: block;
}
#subscribeUsingDescription {
margin-bottom: 0.5em;
}
#subscribeButton {
margin-top: 0.5em;
margin-inline-start: auto;
}
#feedBody {
border: 1px solid THreeDShadow;
padding: 3em;
@ -21,9 +35,14 @@ html {
margin: -4em auto 0 auto;
background-color: InfoBackground;
-moz-appearance: -moz-gtk-info-bar;
display: flex;
}
#feedHeader {
#feedHeaderContainerSpacer {
flex-grow: 1;
}
#feedHeader {
margin-top: 4.9em;
margin-bottom: 1em;
-moz-margin-start: 1.4em;
@ -65,6 +84,7 @@ html {
#feedSubscribeLine {
padding-top: 0.2em;
padding-inline-start: 0.5em;
}
/* Don't print subscription UI */

View File

@ -6,6 +6,3 @@
padding: 3px;
}
.chooseApplicationMenuItem {
list-style-image: url("chrome://browser/skin/preferences/application.png");
}

View File

@ -7,6 +7,20 @@ html {
font: 3mm tahoma,arial,helvetica,sans-serif;
}
#subscribeUsingDescription,
#subscribeButton {
display: block;
}
#subscribeUsingDescription {
margin-bottom: 0.5em;
}
#subscribeButton {
margin-top: 0.5em;
margin-inline-start: auto;
}
#feedBody {
border: 1px solid THreeDShadow;
padding: 3em;
@ -15,6 +29,14 @@ html {
background: -moz-Field;
}
#feedHeaderContainer {
display: flex;
}
#feedHeaderContainerSpacer {
flex-grow: 1;
}
#feedHeader {
border: 1px solid ThreeDShadow;
border-radius: 10px;

View File

@ -5,25 +5,3 @@
.alwaysUse {
padding: 5px;
}
.handlersMenuPopup > menuitem {
-moz-padding-start: 23px;
}
.handlersMenuPopup > menuitem.menuitem-iconic {
-moz-padding-start: 2px;
}
.handlersMenuPopup > .menuitem-iconic > .menu-iconic-left {
display: -moz-box;
min-width: 16px;
-moz-padding-end: 2px;
}
.chooseApplicationMenuItem {
list-style-image: url("chrome://browser/skin/preferences/application.png");
}
#feedHeader[dir="rtl"] .handlersMenuList > menupopup {
direction: rtl;
}

View File

@ -7,6 +7,20 @@ html {
font: 3mm tahoma,arial,helvetica,sans-serif;
}
#subscribeUsingDescription,
#subscribeButton {
display: block;
}
#subscribeUsingDescription {
margin-bottom: 0.5em;
}
#subscribeButton {
margin-top: 0.5em;
margin-inline-start: auto;
}
#feedBody {
border: 1px solid THreeDShadow;
padding: 3em;
@ -20,9 +34,14 @@ html {
border-radius: 10px;
margin: -4em auto 0 auto;
background-color: InfoBackground;
display: flex;
}
#feedHeader {
#feedHeaderContainerSpacer {
flex-grow: 1;
}
#feedHeader {
margin-top: 4.9em;
margin-bottom: 1em;
-moz-margin-start: 1.4em;
@ -64,6 +83,7 @@ html {
#feedSubscribeLine {
padding-top: 0.2em;
padding-inline-start: 0.5em;
}
/* Don't print subscription UI */

View File

@ -261,6 +261,7 @@ this.AppConstants = Object.freeze({
MOZ_APP_VERSION: "@MOZ_APP_VERSION@",
MOZ_APP_VERSION_DISPLAY: "@MOZ_APP_VERSION_DISPLAY@",
MOZ_BUILD_APP: "@MOZ_BUILD_APP@",
MOZ_MACBUNDLE_NAME: "@MOZ_MACBUNDLE_NAME@",
MOZ_UPDATE_CHANNEL: "@MOZ_UPDATE_CHANNEL@",
INSTALL_LOCALE: "@AB_CD@",
MOZ_WIDGET_TOOLKIT: "@MOZ_WIDGET_TOOLKIT@",

View File

@ -103,6 +103,7 @@ for var in ('ANDROID_PACKAGE_NAME',
'MOZ_APP_NAME',
'MOZ_APP_VERSION',
'MOZ_APP_VERSION_DISPLAY',
'MOZ_MACBUNDLE_NAME',
'MOZ_WIDGET_TOOLKIT',
'DLL_PREFIX',
'DLL_SUFFIX',