1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/browser-feeds.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,171 @@ 1.4 +# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 +# This Source Code Form is subject to the terms of the Mozilla Public 1.6 +# License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 +# file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.8 + 1.9 +/** 1.10 + * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages 1.11 + * and shows UI when they are discovered. 1.12 + */ 1.13 +var FeedHandler = { 1.14 + /** Called when the user clicks on the Subscribe to This Page... menu item, 1.15 + * or when the user clicks the feed button when the page contains multiple 1.16 + * feeds. 1.17 + * Builds a menu of unique feeds associated with the page, and if there 1.18 + * is only one, shows the feed inline in the browser window. 1.19 + * @param container 1.20 + * The feed list container (menupopup or subview) to be populated. 1.21 + * @param isSubview 1.22 + * Whether we're creating a subview (true) or menu (false/undefined) 1.23 + * @returns true if the menu/subview should be shown, false if there was only 1.24 + * one feed and the feed should be shown inline in the browser 1.25 + * window (do not show the menupopup/subview). 1.26 + */ 1.27 + buildFeedList: function(container, isSubview) { 1.28 + var feeds = gBrowser.selectedBrowser.feeds; 1.29 + if (!isSubview && feeds == null) { 1.30 + // XXX hack -- menu opening depends on setting of an "open" 1.31 + // attribute, and the menu refuses to open if that attribute is 1.32 + // set (because it thinks it's already open). onpopupshowing gets 1.33 + // called after the attribute is unset, and it doesn't get unset 1.34 + // if we return false. so we unset it here; otherwise, the menu 1.35 + // refuses to work past this point. 1.36 + container.parentNode.removeAttribute("open"); 1.37 + return false; 1.38 + } 1.39 + 1.40 + for (let i = container.childNodes.length - 1; i >= 0; --i) { 1.41 + let node = container.childNodes[i]; 1.42 + if (isSubview && node.localName == "label") 1.43 + continue; 1.44 + container.removeChild(node); 1.45 + } 1.46 + 1.47 + if (!feeds || feeds.length <= 1) 1.48 + return false; 1.49 + 1.50 + // Build the menu showing the available feed choices for viewing. 1.51 + var itemNodeType = isSubview ? "toolbarbutton" : "menuitem"; 1.52 + for (let feedInfo of feeds) { 1.53 + var item = document.createElement(itemNodeType); 1.54 + var baseTitle = feedInfo.title || feedInfo.href; 1.55 + var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]); 1.56 + item.setAttribute("label", labelStr); 1.57 + item.setAttribute("feed", feedInfo.href); 1.58 + item.setAttribute("tooltiptext", feedInfo.href); 1.59 + item.setAttribute("crop", "center"); 1.60 + let className = "feed-" + itemNodeType; 1.61 + if (isSubview) { 1.62 + className += " subviewbutton"; 1.63 + } 1.64 + item.setAttribute("class", className); 1.65 + container.appendChild(item); 1.66 + } 1.67 + return true; 1.68 + }, 1.69 + 1.70 + /** 1.71 + * Subscribe to a given feed. Called when 1.72 + * 1. Page has a single feed and user clicks feed icon in location bar 1.73 + * 2. Page has a single feed and user selects Subscribe menu item 1.74 + * 3. Page has multiple feeds and user selects from feed icon popup (or subview) 1.75 + * 4. Page has multiple feeds and user selects from Subscribe submenu 1.76 + * @param href 1.77 + * The feed to subscribe to. May be null, in which case the 1.78 + * event target's feed attribute is examined. 1.79 + * @param event 1.80 + * The event this method is handling. Used to decide where 1.81 + * to open the preview UI. (Optional, unless href is null) 1.82 + */ 1.83 + subscribeToFeed: function(href, event) { 1.84 + // Just load the feed in the content area to either subscribe or show the 1.85 + // preview UI 1.86 + if (!href) 1.87 + href = event.target.getAttribute("feed"); 1.88 + urlSecurityCheck(href, gBrowser.contentPrincipal, 1.89 + Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL); 1.90 + var feedURI = makeURI(href, document.characterSet); 1.91 + // Use the feed scheme so X-Moz-Is-Feed will be set 1.92 + // The value doesn't matter 1.93 + if (/^https?$/.test(feedURI.scheme)) 1.94 + href = "feed:" + href; 1.95 + this.loadFeed(href, event); 1.96 + }, 1.97 + 1.98 + loadFeed: function(href, event) { 1.99 + var feeds = gBrowser.selectedBrowser.feeds; 1.100 + try { 1.101 + openUILink(href, event, { ignoreAlt: true }); 1.102 + } 1.103 + finally { 1.104 + // We might default to a livebookmarks modal dialog, 1.105 + // so reset that if the user happens to click it again 1.106 + gBrowser.selectedBrowser.feeds = feeds; 1.107 + } 1.108 + }, 1.109 + 1.110 + get _feedMenuitem() { 1.111 + delete this._feedMenuitem; 1.112 + return this._feedMenuitem = document.getElementById("singleFeedMenuitemState"); 1.113 + }, 1.114 + 1.115 + get _feedMenupopup() { 1.116 + delete this._feedMenupopup; 1.117 + return this._feedMenupopup = document.getElementById("multipleFeedsMenuState"); 1.118 + }, 1.119 + 1.120 + /** 1.121 + * Update the browser UI to show whether or not feeds are available when 1.122 + * a page is loaded or the user switches tabs to a page that has feeds. 1.123 + */ 1.124 + updateFeeds: function() { 1.125 + if (this._updateFeedTimeout) 1.126 + clearTimeout(this._updateFeedTimeout); 1.127 + 1.128 + var feeds = gBrowser.selectedBrowser.feeds; 1.129 + var haveFeeds = feeds && feeds.length > 0; 1.130 + 1.131 + var feedButton = document.getElementById("feed-button"); 1.132 + if (feedButton) { 1.133 + if (haveFeeds) { 1.134 + feedButton.removeAttribute("disabled"); 1.135 + } else { 1.136 + feedButton.setAttribute("disabled", "true"); 1.137 + } 1.138 + } 1.139 + 1.140 + if (!haveFeeds) { 1.141 + this._feedMenuitem.setAttribute("disabled", "true"); 1.142 + this._feedMenuitem.removeAttribute("hidden"); 1.143 + this._feedMenupopup.setAttribute("hidden", "true"); 1.144 + return; 1.145 + } 1.146 + 1.147 + if (feeds.length > 1) { 1.148 + this._feedMenuitem.setAttribute("hidden", "true"); 1.149 + this._feedMenupopup.removeAttribute("hidden"); 1.150 + } else { 1.151 + this._feedMenuitem.setAttribute("feed", feeds[0].href); 1.152 + this._feedMenuitem.removeAttribute("disabled"); 1.153 + this._feedMenuitem.removeAttribute("hidden"); 1.154 + this._feedMenupopup.setAttribute("hidden", "true"); 1.155 + } 1.156 + }, 1.157 + 1.158 + addFeed: function(link, browserForLink) { 1.159 + if (!browserForLink.feeds) 1.160 + browserForLink.feeds = []; 1.161 + 1.162 + browserForLink.feeds.push({ href: link.href, title: link.title }); 1.163 + 1.164 + // If this addition was for the current browser, update the UI. For 1.165 + // background browsers, we'll update on tab switch. 1.166 + if (browserForLink == gBrowser.selectedBrowser) { 1.167 + // Batch updates to avoid updating the UI for multiple onLinkAdded events 1.168 + // fired within 100ms of each other. 1.169 + if (this._updateFeedTimeout) 1.170 + clearTimeout(this._updateFeedTimeout); 1.171 + this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100); 1.172 + } 1.173 + } 1.174 +};