|
1 # -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 # This Source Code Form is subject to the terms of the Mozilla Public |
|
3 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
5 |
|
6 /** |
|
7 * The Feed Handler object manages discovery of RSS/ATOM feeds in web pages |
|
8 * and shows UI when they are discovered. |
|
9 */ |
|
10 var FeedHandler = { |
|
11 /** Called when the user clicks on the Subscribe to This Page... menu item, |
|
12 * or when the user clicks the feed button when the page contains multiple |
|
13 * feeds. |
|
14 * Builds a menu of unique feeds associated with the page, and if there |
|
15 * is only one, shows the feed inline in the browser window. |
|
16 * @param container |
|
17 * The feed list container (menupopup or subview) to be populated. |
|
18 * @param isSubview |
|
19 * Whether we're creating a subview (true) or menu (false/undefined) |
|
20 * @returns true if the menu/subview should be shown, false if there was only |
|
21 * one feed and the feed should be shown inline in the browser |
|
22 * window (do not show the menupopup/subview). |
|
23 */ |
|
24 buildFeedList: function(container, isSubview) { |
|
25 var feeds = gBrowser.selectedBrowser.feeds; |
|
26 if (!isSubview && feeds == null) { |
|
27 // XXX hack -- menu opening depends on setting of an "open" |
|
28 // attribute, and the menu refuses to open if that attribute is |
|
29 // set (because it thinks it's already open). onpopupshowing gets |
|
30 // called after the attribute is unset, and it doesn't get unset |
|
31 // if we return false. so we unset it here; otherwise, the menu |
|
32 // refuses to work past this point. |
|
33 container.parentNode.removeAttribute("open"); |
|
34 return false; |
|
35 } |
|
36 |
|
37 for (let i = container.childNodes.length - 1; i >= 0; --i) { |
|
38 let node = container.childNodes[i]; |
|
39 if (isSubview && node.localName == "label") |
|
40 continue; |
|
41 container.removeChild(node); |
|
42 } |
|
43 |
|
44 if (!feeds || feeds.length <= 1) |
|
45 return false; |
|
46 |
|
47 // Build the menu showing the available feed choices for viewing. |
|
48 var itemNodeType = isSubview ? "toolbarbutton" : "menuitem"; |
|
49 for (let feedInfo of feeds) { |
|
50 var item = document.createElement(itemNodeType); |
|
51 var baseTitle = feedInfo.title || feedInfo.href; |
|
52 var labelStr = gNavigatorBundle.getFormattedString("feedShowFeedNew", [baseTitle]); |
|
53 item.setAttribute("label", labelStr); |
|
54 item.setAttribute("feed", feedInfo.href); |
|
55 item.setAttribute("tooltiptext", feedInfo.href); |
|
56 item.setAttribute("crop", "center"); |
|
57 let className = "feed-" + itemNodeType; |
|
58 if (isSubview) { |
|
59 className += " subviewbutton"; |
|
60 } |
|
61 item.setAttribute("class", className); |
|
62 container.appendChild(item); |
|
63 } |
|
64 return true; |
|
65 }, |
|
66 |
|
67 /** |
|
68 * Subscribe to a given feed. Called when |
|
69 * 1. Page has a single feed and user clicks feed icon in location bar |
|
70 * 2. Page has a single feed and user selects Subscribe menu item |
|
71 * 3. Page has multiple feeds and user selects from feed icon popup (or subview) |
|
72 * 4. Page has multiple feeds and user selects from Subscribe submenu |
|
73 * @param href |
|
74 * The feed to subscribe to. May be null, in which case the |
|
75 * event target's feed attribute is examined. |
|
76 * @param event |
|
77 * The event this method is handling. Used to decide where |
|
78 * to open the preview UI. (Optional, unless href is null) |
|
79 */ |
|
80 subscribeToFeed: function(href, event) { |
|
81 // Just load the feed in the content area to either subscribe or show the |
|
82 // preview UI |
|
83 if (!href) |
|
84 href = event.target.getAttribute("feed"); |
|
85 urlSecurityCheck(href, gBrowser.contentPrincipal, |
|
86 Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL); |
|
87 var feedURI = makeURI(href, document.characterSet); |
|
88 // Use the feed scheme so X-Moz-Is-Feed will be set |
|
89 // The value doesn't matter |
|
90 if (/^https?$/.test(feedURI.scheme)) |
|
91 href = "feed:" + href; |
|
92 this.loadFeed(href, event); |
|
93 }, |
|
94 |
|
95 loadFeed: function(href, event) { |
|
96 var feeds = gBrowser.selectedBrowser.feeds; |
|
97 try { |
|
98 openUILink(href, event, { ignoreAlt: true }); |
|
99 } |
|
100 finally { |
|
101 // We might default to a livebookmarks modal dialog, |
|
102 // so reset that if the user happens to click it again |
|
103 gBrowser.selectedBrowser.feeds = feeds; |
|
104 } |
|
105 }, |
|
106 |
|
107 get _feedMenuitem() { |
|
108 delete this._feedMenuitem; |
|
109 return this._feedMenuitem = document.getElementById("singleFeedMenuitemState"); |
|
110 }, |
|
111 |
|
112 get _feedMenupopup() { |
|
113 delete this._feedMenupopup; |
|
114 return this._feedMenupopup = document.getElementById("multipleFeedsMenuState"); |
|
115 }, |
|
116 |
|
117 /** |
|
118 * Update the browser UI to show whether or not feeds are available when |
|
119 * a page is loaded or the user switches tabs to a page that has feeds. |
|
120 */ |
|
121 updateFeeds: function() { |
|
122 if (this._updateFeedTimeout) |
|
123 clearTimeout(this._updateFeedTimeout); |
|
124 |
|
125 var feeds = gBrowser.selectedBrowser.feeds; |
|
126 var haveFeeds = feeds && feeds.length > 0; |
|
127 |
|
128 var feedButton = document.getElementById("feed-button"); |
|
129 if (feedButton) { |
|
130 if (haveFeeds) { |
|
131 feedButton.removeAttribute("disabled"); |
|
132 } else { |
|
133 feedButton.setAttribute("disabled", "true"); |
|
134 } |
|
135 } |
|
136 |
|
137 if (!haveFeeds) { |
|
138 this._feedMenuitem.setAttribute("disabled", "true"); |
|
139 this._feedMenuitem.removeAttribute("hidden"); |
|
140 this._feedMenupopup.setAttribute("hidden", "true"); |
|
141 return; |
|
142 } |
|
143 |
|
144 if (feeds.length > 1) { |
|
145 this._feedMenuitem.setAttribute("hidden", "true"); |
|
146 this._feedMenupopup.removeAttribute("hidden"); |
|
147 } else { |
|
148 this._feedMenuitem.setAttribute("feed", feeds[0].href); |
|
149 this._feedMenuitem.removeAttribute("disabled"); |
|
150 this._feedMenuitem.removeAttribute("hidden"); |
|
151 this._feedMenupopup.setAttribute("hidden", "true"); |
|
152 } |
|
153 }, |
|
154 |
|
155 addFeed: function(link, browserForLink) { |
|
156 if (!browserForLink.feeds) |
|
157 browserForLink.feeds = []; |
|
158 |
|
159 browserForLink.feeds.push({ href: link.href, title: link.title }); |
|
160 |
|
161 // If this addition was for the current browser, update the UI. For |
|
162 // background browsers, we'll update on tab switch. |
|
163 if (browserForLink == gBrowser.selectedBrowser) { |
|
164 // Batch updates to avoid updating the UI for multiple onLinkAdded events |
|
165 // fired within 100ms of each other. |
|
166 if (this._updateFeedTimeout) |
|
167 clearTimeout(this._updateFeedTimeout); |
|
168 this._updateFeedTimeout = setTimeout(this.updateFeeds.bind(this), 100); |
|
169 } |
|
170 } |
|
171 }; |