summaryrefslogtreecommitdiff
path: root/browser/base/content/browser-feeds.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/base/content/browser-feeds.js')
-rw-r--r--browser/base/content/browser-feeds.js236
1 files changed, 236 insertions, 0 deletions
diff --git a/browser/base/content/browser-feeds.js b/browser/base/content/browser-feeds.js
new file mode 100644
index 000000000..a93f446b9
--- /dev/null
+++ b/browser/base/content/browser-feeds.js
@@ -0,0 +1,236 @@
+# -*- Mode: javascript; 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/.
+
+/**
+ * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages
+ * and shows UI when they are discovered.
+ */
+var FeedHandler = {
+
+ /* Pale Moon: Address Bar: Feeds
+ * The click handler for the Feed icon in the location bar. Opens the
+ * subscription page if user is not given a choice of feeds.
+ * (Otherwise the list of available feeds will be presented to the
+ * user in a popup menu.)
+ */
+ onFeedButtonPMClick: function(event) {
+ event.stopPropagation();
+
+ if (event.target.hasAttribute("feed") &&
+ event.eventPhase == Event.AT_TARGET &&
+ (event.button == 0 || event.button == 1)) {
+ this.subscribeToFeed(null, event);
+ }
+ },
+
+ /**
+ * The click handler for the Feed icon in the toolbar. Opens the
+ * subscription page if user is not given a choice of feeds.
+ * (Otherwise the list of available feeds will be presented to the
+ * user in a popup menu.)
+ */
+ onFeedButtonClick: function(event) {
+ event.stopPropagation();
+
+ let feeds = gBrowser.selectedBrowser.feeds || [];
+ // If there are multiple feeds, the menu will open, so no need to do
+ // anything. If there are no feeds, nothing to do either.
+ if (feeds.length != 1) {
+ return;
+ }
+
+ if (event.eventPhase == Event.AT_TARGET &&
+ (event.button == 0 || event.button == 1)) {
+ this.subscribeToFeed(feeds[0].href, event);
+ }
+ },
+
+ /** Called when the user clicks on the Subscribe to This Page... menu item.
+ * Builds a menu of unique feeds associated with the page, and if there
+ * is only one, shows the feed inline in the browser window.
+ * @param menuPopup
+ * The feed list menupopup to be populated.
+ * @returns true if the menu should be shown, false if there was only
+ * one feed and the feed should be shown inline in the browser
+ * window (do not show the menupopup).
+ */
+ buildFeedList: function(menuPopup) {
+ var feeds = gBrowser.selectedBrowser.feeds;
+ if (feeds == null) {
+ // XXX hack -- menu opening depends on setting of an "open"
+ // attribute, and the menu refuses to open if that attribute is
+ // set (because it thinks it's already open). onpopupshowing gets
+ // called after the attribute is unset, and it doesn't get unset
+ // if we return false. so we unset it here; otherwise, the menu
+ // refuses to work past this point.
+ menuPopup.parentNode.removeAttribute("open");
+ return false;
+ }
+
+ while (menuPopup.firstChild) {
+ menuPopup.removeChild(menuPopup.firstChild);
+ }
+
+ if (feeds.length == 1) {
+ var feedButtonPM = document.getElementById("ub-feed-button");
+ if (feedButtonPM) {
+ feedButtonPM.setAttribute("feed", feeds[0].href);
+ }
+ return false;
+ }
+
+ if (feeds.length <= 1) {
+ return false;
+ }
+
+ // Build the menu showing the available feed choices for viewing.
+ for (let feedInfo of feeds) {
+ var menuItem = document.createElement("menuitem");
+ var baseTitle = feedInfo.title || feedInfo.href;
+ var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]);
+ menuItem.setAttribute("class", "feed-menuitem");
+ menuItem.setAttribute("label", labelStr);
+ menuItem.setAttribute("feed", feedInfo.href);
+ menuItem.setAttribute("tooltiptext", feedInfo.href);
+ menuItem.setAttribute("crop", "center");
+ menuPopup.appendChild(menuItem);
+ }
+ return true;
+ },
+
+ /**
+ * Subscribe to a given feed. Called when
+ * 1. Page has a single feed and user clicks feed icon in location bar
+ * 2. Page has a single feed and user selects Subscribe menu item
+ * 3. Page has multiple feeds and user selects from feed icon popup
+ * 4. Page has multiple feeds and user selects from Subscribe submenu
+ * @param href
+ * The feed to subscribe to. May be null, in which case the
+ * event target's feed attribute is examined.
+ * @param event
+ * The event this method is handling. Used to decide where
+ * to open the preview UI. (Optional, unless href is null)
+ */
+ subscribeToFeed: function(href, event) {
+ // Just load the feed in the content area to either subscribe or show the
+ // preview UI
+ if (!href) {
+ href = event.target.getAttribute("feed");
+ }
+ urlSecurityCheck(href, gBrowser.contentPrincipal,
+ Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
+ var feedURI = makeURI(href, document.characterSet);
+ // Use the feed scheme so X-Moz-Is-Feed will be set
+ // The value doesn't matter
+ if (/^https?$/.test(feedURI.scheme)) {
+ href = "feed:" + href;
+ }
+ this.loadFeed(href, event);
+ },
+
+ loadFeed: function(href, event) {
+ var feeds = gBrowser.selectedBrowser.feeds;
+ try {
+ openUILink(href, event, { ignoreAlt: true });
+ } finally {
+ // We might default to a livebookmarks modal dialog,
+ // so reset that if the user happens to click it again
+ gBrowser.selectedBrowser.feeds = feeds;
+ }
+ },
+
+ get _feedMenuitem() {
+ delete this._feedMenuitem;
+ return this._feedMenuitem = document.getElementById("singleFeedMenuitemState");
+ },
+
+ get _feedMenupopup() {
+ delete this._feedMenupopup;
+ return this._feedMenupopup = document.getElementById("multipleFeedsMenuState");
+ },
+
+ /**
+ * Update the browser UI to show whether or not feeds are available when
+ * a page is loaded or the user switches tabs to a page that has feeds.
+ */
+ updateFeeds: function() {
+ if (this._updateFeedTimeout) {
+ clearTimeout(this._updateFeedTimeout);
+ }
+
+ var feeds = gBrowser.selectedBrowser.feeds;
+ var haveFeeds = feeds && feeds.length > 0;
+
+ var feedButtonPM = document.getElementById("ub-feed-button");
+
+ var feedButton = document.getElementById("feed-button");
+
+ if (feedButton) {
+ feedButton.disabled = !haveFeeds;
+ }
+
+ if (feedButtonPM) {
+ if (!haveFeeds) {
+ feedButtonPM.collapsed = true;
+ feedButtonPM.removeAttribute("feed");
+ } else {
+ feedButtonPM.collapsed = !gPrefService.getBoolPref("browser.urlbar.rss");
+ }
+ }
+
+ if (!haveFeeds) {
+ this._feedMenuitem.setAttribute("disabled", "true");
+ this._feedMenuitem.removeAttribute("hidden");
+ this._feedMenupopup.setAttribute("hidden", "true");
+ return;
+ }
+
+ if (feeds.length > 1) {
+ if (feedButtonPM) {
+ feedButtonPM.removeAttribute("feed");
+ }
+ this._feedMenuitem.setAttribute("hidden", "true");
+ this._feedMenupopup.removeAttribute("hidden");
+ } else {
+ if (feedButtonPM) {
+ feedButtonPM.setAttribute("feed", feeds[0].href);
+ }
+ this._feedMenuitem.setAttribute("feed", feeds[0].href);
+ this._feedMenuitem.removeAttribute("disabled");
+ this._feedMenuitem.removeAttribute("hidden");
+ this._feedMenupopup.setAttribute("hidden", "true");
+ }
+ },
+
+ addFeed: function(link, targetDoc) {
+ // find which tab this is for, and set the attribute on the browser
+ var browserForLink = gBrowser.getBrowserForDocument(targetDoc);
+ if (!browserForLink) {
+ // ignore feeds loaded in subframes (see bug 305472)
+ return;
+ }
+
+ if (!browserForLink.feeds) {
+ browserForLink.feeds = [];
+ }
+
+ browserForLink.feeds.push({ href: link.href, title: link.title });
+
+ // If this addition was for the current browser, update the UI. For
+ // background browsers, we'll update on tab switch.
+ if (browserForLink == gBrowser.selectedBrowser) {
+ var feedButtonPM = document.getElementById("ub-feed-button");
+ if (feedButtonPM) {
+ feedButtonPM.collapsed = !gPrefService.getBoolPref("browser.urlbar.rss");
+ }
+ // Batch updates to avoid updating the UI for multiple onLinkAdded events
+ // fired within 100ms of each other.
+ if (this._updateFeedTimeout) {
+ clearTimeout(this._updateFeedTimeout);
+ }
+ this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100);
+ }
+ }
+};