summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkurrik@chromium.org <kurrik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-15 06:31:08 +0000
committerkurrik@chromium.org <kurrik@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-15 06:31:08 +0000
commit60a761c6a38e1311cd26be4afa8e253259dc4570 (patch)
treedc1c59aa2f847d6b88a85c7f57c724507fa900c4
parent46648d3a6cac794efa4129f84c56562f32accef7 (diff)
downloadchromium_src-60a761c6a38e1311cd26be4afa8e253259dc4570.zip
chromium_src-60a761c6a38e1311cd26be4afa8e253259dc4570.tar.gz
chromium_src-60a761c6a38e1311cd26be4afa8e253259dc4570.tar.bz2
Improvements to the Google News extension.
* Patch by anujb BUG=None TEST=None TBR=kathyw Review URL: http://codereview.chromium.org/3681008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66100 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news.zipbin22058 -> 0 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json102
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/css/feed.css101
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/css/options.css121
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/feed.html310
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/buzz.pngbin0 -> 892 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/delete-icon.pngbin0 -> 1030 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/fb.pngbin0 -> 428 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/news.gifbin0 -> 3431 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/news_action.png (renamed from chrome/common/extensions/docs/examples/extensions/news/news_action.png)bin1109 -> 1109 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/news_icon.png (renamed from chrome/common/extensions/docs/examples/extensions/news/news_icon.png)bin10782 -> 10782 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/sprite_arrows.gif (renamed from chrome/common/extensions/docs/examples/extensions/news/sprite_arrows.gif)bin1328 -> 1328 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/images/twitter.pngbin0 -> 588 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/javascript/feed.js388
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/javascript/options.js395
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/javascript/util.js29
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/manifest.json19
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/views/background.html27
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/views/feed.html146
-rw-r--r--chrome/common/extensions/docs/examples/extensions/news/views/options.html166
20 files changed, 1486 insertions, 318 deletions
diff --git a/chrome/common/extensions/docs/examples/extensions/news.zip b/chrome/common/extensions/docs/examples/extensions/news.zip
deleted file mode 100644
index cab4e3a..0000000
--- a/chrome/common/extensions/docs/examples/extensions/news.zip
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json b/chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json
new file mode 100644
index 0000000..97e07c1
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json
@@ -0,0 +1,102 @@
+{
+ "extName": {
+ "message": "News Reader (by Google)"
+ },
+ "extDesc": {
+ "message": "Displays the latest stories from Google News in a popup."
+ },
+ "ext_default_title": {
+ "message": "Google News"
+ },
+
+ "1": {
+ "message": "Top Stories"
+ },
+ "n": {
+ "message": "Nation"
+ },
+ "w": {
+ "message": "World"
+ },
+ "b": {
+ "message": "Business"
+ },
+ "t": {
+ "message": "Science/Technology"
+ },
+ "e": {
+ "message": "Entertainment"
+ },
+ "s": {
+ "message": "Sports"
+ },
+ "m": {
+ "message": "Health"
+ },
+ "po": {
+ "message": "Most Popular"
+ },
+
+ "options": {
+ "message": "Options"
+ },
+ "more_stories": {
+ "message": "More stories"
+ },
+
+ "direction": {
+ "message": "ltr"
+ },
+
+ "country": {
+ "message": "Country:"
+ },
+ "topic": {
+ "message": "Topics:"
+ },
+ "save": {
+ "message": "Save"
+ },
+ "saveStatus": {
+ "message": "Options saved"
+ },
+ "storyCount": {
+ "message": "Number of stories:"
+ },
+ "newsOption": {
+ "message": "Google News Options"
+ },
+ "customText": {
+ "message": "Custom Topics:"
+ },
+ "maximumTopics": {
+ "message": "(Maximum $count$)",
+ "placeholders": {
+ "count": {
+ "content": "$1"
+ }
+ }
+ },
+ "submitButton": {
+ "message": "Add"
+ },
+ "deleteTitle": {
+ "message": "Delete"
+ },
+ "invalidChars": {
+ "message": "Invalid character(s)"
+ },
+ "noTopic": {
+ "message": "At least one Topic must be selected"
+ },
+
+ "fetchError": {
+ "message": "Error: Failed to fetch news stories."
+ },
+ "wrongTopic": {
+ "message": "Error: Not a valid feed."
+ },
+ "noStory": {
+ "message": "No story right now"
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/news/css/feed.css b/chrome/common/extensions/docs/examples/extensions/news/css/feed.css
new file mode 100644
index 0000000..49edf8f
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/css/feed.css
@@ -0,0 +1,101 @@
+/**
+ * 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.
+ *
+ * Sets style of different elements in pop-up page.
+ *
+ * Author: navneetg@google.com (Navneet Goel).
+ */
+
+body {
+ font-family: arial, sans-serif;
+ font-size: 12px;
+ min-width: 500px;
+ overflow: visible;
+}
+a {
+ color: #0000CC;
+ cursor: pointer;
+ text-decoration: underline;
+}
+#noStories {
+ background-color: rgb(255, 238, 136);
+ font-size: 13px;
+ font-weight: bold;
+ margin-left: 140px;
+ margin-right: 140px;
+ text-align: center;
+}
+.open_box {
+ background-image: url(/images/sprite_arrows.gif);
+ background-position: 0px -24px;
+ clear: left;
+ cursor: pointer;
+ display: block;
+ height: 12px;
+ margin-top: 2px;
+ overflow: hidden;
+ width: 12px;
+ float: left;
+}
+.opened .open_box {
+ background-position: -12px -24px;
+}
+.item {
+ padding: 2px 0;
+}
+.item_title {
+ cursor: pointer;
+ display: block;
+ min-width: 300px;
+ padding: 0 0 0 17px;
+}
+.item_desc {
+ border: none;
+ display: block;
+ height: 0;
+ margin: 0;
+ min-width: 500px;
+ padding: 0;
+ -webkit-transition: height 0.2s ease-out;
+}
+#title {
+ display: block;
+}
+.error {
+ background-color: rgb(255, 238, 136);
+ font-size: 13px;
+ font-weight: bold;
+ margin-left: 125px;
+ margin-right: 125px;
+ text-align: center;
+ white-space: nowrap;
+}
+.more {
+ color: #88C;
+ display: block;
+ margin-left: 385px;
+ padding-right: 10px;
+ padding-top: 5px;
+ text-align: right;
+}
+.topicsLTR {
+ direction: ltr;
+ font-size: 13px;
+ padding-left: 5px;
+}
+.topicsRTL {
+ direction: rtl;
+ font-size: 13px;
+ padding-right: 5px;
+}
+body.rtl #feed {
+ direction: rtl;
+}
+body.rtl .open_box {
+ float: right;
+}
+body.rtl .item_title {
+ padding: 0 17px 0 0;
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/news/css/options.css b/chrome/common/extensions/docs/examples/extensions/news/css/options.css
new file mode 100644
index 0000000..91aff7e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/css/options.css
@@ -0,0 +1,121 @@
+/**
+ * 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.
+ *
+ * Sets style of different elements in options page.
+ *
+ * Author: navneetg@google.com (Navneet Goel).
+ */
+
+@CHARSET "UTF-8";
+body {
+ background-color: rgb(235, 239, 249);
+ font-family: arial , sans-serif;
+ font-size: 13px;
+}
+.suppr {
+ background-image: url(/images/delete-icon.png);
+ background-repeat: no-repeat;
+ cursor: pointer;
+ display: inline;
+ float: left;
+ height: 17px;
+ margin-top: 3px;
+ overflow: hidden;
+ width: 14px;
+}
+.checkBoxTopic {
+ float: left;
+ padding-left: 2px;
+ padding-top: 1px;
+}
+.checkBox {
+ float: left;
+}
+.boxAndTopic {
+ overflow: auto;
+ padding-bottom: 5px;
+}
+#invalid_status, #save_status {
+ background-color: rgb(255, 241, 168);
+ font-weight: bold;
+ margin-left: 10px;
+ opacity: 0;
+ padding-bottom: 3px;
+ padding-left: 7px;
+ padding-right: 7px;
+ padding-top: 3px;
+}
+#all_content {
+ background-color: white;
+ border-bottom-left-radius: 12px 12px;
+ border-bottom-right-radius: 12px 12px;
+ border-color: #B5C7DE;
+ border-style: solid;
+ border-top-left-radius: 12px 12px;
+ border-top-right-radius: 12px 12px;
+ border-width: 4px;
+ margin: 40px auto 20px;
+ padding: 12px;
+ width: 600px;
+}
+.col2 {
+ padding-left: 20px;
+}
+body.rtl .col1, body.rtl .col2 {
+ text-align: right;
+}
+body.rtl {
+ direction: rtl;
+}
+body.rtl .col2 {
+ padding-right: 20px;
+}
+body.rtl .checkBox, body.rtl .checkBoxTopic {
+ float: right;
+}
+body.rtl table.contentTable {
+ margin:0 55px 0 0;
+}
+body.rtl #save_div{
+ margin: 0 220px 0 0;
+}
+body.rtl #countryList{
+ margin:0 5px 0 0;
+}
+.col1 {
+ padding-top: 3px;
+ width: 115px;
+}
+.all_rows {
+ height: 35px;
+ vertical-align: top;
+}
+body.rtl .cusTopicsClass {
+ float: right;
+}
+.cusTopicsClass {
+ float: left;
+ width: 225px;
+}
+#save_div {
+ margin-left: 220px;
+}
+#countryList {
+ padding-left: 5px;
+}
+#logo {
+ font-size: 15px;
+ font-weight: bold;
+ text-align: center;
+}
+.noborder {
+ border: 0;
+ font-family: arial, sans-serif;
+ height: 15px;
+ outline: none;
+ overflow: hidden;
+ resize: none;
+ width:205px;
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/news/feed.html b/chrome/common/extensions/docs/examples/extensions/news/feed.html
deleted file mode 100644
index 6592a87..0000000
--- a/chrome/common/extensions/docs/examples/extensions/news/feed.html
+++ /dev/null
@@ -1,310 +0,0 @@
-<!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 = 'http://news.google.com/?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 = "Error: " + error;
-}
-
-// Handles errors during the XMLHttpRequest.
-function handleError() {
- handleFeedParsingFailed('Failed to fetch RSS feed.');
-}
-
-// Handles parsing the feed data we got back from XMLHttpRequest.
-function handleResponse() {
- var doc = req.responseXML;
- if (!doc) {
- handleFeedParsingFailed("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 = "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 = "More stories \u00BB";
- 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("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;
- }
- }
-}
-
-window.addEventListener("message", iframeMessageHandler);
-</script>
-</head>
-<body onload="main();">
-<a id="title_a"><img id='title'></a>
-<div id="feed"></div>
-</body>
-</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/news/images/buzz.png b/chrome/common/extensions/docs/examples/extensions/news/images/buzz.png
new file mode 100644
index 0000000..c81c585
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/buzz.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/images/delete-icon.png b/chrome/common/extensions/docs/examples/extensions/news/images/delete-icon.png
new file mode 100644
index 0000000..732b36e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/delete-icon.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/images/fb.png b/chrome/common/extensions/docs/examples/extensions/news/images/fb.png
new file mode 100644
index 0000000..b6cba93
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/fb.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/images/news.gif b/chrome/common/extensions/docs/examples/extensions/news/images/news.gif
new file mode 100644
index 0000000..2d8df79
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/news.gif
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/news_action.png b/chrome/common/extensions/docs/examples/extensions/news/images/news_action.png
index 24b0ca7..24b0ca7 100644
--- a/chrome/common/extensions/docs/examples/extensions/news/news_action.png
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/news_action.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/news_icon.png b/chrome/common/extensions/docs/examples/extensions/news/images/news_icon.png
index 42da406..42da406 100644
--- a/chrome/common/extensions/docs/examples/extensions/news/news_icon.png
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/news_icon.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/sprite_arrows.gif b/chrome/common/extensions/docs/examples/extensions/news/images/sprite_arrows.gif
index 4560faf..4560faf 100644
--- a/chrome/common/extensions/docs/examples/extensions/news/sprite_arrows.gif
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/sprite_arrows.gif
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/images/twitter.png b/chrome/common/extensions/docs/examples/extensions/news/images/twitter.png
new file mode 100644
index 0000000..111f3f4
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/images/twitter.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/news/javascript/feed.js b/chrome/common/extensions/docs/examples/extensions/news/javascript/feed.js
new file mode 100644
index 0000000..f4cc99a
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/javascript/feed.js
@@ -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);
diff --git a/chrome/common/extensions/docs/examples/extensions/news/javascript/options.js b/chrome/common/extensions/docs/examples/extensions/news/javascript/options.js
new file mode 100644
index 0000000..5324a8b
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/javascript/options.js
@@ -0,0 +1,395 @@
+/**
+ * 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 Includes the country selection, topics selection and
+ * selection of no. of news stories to be shown. Include default settings also.
+ * @author navneetg@google.com (Navneet Goel).
+ */
+
+/**
+ * Stores number of selected topics on the options page.
+ */
+var checkCount = 0;
+
+/**
+ * Stores maximum count of custom topics.
+ */
+var MAX_CUS_TOPICS = 10;
+
+/**
+ * Stores temporary added custom topics which are not yet saved.
+ */
+var tempCusTopics = [];
+
+/**
+ * Checks whether ENTER key is pressed or not.
+ */
+function addCustomTopic() {
+ if (window.event.keyCode == 13) {
+ addCusTopic();
+ }
+}
+
+/**
+ * Retrieves and sets last saved country from local storage(if found),
+ * else sets country retrieved from feed.
+ */
+function setCountry() {
+ var country = window.localStorage.getItem('country');
+
+ // If country is not found in localstorage or default value is selected in
+ // drop down menu.
+ if ((!country) || country == 'noCountry') {
+ // XMLHttpRequest object that tries to load the feed for the purpose of
+ // retrieving the country value out of feed.
+ var req = new XMLHttpRequest();
+ req.onload = handleResponse;
+ req.onerror = handleError;
+ req.open('GET', DEFAULT_NEWS_URL, true);
+ req.send(null);
+
+ // Sets country to default Country in dropdown menu.
+ function handleError() {
+ $('countryList').value = 'noCountry';
+ };
+
+ // Handles parsing the feed data got back from XMLHttpRequest.
+ function handleResponse() {
+ // Feed document retrieved from URL.
+ var doc = req.responseXML;
+ if (!doc) {
+ handleError();
+ return;
+ }
+ var imageLink = doc.querySelector('image link');
+ if (imageLink) {
+ // Stores link to set value of country.
+ var newsUrl = imageLink.textContent;
+ }
+
+ // Stores country value
+ $('countryList').value = newsUrl.substring(newsUrl.indexOf('&ned=') + 5,
+ newsUrl.indexOf('&hl='));
+ };
+ } else {
+ $('countryList').value = country;
+ }
+}
+
+/**
+ * Displays various messages to user based on user input.
+ * @param {String} id Id of status element.
+ * @param {Number} timeOut Timeout value of message shown.
+ * @param {String} message Message to be shown.
+ */
+function showUserMessages(id, timeOut, message) {
+ $(id).style.setProperty('-webkit-transition',
+ 'opacity 0s ease-in');
+ $(id).style.opacity = 1;
+ $(id).innerText = chrome.i18n.getMessage(message);
+ window.setTimeout(function() {
+ $(id).style.setProperty(
+ '-webkit-transition', 'opacity' + timeOut + 's ease-in');
+ $(id).style.opacity = 0;
+ }, 1E3
+ );
+}
+
+/**
+ * Sets options page CSS according to the browser language(if found), else sets
+ * to default locale.
+ */
+function setOptionPageCSS() {
+ if (chrome.i18n.getMessage('direction') == 'rtl') {
+ document.querySelector('body').className = 'rtl';
+ }
+}
+
+/**
+ * Initializes the options page by retrieving country, topics and count of
+ * stories from local storage if present, else sets to default settings.
+ */
+function initialize() {
+ setOptionPageCSS();
+ setCountry();
+ setCountAndTopicList();
+ setLocalizedTopicList();
+
+ // Adds a custom topic on press of Enter key.
+ $('newKeyword').onkeypress = addCustomTopic;
+}
+
+/**
+ * Retrieves locale values from locale file.
+ */
+function setLocalizedTopicList() {
+ var getI18nMsg = chrome.i18n.getMessage;
+
+ $('top').innerText = getI18nMsg('1');
+ $('nation').innerText = getI18nMsg('n');
+ $('world').innerText = getI18nMsg('w');
+ $('business').innerText = getI18nMsg('b');
+ $('science').innerText = getI18nMsg('t');
+ $('entertainment').innerText = getI18nMsg('e');
+ $('sports').innerText = getI18nMsg('s');
+ $('health').innerText = getI18nMsg('m');
+ $('most').innerText = getI18nMsg('po');
+ $('select_country').innerText = getI18nMsg('country');
+ $('topic').innerText = getI18nMsg('topic');
+ $('save_button').innerText = getI18nMsg('save');
+ $('story_count').innerText = getI18nMsg('storyCount');
+ $('logo').innerHTML = $('logo').innerHTML + getI18nMsg('newsOption');
+ $('custom_text').innerHTML = getI18nMsg('customText') + '<br/>' +
+ getI18nMsg('maximumTopics',[MAX_CUS_TOPICS]);
+ $('submit_button').value = getI18nMsg('submitButton');
+}
+
+/**
+ * Sets topic list and number of stories retrieved from localstorage(if any)
+ * otherwise sets to default.
+ */
+function setCountAndTopicList() {
+ var topicLists = document.getElementsByClassName('checkBox');
+
+ // Retrieves topics list from localStorage.
+ var topics = JSON.parse(window.localStorage.getItem('topics'));
+
+ // Runs if retrieved topic list from local storage contains topics.
+ if (topics) {
+ for (var x = 0, topicList; topicList = topicLists[x]; x++) {
+
+ // Saves whether checkbox is checked or not.
+ var isPresent = false;
+ for (var y = 0; y < topics.length; y++) {
+ if (topics[y] == topicList.value) {
+ topicList.checked = true;
+ isPresent = true;
+ checkCount++;
+ break;
+ }
+ }
+ if (!isPresent) {
+ topicList.checked = false;
+ }
+ }
+ }
+
+ // Retrieves list of custom topics from localstorage(if any) and shows it
+ // in option page.
+ var keywords = JSON.parse(window.localStorage.getItem('keywords'));
+ if (keywords) {
+
+ // Template to store custom topics in a table.
+ var template = [];
+ var title = chrome.i18n.getMessage('deleteTitle');
+ for (var i = 0; i < keywords.length; i++) {
+ checkCount++;
+
+ template.push('<tr style = "height: 22px;">');
+ template.push('<td id = "keyword_value" class = "cusTopicsClass">');
+ template.push('<textarea class="noborder" readonly>');
+ template.push(keywords[i]);
+ template.push('</textarea>');
+ template.push('<td class = "suppr" onclick = "delCusTopic(this)" ');
+ template.push('title="');
+ template.push(title);
+ template.push('">');
+ template.push('</td>');
+ template.push('</tr>');
+ }
+ $('custom_topics').innerHTML = template.join('');
+ if (keywords.length == MAX_CUS_TOPICS) {
+ $('submit_button').disabled = true;
+ $('newKeyword').readOnly = 'readonly';
+ }
+ }
+ // Check all checkboxes(default settings) if no custom topic list and
+ // checkbox topic list from local storage is found.
+ if (!keywords && !topics) {
+ for (var x = 0, topicList; topicList = topicLists[x]; x++) {
+ topicList.checked = true;
+ checkCount++;
+ }
+ }
+
+ // Retrieves saved value of number of stories.
+ var count = window.localStorage.getItem('count');
+
+ // Sets number of stories in dropdown.
+ if (count) {
+ $('storyCount').value = count;
+ }
+}
+
+/**
+ * Saves checked topic list(if any), Custom topics(if any), number of
+ * stories and country value in local storage.
+ */
+function saveTopicsCountry() {
+ var country = $('countryList').value;
+ var topicLists = document.getElementsByClassName('checkBox');
+
+ // Contains selected number of stories.
+ var count = $('storyCount').value;
+
+ // Stores checked topics list.
+ var topicArr = [];
+ for (var i = 0, topicList; topicList = topicLists[i]; i++) {
+ if (topicList.checked) {
+ topicArr.push(topicList.value);
+ }
+ }
+ var keywords = JSON.parse(window.localStorage.getItem('keywords'));
+
+ // Saves custom topics to local storage(if any).
+ if (tempCusTopics.length > 0) {
+ if (keywords) {
+ keywords = keywords.concat(tempCusTopics);
+ window.localStorage.setItem('keywords', JSON.stringify(keywords));
+ } else {
+ window.localStorage.setItem('keywords', JSON.stringify(tempCusTopics));
+ }
+ tempCusTopics.splice(0, tempCusTopics.length);
+ }
+
+ // Saves checkbox topics(if any).
+ if (topicArr.length > 0) {
+ window.localStorage.setItem('topics', JSON.stringify(topicArr));
+ } else {
+ window.localStorage.removeItem('topics');
+ }
+
+ window.localStorage.setItem('count', count);
+ window.localStorage.setItem('country', country);
+
+ showUserMessages('save_status', 0.5, 'saveStatus');
+ $('save_button').disabled = true;
+}
+
+/**
+ * Disables the save button on options page if no topic is selected by the user.
+ * @param {String} id Id of checkbox checked or unchecked.
+ */
+function manageCheckCount(id) {
+ checkCount = ($(id).checked) ? (checkCount + 1) : (checkCount - 1);
+ $('save_button').disabled = (checkCount == 0) ? true : false;
+}
+
+/**
+ * Enables save button if at least one topic is selected.
+ */
+function enableSaveButton() {
+ if (checkCount != 0) {
+ $('save_button').disabled = false;
+ }
+}
+
+/**
+ * Adds new entered custom topic.
+ */
+function addCusTopic() {
+ // Retrieves custom topic list from local storage(if any), else create new
+ // array list.
+ var keywords = JSON.parse(window.localStorage.getItem('keywords') || "[]");
+
+ // Adds topic only if total number of added custom topics are less than 10.
+ if (keywords.length + tempCusTopics.length <= (MAX_CUS_TOPICS - 1)) {
+
+ // Stores new entered value in input textbox.
+ var val = $('newKeyword').value;
+ if (val) {
+ val = val.trim();
+ if (val.length > 0) {
+ var pattern = /,/g;
+
+ // Runs if comma(,) is not present in topic entered.
+ if (val.match(pattern) == null) {
+ checkCount++;
+ tempCusTopics.push(val);
+
+ // Template to store custom topics in a table.
+ var template = [];
+ var title = chrome.i18n.getMessage('deleteTitle');
+
+ template.push('<tr style = "height: 22px;">');
+ template.push('<td id = "keyword_value" class = "cusTopicsClass">');
+ template.push('<textarea class="noborder" readonly>');
+ template.push(val);
+ template.push('</textarea>');
+ template.push('<td class = "suppr" onclick = "delCusTopic(this)" ');
+ template.push('title="');
+ template.push(title);
+ template.push('">');
+ template.push('</td>');
+ template.push('</tr>');
+
+ $('custom_topics').innerHTML += template.join('');
+ enableSaveButton();
+ } else {
+ showUserMessages('invalid_status', 2.5, 'invalidChars');
+ }
+ }
+ $('newKeyword').value = '';
+ }
+ }
+
+ if ((keywords.length + tempCusTopics.length) == (MAX_CUS_TOPICS)) {
+ $('submit_button').disabled = true;
+ $('newKeyword').readOnly = 'readonly';
+ }
+}
+
+/**
+ * Delete custom topic whenever users click on delete icon.
+ * @param {HTMLTableColElement} obj HTML table column element to be deleted.
+ */
+function delCusTopic(obj) {
+ // Deletes only if total number of topics are greater than 1, else shows
+ // error message.
+ if (checkCount > 1) {
+ var value;
+
+ // Extract custom topic value.
+ value = obj.parentNode.querySelector('.cusTopicsClass textarea').value;
+
+ // Removes custom topic element from UI.
+ $('custom_topics').removeChild(obj.parentNode);
+
+ // Removes custom topic element either from temporary array(if topic is
+ // not yet saved) or from saved topic list and saves new list to
+ // local storage.
+ var flag = 0;
+ for (var i = 0; i < tempCusTopics.length; i++) {
+ if (tempCusTopics[i] == value) {
+ tempCusTopics.splice(i, 1);
+ flag = 1;
+ break;
+ }
+ }
+
+ if (flag == 0) {
+ var keywords = JSON.parse(window.localStorage.getItem('keywords'));
+ for (i = 0; i < keywords.length; i++) {
+ if (keywords[i] == value) {
+ keywords.splice(i, 1);
+ break;
+ }
+ }
+ if (keywords.length > 0) {
+ window.localStorage.setItem('keywords', JSON.stringify(keywords));
+ } else {
+ window.localStorage.removeItem('keywords');
+ }
+ }
+
+ checkCount--;
+ $('submit_button').disabled = false;
+ } else {
+ showUserMessages('save_status', 2.5, 'noTopic');
+ }
+ $('newKeyword').readOnly = false;
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/news/javascript/util.js b/chrome/common/extensions/docs/examples/extensions/news/javascript/util.js
new file mode 100644
index 0000000..f8e3880
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/javascript/util.js
@@ -0,0 +1,29 @@
+/**
+ * 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 Defines the constants and most commonly used functions.
+ * @author navneetg@google.com (Navneet Goel).
+ */
+
+/**
+ * Default feed news URL.
+ */
+var DEFAULT_NEWS_URL = 'http://news.google.com/news?output=rss';
+
+/**
+ * Image URL of Israel country.
+ */
+var ISRAEL_IMAGE_URL = 'http://www.gstatic.com/news/img/logo/iw_il/news.gif';
+
+/**
+ * Alias for getElementById.
+ * @param {String} elementId Element id of the HTML element to be fetched.
+ * @return {Element} Element corresponding to the element id.
+ */
+function $(elementId) {
+ return document.getElementById(elementId);
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/news/manifest.json b/chrome/common/extensions/docs/examples/extensions/news/manifest.json
index f0c7e0e..cff6f2e 100644
--- a/chrome/common/extensions/docs/examples/extensions/news/manifest.json
+++ b/chrome/common/extensions/docs/examples/extensions/news/manifest.json
@@ -1,15 +1,18 @@
{
- "name": "News Reader",
- "version": "1.1",
- "description": "Displays the first 5 items from the 'Google News - top news' RSS feed in a popup.",
- "icons": { "128": "news_icon.png" },
+ "name": "__MSG_extName__",
+ "version": "2.0",
+ "description": "__MSG_extDesc__",
+ "icons": { "128": "images/news_icon.png" },
+ "default_locale":"en",
"browser_action": {
- "default_title": "Google News",
- "default_icon": "news_action.png",
- "popup": "feed.html"
+ "default_title": "__MSG_ext_default_title__",
+ "default_icon": "images/news_action.png",
+ "popup": "views/feed.html"
},
"permissions": [
"tabs",
"http://news.google.com/*"
- ]
+ ],
+ "options_page": "views/options.html",
+ "background_page": "views/background.html"
}
diff --git a/chrome/common/extensions/docs/examples/extensions/news/views/background.html b/chrome/common/extensions/docs/examples/extensions/news/views/background.html
new file mode 100644
index 0000000..c97e977
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/views/background.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<!--
+ * 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 Contains script for running at the background to open up the
+options page when the extension is reloaded.
+-->
+
+<html>
+ <body>
+ <script>
+ //Retrieves value from local storage(if found).
+ var newsFlag = window.localStorage.getItem('newsFlag');
+
+ //Runs if extension installation is done.
+ if(!newsFlag) {
+ var optionsPageURL = chrome.extension.getURL('/views/options.html');
+ chrome.tabs.create({url: optionsPageURL});
+ window.localStorage.setItem('newsFlag','1');
+ }
+ </script>
+ </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/news/views/feed.html b/chrome/common/extensions/docs/examples/extensions/news/views/feed.html
new file mode 100644
index 0000000..43d147b
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/views/feed.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<!--
+ * 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 serves as the pop-up page for showing news
+according to the settings saved in options page otherwise shows default
+settings.
+@author navneetg@google.com (Navneet Goel).
+-->
+
+<html>
+<head>
+<script src = "/javascript/util.js"></script>
+<link rel = "stylesheet" href = "/css/feed.css"/>
+
+<script id = "iframe_script">
+
+/**
+ * Facebook share URL.
+ */
+var FB_SHARE_URL = "http://www.facebook.com/sharer.php?u=";
+
+/**
+ * Twitter share URL.
+ */
+var TWITTER_SHARE_URL = "http://twitter.com/share?&url=";
+
+/**
+ * Buzz share URL.
+ */
+var BUZZ_SHARE_URL = "http://www.google.com/buzz/post?&url=";
+
+/**
+ * Opens new window either of facebook, twitter or google buzz.
+ * @param {String} id Specifies whether to share news on Facebook, Google Buzz
+ * or Twitter.
+ * @param {String} url Contains URL of the News to be shared.
+ */
+function openNewsShareWindow(id, url) {
+ var newsUrl = url.substring(url.indexOf('&url=') + 5);
+ var openUrl;
+ switch (id) {
+ case 'fb':
+ openUrl = FB_SHARE_URL;
+ break;
+ case 'buzz':
+ openUrl = BUZZ_SHARE_URL;
+ break;
+ case 'twitter':
+ openUrl = TWITTER_SHARE_URL;
+ break;
+ }
+ window.open(openUrl + newsUrl, '_blank',
+ 'resizable=0,scrollbars=0,width=690,height=415');
+}
+
+/**
+ * Checks language in image url retrieved from feed and sets style of
+ * title and openbox in pop-up page(if url is found), otherwise sets
+ * to default styling.
+ */
+function setStyleByLang(titleImgUrl) {
+ var openBoxes = document.getElementsByClassName('open_box');
+ var itemTitles = document.getElementsByClassName('item_title');
+
+ if (titleImgUrl != 'NULL') {
+ var pattern = /ar_/gi;
+ var result = titleImgUrl.match(pattern);
+ if (result != null || titleImgUrl == ISRAEL_IMAGE_URL) {
+ document.querySelector('body').className = 'rtl';
+ }
+ }
+}
+
+/**
+ * Reports the height.
+ */
+function reportHeight() {
+ var msg = JSON.stringify({type:"size", size:document.body.offsetHeight});
+ parent.postMessage(msg, "*");
+}
+
+/**
+ * Initialize the iframe body.
+ */
+function frameLoaded() {
+ var links = document.getElementsByTagName("A");
+ for (var i = 0, link; link = links[i]; i++) {
+ var class = link.className;
+ if (class != "item_title" && class != "open_box") {
+ link.addEventListener("click", showStory);
+ }
+ }
+ window.addEventListener("message", messageHandler);
+}
+
+/**
+ * Redirects to Google news site according to clicked URL.
+ * @param {Object} event Onclick event.
+ */
+function showStory(event) {
+ var href = event.currentTarget.href;
+ parent.postMessage(JSON.stringify({type:"show", url:href}), "*");
+ event.preventDefault();
+}
+
+/**
+ * Handles message.
+ * @param {Object} event Onmessage event.
+ */
+function messageHandler(event) {
+ reportHeight();
+}
+</script>
+<script src = "/javascript/feed.js"></script>
+</head>
+
+<body onload = "getTopics();getNewsByTitle();" onunload = "saveLastTopic();">
+
+<div style = "margin-bottom: 15px;">
+ <div style = "float: right;">
+ <div style = "float: right; font-size: 11px">
+ <a id = "option_link" onclick = "chrome.tabs.create({url: '/views/options.html', selected: true})">
+ </a>
+ </div>
+ <div style = "margin-top: 27px">
+ <select id = "topics" onchange = "getNewsByTitle();" style = "display: inline;">
+ </select>
+ </div>
+ </div>
+ <a id = "title_a">
+ <img id = "title" style = "padding-top: 5px;">
+ </a>
+</div>
+
+<div id = "feed">
+</div>
+
+<div id = "noStories">
+</div>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/news/views/options.html b/chrome/common/extensions/docs/examples/extensions/news/views/options.html
new file mode 100644
index 0000000..6bf99b3
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/news/views/options.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<!--
+ * 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 serves as the option page of the extension for
+customizing the settings such as setting country, topics and number of
+news stories to be shown.
+@author navneetg@google.com (Navneet Goel).
+-->
+
+<html>
+ <head>
+ <script src = "/javascript/util.js"></script>
+ <meta http-equiv = "Content-Type" content = "text/html; charset = UTF-8">
+ <link rel = "stylesheet" href = "/css/options.css"/>
+ <script src = "/javascript/options.js"></script>
+ </head>
+ <body onload = "initialize();">
+ <div id = "all_content">
+ <div id = "logo">
+ <img id = "title_image" src = "/images/news.gif"/>
+ <br/>
+ </div>
+ <br/><br/>
+
+ <table class = "contentTable" style = "margin-left: 55px;" width = "96%">
+ <tr class = "all_rows">
+ <td class = "col1"><b id = "select_country"></b></td>
+ <td class = "col2">
+ <select id = "countryList" onchange = "enableSaveButton();">
+ <option value = "noCountry">-Select-</option>
+ <option value = "es_ar">Argentina</option>
+ <option value = "au">Australia</option>
+ <option value = "nl_be">België</option>
+ <option value = "fr_be">Belgique</option>
+ <option value = "en_bw">Botswana</option>
+ <option value = "pt-BR_br">Brasil</option>
+ <option value = "ca">Canada English</option>
+ <option value = "fr_ca">Canada Français</option>
+ <option value = "cs_cz">Česká republika</option>
+ <option value = "es_cl">Chile</option>
+ <option value = "es_co">Colombia</option>
+ <option value = "es_cu">Cuba</option>
+ <option value = "de">Deutschland</option>
+ <option value = "es">España</option>
+ <option value = "es_us">Estados Unidos</option>
+ <option value = "en_et">Ethiopia</option>
+ <option value = "fr">France</option>
+ <option value = "en_gh">Ghana</option>
+ <option value = "in">India</option>
+ <option value = "en_ie">Ireland</option>
+ <option value = "en_il">Israel English</option>
+ <option value = "it">Italia</option>
+ <option value = "en_ke">Kenya</option>
+ <option value = "hu_hu">Magyarország</option>
+ <option value = "en_my">Malaysia</option>
+ <option value = "es_mx">México</option>
+ <option value = "en_na">Namibia</option>
+ <option value = "nl_nl">Nederland</option>
+ <option value = "nz">New Zealand</option>
+ <option value = "en_ng">Nigeria</option>
+ <option value = "no_no">Norge</option>
+ <option value = "de_at">Österreich</option>
+ <option value = "en_pk">Pakistan</option>
+ <option value = "es_pe">Perú</option>
+ <option value = "en_ph">Philippines</option>
+ <option value = "pl_pl">Polska</option>
+ <option value = "pt-PT_pt">Portugal</option>
+ <option value = "de_ch">Schweiz</option>
+ <option value = "fr_sn">Sénégal</option>
+ <option value = "en_sg">Singapore</option>
+ <option value = "en_za">South Africa</option>
+ <option value = "fr_ch">Suisse</option>
+ <option value = "sv_se">Sverige</option>
+ <option value = "en_tz">Tanzania</option>
+ <option value = "tr_tr">Türkiye</option>
+ <option value = "uk">U.K.</option>
+ <option value = "us">U.S.</option>
+ <option value = "en_ug">Uganda</option>
+ <option value = "es_ve">Venezuela</option>
+ <option value = "vi_vn">Việt Nam (Vietnam)</option>
+ <option value = "en_zw">Zimbabwe</option>
+ <option value = "el_gr">Ελλάδα (Greece)</option>
+ <option value = "ru_ru">Россия (Russia)</option>
+ <option value = "ru_ua">Украина / русский (Ukraine)</option>
+ <option value = "uk_ua">Україна / українська (Ukraine)</option>
+ <option value = "iw_il">ישראל (Israel)</option>
+ <option value = "ar_ae">الإمارات (UAE)</option>
+ <option value = "ar_sa">السعودية (KSA)</option>
+ <option value = "ar_me">العالم العربي (Arabic)</option>
+ <option value = "ar_lb">لبنان (Lebanon)</option>
+ <option value = "ar_eg">مصر (Egypt)</option>
+ <option value = "hi_in">हिन्दी (India)</option>
+ <option value = "ta_in">தமிழ்(India)</option>
+ <option value = "te_in">తెలుగు (India)</option>
+ <option value = "ml_in">മലയാളം (India)</option>
+ <option value = "kr">한국 (Korea)</option>
+ <option value = "cn">中国版 (China)</option>
+ <option value = "tw">台灣版 (Taiwan)</option>
+ <option value = "jp">日本 (Japan)</option>
+ <option value = "hk">香港版 (Hong Kong)</option>
+ </select>
+ </td>
+ </tr>
+ <tr class = "all_rows">
+ <td class = "col1"><b id = "story_count"></b></td>
+ <td class = "col2">
+ <select id = "storyCount" style = "padding-left: 3px;" onchange = "enableSaveButton();">
+ <option value = "1">1</option>
+ <option value = "2">2</option>
+ <option value = "3">3</option>
+ <option value = "4">4</option>
+ <option value = "5" selected = "selected">5</option>
+ <option value = "6">6</option>
+ <option value = "7">7</option>
+ <option value = "8">8</option>
+ <option value = "9">9</option>
+ <option value = "10">10</option>
+ </select>
+ </td>
+ </tr>
+ <tr class = "all_rows">
+ <td class = "col1">
+ <div id = "topic" style = "font-weight: bold;"></div>
+ </td>
+ <td class = "col2">
+ <div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = " " id = "check11" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "top"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "n" id = "check13" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "nation"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "w" id = "check14" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "world"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "b" id = "check15" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "business"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "t" id = "check16" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "science"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "e" id = "check17" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "entertainment"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "s" id = "check18" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "sports"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "m" id = "check19" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "health"></div><br/></div>
+ <div class = "boxAndTopic"><input class = "checkBox" type = "checkbox" value = "po" id = "check20" onchange = "manageCheckCount(this.id)"/><div class = "checkBoxTopic" id = "most"></div><br/></div>
+ </div>
+ </td>
+ </tr>
+ <tr class = "all_rows">
+ <td class = "col1">
+ <div id = "custom_text" style = "font-weight: bold;"></div>
+ </td>
+ <td class = "col2">
+ <input id = "newKeyword" type = "text" maxlength = "20" style = "width: 205px;">
+ <input id = "submit_button" type = "submit" onclick = "addCusTopic()" style = "width: 45px;">
+ <span id = "invalid_status"></span>
+ <table>
+ <tbody id = "custom_topics"></tbody>
+ </table>
+ </td>
+ </tr>
+ </table>
+ <br/>
+ <div id = "save_div">
+ <button id = "save_button" type = "button" disabled = "disabled" onclick = "saveTopicsCountry()" style = "width: 80px;">
+ </button>
+ <span id = "save_status"></span>
+ </div>
+ </div>
+ </body>
+</html>