Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(734)

Side by Side Diff: chrome/common/extensions/docs/examples/extensions/news_a11y/feed.js

Issue 8309001: Adding `content_security_policy` to a few sample extensions. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: License and whitespace. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 <!DOCTYPE html> 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 <html> 2 // Use of this source code is governed by a BSD-style license that can be
3 <head> 3 // found in the LICENSE file.
4 <style>
5 body {
6 font-family: helvetica, arial, sans-serif;
7 font-size: 12px;
8 overflow: hidden;
9 }
10 4
11 a { 5 // Feed
12 color:#0000CC;
13 text-decoration: underline;
14 cursor: pointer;
15 }
16
17 .open_box {
18 display: block;
19 overflow: hidden;
20 margin-right: 4px;
21 margin-top: 2px;
22 height: 12px;
23 width: 12px;
24 float: left;
25 clear: left;
26 background-image: url(sprite_arrows.gif);
27 background-position: 0px -24px;
28 cursor: pointer;
29 }
30
31 .opened .open_box {
32 background-position:-12px -24px;
33 }
34
35 .item {
36 padding: 2px 0px;
37 }
38
39 .item_title {
40 display: block;
41 min-width: 300px;
42 padding-left: 15px;
43 cursor: pointer;
44 }
45
46 .item_desc {
47 min-width: 500px;
48 height: 0px;
49 display: block;
50 border: none;
51 padding: 0px;
52 margin: 0px;
53 -webkit-transition: height 0.2s ease-out;
54 }
55
56 #title {
57 display: block;
58 margin-left: auto;
59 }
60
61 .error {
62 white-space: nowrap;
63 color: red;
64 }
65
66 .more {
67 display: block;
68 text-align: right;
69 padding-top: 20px;
70 padding-right: 10px;
71 color: #88C;
72 }
73
74 </style>
75 <script id="iframe_script">
76 function reportHeight() {
77 var msg = JSON.stringify({type:"size", size:document.body.offsetHeight});
78 parent.postMessage(msg, "*");
79 }
80
81 function frameLoaded() {
82 var links = document.getElementsByTagName("A");
83 for (i = 0; i < links.length; i++) {
84 var class = links[i].className;
85 if (class != "item_title" && class != "open_box") {
86 links[i].addEventListener("click", showStory);
87 }
88 }
89 window.addEventListener("message", messageHandler);
90 }
91
92 function showStory(event) {
93 var href = event.currentTarget.href;
94 parent.postMessage(JSON.stringify({type:"show", url:href}), "*");
95 event.preventDefault();
96 }
97
98 function messageHandler(event) {
99 reportHeight();
100 }
101
102 </script>
103 <script>
104 // Feed URL.
105 var feedUrl = 'http://news.google.com/?output=rss'; 6 var feedUrl = 'http://news.google.com/?output=rss';
106 7
107 // The XMLHttpRequest object that tries to load and parse the feed. 8 // The XMLHttpRequest object that tries to load and parse the feed.
108 var req; 9 var req;
109 10
110 function main() { 11 function main() {
111 req = new XMLHttpRequest(); 12 req = new XMLHttpRequest();
112 req.onload = handleResponse; 13 req.onload = handleResponse;
113 req.onerror = handleError; 14 req.onerror = handleError;
114 req.open("GET", feedUrl, true); 15 req.open('GET', feedUrl, true);
115 req.send(null); 16 req.send(null);
116 } 17 }
117 18
118 // Handles feed parsing errors. 19 // Handles feed parsing errors.
119 function handleFeedParsingFailed(error) { 20 function handleFeedParsingFailed(error) {
120 var feed = document.getElementById("feed"); 21 var feed = document.getElementById('feed');
121 feed.className = "error"; 22 feed.className = 'error';
122 feed.innerText = "Error: " + error; 23 feed.innerText = 'Error: ' + error;
123 } 24 }
124 25
125 // Handles errors during the XMLHttpRequest. 26 // Handles errors during the XMLHttpRequest.
126 function handleError() { 27 function handleError() {
127 handleFeedParsingFailed('Failed to fetch RSS feed.'); 28 handleFeedParsingFailed('Failed to fetch RSS feed.');
128 } 29 }
129 30
130 // Handles parsing the feed data we got back from XMLHttpRequest. 31 // Handles parsing the feed data we got back from XMLHttpRequest.
131 function handleResponse() { 32 function handleResponse() {
132 var doc = req.responseXML; 33 var doc = req.responseXML;
133 if (!doc) { 34 if (!doc) {
134 handleFeedParsingFailed("Not a valid feed."); 35 handleFeedParsingFailed('Not a valid feed.');
135 return; 36 return;
136 } 37 }
137 buildPreview(doc); 38 buildPreview(doc);
138 } 39 }
139 40
140 // The maximum number of feed items to show in the preview. 41 // The maximum number of feed items to show in the preview.
141 var maxFeedItems = 5; 42 var maxFeedItems = 5;
142 43
143 // Where the more stories link should navigate to. 44 // Where the more stories link should navigate to.
144 var moreStoriesUrl; 45 var moreStoriesUrl;
145 46
146 function buildPreview(doc) { 47 function buildPreview(doc) {
147 // Get the link to the feed source. 48 // Get the link to the feed source.
148 var link = doc.getElementsByTagName("link"); 49 var link = doc.getElementsByTagName('link');
149 var parentTag = link[0].parentNode.tagName; 50 var parentTag = link[0].parentNode.tagName;
150 if (parentTag != "item" && parentTag != "entry") { 51 if (parentTag != 'item' && parentTag != 'entry') {
151 moreStoriesUrl = link[0].textContent; 52 moreStoriesUrl = link[0].textContent;
152 } 53 }
153 54
154 // Setup the title image. 55 // Setup the title image.
155 var images = doc.getElementsByTagName("image"); 56 var images = doc.getElementsByTagName('image');
156 var titleImg; 57 var titleImg;
157 if (images.length != 0) { 58 if (images.length != 0) {
158 var urls = images[0].getElementsByTagName("url"); 59 var urls = images[0].getElementsByTagName('url');
159 if (urls.length != 0) { 60 if (urls.length != 0) {
160 titleImg = urls[0].textContent; 61 titleImg = urls[0].textContent;
161 } 62 }
162 } 63 }
163 var img = document.getElementById("title"); 64 var img = document.getElementById('title');
164 // Listen for mouse and key events 65 // Listen for mouse and key events
165 if (titleImg) { 66 if (titleImg) {
166 img.src = titleImg; 67 img.src = titleImg;
167 if (moreStoriesUrl) { 68 if (moreStoriesUrl) {
168 document.getElementById("title_a").addEventListener("click", » moreStories); 69 document.getElementById('title_a').addEventListener('click',
169 document.getElementById("title_a").addEventListener("keydown", 70 moreStories);
71 document.getElementById('title_a').addEventListener('keydown',
170 function(event) { 72 function(event) {
171 if (event.keyCode == 13) { 73 if (event.keyCode == 13) {
172 moreStories(event); 74 moreStories(event);
173 }}); 75 }});
174 } 76 }
175 } else { 77 } else {
176 img.style.display = "none"; 78 img.style.display = 'none';
177 } 79 }
178 80
179 // Construct the iframe's HTML. 81 // Construct the iframe's HTML.
180 var iframe_src = "<!doctype html><html><head><script>" + 82 var iframe_src = '<!doctype html><html><head><script ' +
181 document.getElementById("iframe_script").textContent + "<" + 83 'src="chrome-extension://ldglnfnokeifbcaeppacaejckagballg/' +
182 "/script></head><body onload='frameLoaded();' " + 84 'feed_iframe.js"><' + '/script><link href="chrome-extension://ldglnf' +
183 "style='padding:0px;margin:0px;'>"; 85 'nokeifbcaeppacaejckagballg/feed_iframe.css" rel="stylesheet" ' +
86 'type="text/css"></head><body>';
184 87
185 var feed = document.getElementById("feed"); 88 var feed = document.getElementById('feed');
186 // Set ARIA role indicating the feed element has a tree structure 89 // Set ARIA role indicating the feed element has a tree structure
187 feed.setAttribute("role", "tree"); 90 feed.setAttribute('role', 'tree');
188 91
189 var entries = doc.getElementsByTagName('entry'); 92 var entries = doc.getElementsByTagName('entry');
190 if (entries.length == 0) { 93 if (entries.length == 0) {
191 entries = doc.getElementsByTagName('item'); 94 entries = doc.getElementsByTagName('item');
192 } 95 }
193 var count = Math.min(entries.length, maxFeedItems); 96 var count = Math.min(entries.length, maxFeedItems);
194 for (var i = 0; i < count; i++) { 97 for (var i = 0; i < count; i++) {
195 item = entries.item(i); 98 item = entries.item(i);
196 99
197 // Grab the title for the feed item. 100 // Grab the title for the feed item.
198 var itemTitle = item.getElementsByTagName('title')[0]; 101 var itemTitle = item.getElementsByTagName('title')[0];
199 if (itemTitle) { 102 if (itemTitle) {
200 itemTitle = itemTitle.textContent; 103 itemTitle = itemTitle.textContent;
201 } else { 104 } else {
202 itemTitle = "Unknown title"; 105 itemTitle = 'Unknown title';
203 } 106 }
204 107
205 // Grab the description. 108 // Grab the description.
206 var itemDesc = item.getElementsByTagName('description')[0]; 109 var itemDesc = item.getElementsByTagName('description')[0];
207 if (!itemDesc) { 110 if (!itemDesc) {
208 itemDesc = item.getElementsByTagName('summary')[0]; 111 itemDesc = item.getElementsByTagName('summary')[0];
209 if (!itemDesc) { 112 if (!itemDesc) {
210 itemDesc = item.getElementsByTagName('content')[0]; 113 itemDesc = item.getElementsByTagName('content')[0];
211 } 114 }
212 } 115 }
213 if (itemDesc) { 116 if (itemDesc) {
214 itemDesc = itemDesc.childNodes[0].nodeValue; 117 itemDesc = itemDesc.childNodes[0].nodeValue;
215 } else { 118 } else {
216 itemDesc = ''; 119 itemDesc = '';
217 } 120 }
218 121
219 var item = document.createElement("div"); 122 var item = document.createElement('div');
220 item.className = "item"; 123 item.className = 'item';
221 var box = document.createElement("div"); 124 var box = document.createElement('div');
222 box.className = "open_box"; 125 box.className = 'open_box';
223 box.addEventListener("click", showDesc); 126 box.addEventListener('click', showDesc);
224 // Disable focusing on box image separately from rest of tree item 127 // Disable focusing on box image separately from rest of tree item
225 box.tabIndex = -1; 128 box.tabIndex = -1;
226 item.appendChild(box); 129 item.appendChild(box);
227 130
228 var title = document.createElement("a"); 131 var title = document.createElement('a');
229 title.className = "item_title"; 132 title.className = 'item_title';
230 // Give title an ID for use with ARIA 133 // Give title an ID for use with ARIA
231 title.id = "item" + i; 134 title.id = 'item' + i;
232 title.innerText = itemTitle; 135 title.innerText = itemTitle;
233 title.addEventListener("click", showDesc); 136 title.addEventListener('click', showDesc);
234 title.addEventListener("keydown", keyHandlerShowDesc); 137 title.addEventListener('keydown', keyHandlerShowDesc);
235 // Update aria-activedescendant property in response to focus change 138 // Update aria-activedescendant property in response to focus change
236 // within the tree 139 // within the tree
237 title.addEventListener("focus", function(event) { 140 title.addEventListener('focus', function(event) {
238 feed.setAttribute( 141 feed.setAttribute(
239 "aria-activedescendant", this.id); 142 'aria-activedescendant', this.id);
240 }); 143 });
241 // Enable keyboard focus on the item title element 144 // Enable keyboard focus on the item title element
242 title.tabIndex = 0; 145 title.tabIndex = 0;
243 // Set ARIA role role indicating that the title element is a node in the 146 // Set ARIA role role indicating that the title element is a node in the
244 // tree structure 147 // tree structure
245 title.setAttribute("role", "treeitem"); 148 title.setAttribute('role', 'treeitem');
246 // Set the ARIA state indicating this tree item is currently collapsed. 149 // Set the ARIA state indicating this tree item is currently collapsed.
247 title.setAttribute("aria-expanded", "false"); 150 title.setAttribute('aria-expanded', 'false');
248 // Set ARIA property indicating that all items are at the same hierarchical 151 // Set ARIA property indicating that all items are at the same hierarchical
249 // level (no nesting) 152 // level (no nesting)
250 title.setAttribute("aria-level", "1"); 153 title.setAttribute('aria-level', '1');
251 item.appendChild(title); 154 item.appendChild(title);
252 155
253 var desc = document.createElement("iframe"); 156 var desc = document.createElement('iframe');
254 desc.scrolling = "no"; 157 desc.scrolling = 'no';
255 desc.className = "item_desc"; 158 desc.className = 'item_desc';
256 // Disable keyboard focus on elements in iFrames that have not been 159 // Disable keyboard focus on elements in iFrames that have not been
257 // displayed yet 160 // displayed yet
258 desc.tabIndex = -1; 161 desc.tabIndex = -1;
259 162
260 item.appendChild(desc);
261 feed.appendChild(item);
262
263 // The story body is created as an iframe with a data: URL in order to 163 // The story body is created as an iframe with a data: URL in order to
264 // isolate it from this page and protect against XSS. As a data URL, it 164 // isolate it from this page and protect against XSS. As a data URL, it
265 // has limited privileges and must communicate back using postMessage(). 165 // has limited privileges and must communicate back using postMessage().
266 desc.src="data:text/html," + iframe_src + itemDesc + "</body></html>"; 166 desc.src='data:text/html,' + iframe_src + itemDesc + '</body></html>';
167
168 item.appendChild(desc);
169 feed.appendChild(item);
267 } 170 }
268 171
269 if (moreStoriesUrl) { 172 if (moreStoriesUrl) {
270 var more = document.createElement("a"); 173 var more = document.createElement('a');
271 more.className = "more"; 174 more.className = 'more';
272 more.innerText = "More stories \u00BB"; 175 more.innerText = 'More stories \u00BB';
273 more.tabIndex = 0; 176 more.tabIndex = 0;
274 more.addEventListener("click", moreStories); 177 more.addEventListener('click', moreStories);
275 more.addEventListener("keydown", function(event) { 178 more.addEventListener('keydown', function(event) {
276 if (event.keyCode == 13) { 179 if (event.keyCode == 13) {
277 moreStories(event); 180 moreStories(event);
278 }}); 181 }});
279 feed.appendChild(more); 182 feed.appendChild(more);
280 } 183 }
281 } 184 }
282 185
283 // Show |url| in a new tab. 186 // Show |url| in a new tab.
284 function showUrl(url) { 187 function showUrl(url) {
285 // Only allow http and https URLs. 188 // Only allow http and https URLs.
286 if (url.indexOf("http:") != 0 && url.indexOf("https:") != 0) { 189 if (url.indexOf('http:') != 0 && url.indexOf('https:') != 0) {
287 return; 190 return;
288 } 191 }
289 chrome.tabs.create({url: url}); 192 chrome.tabs.create({url: url});
290 } 193 }
291 194
292 function moreStories(event) { 195 function moreStories(event) {
293 showUrl(moreStoriesUrl); 196 showUrl(moreStoriesUrl);
294 } 197 }
295 198
296 function keyHandlerShowDesc(event) { 199 function keyHandlerShowDesc(event) {
297 // Display content under heading when spacebar or right-arrow pressed 200 // Display content under heading when spacebar or right-arrow pressed
298 // Hide content when spacebar pressed again or left-arrow pressed 201 // Hide content when spacebar pressed again or left-arrow pressed
299 // Move to next heading when down-arrow pressed 202 // Move to next heading when down-arrow pressed
300 // Move to previous heading when up-arrow pressed 203 // Move to previous heading when up-arrow pressed
301 if (event.keyCode == 32) { 204 if (event.keyCode == 32) {
302 showDesc(event); 205 showDesc(event);
303 } else if ((this.parentNode.className == "item opened") && 206 } else if ((this.parentNode.className == 'item opened') &&
304 (event.keyCode == 37)) { 207 (event.keyCode == 37)) {
305 showDesc(event); 208 showDesc(event);
306 } else if ((this.parentNode.className == "item") && (event.keyCode == 39)) { 209 } else if ((this.parentNode.className == 'item') && (event.keyCode == 39)) {
307 showDesc(event); 210 showDesc(event);
308 } else if (event.keyCode == 40) { 211 } else if (event.keyCode == 40) {
309 if (this.parentNode.nextSibling) { 212 if (this.parentNode.nextSibling) {
310 this.parentNode.nextSibling.children[1].focus(); 213 this.parentNode.nextSibling.children[1].focus();
311 } 214 }
312 } else if (event.keyCode == 38) { 215 } else if (event.keyCode == 38) {
313 if (this.parentNode.previousSibling) { 216 if (this.parentNode.previousSibling) {
314 this.parentNode.previousSibling.children[1].focus(); 217 this.parentNode.previousSibling.children[1].focus();
315 } 218 }
316 } 219 }
317 } 220 }
318 221
319 function showDesc(event) { 222 function showDesc(event) {
320 var item = event.currentTarget.parentNode; 223 var item = event.currentTarget.parentNode;
321 var items = document.getElementsByClassName("item"); 224 var items = document.getElementsByClassName('item');
322 for (var i = 0; i < items.length; i++) { 225 for (var i = 0; i < items.length; i++) {
323 var iframe = items[i].getElementsByClassName("item_desc")[0]; 226 var iframe = items[i].getElementsByClassName('item_desc')[0];
324 if (items[i] == item && items[i].className == "item") { 227 if (items[i] == item && items[i].className == 'item') {
325 items[i].className = "item opened"; 228 items[i].className = 'item opened';
326 iframe.contentWindow.postMessage("reportHeight", "*"); 229 iframe.contentWindow.postMessage('reportHeight', '*');
327 // Set the ARIA state indicating the tree item is currently expanded. 230 // Set the ARIA state indicating the tree item is currently expanded.
328 items[i].getElementsByClassName("item_title")[0]. 231 items[i].getElementsByClassName('item_title')[0].
329 setAttribute("aria-expanded", "true"); 232 setAttribute('aria-expanded', 'true');
330 iframe.tabIndex = 0; 233 iframe.tabIndex = 0;
331 } else { 234 } else {
332 items[i].className = "item"; 235 items[i].className = 'item';
333 iframe.style.height = "0px"; 236 iframe.style.height = '0px';
334 // Set the ARIA state indicating the tree item is currently collapsed. 237 // Set the ARIA state indicating the tree item is currently collapsed.
335 items[i].getElementsByClassName("item_title")[0]. 238 items[i].getElementsByClassName('item_title')[0].
336 setAttribute("aria-expanded", "false"); 239 setAttribute('aria-expanded', 'false');
337 iframe.tabIndex = -1; 240 iframe.tabIndex = -1;
338 } 241 }
339 } 242 }
340 } 243 }
341 244
342 function iframeMessageHandler(e) { 245 function iframeMessageHandler(e) {
343 // Only listen to messages from one of our own iframes. 246 // Only listen to messages from one of our own iframes.
344 var iframes = document.getElementsByTagName("IFRAME"); 247 var iframes = document.getElementsByTagName('IFRAME');
345 for (var i = 0; i < iframes.length; i++) { 248 for (var i = 0; i < iframes.length; i++) {
346 if (iframes[i].contentWindow == e.source) { 249 if (iframes[i].contentWindow == e.source) {
347 var msg = JSON.parse(e.data); 250 var msg = JSON.parse(e.data);
348 if (msg) { 251 if (msg) {
349 if (msg.type == "size") { 252 if (msg.type == 'size') {
350 iframes[i].style.height = msg.size + "px"; 253 iframes[i].style.height = msg.size + 'px';
351 } else if (msg.type == "show") { 254 } else if (msg.type == 'show') {
352 var url = msg.url; 255 var url = msg.url;
353 if (url.indexOf("http://news.google.com") == 0) { 256 if (url.indexOf('http://news.google.com') == 0) {
354 // If the URL is a redirect URL, strip of the destination and go to 257 // If the URL is a redirect URL, strip of the destination and go to
355 // that directly. This is necessary because the Google news 258 // that directly. This is necessary because the Google news
356 // redirector blocks use of the redirects in this case. 259 // redirector blocks use of the redirects in this case.
357 var index = url.indexOf("&url="); 260 var index = url.indexOf('&url=');
358 if (index >= 0) { 261 if (index >= 0) {
359 url = url.substring(index + 5); 262 url = url.substring(index + 5);
360 index = url.indexOf("&"); 263 index = url.indexOf('&');
361 if (index >= 0) 264 if (index >= 0)
362 url = url.substring(0, index); 265 url = url.substring(0, index);
363 } 266 }
364 } 267 }
365 showUrl(url); 268 showUrl(url);
366 } 269 }
367 } 270 }
368 return; 271 return;
369 } 272 }
370 } 273 }
371 } 274 }
372 275
373 window.addEventListener("message", iframeMessageHandler); 276 window.addEventListener('message', iframeMessageHandler);
374 </script> 277 document.addEventListener('DOMContentLoaded', main);
375 </head>
376 <body onload="main();">
377 <a id="title_a" tabIndex="0"><img id='title' alt="Google News logo"></a>
378 <div id="feed"></div>
379 </body>
380 </html>
381
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698