Bug 1477669 - remove feed preview code and associated files/code, r=flod,mak,nika
Differential Revision: https://phabricator.services.mozilla.com/D8524 --HG-- extra : moz-landing-system : lando
|
@ -742,10 +742,6 @@ pref("layout.spellcheckDefault", 1);
|
|||
|
||||
pref("browser.send_pings", false);
|
||||
|
||||
pref("browser.feeds.handler", "ask");
|
||||
pref("browser.videoFeeds.handler", "ask");
|
||||
pref("browser.audioFeeds.handler", "ask");
|
||||
|
||||
// At startup, if the handler service notices that the version number in the
|
||||
// region.properties file is newer than the version number in the handler
|
||||
// service datastore, it will add any new handlers it finds in the prefs (as
|
||||
|
|
|
@ -1,409 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
|
||||
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
|
||||
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
|
||||
const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
|
||||
|
||||
const PREF_SHOW_FIRST_RUN_UI = "browser.feeds.showFirstRunUI";
|
||||
|
||||
const PREF_SELECTED_APP = "browser.feeds.handlers.application";
|
||||
const PREF_SELECTED_ACTION = "browser.feeds.handler";
|
||||
const PREF_SELECTED_READER = "browser.feeds.handler.default";
|
||||
|
||||
const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
|
||||
const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
|
||||
const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
|
||||
|
||||
const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
|
||||
const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
|
||||
const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
|
||||
|
||||
const PREF_UPDATE_DELAY = 2000;
|
||||
|
||||
const SETTABLE_PREFS = new Set([
|
||||
PREF_VIDEO_SELECTED_ACTION,
|
||||
PREF_AUDIO_SELECTED_ACTION,
|
||||
PREF_SELECTED_ACTION,
|
||||
PREF_VIDEO_SELECTED_READER,
|
||||
PREF_AUDIO_SELECTED_READER,
|
||||
PREF_SELECTED_READER,
|
||||
]);
|
||||
|
||||
const EXECUTABLE_PREFS = new Set([
|
||||
PREF_SELECTED_APP,
|
||||
PREF_VIDEO_SELECTED_APP,
|
||||
PREF_AUDIO_SELECTED_APP,
|
||||
]);
|
||||
|
||||
const VALID_ACTIONS = new Set(["ask", "reader", "bookmarks"]);
|
||||
const VALID_READERS = new Set(["client", "default", "bookmarks"]);
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "SHOULD_LOG",
|
||||
"feeds.log", false);
|
||||
|
||||
function LOG(str) {
|
||||
if (SHOULD_LOG)
|
||||
dump("*** Feeds: " + str + "\n");
|
||||
}
|
||||
|
||||
function getPrefActionForType(t) {
|
||||
switch (t) {
|
||||
case Ci.nsIFeed.TYPE_VIDEO:
|
||||
return PREF_VIDEO_SELECTED_ACTION;
|
||||
|
||||
case Ci.nsIFeed.TYPE_AUDIO:
|
||||
return PREF_AUDIO_SELECTED_ACTION;
|
||||
|
||||
default:
|
||||
return PREF_SELECTED_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
function getPrefReaderForType(t) {
|
||||
switch (t) {
|
||||
case Ci.nsIFeed.TYPE_VIDEO:
|
||||
return PREF_VIDEO_SELECTED_READER;
|
||||
|
||||
case Ci.nsIFeed.TYPE_AUDIO:
|
||||
return PREF_AUDIO_SELECTED_READER;
|
||||
|
||||
default:
|
||||
return PREF_SELECTED_READER;
|
||||
}
|
||||
}
|
||||
|
||||
function getPrefAppForType(t) {
|
||||
switch (t) {
|
||||
case Ci.nsIFeed.TYPE_VIDEO:
|
||||
return PREF_VIDEO_SELECTED_APP;
|
||||
|
||||
case Ci.nsIFeed.TYPE_AUDIO:
|
||||
return PREF_AUDIO_SELECTED_APP;
|
||||
|
||||
default:
|
||||
return PREF_SELECTED_APP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a feed type to a maybe-feed mimetype.
|
||||
*/
|
||||
function getMimeTypeForFeedType(aFeedType) {
|
||||
switch (aFeedType) {
|
||||
case Ci.nsIFeed.TYPE_VIDEO:
|
||||
return TYPE_MAYBE_VIDEO_FEED;
|
||||
|
||||
case Ci.nsIFeed.TYPE_AUDIO:
|
||||
return TYPE_MAYBE_AUDIO_FEED;
|
||||
|
||||
default:
|
||||
return TYPE_MAYBE_FEED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
|
||||
* and shows UI when they are discovered.
|
||||
*/
|
||||
var FeedHandler = {
|
||||
_prefChangeCallback: null,
|
||||
|
||||
/**
|
||||
* 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, aTypeName, aBrowser) {
|
||||
const prefName = getPrefAppForType(aTypeName);
|
||||
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(prefName, Ci.nsIFile, 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 nsIFile 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.nsIFile);
|
||||
}
|
||||
|
||||
// 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 = Services.io.newURI(aSpec);
|
||||
if (feedURI.schemeIs("http")) {
|
||||
feedURI = feedURI.mutate()
|
||||
.setScheme("feed")
|
||||
.finalize();
|
||||
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);
|
||||
}
|
||||
},
|
||||
|
||||
// nsISupports
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
|
||||
init() {
|
||||
window.messageManager.addMessageListener("FeedWriter:ChooseClientApp", this);
|
||||
window.messageManager.addMessageListener("FeedWriter:GetSubscriptionUI", this);
|
||||
window.messageManager.addMessageListener("FeedWriter:SetFeedPrefsAndSubscribe", this);
|
||||
window.messageManager.addMessageListener("FeedWriter:ShownFirstRun", this);
|
||||
|
||||
Services.ppmm.addMessageListener("FeedConverter:ExecuteClientApp", this);
|
||||
|
||||
const prefs = Services.prefs;
|
||||
prefs.addObserver(PREF_SELECTED_ACTION, this, true);
|
||||
prefs.addObserver(PREF_SELECTED_READER, this, true);
|
||||
prefs.addObserver(PREF_VIDEO_SELECTED_ACTION, this, true);
|
||||
prefs.addObserver(PREF_VIDEO_SELECTED_READER, this, true);
|
||||
prefs.addObserver(PREF_AUDIO_SELECTED_ACTION, this, true);
|
||||
prefs.addObserver(PREF_AUDIO_SELECTED_READER, this, true);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
Services.ppmm.removeMessageListener("FeedConverter:ExecuteClientApp", this);
|
||||
|
||||
this._prefChangeCallback = null;
|
||||
},
|
||||
|
||||
// nsIObserver
|
||||
observe(subject, topic, data) {
|
||||
if (topic == "nsPref:changed") {
|
||||
LOG(`Pref changed ${data}`);
|
||||
if (this._prefChangeCallback) {
|
||||
this._prefChangeCallback.disarm();
|
||||
}
|
||||
// Multiple prefs are set at the same time, debounce to reduce noise
|
||||
// This can happen in one feed and we want to message all feed pages
|
||||
this._prefChangeCallback = new DeferredTask(() => {
|
||||
this._prefChanged(data);
|
||||
}, PREF_UPDATE_DELAY);
|
||||
this._prefChangeCallback.arm();
|
||||
}
|
||||
},
|
||||
|
||||
_prefChanged(prefName) {
|
||||
// Don't observe for PREF_*SELECTED_APP as user likely just picked one
|
||||
// That is also handled by SetApplicationLauncherMenuItem call
|
||||
// Rather than the others which happen on subscription
|
||||
switch (prefName) {
|
||||
case PREF_SELECTED_READER:
|
||||
case PREF_VIDEO_SELECTED_READER:
|
||||
case PREF_AUDIO_SELECTED_READER:
|
||||
case PREF_SELECTED_ACTION:
|
||||
case PREF_VIDEO_SELECTED_ACTION:
|
||||
case PREF_AUDIO_SELECTED_ACTION:
|
||||
const response = {
|
||||
default: this._getReaderForType(Ci.nsIFeed.TYPE_FEED),
|
||||
[Ci.nsIFeed.TYPE_AUDIO]: this._getReaderForType(Ci.nsIFeed.TYPE_AUDIO),
|
||||
[Ci.nsIFeed.TYPE_VIDEO]: this._getReaderForType(Ci.nsIFeed.TYPE_VIDEO),
|
||||
};
|
||||
Services.mm.broadcastAsyncMessage("FeedWriter:PreferenceUpdated",
|
||||
response);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_initSubscriptionUIResponse(feedType) {
|
||||
let showFirstRunUI = Services.prefs.getBoolPref(PREF_SHOW_FIRST_RUN_UI, true);
|
||||
const response = { showFirstRunUI };
|
||||
let selectedClientApp;
|
||||
const feedTypePref = getPrefAppForType(feedType);
|
||||
try {
|
||||
selectedClientApp = Services.prefs.getComplexValue(feedTypePref, Ci.nsIFile);
|
||||
} 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
|
||||
response.defaultMenuItem = this._getFileDisplayName(defaultClientApp);
|
||||
}
|
||||
response.selectedMenuItem = this._getFileDisplayName(selectedClientApp);
|
||||
}
|
||||
response.reader = this._getReaderForType(feedType);
|
||||
return response;
|
||||
},
|
||||
|
||||
_setPref(aPrefName, aPrefValue, aIsComplex = false) {
|
||||
LOG(`FeedWriter._setPref ${aPrefName}`);
|
||||
// Ensure we have a pref that is settable
|
||||
if (aPrefName && SETTABLE_PREFS.has(aPrefName)) {
|
||||
if (aIsComplex) {
|
||||
Services.prefs.setStringPref(aPrefName, aPrefValue);
|
||||
} else {
|
||||
Services.prefs.setCharPref(aPrefName, aPrefValue);
|
||||
}
|
||||
} else {
|
||||
LOG(`FeedWriter._setPref ${aPrefName} not allowed`);
|
||||
}
|
||||
},
|
||||
|
||||
_getReaderForType(feedType) {
|
||||
let handler = Services.prefs.getCharPref(getPrefReaderForType(feedType), "bookmarks");
|
||||
const alwaysUse = this._getAlwaysUseState(feedType);
|
||||
const action = Services.prefs.getCharPref(getPrefActionForType(feedType));
|
||||
return { handler, alwaysUse, action };
|
||||
},
|
||||
|
||||
_getAlwaysUseState(feedType) {
|
||||
try {
|
||||
return Services.prefs.getCharPref(getPrefActionForType(feedType)) != "ask";
|
||||
} catch (ex) { }
|
||||
return false;
|
||||
},
|
||||
|
||||
receiveMessage(msg) {
|
||||
switch (msg.name) {
|
||||
case "FeedWriter:GetSubscriptionUI":
|
||||
const response = this._initSubscriptionUIResponse(msg.data.feedType);
|
||||
msg.target.messageManager
|
||||
.sendAsyncMessage("FeedWriter:GetSubscriptionUIResponse",
|
||||
response);
|
||||
break;
|
||||
case "FeedWriter:ChooseClientApp":
|
||||
this._chooseClientApp(msg.data.title, msg.data.feedType, msg.target);
|
||||
break;
|
||||
case "FeedWriter:ShownFirstRun":
|
||||
Services.prefs.setBoolPref(PREF_SHOW_FIRST_RUN_UI, false);
|
||||
break;
|
||||
case "FeedWriter:SetFeedPrefsAndSubscribe":
|
||||
const settings = msg.data;
|
||||
if (!settings.action || !VALID_ACTIONS.has(settings.action)) {
|
||||
LOG(`Invalid action ${settings.action}`);
|
||||
return;
|
||||
}
|
||||
if (!settings.reader || !VALID_READERS.has(settings.reader)) {
|
||||
LOG(`Invalid reader ${settings.reader}`);
|
||||
return;
|
||||
}
|
||||
|
||||
Services.telemetry.scalarAdd("browser.feeds.feed_subscribed", 1);
|
||||
|
||||
const actionPref = getPrefActionForType(settings.feedType);
|
||||
this._setPref(actionPref, settings.action);
|
||||
const readerPref = getPrefReaderForType(settings.feedType);
|
||||
this._setPref(readerPref, settings.reader);
|
||||
|
||||
const feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
|
||||
getService(Ci.nsIFeedResultService);
|
||||
|
||||
feedService.addToClientReader(settings.feedLocation,
|
||||
settings.feedTitle,
|
||||
settings.feedSubtitle,
|
||||
settings.feedType,
|
||||
settings.reader);
|
||||
break;
|
||||
case "FeedConverter:ExecuteClientApp":
|
||||
// Always check feedHandler is from a set array of executable prefs
|
||||
if (EXECUTABLE_PREFS.has(msg.data.feedHandler)) {
|
||||
this.executeClientApp(msg.data.spec, msg.data.title,
|
||||
msg.data.subtitle, msg.data.feedHandler);
|
||||
} else {
|
||||
LOG(`FeedConverter:ExecuteClientApp - Will not exec ${msg.data.feedHandler}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
|
@ -489,10 +489,6 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
|
|||
-moz-box-flex: 1;
|
||||
}
|
||||
|
||||
#PanelUI-feeds > .feed-toolbarbutton:-moz-locale-dir(rtl) {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
#appMenu_historyMenu > .bookmark-item,
|
||||
#appMenu-library-recentlyClosedTabs > .panel-subview-body > .bookmark-item,
|
||||
#appMenu-library-recentlyClosedWindows > .panel-subview-body > .bookmark-item,
|
||||
|
|
|
@ -1352,7 +1352,6 @@ var gBrowserInit = {
|
|||
gPageStyleMenu.init();
|
||||
LanguageDetectionListener.init();
|
||||
BrowserOnClick.init();
|
||||
FeedHandler.init();
|
||||
ContentBlocking.init();
|
||||
CaptivePortalWatcher.init();
|
||||
ZoomUI.init(window);
|
||||
|
@ -1933,8 +1932,6 @@ var gBrowserInit = {
|
|||
|
||||
BrowserOnClick.uninit();
|
||||
|
||||
FeedHandler.uninit();
|
||||
|
||||
ContentBlocking.uninit();
|
||||
|
||||
CaptivePortalWatcher.uninit();
|
||||
|
|
|
@ -21,7 +21,6 @@ for (let script of [
|
|||
"chrome://browser/content/browser-captivePortal.js",
|
||||
"chrome://browser/content/browser-compacttheme.js",
|
||||
"chrome://browser/content/browser-contentblocking.js",
|
||||
"chrome://browser/content/browser-feeds.js",
|
||||
"chrome://browser/content/browser-media.js",
|
||||
"chrome://browser/content/browser-pageActions.js",
|
||||
"chrome://browser/content/browser-places.js",
|
||||
|
|
|
@ -122,9 +122,6 @@ with Files("browser-compacttheme.js"):
|
|||
with Files("browser-customization.js"):
|
||||
BUG_COMPONENT = ("Firefox", "Toolbars and Customization")
|
||||
|
||||
with Files("browser-feeds.js"):
|
||||
BUG_COMPONENT = ("Firefox", "Toolbars and Customization")
|
||||
|
||||
with Files("browser-fullZoom.js"):
|
||||
BUG_COMPONENT = ("Firefox", "Tabbed Browsing")
|
||||
|
||||
|
|
|
@ -37,8 +37,7 @@ var gTests = [
|
|||
preventDefault: true,
|
||||
},
|
||||
|
||||
// The next test was once handling feedService.forcePreview(). Now it should
|
||||
// just be like Alt click.
|
||||
// The next test should just be like Alt click.
|
||||
{
|
||||
desc: "Shift+Alt left click",
|
||||
setup() {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<rss version="2.0">
|
||||
<channel>
|
||||
<link>http://example.org/</link>
|
||||
<title>t</title>
|
||||
</channel>
|
||||
</rss>
|
|
@ -1,17 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=458579
|
||||
-->
|
||||
<head>
|
||||
<title>Test for page info feeds tab</title>
|
||||
|
||||
<!-- Straight up standard -->
|
||||
<link rel="alternate" type="application/atom+xml" title="1" href="/1.atom" />
|
||||
<link rel="alternate" type="application/rss+xml" title="2" href="/2.rss" />
|
||||
<link rel="feed" title="3" href="/3.xml" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -1,27 +0,0 @@
|
|||
|
||||
function getTestPlugin(pluginName) {
|
||||
var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"]
|
||||
.getService(SpecialPowers.Ci.nsIPluginHost);
|
||||
var tags = ph.getPluginTags();
|
||||
var name = pluginName || "Test Plug-in";
|
||||
for (var tag of tags) {
|
||||
if (tag.name == name) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
|
||||
ok(false, "Could not find plugin tag with plugin name '" + name + "'");
|
||||
return null;
|
||||
}
|
||||
|
||||
// call this to set the test plugin(s) initially expected enabled state.
|
||||
// it will automatically be reset to it's previous value after the test
|
||||
// ends
|
||||
function setTestPluginEnabledState(newEnabledState, pluginName) {
|
||||
var plugin = getTestPlugin(pluginName);
|
||||
var oldEnabledState = plugin.enabledState;
|
||||
plugin.enabledState = newEnabledState;
|
||||
SimpleTest.registerCleanupFunction(function() {
|
||||
getTestPlugin(pluginName).enabledState = oldEnabledState;
|
||||
});
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
audio.ogg
|
||||
bug395533-data.txt
|
||||
contextmenu_common.js
|
||||
ctxmenu-image.png
|
||||
head_plain.js
|
||||
offlineByDefault.js
|
||||
offlineChild.cacheManifest
|
||||
offlineChild.cacheManifest^headers^
|
||||
offlineChild.html
|
||||
offlineChild2.cacheManifest
|
||||
offlineChild2.cacheManifest^headers^
|
||||
offlineChild2.html
|
||||
offlineEvent.cacheManifest
|
||||
offlineEvent.cacheManifest^headers^
|
||||
offlineEvent.html
|
||||
subtst_contextmenu.html
|
||||
video.ogg
|
||||
!/image/test/mochitest/blue.png
|
||||
|
||||
[test_bug395533.html]
|
|
@ -1,12 +0,0 @@
|
|||
var offlineByDefault = {
|
||||
defaultValue: false,
|
||||
set(allow) {
|
||||
this.defaultValue = SpecialPowers.Services.prefs.getBoolPref("offline-apps.allow_by_default", false);
|
||||
SpecialPowers.Services.prefs.setBoolPref("offline-apps.allow_by_default", allow);
|
||||
},
|
||||
reset() {
|
||||
SpecialPowers.Services.prefs.setBoolPref("offline-apps.allow_by_default", this.defaultValue);
|
||||
},
|
||||
};
|
||||
|
||||
offlineByDefault.set(false);
|
|
@ -1,2 +0,0 @@
|
|||
CACHE MANIFEST
|
||||
offlineChild.html
|
|
@ -1 +0,0 @@
|
|||
Content-Type: text/cache-manifest
|
|
@ -1,20 +0,0 @@
|
|||
<html manifest="offlineChild.cacheManifest">
|
||||
<head>
|
||||
<title></title>
|
||||
<script type="text/javascript">
|
||||
|
||||
function finish(success) {
|
||||
window.parent.postMessage(success ? "success" : "failure", "*");
|
||||
}
|
||||
|
||||
applicationCache.oncached = function() { finish(true); };
|
||||
applicationCache.onnoupdate = function() { finish(true); };
|
||||
applicationCache.onerror = function() { finish(false); };
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Child</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -1,2 +0,0 @@
|
|||
CACHE MANIFEST
|
||||
offlineChild2.html
|
|
@ -1 +0,0 @@
|
|||
Content-Type: text/cache-manifest
|
|
@ -1,20 +0,0 @@
|
|||
<html manifest="offlineChild2.cacheManifest">
|
||||
<head>
|
||||
<title></title>
|
||||
<script type="text/javascript">
|
||||
|
||||
function finish(success) {
|
||||
window.parent.postMessage(success ? "success" : "failure", "*");
|
||||
}
|
||||
|
||||
applicationCache.oncached = function() { finish(true); };
|
||||
applicationCache.onnoupdate = function() { finish(true); };
|
||||
applicationCache.onerror = function() { finish(false); };
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Child</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -1,2 +0,0 @@
|
|||
CACHE MANIFEST
|
||||
offlineChild.html
|
|
@ -1 +0,0 @@
|
|||
Content-Type: text/cache-manifest
|
|
@ -1,9 +0,0 @@
|
|||
<html manifest="offlineEvent.cacheManifest">
|
||||
<head>
|
||||
<title></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Child</h1>
|
||||
</body>
|
||||
</html>
|
|
@ -1,38 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=395533
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 395533</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=395533">Mozilla Bug 395533</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug395533-data.txt"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 395533 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
// Need privs because the feed seems to have an about:feeds principal or some
|
||||
// such. It's not same-origin with us in any case.
|
||||
is(SpecialPowers.wrap($("testFrame")).contentDocument.documentElement.id, "",
|
||||
"Text got sniffed as a feed?");
|
||||
});
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -44,7 +44,6 @@ browser.jar:
|
|||
#ifndef MOZILLA_OFFICIAL
|
||||
content/browser/browser-development-helpers.js (content/browser-development-helpers.js)
|
||||
#endif
|
||||
content/browser/browser-feeds.js (content/browser-feeds.js)
|
||||
content/browser/browser-fullScreenAndPointerLock.js (content/browser-fullScreenAndPointerLock.js)
|
||||
content/browser/browser-fullZoom.js (content/browser-fullZoom.js)
|
||||
content/browser/browser-gestureSupport.js (content/browser-gestureSupport.js)
|
||||
|
|
|
@ -13,10 +13,6 @@ SPHINX_TREES['tabbrowser'] = 'content/docs/tabbrowser'
|
|||
with Files('content/docs/sslerrorreport/**'):
|
||||
SCHEDULES.exclusive = ['docs']
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'content/test/general/mochitest.ini',
|
||||
]
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'content/test/chrome/chrome.ini',
|
||||
]
|
||||
|
|
|
@ -60,10 +60,6 @@ static const RedirEntry kRedirMap[] = {
|
|||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
|
||||
{ "feeds", "chrome://browser/content/feeds/subscribe.xhtml",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
|
||||
{ "policies", "chrome://browser/content/policies/aboutPolicies.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
{ "privatebrowsing", "chrome://browser/content/aboutPrivateBrowsing.xhtml",
|
||||
|
|
|
@ -21,7 +21,6 @@ FINAL_LIBRARY = 'xul'
|
|||
LOCAL_INCLUDES += [
|
||||
'../about',
|
||||
'../dirprovider',
|
||||
'../feeds',
|
||||
'../migration',
|
||||
'../sessionstore',
|
||||
'../shell',
|
||||
|
|
|
@ -21,15 +21,6 @@
|
|||
#define NS_RDF_FORWARDPROXY_INFER_DATASOURCE_CID \
|
||||
{ 0x7a024bcf, 0xedd5, 0x4d9a, { 0x86, 0x14, 0xd4, 0x4b, 0xe1, 0xda, 0xda, 0xd3 } }
|
||||
|
||||
#define NS_FEEDSNIFFER_CID \
|
||||
{ 0x6893e69, 0x71d8, 0x4b23, { 0x81, 0xeb, 0x80, 0x31, 0x4d, 0xaf, 0x3e, 0x66 } }
|
||||
|
||||
#define NS_FEEDSNIFFER_CONTRACTID \
|
||||
"@mozilla.org/browser/feeds/sniffer;1"
|
||||
|
||||
#define NS_ABOUTFEEDS_CID \
|
||||
{ 0x12ff56ec, 0x58be, 0x402c, { 0xb0, 0x57, 0x1, 0xf9, 0x61, 0xde, 0x96, 0x9b } }
|
||||
|
||||
// 136e2c4d-c5a4-477c-b131-d93d7d704f64
|
||||
#define NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID \
|
||||
{ 0x136e2c4d, 0xc5a4, 0x477c, { 0xb1, 0x31, 0xd9, 0x3d, 0x7d, 0x70, 0x4f, 0x64 } }
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "nsIEHistoryEnumerator.h"
|
||||
#endif
|
||||
|
||||
#include "nsFeedSniffer.h"
|
||||
#include "AboutRedirector.h"
|
||||
#include "nsIAboutModule.h"
|
||||
|
||||
|
@ -51,15 +50,12 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacAttributionService)
|
|||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
|
||||
#endif
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_BROWSERDIRECTORYPROVIDER_CID);
|
||||
#if defined(XP_WIN)
|
||||
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
|
||||
#endif
|
||||
NS_DEFINE_NAMED_CID(NS_FEEDSNIFFER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_BROWSER_ABOUT_REDIRECTOR_CID);
|
||||
#if defined(XP_WIN)
|
||||
NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
|
||||
|
@ -78,7 +74,6 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
|
|||
#elif defined(MOZ_WIDGET_GTK)
|
||||
{ &kNS_SHELLSERVICE_CID, false, nullptr, nsGNOMEShellServiceConstructor },
|
||||
#endif
|
||||
{ &kNS_FEEDSNIFFER_CID, false, nullptr, nsFeedSnifferConstructor },
|
||||
{ &kNS_BROWSER_ABOUT_REDIRECTOR_CID, false, nullptr, AboutRedirector::Create },
|
||||
#if defined(XP_WIN)
|
||||
{ &kNS_WINIEHISTORYENUMERATOR_CID, false, nullptr, nsIEHistoryEnumeratorConstructor },
|
||||
|
@ -100,11 +95,9 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
|||
#elif defined(MOZ_WIDGET_GTK)
|
||||
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
|
||||
#endif
|
||||
{ NS_FEEDSNIFFER_CONTRACTID, &kNS_FEEDSNIFFER_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "tabcrashed", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "feeds", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "robots", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
|
@ -134,7 +127,6 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
|||
|
||||
static const mozilla::Module::CategoryEntry kBrowserCategories[] = {
|
||||
{ XPCOM_DIRECTORY_PROVIDER_CATEGORY, "browser-directory-provider", NS_BROWSERDIRECTORYPROVIDER_CONTRACTID },
|
||||
{ NS_CONTENT_SNIFFER_CATEGORY, "Feed Sniffer", NS_FEEDSNIFFER_CONTRACTID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
|
|
|
@ -571,9 +571,6 @@
|
|||
onclick="PanelUI.hide();"/>
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);">
|
||||
</panelview>
|
||||
|
||||
<panelview id="PanelUI-containers" flex="1">
|
||||
<vbox id="PanelUI-containersItems"/>
|
||||
</panelview>
|
||||
|
|
|
@ -1,10 +1,2 @@
|
|||
component {229fa115-9412-4d32-baf3-2fc407f76fb1} FeedConverter.js
|
||||
contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
|
||||
contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.video.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
|
||||
contract @mozilla.org/streamconv;1?from=application/vnd.mozilla.maybe.audio.feed&to=*/* {229fa115-9412-4d32-baf3-2fc407f76fb1}
|
||||
component {2376201c-bbc6-472f-9b62-7548040a61c6} FeedConverter.js
|
||||
contract @mozilla.org/browser/feeds/result-service;1 {2376201c-bbc6-472f-9b62-7548040a61c6}
|
||||
component {49bb6593-3aff-4eb3-a068-2712c28bd58e} FeedWriter.js
|
||||
contract @mozilla.org/browser/feeds/result-writer;1 {49bb6593-3aff-4eb3-a068-2712c28bd58e}
|
||||
component {792a7e82-06a0-437c-af63-b2d12e808acc} WebContentConverter.js
|
||||
contract @mozilla.org/embeddor.implemented/web-content-handler-registrar;1 {792a7e82-06a0-437c-af63-b2d12e808acc}
|
||||
|
|
|
@ -1,415 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function LOG(str) {
|
||||
dump("*** " + str + "\n");
|
||||
}
|
||||
|
||||
const FS_CONTRACTID = "@mozilla.org/browser/feeds/result-service;1";
|
||||
const FPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=feed";
|
||||
const PCPH_CONTRACTID = "@mozilla.org/network/protocol;1?name=pcast";
|
||||
|
||||
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
|
||||
const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
|
||||
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
|
||||
const TYPE_ANY = "*/*";
|
||||
|
||||
const PREF_SELECTED_APP = "browser.feeds.handlers.application";
|
||||
const PREF_SELECTED_ACTION = "browser.feeds.handler";
|
||||
const PREF_SELECTED_READER = "browser.feeds.handler.default";
|
||||
|
||||
const PREF_VIDEO_SELECTED_APP = "browser.videoFeeds.handlers.application";
|
||||
const PREF_VIDEO_SELECTED_ACTION = "browser.videoFeeds.handler";
|
||||
const PREF_VIDEO_SELECTED_READER = "browser.videoFeeds.handler.default";
|
||||
|
||||
const PREF_AUDIO_SELECTED_APP = "browser.audioFeeds.handlers.application";
|
||||
const PREF_AUDIO_SELECTED_ACTION = "browser.audioFeeds.handler";
|
||||
const PREF_AUDIO_SELECTED_READER = "browser.audioFeeds.handler.default";
|
||||
|
||||
function getPrefAppForType(t) {
|
||||
switch (t) {
|
||||
case Ci.nsIFeed.TYPE_VIDEO:
|
||||
return PREF_VIDEO_SELECTED_APP;
|
||||
|
||||
case Ci.nsIFeed.TYPE_AUDIO:
|
||||
return PREF_AUDIO_SELECTED_APP;
|
||||
|
||||
default:
|
||||
return PREF_SELECTED_APP;
|
||||
}
|
||||
}
|
||||
|
||||
function getPrefActionForType(t) {
|
||||
switch (t) {
|
||||
case Ci.nsIFeed.TYPE_VIDEO:
|
||||
return PREF_VIDEO_SELECTED_ACTION;
|
||||
|
||||
case Ci.nsIFeed.TYPE_AUDIO:
|
||||
return PREF_AUDIO_SELECTED_ACTION;
|
||||
|
||||
default:
|
||||
return PREF_SELECTED_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
function getPrefReaderForType(t) {
|
||||
switch (t) {
|
||||
case Ci.nsIFeed.TYPE_VIDEO:
|
||||
return PREF_VIDEO_SELECTED_READER;
|
||||
|
||||
case Ci.nsIFeed.TYPE_AUDIO:
|
||||
return PREF_AUDIO_SELECTED_READER;
|
||||
|
||||
default:
|
||||
return PREF_SELECTED_READER;
|
||||
}
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gCanFrameFeeds",
|
||||
"browser.feeds.unsafelyFrameFeeds", false);
|
||||
|
||||
|
||||
function FeedConverter() {
|
||||
}
|
||||
FeedConverter.prototype = {
|
||||
classID: Components.ID("{229fa115-9412-4d32-baf3-2fc407f76fb1}"),
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
_listener: null,
|
||||
|
||||
/**
|
||||
* Records if the feed was sniffed
|
||||
*/
|
||||
_sniffed: false,
|
||||
|
||||
/**
|
||||
* See nsIStreamConverter.idl
|
||||
*/
|
||||
convert(sourceStream, sourceType, destinationType,
|
||||
context) {
|
||||
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIStreamConverter.idl
|
||||
*/
|
||||
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() {
|
||||
this._listener = null;
|
||||
this._request = null;
|
||||
this._processor = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIFeedResultListener.idl
|
||||
*/
|
||||
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
|
||||
// different data types, e.g. news/blogs (traditional feed), video/audio
|
||||
// (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.
|
||||
//
|
||||
// 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
|
||||
// converter needs to consume all of the data and parse it, and based on
|
||||
// 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
|
||||
// a client handler.
|
||||
//
|
||||
// If this is just a feed, not some kind of specialized application, then
|
||||
// auto-handlers can be set and we should obey them.
|
||||
try {
|
||||
let feedService =
|
||||
Cc["@mozilla.org/browser/feeds/result-service;1"].
|
||||
getService(Ci.nsIFeedResultService);
|
||||
if (!this._forcePreviewPage && result.doc) {
|
||||
let feed = result.doc.QueryInterface(Ci.nsIFeed);
|
||||
let handler = Services.prefs.getCharPref(getPrefActionForType(feed.type), "ask");
|
||||
|
||||
if (handler != "ask") {
|
||||
if (handler == "reader")
|
||||
handler = Services.prefs.getCharPref(getPrefReaderForType(feed.type), "bookmarks");
|
||||
try {
|
||||
let title = feed.title ? feed.title.plainText() : "";
|
||||
let desc = feed.subtitle ? feed.subtitle.plainText() : "";
|
||||
feedService.addToClientReader(result.uri.spec, title, desc, feed.type, handler);
|
||||
return;
|
||||
} catch (ex) { /* fallback to preview mode */ }
|
||||
}
|
||||
}
|
||||
|
||||
let chromeChannel;
|
||||
|
||||
// handling a redirect, hence forwarding the loadInfo from the old channel
|
||||
// to the newchannel.
|
||||
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
|
||||
// if the parser returned a document.
|
||||
if (result.doc) {
|
||||
|
||||
// Store the result in the result service so that the display
|
||||
// page can access it.
|
||||
feedService.addFeedResult(result);
|
||||
|
||||
// Now load the actual XUL document.
|
||||
let aboutFeedsURI = Services.io.newURI("about:feeds");
|
||||
chromeChannel = Services.io.newChannelFromURIWithLoadInfo(aboutFeedsURI, loadInfo);
|
||||
chromeChannel.originalURI = result.uri;
|
||||
|
||||
// carry the origin attributes from the channel that loaded the feed.
|
||||
chromeChannel.owner =
|
||||
Services.scriptSecurityManager.createCodebasePrincipal(aboutFeedsURI,
|
||||
loadInfo.originAttributes);
|
||||
} else {
|
||||
chromeChannel = Services.io.newChannelFromURIWithLoadInfo(result.uri, loadInfo);
|
||||
}
|
||||
|
||||
chromeChannel.loadGroup = this._request.loadGroup;
|
||||
chromeChannel.asyncOpen2(this._listener);
|
||||
} finally {
|
||||
this._releaseHandles();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIStreamListener.idl
|
||||
*/
|
||||
onDataAvailable(request, context, inputStream,
|
||||
sourceOffset, count) {
|
||||
if (this._processor)
|
||||
this._processor.onDataAvailable(request, context, inputStream,
|
||||
sourceOffset, count);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStartRequest(request, context) {
|
||||
let channel = request.QueryInterface(Ci.nsIChannel);
|
||||
|
||||
let {loadInfo} = channel;
|
||||
if ((loadInfo.frameOuterWindowID || loadInfo.outerWindowID) != loadInfo.topOuterWindowID &&
|
||||
!gCanFrameFeeds) {
|
||||
// We don't care about frame loads:
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for a header that tells us there was no sniffing
|
||||
// The value doesn't matter.
|
||||
try {
|
||||
let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
|
||||
// Make sure to check requestSucceeded before the potentially-throwing
|
||||
// getResponseHeader.
|
||||
if (!httpChannel.requestSucceeded) {
|
||||
// Just give up, but don't forget to cancel the channel first!
|
||||
request.cancel(Cr.NS_BINDING_ABORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Note: this throws if the header is not set.
|
||||
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.
|
||||
let feedService =
|
||||
Cc["@mozilla.org/browser/feeds/result-service;1"].
|
||||
getService(Ci.nsIFeedResultService);
|
||||
this._forcePreviewPage = feedService.forcePreviewPage;
|
||||
feedService.forcePreviewPage = false;
|
||||
|
||||
// Parse feed data as it comes in
|
||||
this._processor =
|
||||
Cc["@mozilla.org/feed-processor;1"].
|
||||
createInstance(Ci.nsIFeedProcessor);
|
||||
this._processor.listener = this;
|
||||
this._processor.parseAsync(null, channel.URI);
|
||||
|
||||
this._processor.onStartRequest(request, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIRequestObserver.idl
|
||||
*/
|
||||
onStopRequest(request, context, status) {
|
||||
if (this._processor)
|
||||
this._processor.onStopRequest(request, context, status);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsISupports.idl
|
||||
*/
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIFeedResultListener",
|
||||
"nsIStreamConverter",
|
||||
"nsIStreamListener",
|
||||
"nsIRequestObserver"]),
|
||||
};
|
||||
|
||||
/**
|
||||
* Keeps parsed FeedResults around for use elsewhere in the UI after the stream
|
||||
* 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(spec, title, subtitle, feedType, feedReader) {
|
||||
if (!feedReader) {
|
||||
feedReader = "default";
|
||||
}
|
||||
|
||||
let handler = Services.prefs.getCharPref(getPrefActionForType(feedType), "bookmarks");
|
||||
if (handler == "ask" || handler == "reader")
|
||||
handler = feedReader;
|
||||
|
||||
switch (handler) {
|
||||
case "client":
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIFeedResultService.idl
|
||||
*/
|
||||
addFeedResult(feedResult) {
|
||||
if (feedResult.uri == null)
|
||||
throw new Error("null URI!");
|
||||
if (feedResult.uri == null)
|
||||
throw new Error("null feedResult!");
|
||||
let spec = feedResult.uri.spec;
|
||||
if (!this._results[spec])
|
||||
this._results[spec] = [];
|
||||
this._results[spec].push(feedResult);
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIFeedResultService.idl
|
||||
*/
|
||||
getFeedResult(uri) {
|
||||
if (uri == null)
|
||||
throw new Error("null URI!");
|
||||
let resultList = this._results[uri.spec];
|
||||
for (let result of resultList) {
|
||||
if (result.uri == uri)
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* See nsIFeedResultService.idl
|
||||
*/
|
||||
removeFeedResult(uri) {
|
||||
if (uri == null)
|
||||
throw new Error("null URI!");
|
||||
let resultList = this._results[uri.spec];
|
||||
if (!resultList)
|
||||
return;
|
||||
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
|
||||
resultList.splice(resultList.length - deletions, deletions);
|
||||
if (resultList.length == 0)
|
||||
delete this._results[uri.spec];
|
||||
},
|
||||
|
||||
createInstance(outer, iid) {
|
||||
if (outer != null)
|
||||
throw Cr.NS_ERROR_NO_AGGREGATION;
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIFeedResultService",
|
||||
"nsIFactory"]),
|
||||
};
|
||||
|
||||
|
||||
var components = [FeedConverter,
|
||||
FeedResultService];
|
||||
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
|
@ -1,528 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}");
|
||||
const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1";
|
||||
|
||||
function LOG(str) {
|
||||
let shouldLog = Services.prefs.getBoolPref("feeds.log", false);
|
||||
|
||||
if (shouldLog)
|
||||
dump("*** Feeds: " + str + "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function for nsIIOService::newURI.
|
||||
* @param aURLSpec
|
||||
* The URL string from which to create an nsIURI.
|
||||
* @returns an nsIURI object, or null if the creation of the URI failed.
|
||||
*/
|
||||
function makeURI(aURLSpec, aCharset) {
|
||||
try {
|
||||
return Services.io.newURI(aURLSpec, aCharset);
|
||||
} catch (ex) { }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const XML_NS = "http://www.w3.org/XML/1998/namespace";
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const URI_BUNDLE = "chrome://browser/locale/feeds/subscribe.properties";
|
||||
|
||||
const TITLE_ID = "feedTitleText";
|
||||
const SUBTITLE_ID = "feedSubtitleText";
|
||||
|
||||
/**
|
||||
* Converts a number of bytes to the appropriate unit that results in a
|
||||
* number that needs fewer than 4 digits
|
||||
*
|
||||
* @return a pair: [new value with 3 sig. figs., its unit]
|
||||
*/
|
||||
function convertByteUnits(aBytes) {
|
||||
let units = ["bytes", "kilobyte", "megabyte", "gigabyte"];
|
||||
let unitIndex = 0;
|
||||
|
||||
// convert to next unit if it needs 4 digits (after rounding), but only if
|
||||
// we know the name of the next unit
|
||||
while ((aBytes >= 999.5) && (unitIndex < units.length - 1)) {
|
||||
aBytes /= 1024;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
// Get rid of insignificant bits by truncating to 1 or 0 decimal points
|
||||
// 0 -> 0; 1.2 -> 1.2; 12.3 -> 12.3; 123.4 -> 123; 234.5 -> 235
|
||||
aBytes = aBytes.toFixed((aBytes > 0) && (aBytes < 100) ? 1 : 0);
|
||||
|
||||
return [aBytes, units[unitIndex]];
|
||||
}
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(this, "gCanFrameFeeds",
|
||||
"browser.feeds.unsafelyFrameFeeds", false);
|
||||
|
||||
function FeedWriter() {
|
||||
Services.telemetry.scalarAdd("browser.feeds.preview_loaded", 1);
|
||||
}
|
||||
|
||||
FeedWriter.prototype = {
|
||||
_getPropertyAsBag(container, property) {
|
||||
return container.fields.getProperty(property).
|
||||
QueryInterface(Ci.nsIPropertyBag2);
|
||||
},
|
||||
|
||||
_getPropertyAsString(container, property) {
|
||||
try {
|
||||
return container.fields.getPropertyAsAString(property);
|
||||
} catch (e) {
|
||||
}
|
||||
return "";
|
||||
},
|
||||
|
||||
_setContentText(id, text) {
|
||||
let element = this._document.getElementById(id);
|
||||
let textNode = text.createDocumentFragment(element);
|
||||
while (element.hasChildNodes())
|
||||
element.firstChild.remove();
|
||||
element.appendChild(textNode);
|
||||
if (text.base) {
|
||||
element.setAttributeNS(XML_NS, "base", text.base.spec);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Safely sets the href attribute on an anchor tag, providing the URI
|
||||
* specified can be loaded according to rules.
|
||||
* @param element
|
||||
* The element to set a URI attribute on
|
||||
* @param attribute
|
||||
* The attribute of the element to set the URI to, e.g. href or src
|
||||
* @param uri
|
||||
* The URI spec to set as the href
|
||||
*/
|
||||
_safeSetURIAttribute(element, attribute, uri) {
|
||||
const flags = Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL;
|
||||
try {
|
||||
// TODO Is this necessary?
|
||||
Services.scriptSecurityManager.checkLoadURIStrWithPrincipal(this._feedPrincipal, uri, flags);
|
||||
// checkLoadURIStrWithPrincipal will throw if the link URI should not be
|
||||
// loaded, either because our feedURI isn't allowed to load it or per
|
||||
// the rules specified in |flags|, so we'll never "linkify" the link...
|
||||
} catch (e) {
|
||||
// Not allowed to load this link because secman.checkLoadURIStr threw
|
||||
return;
|
||||
}
|
||||
|
||||
element.setAttribute(attribute, uri);
|
||||
},
|
||||
|
||||
__bundle: null,
|
||||
get _bundle() {
|
||||
if (!this.__bundle) {
|
||||
this.__bundle = Services.strings.createBundle(URI_BUNDLE);
|
||||
}
|
||||
return this.__bundle;
|
||||
},
|
||||
|
||||
_getFormattedString(key, params) {
|
||||
return this._bundle.formatStringFromName(key, params, params.length);
|
||||
},
|
||||
|
||||
_getString(key) {
|
||||
return this._bundle.GetStringFromName(key);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a date suitable for displaying in the feed preview.
|
||||
* If the date cannot be parsed, the return value is "false".
|
||||
* @param dateString
|
||||
* A date as extracted from a feed entry. (entry.updated)
|
||||
*/
|
||||
_parseDate(dateString) {
|
||||
// Convert the date into the user's local time zone
|
||||
let dateObj = new Date(dateString);
|
||||
|
||||
// Make sure the date we're given is valid.
|
||||
if (!dateObj.getTime())
|
||||
return false;
|
||||
|
||||
return this._dateFormatter.format(dateObj);
|
||||
},
|
||||
|
||||
__dateFormatter: null,
|
||||
get _dateFormatter() {
|
||||
if (!this.__dateFormatter) {
|
||||
const dtOptions = {
|
||||
timeStyle: "short",
|
||||
dateStyle: "long",
|
||||
};
|
||||
this.__dateFormatter = new Services.intl.DateTimeFormat(undefined, dtOptions);
|
||||
}
|
||||
return this.__dateFormatter;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the feed title into the preview document.
|
||||
* @param container
|
||||
* The feed container
|
||||
*/
|
||||
_setTitleText(container) {
|
||||
if (container.title) {
|
||||
let title = container.title.plainText();
|
||||
this._setContentText(TITLE_ID, container.title);
|
||||
this._document.title = title;
|
||||
}
|
||||
|
||||
let feed = container.QueryInterface(Ci.nsIFeed);
|
||||
if (feed && feed.subtitle)
|
||||
this._setContentText(SUBTITLE_ID, container.subtitle);
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the title image into the preview document if one is present.
|
||||
* @param container
|
||||
* The feed container
|
||||
*/
|
||||
_setTitleImage(container) {
|
||||
try {
|
||||
let parts = container.image;
|
||||
|
||||
// Set up the title image (supplied by the feed)
|
||||
let feedTitleImage = this._document.getElementById("feedTitleImage");
|
||||
this._safeSetURIAttribute(feedTitleImage, "src",
|
||||
parts.getPropertyAsAString("url"));
|
||||
|
||||
// Set up the title image link
|
||||
let feedTitleLink = this._document.getElementById("feedTitleLink");
|
||||
|
||||
let titleText = this._getFormattedString("linkTitleTextFormat",
|
||||
[parts.getPropertyAsAString("title")]);
|
||||
let feedTitleText = this._document.getElementById("feedTitleText");
|
||||
let titleImageWidth = parseInt(parts.getPropertyAsAString("width")) + 15;
|
||||
|
||||
// Fix the margin on the main title, so that the image doesn't run over
|
||||
// the underline
|
||||
feedTitleLink.setAttribute("title", titleText);
|
||||
feedTitleText.style.marginRight = titleImageWidth + "px";
|
||||
|
||||
this._safeSetURIAttribute(feedTitleLink, "href",
|
||||
parts.getPropertyAsAString("link"));
|
||||
} catch (e) {
|
||||
LOG("Failed to set Title Image (this is benign): " + e);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes all entries contained in the feed.
|
||||
* @param container
|
||||
* The container of entries in the feed
|
||||
*/
|
||||
_writeFeedContent(container) {
|
||||
// Build the actual feed content
|
||||
let feed = container.QueryInterface(Ci.nsIFeed);
|
||||
if (feed.items.length == 0)
|
||||
return;
|
||||
|
||||
let feedContent = this._document.getElementById("feedContent");
|
||||
|
||||
for (let i = 0; i < feed.items.length; ++i) {
|
||||
let entry = feed.items.queryElementAt(i, Ci.nsIFeedEntry);
|
||||
entry.QueryInterface(Ci.nsIFeedContainer);
|
||||
|
||||
let entryContainer = this._document.createElementNS(HTML_NS, "div");
|
||||
entryContainer.className = "entry";
|
||||
|
||||
// If the entry has a title, make it a link
|
||||
if (entry.title) {
|
||||
let a = this._document.createElementNS(HTML_NS, "a");
|
||||
let span = this._document.createElementNS(HTML_NS, "span");
|
||||
a.appendChild(span);
|
||||
if (entry.title.base)
|
||||
span.setAttributeNS(XML_NS, "base", entry.title.base.spec);
|
||||
span.appendChild(entry.title.createDocumentFragment(a));
|
||||
|
||||
// Entries are not required to have links, so entry.link can be null.
|
||||
if (entry.link)
|
||||
this._safeSetURIAttribute(a, "href", entry.link.spec);
|
||||
|
||||
let title = this._document.createElementNS(HTML_NS, "h3");
|
||||
title.appendChild(a);
|
||||
|
||||
let lastUpdated = this._parseDate(entry.updated);
|
||||
if (lastUpdated) {
|
||||
let dateDiv = this._document.createElementNS(HTML_NS, "div");
|
||||
dateDiv.className = "lastUpdated";
|
||||
dateDiv.textContent = lastUpdated;
|
||||
title.appendChild(dateDiv);
|
||||
}
|
||||
|
||||
entryContainer.appendChild(title);
|
||||
}
|
||||
|
||||
let body = this._document.createElementNS(HTML_NS, "div");
|
||||
let summary = entry.summary || entry.content;
|
||||
let docFragment = null;
|
||||
if (summary) {
|
||||
if (summary.base)
|
||||
body.setAttributeNS(XML_NS, "base", summary.base.spec);
|
||||
else
|
||||
LOG("no base?");
|
||||
docFragment = summary.createDocumentFragment(body);
|
||||
if (docFragment)
|
||||
body.appendChild(docFragment);
|
||||
|
||||
// If the entry doesn't have a title, append a # permalink
|
||||
// See http://scripting.com/rss.xml for an example
|
||||
if (!entry.title && entry.link) {
|
||||
let a = this._document.createElementNS(HTML_NS, "a");
|
||||
a.appendChild(this._document.createTextNode("#"));
|
||||
this._safeSetURIAttribute(a, "href", entry.link.spec);
|
||||
body.appendChild(this._document.createTextNode(" "));
|
||||
body.appendChild(a);
|
||||
}
|
||||
|
||||
}
|
||||
body.className = "feedEntryContent";
|
||||
entryContainer.appendChild(body);
|
||||
|
||||
if (entry.enclosures && entry.enclosures.length > 0) {
|
||||
let enclosuresDiv = this._buildEnclosureDiv(entry);
|
||||
entryContainer.appendChild(enclosuresDiv);
|
||||
}
|
||||
|
||||
let clearDiv = this._document.createElementNS(HTML_NS, "div");
|
||||
clearDiv.style.clear = "both";
|
||||
|
||||
feedContent.appendChild(entryContainer);
|
||||
feedContent.appendChild(clearDiv);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes a url to a media item and returns the best name it can come up with.
|
||||
* Frequently this is the filename portion (e.g. passing in
|
||||
* http://example.com/foo.mpeg would return "foo.mpeg"), but in more complex
|
||||
* cases, this will return the entire url (e.g. passing in
|
||||
* http://example.com/somedirectory/ would return
|
||||
* http://example.com/somedirectory/).
|
||||
* @param aURL
|
||||
* The URL string from which to create a display name
|
||||
* @returns a string
|
||||
*/
|
||||
_getURLDisplayName(aURL) {
|
||||
let url = makeURI(aURL);
|
||||
url.QueryInterface(Ci.nsIURL);
|
||||
if (url == null || url.fileName.length == 0)
|
||||
return decodeURIComponent(aURL);
|
||||
|
||||
return decodeURIComponent(url.fileName);
|
||||
},
|
||||
|
||||
/**
|
||||
* Takes a FeedEntry with enclosures, generates the HTML code to represent
|
||||
* them, and returns that.
|
||||
* @param entry
|
||||
* FeedEntry with enclosures
|
||||
* @returns element
|
||||
*/
|
||||
_buildEnclosureDiv(entry) {
|
||||
let enclosuresDiv = this._document.createElementNS(HTML_NS, "div");
|
||||
enclosuresDiv.className = "enclosures";
|
||||
|
||||
enclosuresDiv.appendChild(this._document.createTextNode(this._getString("mediaLabel")));
|
||||
|
||||
for (let i_enc = 0; i_enc < entry.enclosures.length; ++i_enc) {
|
||||
let enc = entry.enclosures.queryElementAt(i_enc, Ci.nsIWritablePropertyBag2);
|
||||
|
||||
if (!(enc.hasKey("url")))
|
||||
continue;
|
||||
|
||||
let enclosureDiv = this._document.createElementNS(HTML_NS, "div");
|
||||
enclosureDiv.setAttribute("class", "enclosure");
|
||||
|
||||
let mozicon = "moz-icon://.txt?size=16";
|
||||
let type_text = null;
|
||||
let size_text = null;
|
||||
|
||||
if (enc.hasKey("type")) {
|
||||
type_text = enc.get("type");
|
||||
if (enc.hasKey("typeDesc"))
|
||||
type_text = enc.get("typeDesc");
|
||||
|
||||
if (type_text && type_text.length > 0)
|
||||
mozicon = "moz-icon://goat?size=16&contentType=" + enc.get("type");
|
||||
}
|
||||
|
||||
if (enc.hasKey("length") && /^[0-9]+$/.test(enc.get("length"))) {
|
||||
let enc_size = convertByteUnits(parseInt(enc.get("length")));
|
||||
|
||||
size_text = this._getFormattedString("enclosureSizeText",
|
||||
[enc_size[0],
|
||||
this._getString(enc_size[1])]);
|
||||
}
|
||||
|
||||
let iconimg = this._document.createElementNS(HTML_NS, "img");
|
||||
iconimg.setAttribute("src", mozicon);
|
||||
iconimg.setAttribute("class", "type-icon");
|
||||
enclosureDiv.appendChild(iconimg);
|
||||
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " " ));
|
||||
|
||||
let enc_href = this._document.createElementNS(HTML_NS, "a");
|
||||
enc_href.appendChild(this._document.createTextNode(this._getURLDisplayName(enc.get("url"))));
|
||||
this._safeSetURIAttribute(enc_href, "href", enc.get("url"));
|
||||
enclosureDiv.appendChild(enc_href);
|
||||
|
||||
if (type_text && size_text)
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ", " + size_text + ")"));
|
||||
|
||||
else if (type_text)
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " (" + type_text + ")"));
|
||||
|
||||
else if (size_text)
|
||||
enclosureDiv.appendChild(this._document.createTextNode( " (" + size_text + ")"));
|
||||
|
||||
enclosuresDiv.appendChild(enclosureDiv);
|
||||
}
|
||||
|
||||
return enclosuresDiv;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a valid nsIFeedContainer object from the parsed nsIFeedResult.
|
||||
* Displays error information if there was one.
|
||||
* @returns A valid nsIFeedContainer object containing the contents of
|
||||
* the feed.
|
||||
*/
|
||||
_getContainer() {
|
||||
let feedService =
|
||||
Cc["@mozilla.org/browser/feeds/result-service;1"].
|
||||
getService(Ci.nsIFeedResultService);
|
||||
|
||||
let result;
|
||||
try {
|
||||
result =
|
||||
feedService.getFeedResult(this._getOriginalURI(this._window));
|
||||
} catch (e) {
|
||||
LOG("Subscribe Preview: feed not available?!");
|
||||
}
|
||||
|
||||
if (result.bozo) {
|
||||
LOG("Subscribe Preview: feed result is bozo?!");
|
||||
}
|
||||
|
||||
let container;
|
||||
try {
|
||||
container = result.doc;
|
||||
} catch (e) {
|
||||
LOG("Subscribe Preview: no result.doc? Why didn't the original reload?");
|
||||
return null;
|
||||
}
|
||||
return container;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the original URI object of the feed and ensures that this
|
||||
* component is only ever invoked from the preview document.
|
||||
* @param aWindow
|
||||
* The window of the document invoking the BrowserFeedWriter
|
||||
*/
|
||||
_getOriginalURI(aWindow) {
|
||||
let docShell = aWindow.docShell;
|
||||
let chan = docShell.currentDocumentChannel;
|
||||
|
||||
// We probably need to call Inherit() for this, but right now we can't call
|
||||
// it from JS.
|
||||
let attrs = docShell.getOriginAttributes();
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
let nullPrincipal = ssm.createNullPrincipal(attrs);
|
||||
|
||||
// this channel is not going to be openend, use a nullPrincipal
|
||||
// and the most restrctive securityFlag.
|
||||
let resolvedURI = NetUtil.newChannel({
|
||||
uri: "about:feeds",
|
||||
loadingPrincipal: nullPrincipal,
|
||||
securityFlags: Ci.nsILoadInfo.SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_OTHER,
|
||||
}).URI;
|
||||
|
||||
if (resolvedURI.equals(chan.URI))
|
||||
return chan.originalURI;
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_window: null,
|
||||
_document: null,
|
||||
_feedURI: null,
|
||||
_feedPrincipal: null,
|
||||
|
||||
// BrowserFeedWriter WebIDL methods
|
||||
init(aWindow) {
|
||||
let window = aWindow;
|
||||
if (window != window.top && !gCanFrameFeeds) {
|
||||
return;
|
||||
}
|
||||
this._feedURI = this._getOriginalURI(window);
|
||||
if (!this._feedURI)
|
||||
return;
|
||||
|
||||
this._window = window;
|
||||
this._document = window.document;
|
||||
|
||||
this._feedPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(this._feedURI, {});
|
||||
|
||||
LOG("Subscribe Preview: feed uri = " + this._window.location.href);
|
||||
},
|
||||
|
||||
writeContent() {
|
||||
if (!this._window)
|
||||
return;
|
||||
|
||||
try {
|
||||
// Set up the feed content
|
||||
let container = this._getContainer();
|
||||
if (!container)
|
||||
return;
|
||||
|
||||
this._setTitleText(container);
|
||||
this._setTitleImage(container);
|
||||
this._writeFeedContent(container);
|
||||
} finally {
|
||||
this._removeFeedFromCache();
|
||||
}
|
||||
},
|
||||
|
||||
close() {
|
||||
if (!this._window) {
|
||||
return;
|
||||
}
|
||||
this._document = null;
|
||||
this._window = null;
|
||||
|
||||
this._removeFeedFromCache();
|
||||
this.__bundle = null;
|
||||
this._feedURI = null;
|
||||
},
|
||||
|
||||
_removeFeedFromCache() {
|
||||
if (this._window && this._feedURI) {
|
||||
let feedService = Cc["@mozilla.org/browser/feeds/result-service;1"].
|
||||
getService(Ci.nsIFeedResultService);
|
||||
feedService.removeFeedResult(this._feedURI);
|
||||
this._feedURI = null;
|
||||
}
|
||||
},
|
||||
|
||||
classID: FEEDWRITER_CID,
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FeedWriter]);
|
|
@ -1,33 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
var SubscribeHandler = {
|
||||
/**
|
||||
* The nsIFeedWriter object that produces the UI
|
||||
*/
|
||||
_feedWriter: null,
|
||||
|
||||
init: function SH_init() {
|
||||
this._feedWriter = new BrowserFeedWriter();
|
||||
},
|
||||
|
||||
writeContent: function SH_writeContent() {
|
||||
this._feedWriter.writeContent();
|
||||
},
|
||||
|
||||
uninit: function SH_uninit() {
|
||||
this._feedWriter.close();
|
||||
},
|
||||
};
|
||||
|
||||
SubscribeHandler.init();
|
||||
|
||||
window.onload = function() {
|
||||
SubscribeHandler.writeContent();
|
||||
};
|
||||
|
||||
window.onunload = function() {
|
||||
SubscribeHandler.uninit();
|
||||
};
|
|
@ -1,56 +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 html [
|
||||
<!ENTITY % htmlDTD
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"DTD/xhtml1-strict.dtd">
|
||||
%htmlDTD;
|
||||
<!ENTITY % globalDTD
|
||||
SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
<!ENTITY % feedDTD
|
||||
SYSTEM "chrome://browser/locale/feeds/subscribe.dtd">
|
||||
%feedDTD;
|
||||
]>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<html id="feedHandler"
|
||||
xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src chrome:; img-src *; media-src *" />
|
||||
<title>&feedPage.title;</title>
|
||||
<link rel="stylesheet"
|
||||
href="chrome://browser/skin/feeds/subscribe.css"
|
||||
type="text/css"
|
||||
media="all"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="feedHeaderContainer">
|
||||
<div id="feedHeader" dir="&locale.dir;">
|
||||
<div id="feedIntroText">
|
||||
<p id="feedSubscriptionInfo1" />
|
||||
<p id="feedSubscriptionInfo2" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="feedHeaderContainerSpacer"/>
|
||||
</div>
|
||||
<div id="feedBody">
|
||||
<div id="feedTitle">
|
||||
<a id="feedTitleLink">
|
||||
<img id="feedTitleImage"/>
|
||||
</a>
|
||||
<div id="feedTitleContainer">
|
||||
<h1 id="feedTitleText"/>
|
||||
<h2 id="feedSubtitleText"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="feedContent"/>
|
||||
</div>
|
||||
</body>
|
||||
<script type="application/javascript" src="chrome://browser/content/feeds/subscribe.js"/>
|
||||
</html>
|
|
@ -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/.
|
||||
|
||||
browser.jar:
|
||||
content/browser/feeds/subscribe.xhtml (content/subscribe.xhtml)
|
||||
content/browser/feeds/subscribe.js (content/subscribe.js)
|
|
@ -4,37 +4,13 @@
|
|||
# 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/.
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['test/chrome/chrome.ini']
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
|
||||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIFeedResultService.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'browser-feeds'
|
||||
|
||||
SOURCES += [
|
||||
'nsFeedSniffer.cpp',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'BrowserFeeds.manifest',
|
||||
'FeedConverter.js',
|
||||
'FeedWriter.js',
|
||||
'WebContentConverter.js',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'browsercomps'
|
||||
|
||||
for var in ('MOZ_APP_NAME', 'MOZ_MACBUNDLE_NAME'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'../build',
|
||||
]
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'RSS Discovery and Preview')
|
||||
|
|
|
@ -1,391 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsFeedSniffer.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "nsNetCID.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStringStream.h"
|
||||
|
||||
#include "nsBrowserCompsCID.h"
|
||||
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "nsIStreamConverterService.h"
|
||||
#include "nsIStreamConverter.h"
|
||||
|
||||
#include "nsIStreamListener.h"
|
||||
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIMIMEHeaderParam.h"
|
||||
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsIURI.h"
|
||||
#include <algorithm>
|
||||
|
||||
#define TYPE_ATOM "application/atom+xml"
|
||||
#define TYPE_RSS "application/rss+xml"
|
||||
#define TYPE_MAYBE_FEED "application/vnd.mozilla.maybe.feed"
|
||||
|
||||
#define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
#define NS_RSS "http://purl.org/rss/1.0/"
|
||||
|
||||
#define MAX_BYTES 512u
|
||||
|
||||
static bool sFramePrefCached = false;
|
||||
static bool sFramingAllowed = false;
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsFeedSniffer,
|
||||
nsIContentSniffer,
|
||||
nsIStreamListener,
|
||||
nsIRequestObserver)
|
||||
|
||||
nsresult
|
||||
nsFeedSniffer::ConvertEncodedData(nsIRequest* request,
|
||||
const uint8_t* data,
|
||||
uint32_t length)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
mDecodedData = "";
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(request));
|
||||
if (!httpChannel)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
|
||||
nsAutoCString contentEncoding;
|
||||
mozilla::Unused << httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("Content-Encoding"),
|
||||
contentEncoding);
|
||||
if (!contentEncoding.IsEmpty()) {
|
||||
nsCOMPtr<nsIStreamConverterService> converterService(do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID));
|
||||
if (converterService) {
|
||||
ToLowerCase(contentEncoding);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> converter;
|
||||
rv = converterService->AsyncConvertData(contentEncoding.get(),
|
||||
"uncompressed", this, nullptr,
|
||||
getter_AddRefs(converter));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
converter->OnStartRequest(request, nullptr);
|
||||
|
||||
nsCOMPtr<nsIStringInputStream> rawStream =
|
||||
do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID);
|
||||
if (!rawStream)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = rawStream->SetData((const char*)data, length);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = converter->OnDataAvailable(request, nullptr, rawStream, 0, length);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
converter->OnStopRequest(request, nullptr, NS_OK);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
template<int N>
|
||||
static bool
|
||||
StringBeginsWithLowercaseLiteral(nsAString& aString,
|
||||
const char (&aSubstring)[N])
|
||||
{
|
||||
return StringHead(aString, N).LowerCaseEqualsLiteral(aSubstring);
|
||||
}
|
||||
|
||||
bool
|
||||
HasAttachmentDisposition(nsIHttpChannel* httpChannel)
|
||||
{
|
||||
if (!httpChannel)
|
||||
return false;
|
||||
|
||||
uint32_t disp;
|
||||
nsresult rv = httpChannel->GetContentDisposition(&disp);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && disp == nsIChannel::DISPOSITION_ATTACHMENT)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the first occurrence of a character within a string buffer,
|
||||
* or nullptr if not found
|
||||
*/
|
||||
static const char*
|
||||
FindChar(char c, const char *begin, const char *end)
|
||||
{
|
||||
for (; begin < end; ++begin) {
|
||||
if (*begin == c)
|
||||
return begin;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Determine if a substring is the "documentElement" in the document.
|
||||
*
|
||||
* All of our sniffed substrings: <rss, <feed, <rdf:RDF must be the "document"
|
||||
* element within the XML DOM, i.e. the root container element. Otherwise,
|
||||
* it's possible that someone embedded one of these tags inside a document of
|
||||
* another type, e.g. a HTML document, and we don't want to show the preview
|
||||
* page if the document isn't actually a feed.
|
||||
*
|
||||
* @param start
|
||||
* The beginning of the data being sniffed
|
||||
* @param end
|
||||
* The end of the data being sniffed, right before the substring that
|
||||
* was found.
|
||||
* @returns true if the found substring is the documentElement, false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool
|
||||
IsDocumentElement(const char *start, const char* end)
|
||||
{
|
||||
// For every tag in the buffer, check to see if it's a PI, Doctype or
|
||||
// comment, our desired substring or something invalid.
|
||||
while ( (start = FindChar('<', start, end)) ) {
|
||||
++start;
|
||||
if (start >= end)
|
||||
return false;
|
||||
|
||||
// Check to see if the character following the '<' is either '?' or '!'
|
||||
// (processing instruction or doctype or comment)... these are valid nodes
|
||||
// to have in the prologue.
|
||||
if (*start != '?' && *start != '!')
|
||||
return false;
|
||||
|
||||
// Now advance the iterator until the '>' (We do this because we don't want
|
||||
// to sniff indicator substrings that are embedded within other nodes, e.g.
|
||||
// comments: <!-- <rdf:RDF .. > -->
|
||||
start = FindChar('>', start, end);
|
||||
if (!start)
|
||||
return false;
|
||||
|
||||
++start;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether or not a string exists as the root element in an XML data
|
||||
* string buffer.
|
||||
* @param dataString
|
||||
* The data being sniffed
|
||||
* @param substring
|
||||
* The substring being tested for existence and root-ness.
|
||||
* @returns true if the substring exists and is the documentElement, false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool
|
||||
ContainsTopLevelSubstring(nsACString& dataString, const char *substring)
|
||||
{
|
||||
nsACString::const_iterator start, end;
|
||||
dataString.BeginReading(start);
|
||||
dataString.EndReading(end);
|
||||
|
||||
if (!FindInReadable(nsCString(substring), start, end)){
|
||||
return false;
|
||||
}
|
||||
|
||||
auto offset = start.get() - dataString.Data();
|
||||
|
||||
const char *begin = dataString.BeginReading();
|
||||
|
||||
// Only do the validation when we find the substring.
|
||||
return IsDocumentElement(begin, begin + offset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFeedSniffer::GetMIMETypeFromContent(nsIRequest* request,
|
||||
const uint8_t* data,
|
||||
uint32_t length,
|
||||
nsACString& sniffedType)
|
||||
{
|
||||
nsCOMPtr<nsIHttpChannel> channel(do_QueryInterface(request));
|
||||
if (!channel)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
|
||||
// Check that this is a GET request, since you can't subscribe to a POST...
|
||||
nsAutoCString method;
|
||||
mozilla::Unused << channel->GetRequestMethod(method);
|
||||
if (!method.EqualsLiteral("GET")) {
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!sFramePrefCached) {
|
||||
sFramePrefCached = true;
|
||||
Preferences::AddBoolVarCache(&sFramingAllowed,
|
||||
"browser.feeds.unsafelyFrameFeeds");
|
||||
}
|
||||
|
||||
if (!sFramingAllowed) {
|
||||
// Check that we're the toplevel frame:
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
|
||||
if (!loadInfo) {
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
auto frameID = loadInfo->GetFrameOuterWindowID();
|
||||
if (!frameID) {
|
||||
frameID = loadInfo->GetOuterWindowID();
|
||||
}
|
||||
if (loadInfo->GetTopOuterWindowID() != frameID) {
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// We need to find out if this is a load of a view-source document. In this
|
||||
// case we do not want to override the content type, since the source display
|
||||
// does not need to be converted from feed format to XUL. More importantly,
|
||||
// we don't want to change the content type from something
|
||||
// nsContentDLF::CreateInstance knows about (e.g. application/xml, text/html
|
||||
// etc) to something that only the application fe knows about (maybe.feed)
|
||||
// thus deactivating syntax highlighting.
|
||||
nsCOMPtr<nsIURI> originalURI;
|
||||
channel->GetOriginalURI(getter_AddRefs(originalURI));
|
||||
|
||||
nsAutoCString scheme;
|
||||
originalURI->GetScheme(scheme);
|
||||
if (scheme.EqualsLiteral("view-source")) {
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check the Content-Type to see if it is set correctly. If it is set to
|
||||
// something specific that we think is a reliable indication of a feed, don't
|
||||
// bother sniffing since we assume the site maintainer knows what they're
|
||||
// doing.
|
||||
nsAutoCString contentType;
|
||||
channel->GetContentType(contentType);
|
||||
bool noSniff = contentType.EqualsLiteral(TYPE_RSS) ||
|
||||
contentType.EqualsLiteral(TYPE_ATOM);
|
||||
|
||||
if (noSniff) {
|
||||
// check for an attachment after we have a likely feed.
|
||||
if(HasAttachmentDisposition(channel)) {
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// set the feed header as a response header, since we have good metadata
|
||||
// telling us that the feed is supposed to be RSS or Atom
|
||||
mozilla::DebugOnly<nsresult> rv =
|
||||
channel->SetResponseHeader(NS_LITERAL_CSTRING("X-Moz-Is-Feed"),
|
||||
NS_LITERAL_CSTRING("1"), false);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
sniffedType.AssignLiteral(TYPE_MAYBE_FEED);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Don't sniff arbitrary types. Limit sniffing to situations that
|
||||
// we think can reasonably arise.
|
||||
if (!contentType.EqualsLiteral(TEXT_HTML) &&
|
||||
!contentType.EqualsLiteral(APPLICATION_OCTET_STREAM) &&
|
||||
// Same criterion as XMLHttpRequest. Should we be checking for "+xml"
|
||||
// and check for text/xml and application/xml by hand instead?
|
||||
contentType.Find("xml") == -1) {
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Now we need to potentially decompress data served with
|
||||
// Content-Encoding: gzip
|
||||
nsresult rv = ConvertEncodedData(request, data, length);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
// We cap the number of bytes to scan at MAX_BYTES to prevent picking up
|
||||
// false positives by accidentally reading document content, e.g. a "how to
|
||||
// make a feed" page.
|
||||
const char* testData;
|
||||
if (mDecodedData.IsEmpty()) {
|
||||
testData = (const char*)data;
|
||||
length = std::min(length, MAX_BYTES);
|
||||
} else {
|
||||
testData = mDecodedData.get();
|
||||
length = std::min(mDecodedData.Length(), MAX_BYTES);
|
||||
}
|
||||
|
||||
// The strategy here is based on that described in:
|
||||
// http://blogs.msdn.com/rssteam/articles/PublishersGuide.aspx
|
||||
// for interoperarbility purposes.
|
||||
|
||||
// Thus begins the actual sniffing.
|
||||
nsDependentCSubstring dataString((const char*)testData, length);
|
||||
|
||||
bool isFeed = false;
|
||||
|
||||
// RSS 0.91/0.92/2.0
|
||||
isFeed = ContainsTopLevelSubstring(dataString, "<rss");
|
||||
|
||||
// Atom 1.0
|
||||
if (!isFeed)
|
||||
isFeed = ContainsTopLevelSubstring(dataString, "<feed");
|
||||
|
||||
// RSS 1.0
|
||||
if (!isFeed) {
|
||||
bool foundNS_RDF = FindInReadable(NS_LITERAL_CSTRING(NS_RDF), dataString);
|
||||
bool foundNS_RSS = FindInReadable(NS_LITERAL_CSTRING(NS_RSS), dataString);
|
||||
isFeed = ContainsTopLevelSubstring(dataString, "<rdf:RDF") &&
|
||||
foundNS_RDF && foundNS_RSS;
|
||||
}
|
||||
|
||||
// If we sniffed a feed, coerce our internal type
|
||||
if (isFeed && !HasAttachmentDisposition(channel))
|
||||
sniffedType.AssignLiteral(TYPE_MAYBE_FEED);
|
||||
else
|
||||
sniffedType.Truncate();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFeedSniffer::OnStartRequest(nsIRequest* request, nsISupports* context)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFeedSniffer::AppendSegmentToString(nsIInputStream* inputStream,
|
||||
void* closure,
|
||||
const char* rawSegment,
|
||||
uint32_t toOffset,
|
||||
uint32_t count,
|
||||
uint32_t* writeCount)
|
||||
{
|
||||
nsCString* decodedData = static_cast<nsCString*>(closure);
|
||||
decodedData->Append(rawSegment, count);
|
||||
*writeCount = count;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFeedSniffer::OnDataAvailable(nsIRequest* request, nsISupports* context,
|
||||
nsIInputStream* stream, uint64_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
uint32_t read;
|
||||
return stream->ReadSegments(AppendSegmentToString, &mDecodedData, count,
|
||||
&read);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFeedSniffer::OnStopRequest(nsIRequest* request, nsISupports* context,
|
||||
nsresult status)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
|
||||
#include "nsIContentSniffer.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsFeedSniffer final : public nsIContentSniffer,
|
||||
nsIStreamListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTSNIFFER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
static nsresult AppendSegmentToString(nsIInputStream* inputStream,
|
||||
void* closure,
|
||||
const char* rawSegment,
|
||||
uint32_t toOffset,
|
||||
uint32_t count,
|
||||
uint32_t* writeCount);
|
||||
|
||||
protected:
|
||||
~nsFeedSniffer() {}
|
||||
|
||||
nsresult ConvertEncodedData(nsIRequest* request, const uint8_t* data,
|
||||
uint32_t length);
|
||||
|
||||
private:
|
||||
nsCString mDecodedData;
|
||||
};
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
interface nsIURI;
|
||||
interface nsIRequest;
|
||||
interface nsIFeedResult;
|
||||
|
||||
/**
|
||||
* nsIFeedResultService provides a globally-accessible object for retrieving
|
||||
* the results of feed processing.
|
||||
*/
|
||||
[scriptable, uuid(95309fd2-7b3a-47fb-97f3-5c460d9473cd)]
|
||||
interface nsIFeedResultService : nsISupports
|
||||
{
|
||||
/**
|
||||
* When set to true, forces the preview page to be displayed, regardless
|
||||
* of the user's preferences.
|
||||
*/
|
||||
attribute boolean forcePreviewPage;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* The title of the feed to add.
|
||||
* @param subtitle
|
||||
* 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,
|
||||
in AString title,
|
||||
in AString subtitle,
|
||||
in unsigned long feedType,
|
||||
[optional] in AString feedReader);
|
||||
|
||||
/**
|
||||
* Registers a Feed Result object with a globally accessible service
|
||||
* so that it can be accessed by a singleton method outside the usual
|
||||
* flow of control in document loading.
|
||||
*
|
||||
* @param feedResult
|
||||
* An object implementing nsIFeedResult representing the feed.
|
||||
*/
|
||||
void addFeedResult(in nsIFeedResult feedResult);
|
||||
|
||||
/**
|
||||
* Gets a Feed Handler object registered using addFeedResult.
|
||||
*
|
||||
* @param uri
|
||||
* The URI of the feed a handler is being requested for
|
||||
*/
|
||||
nsIFeedResult getFeedResult(in nsIURI uri);
|
||||
|
||||
/**
|
||||
* Unregisters a Feed Handler object registered using addFeedResult.
|
||||
* @param uri
|
||||
* The feed URI the handler was registered under. This must be
|
||||
* the same *instance* the feed was registered under.
|
||||
*/
|
||||
void removeFeedResult(in nsIURI uri);
|
||||
};
|
|
@ -1,5 +0,0 @@
|
|||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>t</title>
|
||||
</channel>
|
||||
</rss>
|
|
@ -1 +0,0 @@
|
|||
Content-Type: text/xml
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<rdf:RDF
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns="http://my.netscape.com/rdf/simple/0.9/">
|
||||
<channel>
|
||||
<title>Tinderbox - Firefox</title>
|
||||
<description>Build bustages for Firefox</description>
|
||||
<link>http://tinderbox.mozilla.org/showbuilds.cgi?tree=Firefox</link>
|
||||
</channel>
|
||||
<image>
|
||||
<title>Bad</title>
|
||||
<url>http://tinderbox.mozilla.org/channelflames.gif</url>
|
||||
<link>http://tinderbox.mozilla.org/showbuilds.cgi?tree=Firefox</link>
|
||||
</image>
|
||||
<item><title>The tree is currently closed</title><link>http://tinderbox.mozilla.org/showbuilds.cgi?tree=Firefox</link></item>
|
||||
|
||||
<item><title>MacOSX Darwin 8.8.4 qm-xserve01 dep unit test is in flames</title><link>http://tinderbox.mozilla.org/showbuilds.cgi?tree=Firefox</link></item>
|
||||
</rdf:RDF>
|
|
@ -1,63 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
|
||||
<title>Example Feed</title>
|
||||
<link href="http://example.org/"/>
|
||||
<updated>2003-12-13T18:30:02Z</updated>
|
||||
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>Good item</title>
|
||||
<link href="http://example.org/first"/>
|
||||
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
|
||||
<updated>2003-12-13T18:30:02Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>data: link</title>
|
||||
<link href="data:text/plain,Hi"/>
|
||||
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6b</id>
|
||||
<updated>2003-12-13T18:30:03Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>javascript: link</title>
|
||||
<link href="javascript:alert('Hi')"/>
|
||||
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6c</id>
|
||||
<updated>2003-12-13T18:30:04Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>file: link</title>
|
||||
<link href="file:///var/"/>
|
||||
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6d</id>
|
||||
<updated>2003-12-13T18:30:05Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>chrome: link</title>
|
||||
<link href="chrome://browser/content/browser.js"/>
|
||||
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6e</id>
|
||||
<updated>2003-12-13T18:30:06Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
</feed>
|
|
@ -1,44 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="http://www.example.com/">
|
||||
|
||||
<title type="xhtml" xml:base="/foo/bar/">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">Example of a <em>special</em> feed (<img height="20px" src="baz.png" alt="base test sprite"/>)</div>
|
||||
</title>
|
||||
|
||||
<subtitle type="html" xml:base="/foo/bar/">
|
||||
<![CDATA[
|
||||
With a <em>special</em> subtitle (<img height="20px" src="baz.png" alt="base test sprite"/>)
|
||||
]]>
|
||||
</subtitle>
|
||||
|
||||
<link href="http://example.org/"/>
|
||||
|
||||
<updated>2010-09-02T18:30:02Z</updated>
|
||||
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
|
||||
<id>urn:uuid:22906062-ecbd-46e2-b6a7-3039506a398f</id>
|
||||
|
||||
<entry>
|
||||
<title type="xhtml" xml:base="/foo/bar/">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">Some <abbr title="Extensible Hyper-text Mark-up Language">XHTML</abbr> examples (<img height="20px" src="baz.png" alt="base test sprite"/>)</div>
|
||||
</title>
|
||||
<id>urn:uuid:b48083a7-71a7-4c9c-8515-b7c0d22955e7</id>
|
||||
<updated>2010-09-02T18:30:02Z</updated>
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
<entry>
|
||||
<title type="html" xml:base="/foo/bar/">
|
||||
<![CDATA[
|
||||
Some <abbr title="Hyper-text Mark-up Language">HTML</abbr> examples (<img height="20px" src="baz.png" alt="base test sprite"/>)
|
||||
]]>
|
||||
</title>
|
||||
<id>urn:uuid:1424967a-280a-414d-b0ab-8b11c4ac1bb7</id>
|
||||
<updated>2010-09-02T18:30:02Z</updated>
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
</feed>
|
|
@ -1,24 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title>Channel title</title>
|
||||
<description>Channel description</description>
|
||||
<link>Channel link</link>
|
||||
<item>
|
||||
<title>Episode 1</title>
|
||||
<enclosure url="http://www.example.com/podcasts/Episode%201" length="0" type="audio/x-m4a" />
|
||||
</item>
|
||||
<item>
|
||||
<title>Episode 2</title>
|
||||
<enclosure url="http://www.example.com/podcasts/Episode%20%232" length="0" type="audio/x-m4a" />
|
||||
</item>
|
||||
<item>
|
||||
<title>Episode 3</title>
|
||||
<enclosure url="http://www.example.com/podcasts/Episode%20%233/" length="0" type="audio/x-m4a" />
|
||||
</item>
|
||||
<item>
|
||||
<title>Episode 4</title>
|
||||
<enclosure url="http://www.example.com/podcasts/Is%20This%20Episode%20%234%3F" length="0" type="audio/x-m4a" />
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/chrome-test"
|
||||
]
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
[DEFAULT]
|
||||
prefs =
|
||||
browser.feeds.unsafelyFrameFeeds=true
|
||||
|
||||
support-files = sample_feed.atom
|
||||
!/browser/components/feeds/test/bug408328-data.xml
|
||||
!/browser/components/feeds/test/valid-feed.xml
|
||||
!/browser/components/feeds/test/valid-unsniffable-feed.xml
|
||||
|
||||
[test_bug368464.html]
|
||||
[test_bug408328.html]
|
||||
[test_maxSniffing.html]
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
|
||||
<title>Example Feed</title>
|
||||
<link href="http://example.org/"/>
|
||||
<updated>2003-12-13T18:30:02Z</updated>
|
||||
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>Atom-Powered Robots Run Amok</title>
|
||||
<link href="http://example.org/2003/12/13/atom03"/>
|
||||
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
|
||||
<updated>2003-12-13T18:30:02Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
</feed>
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=368464
|
||||
-->
|
||||
<head>
|
||||
<title>Test that RSS 0.90 isn't sniffed</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=368464">Mozilla Bug 368464</a>
|
||||
<p id="display"><iframe id="testFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/bug368464-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 368464 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
ok($("testFrame").contentDocument.documentElement.id != "feedHandler",
|
||||
"RSS 0.90 shouldn't be sniffed as a feed");
|
||||
});
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=408328
|
||||
-->
|
||||
<head>
|
||||
<title>Test feed preview safe-linkification</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=408328">Mozilla Bug 408328</a>
|
||||
<p id="display"><iframe id="testFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/bug408328-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 408328 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
var links = $("testFrame").contentDocument.getElementById("feedContent").getElementsByTagName("a");
|
||||
is(links.length, 5, "wrong number of linked items in feed preview");
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
if (links[i].href)
|
||||
is(links[i].href, "http://example.org/first", "bad linkified item");
|
||||
}
|
||||
});
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=739040
|
||||
-->
|
||||
<head>
|
||||
<title>Test that we only sniff 512 bytes</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=739040">Mozilla Bug 739040</a>
|
||||
<p id="display">
|
||||
<iframe id="validTestFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/valid-feed.xml"></iframe>
|
||||
<iframe id="unsniffableTestFrame" src="http://mochi.test:8888/tests/browser/components/feeds/test/valid-unsniffable-feed.xml"></iframe>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 739040 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
is($("validTestFrame").contentDocument.documentElement.id, "feedHandler",
|
||||
"valid feed should be sniffed");
|
||||
isnot($("unsniffableTestFrame").contentDocument.documentElement.id, "feedHandler",
|
||||
"unsniffable feed should not be sniffed");
|
||||
});
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,20 +1,2 @@
|
|||
[DEFAULT]
|
||||
prefs =
|
||||
browser.feeds.unsafelyFrameFeeds=true
|
||||
|
||||
support-files =
|
||||
bug368464-data.xml
|
||||
bug408328-data.xml
|
||||
bug436801-data.xml
|
||||
bug494328-data.xml
|
||||
valid-feed.xml
|
||||
valid-unsniffable-feed.xml
|
||||
|
||||
[test_bug364677.html]
|
||||
support-files =
|
||||
bug364677-data.xml
|
||||
bug364677-data.xml^headers^
|
||||
[test_bug436801.html]
|
||||
[test_bug494328.html]
|
||||
[test_registerHandler.html]
|
||||
[test_registerHandler_disabled.html]
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=364677
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 364677</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=364677">Mozilla Bug 364677</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug364677-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 364677 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
is(SpecialPowers.wrap($("testFrame")).contentDocument.documentElement.id, "feedHandler",
|
||||
"Feed served as text/xml without a channel/link should have been sniffed");
|
||||
});
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=436801
|
||||
-->
|
||||
<head>
|
||||
<title>Test feed preview subscribe UI</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=436801">Mozilla Bug 436801</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug436801-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
var doc = SpecialPowers.wrap($("testFrame")).contentDocument;
|
||||
|
||||
checkNode(doc.getElementById("feedTitleText"), [
|
||||
"ELEMENT", "h1", [
|
||||
["TEXT", "Example of a "],
|
||||
["ELEMENT", "em", [
|
||||
["TEXT", "special"],
|
||||
]],
|
||||
["TEXT", " feed ("],
|
||||
["ELEMENT", "img", { "src": "baz.png" }],
|
||||
["TEXT", ")"],
|
||||
],
|
||||
]);
|
||||
|
||||
checkNode(doc.getElementById("feedSubtitleText"), [
|
||||
"ELEMENT", "h2", [
|
||||
["TEXT", "With a "],
|
||||
["ELEMENT", "em", [
|
||||
["TEXT", "special"],
|
||||
]],
|
||||
["TEXT", " subtitle ("],
|
||||
["ELEMENT", "img", { "src": "baz.png" }],
|
||||
["TEXT", ")"],
|
||||
],
|
||||
]);
|
||||
|
||||
checkNode(doc.querySelector(".entry").firstChild.firstChild.firstChild, [
|
||||
"ELEMENT", "span", [
|
||||
["TEXT", "Some "],
|
||||
["ELEMENT", "abbr", { title: "Extensible Hyper-text Mark-up Language" }, [
|
||||
["TEXT", "XHTML"],
|
||||
]],
|
||||
["TEXT", " examples ("],
|
||||
["ELEMENT", "img", { "src": "baz.png" }],
|
||||
["TEXT", ")"],
|
||||
],
|
||||
]);
|
||||
|
||||
checkNode(doc.querySelectorAll(".entry")[1].firstChild.firstChild.firstChild, [
|
||||
"ELEMENT", "span", [
|
||||
["TEXT", "Some "],
|
||||
["ELEMENT", "abbr", { title: "Hyper-text Mark-up Language" }, [
|
||||
["TEXT", "HTML"],
|
||||
]],
|
||||
["TEXT", " examples ("],
|
||||
["ELEMENT", "img", { "src": "baz.png" }],
|
||||
["TEXT", ")"],
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
function checkNode(node, schema) {
|
||||
var typeName = schema.shift() + "_NODE";
|
||||
var type = Node[typeName];
|
||||
is(node.nodeType, type, "Node should be expected type " + typeName);
|
||||
if (type == Node.TEXT_NODE) {
|
||||
var text = schema.shift();
|
||||
is(node.data, text, "Text should match");
|
||||
return;
|
||||
}
|
||||
// type == Node.ELEMENT_NODE
|
||||
var tag = schema.shift();
|
||||
is(node.localName, tag, "Element should have expected tag");
|
||||
while (schema.length) {
|
||||
let val = schema.shift();
|
||||
if (Array.isArray(val))
|
||||
var childSchema = val;
|
||||
else
|
||||
var attrSchema = val;
|
||||
}
|
||||
if (attrSchema) {
|
||||
var nsTable = {
|
||||
xml: "http://www.w3.org/XML/1998/namespace",
|
||||
};
|
||||
for (var name in attrSchema) {
|
||||
var [ns, nsName] = name.split(":");
|
||||
let val = nsName ? node.getAttributeNS(nsTable[ns], nsName) :
|
||||
node.getAttribute(name);
|
||||
is(val, attrSchema[name], "Attribute " + name + " should match");
|
||||
}
|
||||
}
|
||||
if (childSchema) {
|
||||
var numChildren = node.childNodes.length;
|
||||
is(childSchema.length, numChildren,
|
||||
"Element should have expected number of children");
|
||||
for (var i = 0; i < numChildren; i++)
|
||||
checkNode(node.childNodes[i], childSchema[i]);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,36 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=494328
|
||||
-->
|
||||
<head>
|
||||
<title>Test for bug 494328</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=494328">Mozilla Bug 494328</a>
|
||||
<p id="display"><iframe id="testFrame" src="bug494328-data.xml"></iframe></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 494328 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
var links = SpecialPowers.wrap($("testFrame")).contentDocument.getElementById("feedContent").querySelectorAll("div.enclosure > a");
|
||||
is(links[0].textContent, "Episode 1", "filename decoded incorrectly");
|
||||
is(links[1].textContent, "Episode #2", "filename decoded incorrectly");
|
||||
is(links[2].textContent, "http://www.example.com/podcasts/Episode #3/", "filename decoded incorrectly");
|
||||
is(links[3].textContent, "Is This Episode #4?", "filename decoded incorrectly");
|
||||
});
|
||||
addLoadEvent(SimpleTest.finish);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
|
||||
<title>Example Feed</title>
|
||||
<link href="http://example.org/"/>
|
||||
<updated>2010-08-22T18:30:02Z</updated>
|
||||
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
<id>urn:uuid:e2df8375-99be-4848-b05e-b9d407555267</id>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>Item</title>
|
||||
<link href="http://example.org/first"/>
|
||||
<id>urn:uuid:9e0f4bed-33d3-4a9d-97ab-ecaa31b3f14a</id>
|
||||
<updated>2010-08-22T18:30:02Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
</feed>
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 512 bytes!
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
-->
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
|
||||
<title>Example Feed</title>
|
||||
<link href="http://example.org/"/>
|
||||
<updated>2010-08-22T18:30:02Z</updated>
|
||||
|
||||
<author>
|
||||
<name>John Doe</name>
|
||||
</author>
|
||||
<id>urn:uuid:e2df8375-99be-4848-b05e-b9d407555267</id>
|
||||
|
||||
<entry>
|
||||
|
||||
<title>Item</title>
|
||||
<link href="http://example.org/first"/>
|
||||
<id>urn:uuid:9e0f4bed-33d3-4a9d-97ab-ecaa31b3f14a</id>
|
||||
<updated>2010-08-22T18:30:02Z</updated>
|
||||
|
||||
<summary>Some text.</summary>
|
||||
</entry>
|
||||
|
||||
</feed>
|
|
@ -500,7 +500,6 @@ const listeners = {
|
|||
"AsyncPrefs:ResetPref": ["AsyncPrefs"],
|
||||
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN AsyncPrefs.init
|
||||
|
||||
"FeedConverter:addLiveBookmark": ["Feeds"],
|
||||
"webrtc:UpdateGlobalIndicators": ["webrtcUI"],
|
||||
"webrtc:UpdatingIndicators": ["webrtcUI"],
|
||||
},
|
||||
|
|
|
@ -17,9 +17,7 @@ var gAppManagerDialog = {
|
|||
window);
|
||||
|
||||
const appDescElem = document.getElementById("appDescription");
|
||||
if (this.handlerInfo.type == TYPE_MAYBE_FEED) {
|
||||
document.l10n.setAttributes(appDescElem, "app-manager-handle-webfeeds");
|
||||
} else if (this.handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) {
|
||||
if (this.handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) {
|
||||
document.l10n.setAttributes(appDescElem, "app-manager-handle-file", {
|
||||
type: this.handlerInfo.typeDescription,
|
||||
});
|
||||
|
|
|
@ -25,9 +25,6 @@ XPCOMUtils.defineLazyServiceGetters(this, {
|
|||
});
|
||||
|
||||
// Constants & Enumeration Values
|
||||
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
|
||||
const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
|
||||
const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
|
||||
const TYPE_PDF = "application/pdf";
|
||||
|
||||
const PREF_PDFJS_DISABLED = "pdfjs.disabled";
|
||||
|
@ -46,38 +43,6 @@ const PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS =
|
|||
// Strings to identify ExtensionSettingsStore overrides
|
||||
const CONTAINERS_KEY = "privacy.containers";
|
||||
|
||||
/*
|
||||
* Preferences where we store handling information about the feed type.
|
||||
*
|
||||
* browser.feeds.handler
|
||||
* - "bookmarks", "reader" (clarified further using the .default preference),
|
||||
* or "ask" -- indicates the default handler being used to process feeds;
|
||||
* "bookmarks" is obsolete; to specify that the handler is bookmarks,
|
||||
* set browser.feeds.handler.default to "bookmarks";
|
||||
*
|
||||
* browser.feeds.handler.default
|
||||
* - "bookmarks" or "client" -- indicates the chosen feed reader used
|
||||
* to display feeds, either transiently (i.e., when the "use as default"
|
||||
* checkbox is unchecked, corresponds to when browser.feeds.handler=="ask")
|
||||
* or more permanently (i.e., the item displayed in the dropdown in Feeds
|
||||
* preferences)
|
||||
*
|
||||
* browser.feeds.handlers.application
|
||||
* - nsIFile, stores the current client-side feed reading app if one has
|
||||
* been chosen
|
||||
*/
|
||||
const PREF_FEED_SELECTED_APP = "browser.feeds.handlers.application";
|
||||
const PREF_FEED_SELECTED_ACTION = "browser.feeds.handler";
|
||||
const PREF_FEED_SELECTED_READER = "browser.feeds.handler.default";
|
||||
|
||||
const PREF_VIDEO_FEED_SELECTED_APP = "browser.videoFeeds.handlers.application";
|
||||
const PREF_VIDEO_FEED_SELECTED_ACTION = "browser.videoFeeds.handler";
|
||||
const PREF_VIDEO_FEED_SELECTED_READER = "browser.videoFeeds.handler.default";
|
||||
|
||||
const PREF_AUDIO_FEED_SELECTED_APP = "browser.audioFeeds.handlers.application";
|
||||
const PREF_AUDIO_FEED_SELECTED_ACTION = "browser.audioFeeds.handler";
|
||||
const PREF_AUDIO_FEED_SELECTED_READER = "browser.audioFeeds.handler.default";
|
||||
|
||||
// The nsHandlerInfoAction enumeration values in nsIHandlerInfo identify
|
||||
// the actions the application can take with content of various types.
|
||||
// But since nsIHandlerInfo doesn't support plugins, there's no value
|
||||
|
@ -88,7 +53,7 @@ const ICON_URL_APP = AppConstants.platform == "linux" ?
|
|||
"moz-icon://dummy.exe?size=16" :
|
||||
"chrome://browser/skin/preferences/application.png";
|
||||
|
||||
// For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
|
||||
// For CSS. Can be one of "ask", "save" or "plugin". If absent, the icon URL
|
||||
// was set by us to a custom handler icon and CSS should not try to override it.
|
||||
const APP_ICON_ATTR_NAME = "appHandlerIcon";
|
||||
|
||||
|
@ -179,18 +144,6 @@ Preferences.addAll([
|
|||
{ id: "layers.acceleration.disabled", type: "bool", inverted: true },
|
||||
|
||||
// Files and Applications
|
||||
{ id: "browser.feeds.handler", type: "string" },
|
||||
{ id: "browser.feeds.handler.default", type: "string" },
|
||||
{ id: "browser.feeds.handlers.application", type: "file" },
|
||||
|
||||
{ id: "browser.videoFeeds.handler", type: "string" },
|
||||
{ id: "browser.videoFeeds.handler.default", type: "string" },
|
||||
{ id: "browser.videoFeeds.handlers.application", type: "file" },
|
||||
|
||||
{ id: "browser.audioFeeds.handler", type: "string" },
|
||||
{ id: "browser.audioFeeds.handler.default", type: "string" },
|
||||
{ id: "browser.audioFeeds.handlers.application", type: "file" },
|
||||
|
||||
{ id: "pref.downloads.disable_button.edit_actions", type: "bool" },
|
||||
|
||||
// DRM content
|
||||
|
@ -549,17 +502,6 @@ var gMainPane = {
|
|||
// the view when they change.
|
||||
Services.prefs.addObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
|
||||
Services.prefs.addObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
|
||||
Services.prefs.addObserver(PREF_FEED_SELECTED_APP, this);
|
||||
Services.prefs.addObserver(PREF_FEED_SELECTED_ACTION, this);
|
||||
Services.prefs.addObserver(PREF_FEED_SELECTED_READER, this);
|
||||
|
||||
Services.prefs.addObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
|
||||
Services.prefs.addObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
|
||||
Services.prefs.addObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
|
||||
|
||||
Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
|
||||
Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
|
||||
Services.prefs.addObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
|
||||
|
||||
setEventListener("filter", "command", gMainPane.filter);
|
||||
setEventListener("typeColumn", "click", gMainPane.sort);
|
||||
|
@ -1333,17 +1275,6 @@ var gMainPane = {
|
|||
window.removeEventListener("unload", this);
|
||||
Services.prefs.removeObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
|
||||
Services.prefs.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
|
||||
Services.prefs.removeObserver(PREF_FEED_SELECTED_APP, this);
|
||||
Services.prefs.removeObserver(PREF_FEED_SELECTED_ACTION, this);
|
||||
Services.prefs.removeObserver(PREF_FEED_SELECTED_READER, this);
|
||||
|
||||
Services.prefs.removeObserver(PREF_VIDEO_FEED_SELECTED_APP, this);
|
||||
Services.prefs.removeObserver(PREF_VIDEO_FEED_SELECTED_ACTION, this);
|
||||
Services.prefs.removeObserver(PREF_VIDEO_FEED_SELECTED_READER, this);
|
||||
|
||||
Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
|
||||
Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
|
||||
Services.prefs.removeObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
|
||||
|
||||
Services.prefs.removeObserver(PREF_CONTAINERS_EXTENSION, this);
|
||||
},
|
||||
|
@ -1392,23 +1323,11 @@ var gMainPane = {
|
|||
// Composed Model Construction
|
||||
|
||||
_loadData() {
|
||||
this._loadFeedHandler();
|
||||
this._loadInternalHandlers();
|
||||
this._loadPluginHandlers();
|
||||
this._loadApplicationHandlers();
|
||||
},
|
||||
|
||||
_loadFeedHandler() {
|
||||
this._handledTypes[TYPE_MAYBE_FEED] = feedHandlerInfo;
|
||||
feedHandlerInfo.handledOnlyByPlugin = false;
|
||||
|
||||
this._handledTypes[TYPE_MAYBE_VIDEO_FEED] = videoFeedHandlerInfo;
|
||||
videoFeedHandlerInfo.handledOnlyByPlugin = false;
|
||||
|
||||
this._handledTypes[TYPE_MAYBE_AUDIO_FEED] = audioFeedHandlerInfo;
|
||||
audioFeedHandlerInfo.handledOnlyByPlugin = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Load higher level internal handlers so they can be turned on/off in the
|
||||
* applications menu.
|
||||
|
@ -1675,12 +1594,7 @@ var gMainPane = {
|
|||
{
|
||||
var askMenuItem = document.createXULElement("menuitem");
|
||||
askMenuItem.setAttribute("action", Ci.nsIHandlerInfo.alwaysAsk);
|
||||
let label;
|
||||
if (isFeedType(handlerInfo.type))
|
||||
label = gMainPane._prefsBundle.getFormattedString("previewInApp",
|
||||
[this._brandShortName]);
|
||||
else
|
||||
label = gMainPane._prefsBundle.getString("alwaysAsk");
|
||||
let label = gMainPane._prefsBundle.getString("alwaysAsk");
|
||||
askMenuItem.setAttribute("label", label);
|
||||
askMenuItem.setAttribute("tooltiptext", label);
|
||||
askMenuItem.setAttribute(APP_ICON_ATTR_NAME, "ask");
|
||||
|
@ -1689,10 +1603,8 @@ var gMainPane = {
|
|||
|
||||
// Create a menu item for saving to disk.
|
||||
// Note: this option isn't available to protocol types, since we don't know
|
||||
// what it means to save a URL having a certain scheme to disk, nor is it
|
||||
// available to feeds, since the feed code doesn't implement the capability.
|
||||
if ((handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo) &&
|
||||
!isFeedType(handlerInfo.type)) {
|
||||
// what it means to save a URL having a certain scheme to disk.
|
||||
if ((handlerInfo.wrappedHandlerInfo instanceof Ci.nsIMIMEInfo)) {
|
||||
var saveMenuItem = document.createXULElement("menuitem");
|
||||
saveMenuItem.setAttribute("action", Ci.nsIHandlerInfo.saveToDisk);
|
||||
let label = gMainPane._prefsBundle.getString("saveFile");
|
||||
|
@ -1702,18 +1614,6 @@ var gMainPane = {
|
|||
menuPopup.appendChild(saveMenuItem);
|
||||
}
|
||||
|
||||
// If this is the feed type, add a Live Bookmarks item.
|
||||
if (isFeedType(handlerInfo.type)) {
|
||||
internalMenuItem = document.createXULElement("menuitem");
|
||||
internalMenuItem.setAttribute("action", Ci.nsIHandlerInfo.handleInternally);
|
||||
let label = gMainPane._prefsBundle.getFormattedString("addLiveBookmarksInApp",
|
||||
[this._brandShortName]);
|
||||
internalMenuItem.setAttribute("label", label);
|
||||
internalMenuItem.setAttribute("tooltiptext", label);
|
||||
internalMenuItem.setAttribute(APP_ICON_ATTR_NAME, "feed");
|
||||
menuPopup.appendChild(internalMenuItem);
|
||||
}
|
||||
|
||||
// Add a separator to distinguish these items from the helper app items
|
||||
// that follow them.
|
||||
let menuseparator = document.createXULElement("menuseparator");
|
||||
|
@ -1950,10 +1850,11 @@ var gMainPane = {
|
|||
|
||||
// Whether or not we are currently storing the action selected by the user.
|
||||
// We use this to suppress notification-triggered updates to the list when
|
||||
// we make changes that may spawn such updates, specifically when we change
|
||||
// the action for the feed type, which results in feed preference updates,
|
||||
// which spawn "pref changed" notifications that would otherwise cause us
|
||||
// to rebuild the view unnecessarily.
|
||||
// we make changes that may spawn such updates.
|
||||
// XXXgijs: this was definitely necessary when we changed feed preferences
|
||||
// from within _storeAction and its calltree. Now, it may still be
|
||||
// necessary, either to avoid calling _rebuildView or to avoid the plugin-
|
||||
// related prefs change code. bug 1499350 has more details.
|
||||
_storingAction: false,
|
||||
|
||||
onSelectAction(aActionItem) {
|
||||
|
@ -2058,14 +1959,7 @@ var gMainPane = {
|
|||
var params = {};
|
||||
var handlerInfo = this.selectedHandlerListItem.handlerInfoWrapper;
|
||||
|
||||
if (isFeedType(handlerInfo.type)) {
|
||||
// MIME info will be null, create a temp object.
|
||||
params.mimeInfo = gMIMEService.getFromTypeAndExtension(handlerInfo.type,
|
||||
handlerInfo.primaryExtension);
|
||||
} else {
|
||||
params.mimeInfo = handlerInfo.wrappedHandlerInfo;
|
||||
}
|
||||
|
||||
params.mimeInfo = handlerInfo.wrappedHandlerInfo;
|
||||
params.title = gMainPane._prefsBundle.getString("fpTitleChooseApp");
|
||||
params.description = handlerInfo.description;
|
||||
params.filename = null;
|
||||
|
@ -2454,10 +2348,6 @@ function getLocalHandlerApp(aFile) {
|
|||
return localHandlerApp;
|
||||
}
|
||||
|
||||
function isFeedType(t) {
|
||||
return t == TYPE_MAYBE_FEED || t == TYPE_MAYBE_VIDEO_FEED || t == TYPE_MAYBE_AUDIO_FEED;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
let gHandlerListItemFragment = MozXULElement.parseXULToFragment(`
|
||||
<richlistitem>
|
||||
|
@ -2618,12 +2508,8 @@ class HandlerInfoWrapper {
|
|||
*/
|
||||
get actionDescription() {
|
||||
// alwaysAskBeforeHandling overrides the preferred action, so if that flag
|
||||
// is set, then describe that behavior instead. For most types, this is
|
||||
// the "alwaysAsk" string, but for the feed type we show something special.
|
||||
// is set, then describe that behavior instead.
|
||||
if (this.alwaysAskBeforeHandling) {
|
||||
if (isFeedType(this.type))
|
||||
return gMainPane._prefsBundle.getFormattedString("previewInApp",
|
||||
[gMainPane._brandShortName]);
|
||||
return gMainPane._prefsBundle.getString("alwaysAsk");
|
||||
}
|
||||
|
||||
|
@ -2641,12 +2527,6 @@ class HandlerInfoWrapper {
|
|||
return gMainPane._prefsBundle.getFormattedString("useApp", [name]);
|
||||
|
||||
case Ci.nsIHandlerInfo.handleInternally:
|
||||
// For the feed type, handleInternally means live bookmarks.
|
||||
if (isFeedType(this.type)) {
|
||||
return gMainPane._prefsBundle.getFormattedString("addLiveBookmarksInApp",
|
||||
[gMainPane._brandShortName]);
|
||||
}
|
||||
|
||||
if (this instanceof InternalHandlerInfoWrapper) {
|
||||
return gMainPane._prefsBundle.getFormattedString("previewInApp",
|
||||
[gMainPane._brandShortName]);
|
||||
|
@ -2688,9 +2568,7 @@ class HandlerInfoWrapper {
|
|||
return "save";
|
||||
|
||||
case Ci.nsIHandlerInfo.handleInternally:
|
||||
if (isFeedType(this.type)) {
|
||||
return "feed";
|
||||
} else if (this instanceof InternalHandlerInfoWrapper) {
|
||||
if (this instanceof InternalHandlerInfoWrapper) {
|
||||
return "ask";
|
||||
}
|
||||
|
||||
|
@ -2944,269 +2822,6 @@ class HandlerInfoWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This object implements nsIHandlerInfo for the feed types. It's a separate
|
||||
* object because we currently store handling information for the feed type
|
||||
* in a set of preferences rather than the nsIHandlerService-managed datastore.
|
||||
*
|
||||
* This object inherits from HandlerInfoWrapper in order to get functionality
|
||||
* that isn't special to the feed type.
|
||||
*/
|
||||
class FeedHandlerInfo extends HandlerInfoWrapper {
|
||||
constructor(aMIMEType, properties) {
|
||||
super(aMIMEType, null);
|
||||
Object.assign(this, properties);
|
||||
}
|
||||
|
||||
get description() {
|
||||
return gMainPane._prefsBundle.getString(this._appPrefLabel);
|
||||
}
|
||||
|
||||
get preferredApplicationHandler() {
|
||||
switch (Preferences.get(this._prefSelectedReader).value) {
|
||||
case "client":
|
||||
var file = Preferences.get(this._prefSelectedApp).value;
|
||||
if (file)
|
||||
return getLocalHandlerApp(file);
|
||||
|
||||
return null;
|
||||
|
||||
case "bookmarks":
|
||||
default:
|
||||
// When the pref is set to bookmarks, we handle feeds internally,
|
||||
// we don't forward them to a local or web handler app, so there is
|
||||
// no preferred handler.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
set preferredApplicationHandler(aNewValue) {
|
||||
if (aNewValue instanceof Ci.nsILocalHandlerApp) {
|
||||
Preferences.get(this._prefSelectedApp).value = aNewValue.executable;
|
||||
Preferences.get(this._prefSelectedReader).value = "client";
|
||||
}
|
||||
}
|
||||
|
||||
get possibleApplicationHandlers() {
|
||||
if (this._possibleApplicationHandlers)
|
||||
return this._possibleApplicationHandlers;
|
||||
|
||||
// A minimal implementation of nsIMutableArray. It only supports the two
|
||||
// methods its callers invoke, namely appendElement and nsIArray::enumerate.
|
||||
this._possibleApplicationHandlers = {
|
||||
_inner: [],
|
||||
_removed: [],
|
||||
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIMutableArray", "nsIArray"]),
|
||||
|
||||
get length() {
|
||||
return this._inner.length;
|
||||
},
|
||||
|
||||
enumerate() {
|
||||
return this._inner.values();
|
||||
},
|
||||
|
||||
appendElement(aHandlerApp, aWeak) {
|
||||
this._inner.push(aHandlerApp);
|
||||
},
|
||||
|
||||
removeElementAt(aIndex) {
|
||||
this._removed.push(this._inner[aIndex]);
|
||||
this._inner.splice(aIndex, 1);
|
||||
},
|
||||
|
||||
queryElementAt(aIndex, aInterface) {
|
||||
return this._inner[aIndex].QueryInterface(aInterface);
|
||||
},
|
||||
};
|
||||
|
||||
// Add the selected local app if it's different from the OS default handler.
|
||||
// Unlike for other types, we can store only one local app at a time for the
|
||||
// feed type, since we store it in a preference that historically stores
|
||||
// only a single path. But we display all the local apps the user chooses
|
||||
// while the prefpane is open, only dropping the list when the user closes
|
||||
// the prefpane, for maximum usability and consistency with other types.
|
||||
var preferredAppFile = Preferences.get(this._prefSelectedApp).value;
|
||||
if (preferredAppFile) {
|
||||
let preferredApp = getLocalHandlerApp(preferredAppFile);
|
||||
let defaultApp = this._defaultApplicationHandler;
|
||||
if (!defaultApp || !defaultApp.equals(preferredApp))
|
||||
this._possibleApplicationHandlers.appendElement(preferredApp);
|
||||
}
|
||||
|
||||
return this._possibleApplicationHandlers;
|
||||
}
|
||||
|
||||
get _defaultApplicationHandler() {
|
||||
if (typeof this.__defaultApplicationHandler != "undefined")
|
||||
return this.__defaultApplicationHandler;
|
||||
|
||||
var defaultFeedReader = null;
|
||||
if (AppConstants.HAVE_SHELL_SERVICE) {
|
||||
try {
|
||||
defaultFeedReader = getShellService().defaultFeedReader;
|
||||
} catch (ex) {
|
||||
// no default reader or getShellService() is null
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultFeedReader) {
|
||||
let handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
|
||||
createInstance(Ci.nsIHandlerApp);
|
||||
handlerApp.name = getFileDisplayName(defaultFeedReader);
|
||||
handlerApp.QueryInterface(Ci.nsILocalHandlerApp);
|
||||
handlerApp.executable = defaultFeedReader;
|
||||
|
||||
this.__defaultApplicationHandler = handlerApp;
|
||||
} else {
|
||||
this.__defaultApplicationHandler = null;
|
||||
}
|
||||
|
||||
return this.__defaultApplicationHandler;
|
||||
}
|
||||
|
||||
get hasDefaultHandler() {
|
||||
if (AppConstants.HAVE_SHELL_SERVICE) {
|
||||
try {
|
||||
if (getShellService().defaultFeedReader)
|
||||
return true;
|
||||
} catch (ex) {
|
||||
// no default reader or getShellService() is null
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
get defaultDescription() {
|
||||
if (this.hasDefaultHandler)
|
||||
return this._defaultApplicationHandler.name;
|
||||
|
||||
// Should we instead return null?
|
||||
return "";
|
||||
}
|
||||
|
||||
// What to do with content of this type.
|
||||
get preferredAction() {
|
||||
switch (Preferences.get(this._prefSelectedAction).value) {
|
||||
|
||||
case "bookmarks":
|
||||
return Ci.nsIHandlerInfo.handleInternally;
|
||||
|
||||
case "reader": {
|
||||
let preferredApp = this.preferredApplicationHandler;
|
||||
let defaultApp = this._defaultApplicationHandler;
|
||||
|
||||
// If we have a valid preferred app, return useSystemDefault if it's
|
||||
// the default app; otherwise return useHelperApp.
|
||||
if (gMainPane.isValidHandlerApp(preferredApp)) {
|
||||
if (defaultApp && defaultApp.equals(preferredApp))
|
||||
return Ci.nsIHandlerInfo.useSystemDefault;
|
||||
|
||||
return Ci.nsIHandlerInfo.useHelperApp;
|
||||
}
|
||||
|
||||
// The pref is set to "reader", but we don't have a valid preferred app.
|
||||
// What do we do now? Not sure this is the best option (perhaps we
|
||||
// should direct the user to the default app, if any), but for now let's
|
||||
// direct the user to live bookmarks.
|
||||
return Ci.nsIHandlerInfo.handleInternally;
|
||||
}
|
||||
|
||||
// If the action is "ask", then alwaysAskBeforeHandling will override
|
||||
// the action, so it doesn't matter what we say it is, it just has to be
|
||||
// something that doesn't cause the controller to hide the type.
|
||||
case "ask":
|
||||
default:
|
||||
return Ci.nsIHandlerInfo.handleInternally;
|
||||
}
|
||||
}
|
||||
|
||||
set preferredAction(aNewValue) {
|
||||
switch (aNewValue) {
|
||||
|
||||
case Ci.nsIHandlerInfo.handleInternally:
|
||||
Preferences.get(this._prefSelectedReader).value = "bookmarks";
|
||||
break;
|
||||
|
||||
case Ci.nsIHandlerInfo.useHelperApp:
|
||||
Preferences.get(this._prefSelectedAction).value = "reader";
|
||||
// The controller has already set preferredApplicationHandler
|
||||
// to the new helper app.
|
||||
break;
|
||||
|
||||
case Ci.nsIHandlerInfo.useSystemDefault:
|
||||
Preferences.get(this._prefSelectedAction).value = "reader";
|
||||
this.preferredApplicationHandler = this._defaultApplicationHandler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
get alwaysAskBeforeHandling() {
|
||||
return Preferences.get(this._prefSelectedAction).value == "ask";
|
||||
}
|
||||
|
||||
set alwaysAskBeforeHandling(aNewValue) {
|
||||
if (aNewValue)
|
||||
Preferences.get(this._prefSelectedAction).value = "ask";
|
||||
else
|
||||
Preferences.get(this._prefSelectedAction).value = "reader";
|
||||
}
|
||||
|
||||
get primaryExtension() {
|
||||
return "xml";
|
||||
}
|
||||
|
||||
// Changes to the preferred action and handler take effect immediately
|
||||
// (we write them out to the preferences right as they happen),
|
||||
// so we when the controller calls store() after modifying the handlers,
|
||||
// the only thing we need to store is the removal of possible handlers
|
||||
// XXX Should we hold off on making the changes until this method gets called?
|
||||
store() {
|
||||
for (let app of this._possibleApplicationHandlers._removed) {
|
||||
if (app instanceof Ci.nsILocalHandlerApp) {
|
||||
let pref = Preferences.get(PREF_FEED_SELECTED_APP);
|
||||
var preferredAppFile = pref.value;
|
||||
if (preferredAppFile) {
|
||||
let preferredApp = getLocalHandlerApp(preferredAppFile);
|
||||
if (app.equals(preferredApp))
|
||||
pref.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
this._possibleApplicationHandlers._removed = [];
|
||||
}
|
||||
|
||||
get smallIcon() {
|
||||
return this._smallIcon;
|
||||
}
|
||||
}
|
||||
|
||||
var feedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_FEED, {
|
||||
_prefSelectedApp: PREF_FEED_SELECTED_APP,
|
||||
_prefSelectedAction: PREF_FEED_SELECTED_ACTION,
|
||||
_prefSelectedReader: PREF_FEED_SELECTED_READER,
|
||||
_smallIcon: "chrome://browser/skin/feeds/feedIcon16.png",
|
||||
_appPrefLabel: "webFeed",
|
||||
});
|
||||
|
||||
var videoFeedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_VIDEO_FEED, {
|
||||
_prefSelectedApp: PREF_VIDEO_FEED_SELECTED_APP,
|
||||
_prefSelectedAction: PREF_VIDEO_FEED_SELECTED_ACTION,
|
||||
_prefSelectedReader: PREF_VIDEO_FEED_SELECTED_READER,
|
||||
_smallIcon: "chrome://browser/skin/feeds/videoFeedIcon16.png",
|
||||
_appPrefLabel: "videoPodcastFeed",
|
||||
});
|
||||
|
||||
var audioFeedHandlerInfo = new FeedHandlerInfo(TYPE_MAYBE_AUDIO_FEED, {
|
||||
_prefSelectedApp: PREF_AUDIO_FEED_SELECTED_APP,
|
||||
_prefSelectedAction: PREF_AUDIO_FEED_SELECTED_ACTION,
|
||||
_prefSelectedReader: PREF_AUDIO_FEED_SELECTED_READER,
|
||||
_smallIcon: "chrome://browser/skin/feeds/audioFeedIcon16.png",
|
||||
_appPrefLabel: "audioPodcastFeed",
|
||||
});
|
||||
|
||||
/**
|
||||
* InternalHandlerInfoWrapper provides a basic mechanism to create an internal
|
||||
* mime type handler that can be enabled/disabled in the applications preference
|
||||
|
|
|
@ -684,9 +684,3 @@ nsGNOMEShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACStr
|
|||
const char* specStr = spec.get();
|
||||
return process->Run(false, &specStr, 1);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGNOMEShellService::GetDefaultFeedReader(nsIFile** _retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -92,9 +92,4 @@ interface nsIShellService : nsISupports
|
|||
* The uri to be loaded by the application
|
||||
*/
|
||||
void openApplicationWithURI(in nsIFile aApplication, in ACString aURI);
|
||||
|
||||
/**
|
||||
* The default system handler for web feeds
|
||||
*/
|
||||
readonly attribute nsIFile defaultFeedReader;
|
||||
};
|
||||
|
|
|
@ -383,42 +383,3 @@ nsMacShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACStrin
|
|||
|
||||
return err != noErr ? NS_ERROR_FAILURE : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsMacShellService::GetDefaultFeedReader(nsIFile** _retval)
|
||||
{
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
*_retval = nullptr;
|
||||
|
||||
CFStringRef defaultHandlerID = ::LSCopyDefaultHandlerForURLScheme(CFSTR("feed"));
|
||||
if (!defaultHandlerID) {
|
||||
defaultHandlerID = ::CFStringCreateWithCString(kCFAllocatorDefault,
|
||||
SAFARI_BUNDLE_IDENTIFIER,
|
||||
kCFStringEncodingASCII);
|
||||
}
|
||||
|
||||
CFURLRef defaultHandlerURL = nullptr;
|
||||
OSStatus status = ::LSFindApplicationForInfo(kLSUnknownCreator,
|
||||
defaultHandlerID,
|
||||
nullptr, // inName
|
||||
nullptr, // outAppRef
|
||||
&defaultHandlerURL);
|
||||
|
||||
if (status == noErr && defaultHandlerURL) {
|
||||
nsCOMPtr<nsILocalFileMac> defaultReader =
|
||||
do_CreateInstance("@mozilla.org/file/local;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = defaultReader->InitWithCFURL(defaultHandlerURL);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
NS_ADDREF(*_retval = defaultReader);
|
||||
rv = NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
::CFRelease(defaultHandlerURL);
|
||||
}
|
||||
|
||||
::CFRelease(defaultHandlerID);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -760,50 +760,3 @@ nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication,
|
|||
const char* specStr = spec.get();
|
||||
return process->Run(false, &specStr, 1);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::GetDefaultFeedReader(nsIFile** _retval)
|
||||
{
|
||||
*_retval = nullptr;
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIWindowsRegKey> regKey =
|
||||
do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CLASSES_ROOT,
|
||||
NS_LITERAL_STRING("feed\\shell\\open\\command"),
|
||||
nsIWindowsRegKey::ACCESS_READ);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString path;
|
||||
rv = regKey->ReadStringValue(EmptyString(), path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (path.IsEmpty())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (path.First() == '"') {
|
||||
// Everything inside the quotes
|
||||
path = Substring(path, 1, path.FindChar('"', 1) - 1);
|
||||
}
|
||||
else {
|
||||
// Everything up to the first space
|
||||
path = Substring(path, 0, path.FindChar(' '));
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> defaultReader =
|
||||
do_CreateInstance("@mozilla.org/file/local;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = defaultReader->InitWithPath(path);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool exists;
|
||||
rv = defaultReader->Exists(&exists);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!exists)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ADDREF(*_retval = defaultReader);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ MockShellService.prototype = {
|
|||
openApplication(aApplication) {},
|
||||
desktopBackgroundColor: 0,
|
||||
openApplicationWithURI(aApplication, aURI) {},
|
||||
defaultFeedReader: 0,
|
||||
};
|
||||
|
||||
var mockShellService = new MockObjectRegisterer("@mozilla.org/browser/shell-service;1",
|
||||
|
|
|
@ -176,8 +176,6 @@
|
|||
@BINPATH@/components/nsDNSServiceDiscovery.js
|
||||
#endif
|
||||
@RESPATH@/browser/components/BrowserFeeds.manifest
|
||||
@RESPATH@/browser/components/FeedConverter.js
|
||||
@RESPATH@/browser/components/FeedWriter.js
|
||||
@RESPATH@/browser/components/WebContentConverter.js
|
||||
@RESPATH@/browser/components/BrowserComponents.manifest
|
||||
@RESPATH@/browser/components/nsBrowserContentHandler.js
|
||||
|
|
|
@ -10,8 +10,6 @@ app-manager-remove =
|
|||
.label = Remove
|
||||
.accesskey = R
|
||||
|
||||
app-manager-handle-webfeeds = The following applications can be used to handle Web Feeds.
|
||||
|
||||
# Variables:
|
||||
# $type (String) - the URI scheme of the link (e.g. mailto:)
|
||||
app-manager-handle-protocol = The following applications can be used to handle { $type } links.
|
||||
|
|
|
@ -1,10 +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/. -->
|
||||
|
||||
<!ENTITY feedPage.title
|
||||
"Viewing Feed">
|
||||
<!ENTITY feedSubscribeNow
|
||||
"Subscribe Now">
|
||||
<!ENTITY feedLiveBookmarks
|
||||
"Live Bookmarks">
|
|
@ -2,49 +2,6 @@
|
|||
# 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/.
|
||||
|
||||
linkTitleTextFormat=Go to %S
|
||||
addHandler=Add “%S” (%S) as a Feed Reader?
|
||||
addHandlerAddButton=Add Feed Reader
|
||||
addHandlerAddButtonAccesskey=A
|
||||
handlerRegistered=“%S” is already registered as a Feed Reader
|
||||
liveBookmarks=Live Bookmarks
|
||||
subscribeNow=Subscribe Now
|
||||
chooseApplicationMenuItem=Choose Application…
|
||||
chooseApplicationDialogTitle=Choose Application
|
||||
alwaysUse=Always use %S to subscribe to feeds
|
||||
mediaLabel=Media files
|
||||
|
||||
# LOCALIZATION NOTE: The next string is for the size of the enclosed media.
|
||||
# e.g. enclosureSizeText : "50.23 MB"
|
||||
# %1$S = size (in bytes or megabytes, ...)
|
||||
# %2$S = unit of measure (bytes, KB, MB, ...)
|
||||
enclosureSizeText=%1$S %2$S
|
||||
|
||||
bytes=bytes
|
||||
kilobyte=KB
|
||||
megabyte=MB
|
||||
gigabyte=GB
|
||||
|
||||
# LOCALIZATION NOTE: The next three strings explains to the user what they're
|
||||
# doing.
|
||||
# e.g. alwaysUseForVideoPodcasts : "Always use Miro to subscribe to video podcasts."
|
||||
# %S = application to use (Miro, iTunes, ...)
|
||||
alwaysUseForFeeds=Always use %S to subscribe to feeds.
|
||||
alwaysUseForAudioPodcasts=Always use %S to subscribe to podcasts.
|
||||
alwaysUseForVideoPodcasts=Always use %S to subscribe to video podcasts.
|
||||
|
||||
subscribeFeedUsing=Subscribe to this feed using
|
||||
subscribeAudioPodcastUsing=Subscribe to this podcast using
|
||||
subscribeVideoPodcastUsing=Subscribe to this video podcast using
|
||||
|
||||
feedSubscriptionFeed1=This is a “feed” of frequently changing content on this site.
|
||||
feedSubscriptionAudioPodcast1=This is a “podcast” of frequently changing content on this site.
|
||||
feedSubscriptionVideoPodcast1=This is a “video podcast” of frequently changing content on this site.
|
||||
|
||||
feedSubscriptionFeed2=You can subscribe to this feed to receive updates when this content changes.
|
||||
feedSubscriptionAudioPodcast2=You can subscribe to this podcast to receive updates when this content changes.
|
||||
feedSubscriptionVideoPodcast2=You can subscribe to this video podcast to receive updates when this content changes.
|
||||
|
||||
# LOCALIZATION NOTE (addProtocolHandlerMessage):
|
||||
# Message displayed when adding a protocol handler:
|
||||
# %1$S is the application's domain, %2$S is the type of protocol
|
||||
|
|
|
@ -50,7 +50,6 @@
|
|||
locale/browser/safebrowsing/phishing-afterload-warning-message.dtd (%chrome/browser/safebrowsing/phishing-afterload-warning-message.dtd)
|
||||
locale/browser/safebrowsing/report-phishing.dtd (%chrome/browser/safebrowsing/report-phishing.dtd)
|
||||
locale/browser/safebrowsing/safebrowsing.properties (%chrome/browser/safebrowsing/safebrowsing.properties)
|
||||
locale/browser/feeds/subscribe.dtd (%chrome/browser/feeds/subscribe.dtd)
|
||||
locale/browser/feeds/subscribe.properties (%chrome/browser/feeds/subscribe.properties)
|
||||
locale/browser/migration/migration.dtd (%chrome/browser/migration/migration.dtd)
|
||||
locale/browser/migration/migration.properties (%chrome/browser/migration/migration.properties)
|
||||
|
|
Двоичные данные
browser/themes/linux/feeds/feedIcon.png
До Ширина: | Высота: | Размер: 1.6 KiB |
Двоичные данные
browser/themes/linux/feeds/feedIcon16.png
До Ширина: | Высота: | Размер: 686 B |
|
@ -1,185 +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/. */
|
||||
|
||||
html {
|
||||
background: -moz-Dialog;
|
||||
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;
|
||||
padding-inline-start: 30px;
|
||||
margin: 2em auto;
|
||||
background: -moz-Field;
|
||||
}
|
||||
|
||||
#feedHeaderContainer {
|
||||
border: 1px solid ThreeDShadow;
|
||||
border-radius: 10px;
|
||||
margin: -4em auto 0 auto;
|
||||
background-color: InfoBackground;
|
||||
-moz-appearance: -moz-gtk-info-bar;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#feedHeaderContainerSpacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#feedHeader {
|
||||
margin-top: 4.9em;
|
||||
margin-bottom: 1em;
|
||||
margin-inline-start: 1.4em;
|
||||
margin-inline-end: 1em;
|
||||
padding-inline-start: 2.9em;
|
||||
font-size: 110%;
|
||||
color: -moz-gtk-info-bar-text;
|
||||
}
|
||||
|
||||
.feedBackground {
|
||||
background: url("chrome://browser/skin/feeds/feedIcon.png") 0% 10% no-repeat;
|
||||
}
|
||||
|
||||
.videoPodcastBackground {
|
||||
background: url("chrome://browser/skin/feeds/videoFeedIcon.png") 0% 10% no-repeat;
|
||||
}
|
||||
|
||||
.audioPodcastBackground {
|
||||
background: url("chrome://browser/skin/feeds/audioFeedIcon.png") 0% 10% no-repeat;
|
||||
}
|
||||
|
||||
#feedHeader[dir="rtl"] {
|
||||
background-position: 100% 10%;
|
||||
}
|
||||
|
||||
#feedIntroText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#feedHeader[firstrun="true"] #feedIntroText {
|
||||
padding-top: 0.1em;
|
||||
padding-inline-start: 0.6em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#feedHeader[firstrun="true"] > #feedSubscribeLine {
|
||||
padding-inline-start: 1.8em;
|
||||
}
|
||||
|
||||
#feedSubscribeLine {
|
||||
padding-top: 0.2em;
|
||||
padding-inline-start: 0.5em;
|
||||
}
|
||||
|
||||
/* Don't print subscription UI */
|
||||
@media print {
|
||||
#feedHeaderContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 3em;
|
||||
color: -moz-fieldText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 160%;
|
||||
border-bottom: 2px solid ThreeDLightShadow;
|
||||
margin: 0 0 .2em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: GrayText;
|
||||
font-size: 110%;
|
||||
font-weight: normal;
|
||||
margin: 0 0 .6em 0;
|
||||
}
|
||||
|
||||
#feedTitleLink {
|
||||
float: right;
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a[href] img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#feedTitleContainer {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: .6em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#feedTitleImage {
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
max-width: 300px;
|
||||
max-height: 150px;
|
||||
}
|
||||
|
||||
.feedEntryContent {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.link:hover:active {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.lastUpdated {
|
||||
font-size: 85%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.enclosures {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
background: -moz-Dialog;
|
||||
}
|
||||
|
||||
.enclosure {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.handlersMenuList > .menulist-label-box > .menulist-icon {
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
}
|
|
@ -13,7 +13,6 @@ browser.jar:
|
|||
skin/classic/browser/monitor_16-10.png
|
||||
* skin/classic/browser/pageInfo.css
|
||||
skin/classic/browser/pageInfo.png
|
||||
skin/classic/browser/page-livemarks.png
|
||||
* skin/classic/browser/searchbar.css
|
||||
skin/classic/browser/setDesktopBackground.css
|
||||
skin/classic/browser/slowStartup-16.png
|
||||
|
@ -22,9 +21,6 @@ browser.jar:
|
|||
* skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
* skin/classic/browser/downloads/allDownloadsView.css (downloads/allDownloadsView.css)
|
||||
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/notification-icons/geo-blocked.svg (notification-icons/geo-blocked.svg)
|
||||
skin/classic/browser/notification-icons/geo-detailed.svg (notification-icons/geo-detailed.svg)
|
||||
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
|
||||
|
@ -46,8 +42,3 @@ browser.jar:
|
|||
skin/classic/browser/window-controls/restore.svg (window-controls/restore.svg)
|
||||
|
||||
skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
|
||||
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon16.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
% override chrome://browser/skin/feeds/videoFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
% override chrome://browser/skin/feeds/videoFeedIcon16.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
|
|
Двоичные данные
browser/themes/linux/page-livemarks.png
До Ширина: | Высота: | Размер: 638 B |
|
@ -40,10 +40,6 @@
|
|||
-moz-image-region: rect(0px, 64px, 32px, 32px)
|
||||
}
|
||||
|
||||
#feedTab {
|
||||
-moz-image-region: rect(0px, 96px, 32px, 64px)
|
||||
}
|
||||
|
||||
#permTab {
|
||||
-moz-image-region: rect(0px, 128px, 32px, 96px)
|
||||
}
|
||||
|
@ -136,39 +132,6 @@ treechildren::-moz-tree-cell-text(broken) {
|
|||
color: graytext;
|
||||
}
|
||||
|
||||
/* Feeds Tab */
|
||||
#feedPanel {
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
#feedtree {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#feedListbox richlistitem {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding-inline-start: 7px;
|
||||
padding-inline-end: 7px;
|
||||
min-height: 25px;
|
||||
border-bottom: 1px dotted ThreeDShadow;
|
||||
color: -moz-FieldText;
|
||||
}
|
||||
|
||||
#feedListbox richlistitem[selected="true"] {
|
||||
background-color: -moz-Dialog;
|
||||
color: -moz-DialogText;
|
||||
}
|
||||
|
||||
#feedListbox {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.feedTitle {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Permissions Tab */
|
||||
|
||||
#permList {
|
||||
|
|
|
@ -40,11 +40,6 @@ menuitem[appHandlerIcon="save"] {
|
|||
list-style-image: url("moz-icon://stock/gtk-save?size=menu");
|
||||
}
|
||||
|
||||
richlistitem[appHandlerIcon="feed"],
|
||||
menuitem[appHandlerIcon="feed"] {
|
||||
list-style-image: url("chrome://browser/skin/page-livemarks.png");
|
||||
}
|
||||
|
||||
richlistitem[appHandlerIcon="plugin"],
|
||||
menuitem[appHandlerIcon="plugin"] {
|
||||
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.svg");
|
||||
|
|
Двоичные данные
browser/themes/osx/feeds/feedIcon.png
До Ширина: | Высота: | Размер: 1.6 KiB |
Двоичные данные
browser/themes/osx/feeds/feedIcon16.png
До Ширина: | Высота: | Размер: 762 B |
|
@ -1,178 +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/. */
|
||||
|
||||
html {
|
||||
background: -moz-Dialog;
|
||||
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;
|
||||
padding-inline-start: 30px;
|
||||
margin: 2em auto;
|
||||
background: -moz-Field;
|
||||
}
|
||||
|
||||
#feedHeaderContainer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#feedHeaderContainerSpacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#feedHeader {
|
||||
border: 1px solid ThreeDShadow;
|
||||
border-radius: 10px;
|
||||
padding-top: 4em;
|
||||
padding-bottom: .3em;
|
||||
padding-inline-start: .3em;
|
||||
padding-inline-end: .3em;
|
||||
margin: -4em auto 0 auto;
|
||||
font-size: 110%;
|
||||
color: InfoText;
|
||||
padding: 5em 3em 0 3em;
|
||||
}
|
||||
|
||||
.feedBackground {
|
||||
background: url("chrome://browser/skin/feeds/feedIcon.png") 1.4em 5.9em no-repeat rgb(255,255,225);
|
||||
}
|
||||
|
||||
.videoPodcastBackground {
|
||||
background: url("chrome://browser/skin/feeds/videoFeedIcon.png") 1.4em 5.9em no-repeat rgb(255,255,225);
|
||||
}
|
||||
|
||||
.audioPodcastBackground {
|
||||
background: url("chrome://browser/skin/feeds/audioFeedIcon.png") 1.4em 5.9em no-repeat rgb(255,255,225);
|
||||
}
|
||||
|
||||
#feedHeader[firstrun="true"] #feedIntroText {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#feedIntroText {
|
||||
display: none;
|
||||
margin-inline-start: 2em;
|
||||
}
|
||||
|
||||
#feedSubscribeLine {
|
||||
padding: 0 1em 1em 2em;
|
||||
}
|
||||
|
||||
#feedHeader[firstrun="true"] #feedSubscribeLine {
|
||||
padding-left: 3.7em;
|
||||
}
|
||||
|
||||
/* Don't print subscription UI */
|
||||
@media print {
|
||||
#feedHeaderContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 3em;
|
||||
color: -moz-fieldText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 160%;
|
||||
border-bottom: 2px solid ThreeDLightShadow;
|
||||
margin: 0 0 .2em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #C0C0C0;
|
||||
font-size: 110%;
|
||||
font-weight: normal;
|
||||
margin: 0 0 .6em 0;
|
||||
}
|
||||
|
||||
#feedTitleLink {
|
||||
float: right;
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a[href] img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#feedTitleContainer {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: .6em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#feedTitleImage {
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
max-width: 300px;
|
||||
max-height: 150px;
|
||||
}
|
||||
|
||||
.feedEntryContent {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.link:hover:active {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.lastUpdated {
|
||||
font-size: 85%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.enclosures {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
background: -moz-Dialog;
|
||||
}
|
||||
|
||||
.enclosure {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.handlersMenuList > .menulist-label-box > .menulist-icon {
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
}
|
|
@ -14,7 +14,6 @@ browser.jar:
|
|||
skin/classic/browser/panel-expander-open.png
|
||||
skin/classic/browser/panel-expander-open@2x.png
|
||||
skin/classic/browser/panel-plus-sign.png
|
||||
skin/classic/browser/page-livemarks.png
|
||||
* skin/classic/browser/pageInfo.css
|
||||
* skin/classic/browser/searchbar.css
|
||||
skin/classic/browser/slowStartup-16.png
|
||||
|
@ -25,9 +24,6 @@ browser.jar:
|
|||
* skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
* skin/classic/browser/downloads/allDownloadsView.css (downloads/allDownloadsView.css)
|
||||
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/setDesktopBackground.css
|
||||
skin/classic/browser/monitor.png
|
||||
skin/classic/browser/monitor_16-10.png
|
||||
|
@ -52,8 +48,4 @@ browser.jar:
|
|||
skin/classic/browser/tabbrowser/tabDragIndicator@2x.png (tabbrowser/tabDragIndicator@2x.png)
|
||||
skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
|
||||
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon16.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
% override chrome://browser/skin/feeds/videoFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
% override chrome://browser/skin/feeds/videoFeedIcon16.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
% override chrome://browser/skin/notification-icons/geo-detailed.svg chrome://browser/skin/notification-icons/geo.svg
|
||||
|
|
Двоичные данные
browser/themes/osx/page-livemarks.png
До Ширина: | Высота: | Размер: 606 B |
|
@ -109,29 +109,6 @@ treechildren::-moz-tree-cell-text(broken) {
|
|||
color: graytext;
|
||||
}
|
||||
|
||||
/* Feeds Tab */
|
||||
#feedtree {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#feedListbox richlistitem {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding-inline-start: 7px;
|
||||
padding-inline-end: 7px;
|
||||
min-height: 25px;
|
||||
border-bottom: 1px dotted ThreeDShadow;
|
||||
}
|
||||
|
||||
#feedListbox richlistitem[selected="true"] {
|
||||
background-color: -moz-Dialog;
|
||||
color: -moz-DialogText;
|
||||
}
|
||||
|
||||
.feedTitle {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Permissions Tab */
|
||||
#permList {
|
||||
margin: .5em;
|
||||
|
|
|
@ -51,11 +51,6 @@ menuitem[appHandlerIcon="save"] {
|
|||
list-style-image: url("chrome://browser/skin/preferences/saveFile.png");
|
||||
}
|
||||
|
||||
richlistitem[appHandlerIcon="feed"],
|
||||
menuitem[appHandlerIcon="feed"] {
|
||||
list-style-image: url("chrome://browser/skin/page-livemarks.png");
|
||||
}
|
||||
|
||||
richlistitem[appHandlerIcon="plugin"],
|
||||
menuitem[appHandlerIcon="plugin"] {
|
||||
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.svg");
|
||||
|
|
|
@ -882,11 +882,6 @@ notification[value="translation"] {
|
|||
}
|
||||
|
||||
/* Bookmarks roots menu-items */
|
||||
#subscribeToPageMenuitem:not([disabled]),
|
||||
#subscribeToPageMenupopup {
|
||||
list-style-image: url("chrome://browser/skin/feeds/feedIcon16.png");
|
||||
}
|
||||
|
||||
#bookmarksToolbarFolderMenu,
|
||||
#BMB_bookmarksToolbar,
|
||||
#panelMenu_bookmarksToolbar {
|
||||
|
|
Двоичные данные
browser/themes/windows/feeds/feedIcon.png
До Ширина: | Высота: | Размер: 1.7 KiB |
Двоичные данные
browser/themes/windows/feeds/feedIcon16.png
До Ширина: | Высота: | Размер: 743 B |
|
@ -1,184 +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/. */
|
||||
|
||||
html {
|
||||
background: -moz-Dialog;
|
||||
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;
|
||||
padding-inline-start: 30px;
|
||||
margin: 2em auto;
|
||||
background: -moz-Field;
|
||||
}
|
||||
|
||||
#feedHeaderContainer {
|
||||
border: 1px solid ThreeDShadow;
|
||||
border-radius: 10px;
|
||||
margin: -4em auto 0 auto;
|
||||
background-color: InfoBackground;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#feedHeaderContainerSpacer {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
#feedHeader {
|
||||
margin-top: 4.9em;
|
||||
margin-bottom: 1em;
|
||||
margin-inline-start: 1.4em;
|
||||
margin-inline-end: 1em;
|
||||
padding-inline-start: 2.9em;
|
||||
font-size: 110%;
|
||||
color: InfoText;
|
||||
}
|
||||
|
||||
#feedIntroText {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.feedBackground {
|
||||
background: url("chrome://browser/skin/feeds/feedIcon.png") 0% 10% no-repeat InfoBackground;
|
||||
}
|
||||
|
||||
.videoPodcastBackground {
|
||||
background: url("chrome://browser/skin/feeds/videoFeedIcon.png") 0% 10% no-repeat InfoBackground;
|
||||
}
|
||||
|
||||
.audioPodcastBackground {
|
||||
background: url("chrome://browser/skin/feeds/audioFeedIcon.png") 0% 10% no-repeat InfoBackground;
|
||||
}
|
||||
|
||||
#feedHeader[dir="rtl"] {
|
||||
background-position: 100% 10%;
|
||||
}
|
||||
|
||||
#feedHeader[firstrun="true"] #feedIntroText {
|
||||
padding-top: 0.1em;
|
||||
padding-inline-start: 0.6em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#feedHeader[firstrun="true"] > #feedSubscribeLine {
|
||||
padding-inline-start: 1.8em;
|
||||
}
|
||||
|
||||
#feedSubscribeLine {
|
||||
padding-top: 0.2em;
|
||||
padding-inline-start: 0.5em;
|
||||
}
|
||||
|
||||
/* Don't print subscription UI */
|
||||
@media print {
|
||||
#feedHeaderContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 3em;
|
||||
color: -moz-fieldText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 160%;
|
||||
border-bottom: 2px solid ThreeDLightShadow;
|
||||
margin: 0 0 .2em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: GrayText;
|
||||
font-size: 110%;
|
||||
font-weight: normal;
|
||||
margin: 0 0 .6em 0;
|
||||
}
|
||||
|
||||
#feedTitleLink {
|
||||
float: right;
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a[href] img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
#feedTitleContainer {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: .6em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#feedTitleImage {
|
||||
margin-inline-start: .6em;
|
||||
margin-inline-end: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
max-width: 300px;
|
||||
max-height: 150px;
|
||||
}
|
||||
|
||||
.feedEntryContent {
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0000FF;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.link:hover:active {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.lastUpdated {
|
||||
font-size: 85%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.type-icon {
|
||||
vertical-align: bottom;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.enclosures {
|
||||
border: 1px solid THreeDShadow;
|
||||
padding: 1em;
|
||||
margin: 1em auto;
|
||||
background: -moz-Dialog;
|
||||
}
|
||||
|
||||
.enclosure {
|
||||
vertical-align: middle;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.handlersMenuList > .menulist-label-box > .menulist-icon {
|
||||
max-width: 16px;
|
||||
max-height: 16px;
|
||||
}
|
|
@ -21,9 +21,6 @@ browser.jar:
|
|||
* skin/classic/browser/customizableui/panelUI.css (customizableui/panelUI.css)
|
||||
* skin/classic/browser/downloads/allDownloadsView.css (downloads/allDownloadsView.css)
|
||||
* skin/classic/browser/downloads/downloads.css (downloads/downloads.css)
|
||||
skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png)
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/notification-icons/geo-blocked.svg (notification-icons/geo-blocked.svg)
|
||||
skin/classic/browser/notification-icons/geo-detailed.svg (notification-icons/geo-detailed.svg)
|
||||
skin/classic/browser/notification-icons/geo.svg (notification-icons/geo.svg)
|
||||
|
@ -55,9 +52,3 @@ browser.jar:
|
|||
skin/classic/browser/window-controls/restore-highcontrast.svg (window-controls/restore-highcontrast.svg)
|
||||
skin/classic/browser/window-controls/restore-themes.svg (window-controls/restore-themes.svg)
|
||||
skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
|
||||
|
||||
% override chrome://browser/skin/page-livemarks.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon16.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
% override chrome://browser/skin/feeds/videoFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
% override chrome://browser/skin/feeds/videoFeedIcon16.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
|
|
|
@ -58,15 +58,6 @@
|
|||
-moz-image-region: rect(32px, 64px, 64px, 32px)
|
||||
}
|
||||
|
||||
#feedTab {
|
||||
-moz-image-region: rect(0px, 96px, 32px, 64px)
|
||||
}
|
||||
|
||||
#feedTab:hover,
|
||||
#feedTab[selected="true"] {
|
||||
-moz-image-region: rect(32px, 96px, 64px, 64px)
|
||||
}
|
||||
|
||||
#permTab {
|
||||
-moz-image-region: rect(0px, 128px, 32px, 96px)
|
||||
}
|
||||
|
@ -161,29 +152,6 @@ treechildren::-moz-tree-cell-text(broken) {
|
|||
color: graytext;
|
||||
}
|
||||
|
||||
/* Feeds Tab */
|
||||
#feedtree {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
#feedListbox richlistitem {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
padding-inline-start: 7px;
|
||||
padding-inline-end: 7px;
|
||||
min-height: 25px;
|
||||
border-bottom: 1px dotted ThreeDShadow;
|
||||
}
|
||||
|
||||
#feedListbox richlistitem[selected="true"] {
|
||||
background-color: -moz-Dialog;
|
||||
color: -moz-DialogText;
|
||||
}
|
||||
|
||||
.feedTitle {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Permissions Tab */
|
||||
#permList {
|
||||
margin: .5em;
|
||||
|
|
|
@ -40,11 +40,6 @@ menuitem[appHandlerIcon="save"] {
|
|||
list-style-image: url("chrome://browser/skin/preferences/saveFile.png");
|
||||
}
|
||||
|
||||
richlistitem[appHandlerIcon="feed"],
|
||||
menuitem[appHandlerIcon="feed"] {
|
||||
list-style-image: url("chrome://browser/skin/page-livemarks.png");
|
||||
}
|
||||
|
||||
richlistitem[appHandlerIcon="plugin"],
|
||||
menuitem[appHandlerIcon="plugin"] {
|
||||
list-style-image: url("chrome://mozapps/skin/plugins/pluginGeneric.svg");
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct FeedWriterEnabled {
|
||||
static bool IsEnabled(JSContext* cx, JSObject* aGlobal)
|
||||
{
|
||||
return nsContentUtils::IsSpecificAboutPage(aGlobal, "about:feeds");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -129,7 +129,6 @@ if CONFIG['MOZ_WEBRTC']:
|
|||
|
||||
EXPORTS.mozilla += [
|
||||
'CORSMode.h',
|
||||
'FeedWriterEnabled.h',
|
||||
'FlushType.h',
|
||||
'FullscreenChange.h',
|
||||
'RangeBoundary.h',
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*/
|
||||
|
||||
[JSImplementation="@mozilla.org/browser/feeds/result-writer;1",
|
||||
Func="mozilla::FeedWriterEnabled::IsEnabled",
|
||||
Constructor]
|
||||
interface BrowserFeedWriter {
|
||||
/**
|
||||
* Writes the feed content, assumes that the feed writer is initialized.
|
||||
*/
|
||||
void writeContent();
|
||||
|
||||
/**
|
||||
* Uninitialize the feed writer.
|
||||
*/
|
||||
void close();
|
||||
};
|
|
@ -1091,11 +1091,6 @@ if CONFIG['MOZ_WEBSPEECH']:
|
|||
'SpeechSynthesisEvent.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_BUILD_APP'] in ['browser', 'xulrunner'] or CONFIG['MOZ_SUITE']:
|
||||
WEBIDL_FILES += [
|
||||
'BrowserFeedWriter.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
|
||||
WEBIDL_FILES += [
|
||||
'External.webidl',
|
||||
|
|
|
@ -20,7 +20,6 @@ module.exports = {
|
|||
"globals": {
|
||||
"AddonManagerPermissions": false,
|
||||
"BroadcastChannel": false,
|
||||
"BrowserFeedWriter": false,
|
||||
"CSSAnimation": false,
|
||||
"CSSPrimitiveValue": false,
|
||||
"CSSValueList": false,
|
||||
|
|