| Index: chrome/common/extensions/docs/examples/extensions/news/javascript/feed.js
|
| ===================================================================
|
| --- chrome/common/extensions/docs/examples/extensions/news/javascript/feed.js (revision 0)
|
| +++ chrome/common/extensions/docs/examples/extensions/news/javascript/feed.js (revision 0)
|
| @@ -0,0 +1,388 @@
|
| +/**
|
| + * Copyright (c) 2010 The Chromium Authors. All rights reserved. Use of this
|
| + * source code is governed by a BSD-style license that can be found in the
|
| + * LICENSE file.
|
| + */
|
| +
|
| +/**
|
| + * @fileoverview This file retrieves news feed and shows news in pop-up
|
| + * page according to country, topics and no. of stories selected in the
|
| + * option page.
|
| + */
|
| +
|
| +// Store value retrieved from locale.
|
| +var moreStoriesLocale = chrome.i18n.getMessage('more_stories') + ' \u00BB ';
|
| +var directionLocale = chrome.i18n.getMessage('direction');
|
| +
|
| +// Feed URL.
|
| +var feedUrl = DEFAULT_NEWS_URL;
|
| +
|
| +//The XMLHttpRequest object that tries to load and parse the feed.
|
| +var req;
|
| +
|
| +/**
|
| + * Sends request to Google News server
|
| + */
|
| +function main() {
|
| + req = new XMLHttpRequest();
|
| + req.onload = handleResponse;
|
| + req.onerror = handleError;
|
| + req.open('GET', feedUrl, true);
|
| + req.send(null);
|
| +}
|
| +
|
| +/**
|
| + * Handles feed parsing errors.
|
| + * @param {String} error The localized error message.
|
| + */
|
| +function handleFeedParsingFailed(error) {
|
| + var feed = $('feed');
|
| + $('noStories').style.display = 'none';
|
| + feed.className = 'error';
|
| + feed.innerText = error;
|
| +}
|
| +
|
| +/**
|
| + * Handles errors during the XMLHttpRequest.
|
| + */
|
| +function handleError() {
|
| + handleFeedParsingFailed(chrome.i18n.getMessage('fetchError'));
|
| + $('topics').style.display = 'none';
|
| +}
|
| +
|
| +/**
|
| + * Parses the feed response.
|
| + */
|
| +function handleResponse() {
|
| + var doc = req.responseXML;
|
| + if (!doc) {
|
| + handleFeedParsingFailed(chrome.i18n.getMessage('wrongTopic'));
|
| + var img = $('title');
|
| + if(!img.src) {
|
| + img.src = "/images/news.gif";
|
| + }
|
| +
|
| + document.querySelector('body').style.minHeight = 0;
|
| + return;
|
| + }
|
| + buildPreview(doc);
|
| +}
|
| +
|
| +// Stores no. of stories selected in options page.
|
| +var maxFeedItems = (window.localStorage.getItem('count')) ?
|
| + window.localStorage.getItem('count') : 5;
|
| +
|
| +// Where the more stories link should navigate to.
|
| +var moreStoriesUrl;
|
| +
|
| +/**
|
| + * Generates news iframe in pop-up page by parsing retrieved feed.
|
| + * @param {HTMLDocument} doc HTML Document received in feed.
|
| + */
|
| +function buildPreview(doc) {
|
| + // Get the link to the feed source.
|
| + var link = doc.querySelector('link');
|
| + var parentTag = link.parentNode.tagName;
|
| + if (parentTag != 'item' && parentTag != 'entry') {
|
| + moreStoriesUrl = link.textContent;
|
| + }
|
| +
|
| + // Setup the title image.
|
| + var image = doc.querySelector('image');
|
| + var titleImg;
|
| +
|
| + // Stores whether language script is Right to Left or not for setting style
|
| + // of share buttons(Facebook, Twitter and Google Buzz) in iframe.
|
| + var isRtl = 'lTR';
|
| +
|
| + if (image) {
|
| + var url = image.querySelector('url');
|
| + if (url) {
|
| + titleImg = url.textContent;
|
| +
|
| + // Stores URL of title image to be shown on pop-up page.
|
| + var titleImgUrl = titleImg;
|
| + var pattern = /ar_/gi;
|
| + var result = titleImgUrl.match(pattern);
|
| + if (result != null || titleImgUrl == ISRAEL_IMAGE_URL) {
|
| + isRtl = 'rTL';
|
| + }
|
| + }
|
| + }
|
| +
|
| + var img = $('title');
|
| + if (titleImg) {
|
| + img.src = titleImg;
|
| + if (moreStoriesUrl) {
|
| + $('title_a').addEventListener('click', moreStories);
|
| + }
|
| + } else {
|
| + img.style.display = 'none';
|
| + }
|
| +
|
| + // Construct the iframe's HTML.
|
| + var iframe_src = '<!doctype html><html><head><script>' +
|
| + $('iframe_script').textContent + '<' +
|
| + '/script><style> ' +
|
| + '.rTL {margin-right: 102px; text-align: right;} ' +
|
| + '.lTR {margin-left: 102px; text-align: left;} ' +
|
| + '</style></head><body onload="frameLoaded();" ' +
|
| + 'style="padding:0px;margin:0px;">';
|
| +
|
| + var feed = $('feed');
|
| + feed.className = '';
|
| + var entries = doc.getElementsByTagName('entry');
|
| + if (entries.length == 0) {
|
| + entries = doc.getElementsByTagName('item');
|
| + }
|
| + var count = Math.min(entries.length, maxFeedItems);
|
| +
|
| + // Stores required height by pop-up page.
|
| + var minHeight = 19;
|
| + minHeight = (minHeight * (count - 1)) + 100;
|
| + document.querySelector('body').style.minHeight = minHeight + 'px';
|
| + $('feed').innerHTML = '';
|
| +
|
| + for (var i = 0; i < count; i++) {
|
| + item = entries.item(i);
|
| +
|
| + // Grab the title for the feed item.
|
| + var itemTitle = item.querySelector('title');
|
| + if (itemTitle) {
|
| + itemTitle = itemTitle.textContent;
|
| + } else {
|
| + itemTitle = 'Unknown title';
|
| + }
|
| +
|
| + // Grab the description.
|
| + var itemDesc = item.querySelector('description');
|
| + if (!itemDesc) {
|
| + itemDesc = item.querySelector('summary');
|
| + if (!itemDesc) {
|
| + itemDesc = item.querySelector('content');
|
| + }
|
| + }
|
| + if (itemDesc) {
|
| + itemDesc = itemDesc.childNodes[0].nodeValue;
|
| +
|
| + } else {
|
| + itemDesc = '';
|
| + }
|
| + var itemLink = item.querySelector('link');
|
| + if (itemLink) {
|
| + itemLink = itemLink.textContent;
|
| + } else {
|
| + itemLink = 'Unknown itemLink';
|
| + }
|
| + 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);
|
| +
|
| + // Adds share buttons images(Facebook, Twitter and Google Buzz).
|
| + itemDesc += "<div class = '" + isRtl + "'>";
|
| + itemDesc += "<a style='cursor: pointer' id='fb' " +
|
| + "onclick='openNewsShareWindow(this.id,\"" + itemLink + "\")'>" +
|
| + "<img src='" + chrome.extension.getURL('/images/fb.png') + "'/></a>";
|
| + itemDesc += " <a style='cursor: pointer' id='twitter' " +
|
| + "onclick='openNewsShareWindow(this.id,\"" + itemLink + "\")'>" +
|
| + "<img src='" + chrome.extension.getURL('/images/twitter.png') + "'/></a>";
|
| + itemDesc += " <a style='cursor: pointer' id='buzz' " +
|
| + "onclick='openNewsShareWindow(this.id,\"" + itemLink + "\")'>" +
|
| + "<img src='" + chrome.extension.getURL('/images/buzz.png') + "'/></a>";
|
| + itemDesc += '</div>';
|
| +
|
| + // 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;charset=utf-8,' + iframe_src + itemDesc +
|
| + '</body></html>';
|
| + }
|
| + if (moreStoriesUrl && entries.length != 0) {
|
| + var more = document.createElement('a');
|
| + more.className = 'more';
|
| + more.innerText = moreStoriesLocale;
|
| + more.addEventListener('click', moreStories);
|
| + feed.appendChild(more);
|
| + }
|
| + setStyleByLang(titleImgUrl);
|
| +
|
| + // Checks whether feed retrieved has news story or not. If not, then shows
|
| + // error message accordingly.
|
| + if (entries.length == 0) {
|
| + $('noStories').innerText = chrome.i18n.getMessage('noStory');
|
| + $('noStories').style.display = 'block';
|
| + } else {
|
| + $('noStories').style.display = 'none';
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Show |url| in a new tab.
|
| + * @param {String} url The news URL.
|
| + */
|
| +function showUrl(url) {
|
| + // Only allow http and https URLs.
|
| + if (url.indexOf('http:') != 0 && url.indexOf('https:') != 0) {
|
| + return;
|
| + }
|
| + chrome.tabs.create({url: url});
|
| +}
|
| +
|
| +/**
|
| + * Redirects to Google news site for more stories.
|
| + * @param {Object} event Onclick event.
|
| + */
|
| +function moreStories(event) {
|
| + showUrl(moreStoriesUrl);
|
| +}
|
| +
|
| +/**
|
| + * Shows description of the news when users clicks on news title.
|
| + * @param {Object} event Onclick event.
|
| + */
|
| +function showDesc(event) {
|
| + var item_ = event.currentTarget.parentNode;
|
| + var items = document.getElementsByClassName('item');
|
| + for (var i = 0, item; item = items[i]; i++) {
|
| + var iframe = item.querySelector('.item_desc');
|
| + if (item == item_ && item.className == 'item') {
|
| + item.className = 'item opened';
|
| + iframe.contentWindow.postMessage('reportHeight', '*');
|
| + } else {
|
| + item.className = 'item';
|
| + iframe.style.height = '0px';
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Handles messages between different iframes and sets the display of iframe.
|
| + * @param {Object} e Onmessage event.
|
| + */
|
| +function iframeMessageHandler(e) {
|
| + var iframes = document.getElementsByTagName('IFRAME');
|
| + for (var i = 0, iframe; iframe = iframes[i]; i++) {
|
| + if (iframe.contentWindow == e.source) {
|
| + var msg = JSON.parse(e.data);
|
| + if (msg) {
|
| + if (msg.type == 'size') {
|
| + iframe.style.height = msg.size + 'px';
|
| + } else if (msg.type == 'show') {
|
| + var url = msg.url;
|
| + if (url.indexOf('http://news.google.com') == 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;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Saves last viewed topic by user in local storage on unload of pop-up page.
|
| + */
|
| +function saveLastTopic() {
|
| + var topicVal = $('topics').value;
|
| + window.localStorage.setItem('lastTopic', topicVal);
|
| +}
|
| +
|
| +/**
|
| + * Sets the URL according to selected topic(or default topic), then retrieves
|
| + * feed and sets pop-up page.
|
| + */
|
| +function getNewsByTitle() {
|
| + var country = window.localStorage.getItem('country');
|
| + country = (country == 'noCountry' || !country) ? '' : country;
|
| +
|
| + // Sets direction of topics showed under dropdown in pop-up page according
|
| + // to set language in browser.
|
| + $('topics').className = (directionLocale == 'rtl') ? 'topicsRTL' :
|
| + 'topicsLTR';
|
| +
|
| + var topicVal = $('topics').value;
|
| +
|
| + // Sets Feed URL in case of custom topic selected.
|
| + var keywords = JSON.parse(window.localStorage.getItem('keywords'));
|
| + var isFound = false;
|
| + if (keywords) {
|
| + for (i = 0; i < keywords.length; i++) {
|
| + if (topicVal == keywords[i]) {
|
| + isFound = true;
|
| + feedUrl = DEFAULT_NEWS_URL + '&cf=all&ned=' + country + '&q=' + topicVal +
|
| + '&hl=' + country;
|
| + break;
|
| + }
|
| + }
|
| + }
|
| + if (!isFound) {
|
| + feedUrl = DEFAULT_NEWS_URL + '&cf=all&ned=' + country +
|
| + '&topic=' + topicVal;
|
| + }
|
| + main();
|
| +}
|
| +
|
| +/**
|
| + * Shows topic list retrieved from local storage(if any),else shows
|
| + * default topics list.
|
| + */
|
| +function getTopics() {
|
| + var topics = JSON.parse(window.localStorage.getItem('topics'));
|
| + var keywords = JSON.parse(window.localStorage.getItem('keywords'));
|
| + var element = $('topics');
|
| +
|
| + // Sets all topics as default list if no list is found from local storage.
|
| + if (!topics && !keywords) {
|
| + topics = [' ','n','w','b','t','e','s','m','po'];
|
| + }
|
| +
|
| + if (topics) {
|
| + for (var i = 0; i < (topics.length); i++) {
|
| + var val = (topics[i] == ' ') ? '1' : topics[i];
|
| + element.options[element.options.length] = new Option(
|
| + chrome.i18n.getMessage(val), topics[i]);
|
| + }
|
| + }
|
| +
|
| + // Shows custom topics in list(if any).
|
| + if (keywords) {
|
| + for (i = 0; i < (keywords.length); i++) {
|
| + element.options[element.options.length] = new Option(keywords[i],
|
| + keywords[i]);
|
| + }
|
| + }
|
| +
|
| + $('option_link').innerText = chrome.i18n.getMessage('options');
|
| +
|
| + var topicVal = window.localStorage.getItem('lastTopic');
|
| + if (topicVal) {
|
| + $('topics').value = topicVal;
|
| + }
|
| +}
|
| +
|
| +window.addEventListener('message', iframeMessageHandler);
|
|
|