Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Stories are now loaded into LocalStorage every X number of minutes so…

… that they can be loaded more quickly, improving the responsiveness of the UI
  • Loading branch information...
commit 81c106544e1265d8df3964af9fb672a48dcb27ec 1 parent db528f8
@adamalbrecht authored
View
BIN  ajax-loader.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
16 background.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="core.js" />
+<script src="json2.js" />
+<script>
+var requestInterval = 60000; //miliseconds
+function startRequest() {
+ UpdateFeed();
+ window.setTimeout(startRequest, requestInterval);
+}
+</script>
+</head>
+<body onload='startRequest()'>
+</body>
+</html>
View
130 core.js
@@ -0,0 +1,130 @@
+var feedUrl = 'http://news.ycombinator.com/rss';
+var maxFeedItems = 15;
+var req;
+var buildPopupAfterResponse = false;
+var OnFeedSuccess = null;
+var OnFeedFail = null;
+
+function UpdateFeed() {
+ req = new XMLHttpRequest();
+ req.onload = HandleRssResponse;
+ req.onerror = handleError;
+ req.open("GET", feedUrl, true);
+ req.send(null);
+}
+
+function HandleRssResponse() {
+ var doc = req.responseXML;
+ if (!doc) {
+ doc = parseXml(req.responseText);
+ }
+ if (!doc) {
+ handleFeedParsingFailed("Not a valid feed.");
+ return;
+ }
+ links = parseHNLinks(doc);
+ SaveLinksToLocalStorage(links);
+ if (buildPopupAfterResponse == true) {
+ buildPopup(links);
+ buildPopupAfterResponse = false;
+ }
+}
+
+function handleError() {
+ handleFeedParsingFailed('Failed to fetch RSS feed.');
+}
+
+function handleFeedParsingFailed(error) {
+ var feed = document.getElementById("feed");
+ feed.className = "error"
+ feed.innerText = "Error: " + error;
+}
+
+function parseXml(xml) {
+ var xmlDoc;
+ try {
+ xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
+ xmlDoc.async = false;
+ xmlDoc.loadXML(xml);
+ } catch (e) {
+ xmlDoc = (new DOMParser).parseFromString(xml, 'text/xml');
+ }
+
+ return xmlDoc;
+}
+
+function parseHNLinks(doc) {
+ var entries = doc.getElementsByTagName('entry');
+ if (entries.length == 0) {
+ entries = doc.getElementsByTagName('item');
+ }
+ var count = Math.min(entries.length, maxFeedItems);
+ var links = new Array();
+ for (var i=0; i< count; i++) {
+ item = entries.item(i);
+ var hnLink = new Object();
+ //Grab the title
+ var itemTitle = item.getElementsByTagName('title')[0];
+ if (itemTitle) {
+ hnLink.Title = itemTitle.textContent;
+ } else {
+ hnLink.Title = "Unknown Title";
+ }
+
+ //Grab the Link
+ var itemLink = item.getElementsByTagName('link')[0];
+ if (!itemLink) {
+ itemLink = item.getElementsByTagName('comments')[0];
+ }
+ if (itemLink) {
+ hnLink.Link = itemLink.textContent;
+ } else {
+ hnLink.Link = '';
+ }
+
+ //Grab the comments link
+ var commentsLink = item.getElementsByTagName('comments')[0];
+ if (commentsLink) {
+ hnLink.CommentsLink = commentsLink.textContent;
+ } else {
+ hnLink.CommentsLink = '';
+ }
+
+ links.push(hnLink);
+ }
+ return links;
+}
+
+function SaveLinksToLocalStorage(links) {
+ localStorage["HN.NumLinks"] = links.length;
+ for (var i=0; i<links.length; i++) {
+ localStorage["HN.Link" + i] = JSON.stringify(links[i]);
+ }
+}
+
+function RetrieveLinksFromLocalStorage() {
+ var numLinks = localStorage["HN.NumLinks"];
+ if (numLinks == null) {
+ return null;
+ }
+ else {
+ var links = new Array();
+ for (var i=0; i<numLinks; i++) {
+ links.push(JSON.parse(localStorage["HN.Link" + i]))
+ }
+ return links;
+ }
+}
+
+function openLink() {
+ openUrl(this.href, false);
+}
+
+// Show |url| in a new tab.
+function openUrl(url, take_focus) {
+ // Only allow http and https URLs.
+ if (url.indexOf("http:") != 0 && url.indexOf("https:") != 0) {
+ return;
+ }
+ chrome.tabs.create({url: url, selected: take_focus});
+}
View
28 json2.js
@@ -0,0 +1,28 @@
+if(!this.JSON){this.JSON={};}
+(function(){function f(n){return n<10?'0'+n:n;}
+if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
+f(this.getUTCMonth()+1)+'-'+
+f(this.getUTCDate())+'T'+
+f(this.getUTCHours())+':'+
+f(this.getUTCMinutes())+':'+
+f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
+var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
+function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
+if(typeof rep==='function'){value=rep.call(holder,key,value);}
+switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
+gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
+v=partial.length===0?'[]':gap?'[\n'+gap+
+partial.join(',\n'+gap)+'\n'+
+mind+']':'['+partial.join(',')+']';gap=mind;return v;}
+if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
+v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
+if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
+rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
+return str('',{'':value});};}
+if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
+return reviver.call(holder,key,value);}
+text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
+('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
+if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
+throw new SyntaxError('JSON.parse');};}}());
View
1  manifest.json
@@ -9,6 +9,7 @@
"default_icon": "icon18.gif",
"popup": "popup.html"
},
+ "background_page":"background.html",
"permissions": [
"tabs",
"http://news.ycombinator.com/*"
View
220 popup.html
@@ -5,160 +5,106 @@
body {font-family: verdana,helvetica, arial, sans-serif;font-size: 10pt;overflow: hidden;}
a {text-decoration:none; color:#000;}
a:hover {text-decoration:underline;}
-#container { background:#F6F6EF; width:350px;}
+#container, #spinner { background:#F6F6EF; width:350px;}
#header {height:26px; background: #f60; color:#222;}
#header img { border: 1px solid #fff; float:left; margin:3px;}
#header a, #header span { color:#222; float:left; margin:5px 2px 0 5px; }
#title, a#title { font-weight:bold; font-size:14px; margin-top:5px; }
#feed {min-width:auto; margin:5px; font-size:9pt; padding-bottom:2px; }
-#feed table, #feed a:visited, #feed a.comments, #feed td:nth-child(1) { color:#828282;}
+#feed table, #feed a:visited, #feed a.comments, #feed td:nth-child(1), #footer, #footer a { color:#828282;}
#feed td { vertical-align:top; }
.link { padding: 2px 0px; }
.link span { margin-right:3px;}
.comments { font-size:7pt; margin-left:5px; }
.error {white-space: nowrap;color: red;}
+#footer {float:right; font-size:11px;}
+#spinner {height:300px; text-align:center; padding-top:50px;}
</style>
+<script src="core.js" />
+<script src="json2.js" />
<script>
- var feedUrl = 'http://news.ycombinator.com/rss';
- var maxFeedItems = 15;
- var req;
-
function main() {
- req = new XMLHttpRequest();
- req.onload = HandleRssResponse;
- req.onerror = handleError;
- req.open("GET", feedUrl, true);
- req.send(null);
- }
-
- function HandleRssResponse() {
- var doc = req.responseXML;
- if (!doc) {
- doc = parseXml(req.responseText);
- }
- if (!doc) {
- handleFeedParsingFailed("Not a valid feed.");
- return;
- }
- var links = parseHNLinks(doc);
- buildPopup(links);
- }
-
- function handleError() {
- handleFeedParsingFailed('Failed to fetch RSS feed.');
- }
-
- function handleFeedParsingFailed(error) {
- var feed = document.getElementById("feed");
- feed.className = "error"
- feed.innerText = "Error: " + error;
- }
-
- function parseXml(xml) {
- var xmlDoc;
- try {
- xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
- xmlDoc.async = false;
- xmlDoc.loadXML(xml);
- } catch (e) {
- xmlDoc = (new DOMParser).parseFromString(xml, 'text/xml');
- }
-
- return xmlDoc;
+ if (localStorage['HN.NumLinks'] == null)
+ {
+ buildPopupAfterResponse = true;
+ UpdateFeed();
+ }
+ else {
+ buildPopup(RetrieveLinksFromLocalStorage());
+ }
}
- function parseHNLinks(doc) {
- var header = document.getElementById("header");
- var feed = document.getElementById("feed");
- var entries = doc.getElementsByTagName('entry');
- if (entries.length == 0) {
- entries = doc.getElementsByTagName('item');
- }
+ function buildPopup(links) {
+ var header = document.getElementById("header");
+ var feed = document.getElementById("feed");
- //Set Title Link
- var title = document.getElementById("title");
- title.addEventListener("click", openLink);
+ //Setup Title Link
+ var title = document.getElementById("title");
+ title.addEventListener("click", openLink);
- //Create Submit Link
- var submitLink = document.getElementById("submitLink");
- submitLink.addEventListener("click", submitCurrentTab);
-
- var count = Math.min(entries.length, maxFeedItems);
- var links = new Array();
- for (var i=0; i< count; i++) {
- item = entries.item(i);
- var hnLink = new Object();
- //Grab the title
- var itemTitle = item.getElementsByTagName('title')[0];
- if (itemTitle) {
- hnLink.Title = itemTitle.textContent;
- } else {
- hnLink.Title = "Unknown Title";
- }
-
- //Grab the Link
- var itemLink = item.getElementsByTagName('link')[0];
- if (!itemLink) {
- itemLink = item.getElementsByTagName('comments')[0];
- }
- if (itemLink) {
- hnLink.Link = itemLink.textContent;
- } else {
- hnLink.Link = '';
- }
+ //Setup Submit Link
+ var submitLink = document.getElementById("submitLink");
+ submitLink.addEventListener("click", submitCurrentTab);
+
+ //Setup Refresh Link
+ var refreshLink = document.getElementById("refresh");
+ refreshLink.addEventListener("click", refreshLinks);
- //Grab the comments link
- var commentsLink = item.getElementsByTagName('comments')[0];
- if (commentsLink) {
- hnLink.CommentsLink = commentsLink.textContent;
- } else {
- hnLink.CommentsLink = '';
- }
-
- links.push(hnLink);
- }
- return links;
- }
-
-function buildPopup(links) {
- for (var i=0; i<links.length; i++) {
- hnLink = links[i];
- var row = document.createElement("tr");
- row.className = "link";
- var num = document.createElement("td");
- num.innerText = i+1;
- var link_col = document.createElement("td")
- var title = document.createElement("a");
- title.className = "link_title";
- title.innerText = hnLink.Title;
- title.href = hnLink.Link;
- title.addEventListener("click", openLink);
- var comments = document.createElement("a");
- comments.className = "comments";
- comments.innerText = "(comments)";
- comments.href = hnLink.CommentsLink;
- comments.addEventListener("click", openLink);
+ for (var i=0; i<links.length; i++) {
+ hnLink = links[i];
+ var row = document.createElement("tr");
+ row.className = "link";
+ var num = document.createElement("td");
+ num.innerText = i+1;
+ var link_col = document.createElement("td")
+ var title = document.createElement("a");
+ title.className = "link_title";
+ title.innerText = hnLink.Title;
+ title.href = hnLink.Link;
+ title.addEventListener("click", openLink);
+ var comments = document.createElement("a");
+ comments.className = "comments";
+ comments.innerText = "(comments)";
+ comments.href = hnLink.CommentsLink;
+ comments.addEventListener("click", openLink);
- link_col.appendChild(title);
- link_col.appendChild(comments);
- row.appendChild(num);
- row.appendChild(link_col)
- feed.appendChild(row);
- }
-}
-
- function openLink() {
- openUrl(this.href, false);
- }
-
- // Show |url| in a new tab.
- function openUrl(url, take_focus) {
- // Only allow http and https URLs.
- if (url.indexOf("http:") != 0 && url.indexOf("https:") != 0) {
- return;
- }
- chrome.tabs.create({url: url, selected: take_focus});
+ link_col.appendChild(title);
+ link_col.appendChild(comments);
+ row.appendChild(num);
+ row.appendChild(link_col)
+ feed.appendChild(row);
+ }
+ hideElement("spinner");
+ showElement("container");
+ }
+
+ function refreshLinks() {
+ var linkTable = document.getElementById("feed");
+ while(linkTable.hasChildNodes()) linkTable.removeChild(linkTable.firstChild); //Remove all current links
+ toggle("container");
+ toggle("spinner");
+ buildPopupAfterResponse = true;
+ UpdateFeed(null, null);
+ }
+
+ function hideElement(id) {
+ var e = document.getElementById(id);
+ e.style.display = 'none';
+ }
+
+ function showElement(id) {
+ var e = document.getElementById(id);
+ e.style.display = 'block';
+ }
+
+ function toggle(id) {
+ var e = document.getElementById(id);
+ if(e.style.display == 'block')
+ e.style.display = 'none';
+ else
+ e.style.display = 'block';
}
+
//Submit the current tab
function submitCurrentTab() {
chrome.windows.getCurrent(function(win){
@@ -171,6 +117,9 @@
</script>
</head>
<body onload="main();">
+ <div id="spinner" style="display:none">
+ <img src="ajax-loader.gif">
+ </div>
<div id="container">
<div id="header">
<img src="icon18.gif">
@@ -180,6 +129,9 @@
</div>
<table id="feed" cellspacing="3" cellpadding="0">
</table>
+ <div id="footer">
+ <a href="#refresh" id="refresh">Refresh</a> | <a href="#settings" id="settings">Settings</a>
+ </div>
</div>
</body>
</html>
Please sign in to comment.
Something went wrong with that request. Please try again.