| <!DOCTYPE html> |
| <html> |
| <head> |
| <style> |
| body { |
| font-family: helvetica, arial, sans-serif; |
| font-size: 12px; |
| overflow: hidden; |
| } |
| |
| a { |
| color:#0000CC; |
| text-decoration: underline; |
| cursor: pointer; |
| } |
| |
| .open_box { |
| display: block; |
| overflow: hidden; |
| margin-right: 4px; |
| margin-top: 2px; |
| height: 12px; |
| width: 12px; |
| float: left; |
| clear: left; |
| background-image: url(sprite_arrows.gif); |
| background-position: 0px -24px; |
| cursor: pointer; |
| } |
| |
| .opened .open_box { |
| background-position:-12px -24px; |
| } |
| |
| .item { |
| padding: 2px 0px; |
| } |
| |
| .item_title { |
| display: block; |
| min-width: 300px; |
| padding-left: 15px; |
| cursor: pointer; |
| } |
| |
| .item_desc { |
| min-width: 500px; |
| height: 0px; |
| display: block; |
| border: none; |
| padding: 0px; |
| margin: 0px; |
| -webkit-transition: height 0.2s ease-out; |
| } |
| |
| #title { |
| display: block; |
| margin-left: auto; |
| } |
| |
| .error { |
| white-space: nowrap; |
| color: red; |
| } |
| |
| .more { |
| display: block; |
| text-align: right; |
| padding-top: 20px; |
| padding-right: 10px; |
| color: #88C; |
| } |
| |
| </style> |
| <script id="iframe_script"> |
| function reportHeight() { |
| var msg = JSON.stringify({type:"size", size:document.body.offsetHeight}); |
| parent.postMessage(msg, "*"); |
| } |
| |
| function frameLoaded() { |
| var links = document.getElementsByTagName("A"); |
| for (i = 0; i < links.length; i++) { |
| var class = links[i].className; |
| if (class != "item_title" && class != "open_box") { |
| links[i].addEventListener("click", showStory); |
| } |
| } |
| window.addEventListener("message", messageHandler); |
| } |
| |
| function showStory(event) { |
| var href = event.currentTarget.href; |
| parent.postMessage(JSON.stringify({type:"show", url:href}), "*"); |
| event.preventDefault(); |
| } |
| |
| function messageHandler(event) { |
| reportHeight(); |
| } |
| |
| </script> |
| <script> |
| // Feed URL. |
| var feedUrl = chrome.i18n.getMessage('newsUrl') + '/?output=rss'; |
| |
| // The XMLHttpRequest object that tries to load and parse the feed. |
| var req; |
| |
| function main() { |
| req = new XMLHttpRequest(); |
| req.onload = handleResponse; |
| req.onerror = handleError; |
| req.open("GET", feedUrl, true); |
| req.send(null); |
| } |
| |
| // Handles feed parsing errors. |
| function handleFeedParsingFailed(error) { |
| var feed = document.getElementById("feed"); |
| feed.className = "error"; |
| feed.innerText = chrome.i18n.getMessage("error", error); |
| } |
| |
| // Handles errors during the XMLHttpRequest. |
| function handleError() { |
| handleFeedParsingFailed(chrome.i18n.getMessage('failed_to_fetch_rss')); |
| } |
| |
| // Handles parsing the feed data we got back from XMLHttpRequest. |
| function handleResponse() { |
| var doc = req.responseXML; |
| if (!doc) { |
| handleFeedParsingFailed(chrome.i18n.getMessage('not_a_valid_feed')); |
| return; |
| } |
| buildPreview(doc); |
| } |
| |
| // The maximum number of feed items to show in the preview. |
| var maxFeedItems = 5; |
| |
| // Where the more stories link should navigate to. |
| var moreStoriesUrl; |
| |
| function buildPreview(doc) { |
| // Get the link to the feed source. |
| var link = doc.getElementsByTagName("link"); |
| var parentTag = link[0].parentNode.tagName; |
| if (parentTag != "item" && parentTag != "entry") { |
| moreStoriesUrl = link[0].textContent; |
| } |
| |
| // Setup the title image. |
| var images = doc.getElementsByTagName("image"); |
| var titleImg; |
| if (images.length != 0) { |
| var urls = images[0].getElementsByTagName("url"); |
| if (urls.length != 0) { |
| titleImg = urls[0].textContent; |
| } |
| } |
| var img = document.getElementById("title"); |
| if (titleImg) { |
| img.src = titleImg; |
| if (moreStoriesUrl) { |
| document.getElementById("title_a").addEventListener("click", moreStories); |
| } |
| } else { |
| img.style.display = "none"; |
| } |
| |
| // Construct the iframe's HTML. |
| var iframe_src = "<!doctype html><html><head><script>" + |
| document.getElementById("iframe_script").textContent + "<" + |
| "/script></head><body onload='frameLoaded();' " + |
| "style='padding:0px;margin:0px;'>"; |
| |
| var feed = document.getElementById("feed"); |
| var entries = doc.getElementsByTagName('entry'); |
| if (entries.length == 0) { |
| entries = doc.getElementsByTagName('item'); |
| } |
| var count = Math.min(entries.length, maxFeedItems); |
| for (var i = 0; i < count; i++) { |
| item = entries.item(i); |
| |
| // Grab the title for the feed item. |
| var itemTitle = item.getElementsByTagName('title')[0]; |
| if (itemTitle) { |
| itemTitle = itemTitle.textContent; |
| } else { |
| itemTitle = chrome.i18n.getMessage("unknown_title"); |
| } |
| |
| // Grab the description. |
| var itemDesc = item.getElementsByTagName('description')[0]; |
| if (!itemDesc) { |
| itemDesc = item.getElementsByTagName('summary')[0]; |
| if (!itemDesc) { |
| itemDesc = item.getElementsByTagName('content')[0]; |
| } |
| } |
| if (itemDesc) { |
| itemDesc = itemDesc.childNodes[0].nodeValue; |
| } else { |
| itemDesc = ''; |
| } |
| |
| var item = document.createElement("div"); |
| item.className = "item"; |
| var box = document.createElement("div"); |
| box.className = "open_box"; |
| box.addEventListener("click", showDesc); |
| item.appendChild(box); |
| |
| var title = document.createElement("a"); |
| title.className = "item_title"; |
| title.innerText = itemTitle; |
| title.addEventListener("click", showDesc); |
| item.appendChild(title); |
| |
| var desc = document.createElement("iframe"); |
| desc.scrolling = "no"; |
| desc.className = "item_desc"; |
| item.appendChild(desc); |
| feed.appendChild(item); |
| |
| // The story body is created as an iframe with a data: URL in order to |
| // isolate it from this page and protect against XSS. As a data URL, it |
| // has limited privileges and must communicate back using postMessage(). |
| desc.src="data:text/html," + iframe_src + itemDesc + "</body></html>"; |
| } |
| |
| if (moreStoriesUrl) { |
| var more = document.createElement("a"); |
| more.className = "more"; |
| more.innerText = chrome.i18n.getMessage("more_stories"); |
| more.addEventListener("click", moreStories); |
| feed.appendChild(more); |
| } |
| } |
| |
| // Show |url| in a new tab. |
| function showUrl(url) { |
| // Only allow http and https URLs. |
| if (url.indexOf("http:") != 0 && url.indexOf("https:") != 0) { |
| return; |
| } |
| chrome.tabs.create({url: url}); |
| } |
| |
| function moreStories(event) { |
| showUrl(moreStoriesUrl); |
| } |
| |
| function showDesc(event) { |
| var item = event.currentTarget.parentNode; |
| var items = document.getElementsByClassName("item"); |
| for (var i = 0; i < items.length; i++) { |
| var iframe = items[i].getElementsByClassName("item_desc")[0]; |
| if (items[i] == item && items[i].className == "item") { |
| items[i].className = "item opened"; |
| iframe.contentWindow.postMessage("reportHeight", "*"); |
| } else { |
| items[i].className = "item"; |
| iframe.style.height = "0px"; |
| } |
| } |
| } |
| |
| function iframeMessageHandler(e) { |
| // Only listen to messages from one of our own iframes. |
| var iframes = document.getElementsByTagName("IFRAME"); |
| for (var i = 0; i < iframes.length; i++) { |
| if (iframes[i].contentWindow == e.source) { |
| var msg = JSON.parse(e.data); |
| if (msg) { |
| if (msg.type == "size") { |
| iframes[i].style.height = msg.size + "px"; |
| } else if (msg.type == "show") { |
| var url = msg.url; |
| if (url.indexOf(chrome.i18n.getMessage('newsUrl')) == 0) { |
| // If the URL is a redirect URL, strip of the destination and go to |
| // that directly. This is necessary because the Google news |
| // redirector blocks use of the redirects in this case. |
| var index = url.indexOf("&url="); |
| if (index >= 0) { |
| url = url.substring(index + 5); |
| index = url.indexOf("&"); |
| if (index >= 0) |
| url = url.substring(0, index); |
| } |
| } |
| showUrl(url); |
| } |
| } |
| return; |
| } |
| } |
| } |
| |
| window.addEventListener("message", iframeMessageHandler); |
| </script> |
| </head> |
| <body onload="main();"> |
| <a id="title_a"><img id='title'></a> |
| <div id="feed"></div> |
| </body> |
| </html> |