diff options
Diffstat (limited to 'base/content/browser-feeds.js')
-rw-r--r-- | base/content/browser-feeds.js | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/base/content/browser-feeds.js b/base/content/browser-feeds.js new file mode 100644 index 0000000..c678772 --- /dev/null +++ b/base/content/browser-feeds.js @@ -0,0 +1,224 @@ +# -*- 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); + } + } +}; |