2 Copyright 2011 - Tommi Laukkanen (www.substanceofcode.com)
4 This file is part of NewsFlow.
6 NewsFlow is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 NewsFlow is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with NewsFlow. If not, see <http://www.gnu.org/licenses/>.
32 var continuation = "";
34 var actionFeedUrl = "";
41 function doWebRequest(method, url, params, callback) {
42 var doc = new XMLHttpRequest();
43 //console.log(method + " " + url);
45 doc.onreadystatechange = function() {
46 if (doc.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
47 var status = doc.status;
49 showError("Google API returned " + status + " " + doc.statusText);
51 } else if (doc.readyState == XMLHttpRequest.DONE) {
53 var contentType = doc.getResponseHeader("Content-Type");
54 data = doc.responseText;
59 doc.open(method, url);
61 //console.log("Authorization GoogleLogin auth=" + sid);
62 doc.setRequestHeader("Authorization", "GoogleLogin auth=" + sid);
63 doc.setRequestHeader("Cookie", "SID=" + sidToken);
66 //console.log("Sending: " + params);
67 doc.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
68 doc.setRequestHeader("Content-Length", String(params.length));
75 /** Parse parameter from given URL */
76 function parseAuth(data, parameterName) {
77 var parameterIndex = data.indexOf(parameterName + "=");
78 if(parameterIndex<0) {
79 // We didn't find parameter
80 console.log("Didn't find Auth");
81 addError("Didn't find Auth");
84 var equalIndex = data.indexOf("=", parameterIndex);
89 var lineBreakIndex = data.indexOf("\n", equalIndex+1)
92 value = data.substring(equalIndex+1, lineBreakIndex);
96 function addError(msg) {
109 function login(email, password) {
111 // waiting.state = "shown";
112 var url = "https://www.google.com/accounts/ClientLogin?Email=" + encodeURIComponent(email) + "&Passwd=" + encodeURIComponent(password) + "&service=reader";
113 doWebRequest("GET", url, "", parseToken);
115 showError("Error while logging in.");
119 function showError(msg) {
120 console.log("ERROR: " + msg)
121 // waiting.state = "hidden";
122 // error.reason = msg;
123 // error.state = "shown";
126 function removeLinks(original) {
128 txt = txt.replace(/<a /g, "<span ");
129 txt = txt.replace(/<\/a>/g, "</span>");
133 function parseToken(data) {
134 sid = parseAuth(data, "Auth");
135 //console.log("Auth=" + sid);
136 sidToken = parseAuth(data, "SID");
137 //console.log("SID=" + sidToken);
138 // logo.state = "hidden"; //.visible = false;
140 //navigation.state = "menu";
141 //waiting.state = "hidden";
143 WorkerScript.sendMessage({"sid": sid, "sidToken": sidToken});
147 addError("Couldn't parse SID");
148 //waiting.state = "hidden";
152 function loadSubscriptions() {
153 //waiting.state = "shown";
154 var url = "http://www.google.com/reader/api/0/subscription/list?output=json";
155 doWebRequest("GET", url, "", parseSubscriptions);
158 function parseSubscriptions(data) {
159 //console.log("Subscriptions: " + data);
161 var tags = eval("[" + data + "]")[0];
162 for(var i in tags.subscriptions) {
163 var tag = tags.subscriptions[i];
165 var title = tag.title;
167 WorkerScript.sendMessage({"title": title, "published": '',"tag": tag, "id":id});
169 //navigation.state = "tags";
170 //waiting.state = "hidden";
173 function loadTags() {
174 //waiting.state = "shown";
175 var url = "http://www.google.com/reader/api/0/tag/list?output=json";
176 doWebRequest("GET", url, "", parseTags);
179 function parseTags(data) {
180 var tags = eval("[" + data + "]")[0];
181 for(var i in tags.tags) {
182 var tag = tags.tags[i];
185 while(title.indexOf("/")>0) {
186 var index = title.indexOf("/");
187 title = title.substring(index+1);
190 WorkerScript.sendMessage({"title": title, "published": '', "tag": tag, "id":id});
192 //navigation.state = "tags";
193 //waiting.state = "hidden";
196 function loadAllNews() {
197 itemsURL = "http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/reading-list";
201 function loadUnreadNews() {
202 itemsURL = "http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/reading-list?xt=user/-/state/com.google/read";
206 function loadStarred() {
207 itemsURL = "http://www.google.com/reader/api/0/stream/contents/user/-/state/com.google/starred";
211 function loadTaggedItems(tag) {
212 itemsURL = "http://www.google.com/reader/api/0/stream/contents/" + tag;
216 function loadSubscriptionItems(subscription) {
217 itemsURL = "http://www.google.com/reader/api/0/stream/contents/" + subscription;
221 function loadNews() {
223 //waiting.state = "shown";
224 doWebRequest("GET", itemsURL, "", parseNews);
226 showError("Error while loading news: " + err);
230 function getNodeValue(node, name) {
232 for(var i=0; i<node.childNodes.length; i++) {
233 var nodeName = node.childNodes[i].nodeName;
235 nodeValue = node.childNodes[i].firstChild.nodeValue;
241 function parseEntry(item) {
243 if(typeof(item.content)!=undefined && item.content!=null) {
244 content = item.content.content;
245 } else if(typeof(item.summary)!=undefined && item.summary!=null) {
246 content = item.summary.content;
250 content = removeLinks(content);
251 var milliseconds = parseInt(parseInt(item.published)*1000);
252 var published = new Date(parseInt(milliseconds));
253 var link = item.alternate[0].href;
254 //console.log("Link: " + link);
256 for(var i in item.categories) {
257 var category = item.categories[i];
258 if(category.indexOf("/reading-list")>0) {
264 WorkerScript.sendMessage({
267 "description": content,
268 "author": item.origin.title,
269 "published": prettyDate(published),
271 "source": item.origin.title,
273 "feedUrl": item.origin.streamId,
278 function parseNews(data) {
280 //console.log("DATA: " + data);
281 var doc = eval("[" + data + "]")[0];
282 if(doc==null || typeof(doc)==undefined) {
283 WorkerScript.sendMessage({
291 //waiting.state = "hidden";
295 //var moreIndex = model.count - 1;
297 continuation = doc.continuation;
298 for(var i in doc.items) {
299 var item = doc.items[i];
304 if(model.get(moreIndex).title.indexOf("Loading...")>-1) {
305 model.remove(moreIndex);
310 "title": "Load more...<br/><br/>",
319 // addError("Error: " + err);
321 // navigation.state = "items";
322 // waiting.state = "hidden";
325 function loadMore() {
326 //waiting.state = "shown";
328 if(itemsURL.indexOf("?")>0) {
333 url += "c=" + continuation;
334 doWebRequest("GET", url, "", parseNews);
337 function getToken() {
338 var url = "http://www.google.com/reader/api/0/token";
339 doWebRequest("GET", url, "", parseAccessToken, null);
342 function parseAccessToken(data) {
345 var url = "http://www.google.com/reader/api/0/edit-tag";
346 var dd = "ac=edit-tags&a=user/-/state/com.google/read&i=" + encodeURIComponent(actionID) + "&s=" + encodeURIComponent(actionFeedUrl) + "&T=" + accessToken;
347 doWebRequest("POST", url, dd, showDone, null);
348 } else if(action=="unread") {
349 var url = "http://www.google.com/reader/api/0/edit-tag";
350 var dd = "ac=edit-tags&a=user/-/state/com.google/kept-unread&r=user/-/state/com.google/read&i=" + encodeURIComponent(actionID) + "&s=" + encodeURIComponent(actionFeedUrl) + "&T=" + accessToken;
351 doWebRequest("POST", url, dd, showDone, null);
352 } else if(action=="fav") {
353 var url = "http://www.google.com/reader/api/0/edit-tag?client=-";
354 var dd = "a=user/-/state/com.google/starred&i=" + encodeURIComponent(actionID) + "&s=" + encodeURIComponent(actionFeedUrl) + "&T=" + accessToken;
355 doWebRequest("POST", url, dd, showDone, null);
356 } else if(action=="tags") {
357 var url = "http://www.google.com/reader/api/0/edit-tag?client=-";
359 "a=user/-/label/" + encodeURIComponent(tags) +
360 "&i=" + encodeURIComponent(actionID) +
361 "&s=" + encodeURIComponent(actionFeedUrl) +
363 doWebRequest("POST", url, dd, showDone, null);
367 function markAsRead(id, feedUrl, showLoadingIndicator) {
369 actionFeedUrl = feedUrl;
370 if(showLoadingIndicator) {
371 waiting.state = "shown";
377 function markAsUnread(id, feedUrl) {
379 actionFeedUrl = feedUrl;
380 //waiting.state = "shown";
382 //done.status = "Marked as unread";
386 function addTags(id, feedUrl, newTags) {
388 actionFeedUrl = feedUrl;
389 //waiting.state = "shown";
391 //done.status = "Added tags";
396 function markAsFavourite(id, feedUrl) {
398 actionFeedUrl = feedUrl;
399 //waiting.state = "shown";
401 //done.status = "Marked as favourite";
405 function showDone(data) {
406 console.log("DONE: " + data);
407 //if(waiting.state!="shown") {
410 //waiting.state = "hidden";
412 if(typeof(data)!=undefined && data!=null) {
414 //done.status = "Marked as read " + data;
415 } else if(action=="unread") {
416 //done.status = "Marked as unread " + data;
418 //done.status = "" + data;
421 //done.state = "shown";
424 function doNothing(data) {
428 function prettyDate(date){
430 var diff = (((new Date()).getTime() - date.getTime()) / 1000);
431 var day_diff = Math.floor(diff / 86400);
433 if ( isNaN(day_diff) || day_diff >= 31 ) {
434 //console.log("Days: " + day_diff);
435 return "some time ago";
436 } else if (day_diff < 0) {
437 //console.log("day_diff: " + day_diff);
441 return day_diff == 0 && (
442 diff < 60 && "just now" ||
443 diff < 120 && "1 minute ago" ||
444 diff < 3600 && Math.floor( diff / 60 ) + " min ago" ||
445 diff < 7200 && "1 hour ago" ||
446 diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
447 day_diff == 1 && "Yesterday" ||
448 day_diff < 7 && day_diff + " days ago" ||
449 day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";
450 day_diff >= 31 && Math.ceil( day_diff / 30 ) + " months ago";
452 console.log("Error: " + err);
453 return "some time ago";
457 // 2011-01-24T18:48:00Z
458 function parseDate(stamp)
461 //console.log("stamp: " + stamp);
462 var parts = stamp.split("T");
471 var dates = parts[0].split("-");
472 year = parseInt(dates[0]);
473 month = parseInt(dates[1])-1;
474 day = parseInt(dates[2]);
476 var times = parts[1].split(":");
477 hours = parseInt(times[0]);
478 minutes = parseInt(times[1]);
483 dt.setUTCMonth(month);
484 dt.setUTCHours(hours);
485 dt.setUTCMinutes(minutes);
486 dt.setUTCSeconds(seconds);
488 //console.log("day: " + day + " year: " + year + " month " + month + " hour " + hours);
492 console.log("Error while parsing date: " + err);
497 /// ======== WorkerScript related functions ========
498 WorkerScript.onMessage = function(message) {
500 // the structure of "message" object is:
501 // - attribute 'action' --> what to do
502 // - other attributes: will be passed on to the right function
504 if(message.action === 'login') {
505 login(message.email, message.password)
508 sid = message.sid; sidToken = message.sidToken;
510 if(message.action === 'getCategoryContent') {
511 // read the feeds in the right category
512 switch(message.category) {
513 case 0: loadAllNews(); break;
514 case 1: loadUnreadNews(); break;
515 case 2: loadStarred(); break;
516 case 3: loadSubscriptions(); break;
517 case 4: loadTags(); break;
520 else if(message.action === 'getSubscriptionItems') {
521 // read the feeds of that subscription
522 loadSubscriptionItems(message.subscription)
524 else if(message.action === 'getTaggedItems') {
525 // read the feeds of that subscription
526 loadTaggedItems(message.tag)