diff -r 000000000000 -r 6474c204b198 browser/base/content/browser-feeds.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/browser/base/content/browser-feeds.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,171 @@ +# -*- 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 = { + /** Called when the user clicks on the Subscribe to This Page... menu item, + * or when the user clicks the feed button when the page contains multiple + * feeds. + * 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 container + * The feed list container (menupopup or subview) to be populated. + * @param isSubview + * Whether we're creating a subview (true) or menu (false/undefined) + * @returns true if the menu/subview should be shown, false if there was only + * one feed and the feed should be shown inline in the browser + * window (do not show the menupopup/subview). + */ + buildFeedList: function(container, isSubview) { + var feeds = gBrowser.selectedBrowser.feeds; + if (!isSubview && feeds == null) { + // XXX hack -- menu opening depends on setting of an "open" + // attribute, and the menu refuses to open if that attribute is + // 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. + container.parentNode.removeAttribute("open"); + return false; + } + + for (let i = container.childNodes.length - 1; i >= 0; --i) { + let node = container.childNodes[i]; + if (isSubview && node.localName == "label") + continue; + container.removeChild(node); + } + + if (!feeds || feeds.length <= 1) + return false; + + // Build the menu showing the available feed choices for viewing. + var itemNodeType = isSubview ? "toolbarbutton" : "menuitem"; + for (let feedInfo of feeds) { + var item = document.createElement(itemNodeType); + var baseTitle = feedInfo.title || feedInfo.href; + var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]); + item.setAttribute("label", labelStr); + item.setAttribute("feed", feedInfo.href); + item.setAttribute("tooltiptext", feedInfo.href); + item.setAttribute("crop", "center"); + let className = "feed-" + itemNodeType; + if (isSubview) { + className += " subviewbutton"; + } + item.setAttribute("class", className); + container.appendChild(item); + } + 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 (or subview) + * 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 feedButton = document.getElementById("feed-button"); + if (feedButton) { + if (haveFeeds) { + feedButton.removeAttribute("disabled"); + } else { + feedButton.setAttribute("disabled", "true"); + } + } + + if (!haveFeeds) { + this._feedMenuitem.setAttribute("disabled", "true"); + this._feedMenuitem.removeAttribute("hidden"); + this._feedMenupopup.setAttribute("hidden", "true"); + return; + } + + if (feeds.length > 1) { + this._feedMenuitem.setAttribute("hidden", "true"); + this._feedMenupopup.removeAttribute("hidden"); + } else { + this._feedMenuitem.setAttribute("feed", feeds[0].href); + this._feedMenuitem.removeAttribute("disabled"); + this._feedMenuitem.removeAttribute("hidden"); + this._feedMenupopup.setAttribute("hidden", "true"); + } + }, + + addFeed: function(link, browserForLink) { + 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) { + // 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); + } + } +};