mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1109714 - Make the feed subscriber UI work in e10s r=mrbkap,jaws
This commit is contained in:
parent
9af1dff99c
commit
237a81888c
@ -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;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -1434,6 +1434,8 @@ var gBrowserInit = {
|
||||
|
||||
BrowserOnClick.uninit();
|
||||
|
||||
FeedHandler.uninit();
|
||||
|
||||
DevEdition.uninit();
|
||||
|
||||
TrackingProtection.uninit();
|
||||
|
@ -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
@ -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])
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
@ -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">━━━━━━━</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">
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -24,11 +24,8 @@ SOURCES += [
|
||||
EXTRA_COMPONENTS += [
|
||||
'BrowserFeeds.manifest',
|
||||
'FeedConverter.js',
|
||||
'WebContentConverter.js',
|
||||
]
|
||||
|
||||
EXTRA_PP_COMPONENTS += [
|
||||
'FeedWriter.js',
|
||||
'WebContentConverter.js',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'browsercomps'
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -6,6 +6,3 @@
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.chooseApplicationMenuItem {
|
||||
list-style-image: url("chrome://browser/skin/preferences/application.png");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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@",
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user