# -*- 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); } } };