1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Grab the querystring, removing question mark at the front and splitting on
7 var queryString = location.search.substring(1).split("&");
9 // The feed URL is the first component and always present.
10 var feedUrl = decodeURIComponent(queryString[0]);
12 // We allow synchronous requests for testing. This component is only present
14 var synchronousRequest = queryString[1] == "synchronous";
16 // The XMLHttpRequest object that tries to load and parse the feed, and (if
17 // testing) also the style sheet and the frame js.
20 // Depending on whether this is run from a test or from the extension, this
21 // will either be a link to the css file within the extension or contain the
22 // contents of the style sheet, fetched through XmlHttpRequest.
25 // Depending on whether this is run from a test or from the extension, this
26 // will either be a link to the js file within the extension or contain the
27 // contents of the style sheet, fetched through XmlHttpRequest.
30 // What to show when we cannot parse the feed name.
31 var unknownName = chrome.i18n.getMessage("rss_subscription_unknown_feed_name");
33 // A list of feed readers, populated by localStorage if available, otherwise
37 // Navigates to the reader of the user's choice (for subscribing to the feed).
39 var select = document.getElementById('readerDropdown');
41 feedReaderList[select.selectedIndex].url.replace(
42 "%s", encodeURIComponent(feedUrl));
44 // Before we navigate, see if we want to skip this step in the future...
46 // See if the user wants to always use this reader.
47 var alwaysUse = document.getElementById('alwaysUse');
48 if (alwaysUse.checked) {
49 window.localStorage.defaultReader =
50 feedReaderList[select.selectedIndex].url;
51 window.localStorage.showPreviewPage = "No";
55 document.location = url;
59 * The main function. Sets up the selection list for possible readers and
63 if (storageEnabled && window.localStorage.readerList)
64 feedReaderList = JSON.parse(window.localStorage.readerList);
66 feedReaderList = defaultReaderList();
68 // Populate the list of readers.
69 var readerDropdown = document.getElementById('readerDropdown');
70 for (i = 0; i < feedReaderList.length; ++i) {
71 readerDropdown.options[i] = new Option(feedReaderList[i].description, i);
72 if (storageEnabled && isDefaultReader(feedReaderList[i].url))
73 readerDropdown.selectedIndex = i;
77 // Add the "Manage..." entry to the dropdown and show the checkbox asking
78 // if we always want to use this reader in the future (skip the preview).
79 readerDropdown.options[i] =
80 new Option(chrome.i18n.getMessage("rss_subscription_manage_label"), "");
81 document.getElementById('alwaysUseSpan').style.display = "block";
84 // Now fetch the data.
85 req = new XMLHttpRequest();
86 if (synchronousRequest) {
87 // Tests that load the html page directly through a file:// url don't have
88 // access to the js and css from the frame so we must load them first and
89 // inject them into the src for the iframe.
90 req.open("GET", "style.css", false);
93 styleSheet = "<style>" + req.responseText + "</style>";
95 req.open("GET", "iframe.js", false);
98 frameScript = "<script>" + req.responseText +
101 // Normal loading just requires links to the css and the js file.
102 styleSheet = "<link rel='stylesheet' type='text/css' href='" +
103 chrome.extension.getURL("style.css") + "'>";
104 frameScript = "<script src='" + chrome.extension.getURL("iframe.js") +
108 req.onload = handleResponse;
109 req.onerror = handleError;
110 // Not everyone sets the mime type correctly, which causes handleResponse
111 // to fail to XML parse the response text from the server. By forcing
112 // it to text/xml we avoid this.
113 req.overrideMimeType('text/xml');
114 req.open("GET", feedUrl, !synchronousRequest);
117 document.getElementById('feedUrl').href = 'view-source:' + feedUrl;
120 // Sets the title for the feed.
121 function setFeedTitle(title) {
122 var titleTag = document.getElementById('title');
123 titleTag.textContent =
124 chrome.i18n.getMessage("rss_subscription_feed_for", title);
127 // Handles errors during the XMLHttpRequest.
128 function handleError() {
129 handleFeedParsingFailed(
130 chrome.i18n.getMessage("rss_subscription_error_fetching"));
133 // Handles feed parsing errors.
134 function handleFeedParsingFailed(error) {
135 setFeedTitle(unknownName);
137 // The tests always expect an IFRAME, so add one showing the error.
138 var html = "<body><span id=\"error\" class=\"item_desc\">" + error +
141 var error_frame = createFrame('error', html);
142 var itemsTag = document.getElementById('items');
143 itemsTag.appendChild(error_frame);
146 function createFrame(frame_id, html) {
147 var csp = '<meta http-equiv="content-security-policy" ' +
148 'value="script-src \'self\'; object-src \'none\'">';
149 frame = document.createElement('iframe');
151 frame.src = "data:text/html;charset=utf-8,<html>" + csp + styleSheet + html +
153 frame.scrolling = "auto";
154 frame.frameBorder = "0";
155 frame.marginWidth = "0";
159 function embedAsIframe(rssText) {
160 var itemsTag = document.getElementById('items');
162 // TODO(aa): Add base URL tag
163 iframe = createFrame('rss', styleSheet + frameScript);
164 itemsTag.appendChild(iframe);
166 iframe.onload = function() {
167 iframe.contentWindow.postMessage(rssText, "*");
171 // Handles parsing the feed data we got back from XMLHttpRequest.
172 function handleResponse() {
173 // Uncomment these three lines to see what the feed data looks like.
174 // var itemsTag = document.getElementById('items');
175 // itemsTag.textContent = req.responseText;
178 var doc = req.responseXML;
180 // If the XMLHttpRequest object fails to parse the feed we make an attempt
181 // ourselves, because sometimes feeds have html/script code appended below a
182 // valid feed, which makes the feed invalid as a whole even though it is
184 var domParser = new DOMParser();
185 doc = domParser.parseFromString(req.responseText, "text/xml");
187 handleFeedParsingFailed(
188 chrome.i18n.getMessage("rss_subscription_not_valid_feed"));
193 // We must find at least one 'entry' or 'item' element before proceeding.
194 var entries = doc.getElementsByTagName('entry');
195 if (entries.length == 0)
196 entries = doc.getElementsByTagName('item');
197 if (entries.length == 0) {
198 handleFeedParsingFailed(
199 chrome.i18n.getMessage("rss_subscription_no_entries"))
203 // Figure out what the title of the whole feed is.
204 var title = doc.getElementsByTagName('title')[0];
206 setFeedTitle(title.textContent);
208 setFeedTitle(unknownName);
210 // Add an IFRAME with the html contents.
211 embedAsIframe(req.responseText);
215 * Handler for when selection changes.
217 function onSelectChanged() {
220 var readerDropdown = document.getElementById('readerDropdown');
222 // If the last item (Manage...) was selected we show the options.
223 var oldSelection = readerDropdown.selectedIndex;
224 if (readerDropdown.selectedIndex == readerDropdown.length - 1)
225 window.location = "options.html";
228 document.addEventListener('DOMContentLoaded', function () {
230 chrome.i18n.getMessage("rss_subscription_default_title");
231 i18nReplace('rss_subscription_subscribe_using');
232 i18nReplace('rss_subscription_subscribe_button');
233 i18nReplace('rss_subscription_always_use');
234 i18nReplace('rss_subscription_feed_preview');
235 i18nReplaceImpl('feedUrl', 'rss_subscription_feed_link', '');
237 var dropdown = document.getElementById('readerDropdown');
238 dropdown.addEventListener('change', onSelectChanged);
239 var button = document.getElementById('rss_subscription_subscribe_button');
240 button.addEventListener('click', navigate);