").html(data).evalScripts();
return data;
},
// Serialize an array of form elements or a set of
// key/values into a query string
param: function( a ) {
var s = [];
// If an array was passed in, assume that it is an array
// of form elements
if ( a.constructor == Array || a.jquery )
// Serialize the form elements
jQuery.each( a, function(){
s.push( encodeURIComponent(this.name) + "=" + encodeURIComponent( this.value ) );
});
// Otherwise, assume that it's an object of key/value pairs
else
// Serialize the key/values
for ( var j in a )
// If the value is an array then the key names need to be repeated
if ( a[j] && a[j].constructor == Array )
jQuery.each( a[j], function(){
s.push( encodeURIComponent(j) + "=" + encodeURIComponent( this ) );
});
else
s.push( encodeURIComponent(j) + "=" + encodeURIComponent( a[j] ) );
// Return the resulting serialization
return s.join("&");
},
// evalulates a script in global context
// not reliable for safari
globalEval: function( data ) {
if ( window.execScript )
window.execScript( data );
else if ( jQuery.browser.safari )
// safari doesn't provide a synchronous global eval
window.setTimeout( data, 0 );
else
eval.call( window, data );
}
});
jQuery.fn.extend({
show: function(speed,callback){
var hidden = this.filter(":hidden");
speed ?
hidden.animate({
height: "show", width: "show", opacity: "show"
}, speed, callback) :
hidden.each(function(){
this.style.display = this.oldblock ? this.oldblock : "";
if ( jQuery.css(this,"display") == "none" )
this.style.display = "block";
});
return this;
},
hide: function(speed,callback){
var visible = this.filter(":visible");
speed ?
visible.animate({
height: "hide", width: "hide", opacity: "hide"
}, speed, callback) :
visible.each(function(){
this.oldblock = this.oldblock || jQuery.css(this,"display");
if ( this.oldblock == "none" )
this.oldblock = "block";
this.style.display = "none";
});
return this;
},
// Save the old toggle function
_toggle: jQuery.fn.toggle,
toggle: function( fn, fn2 ){
var args = arguments;
return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
this._toggle( fn, fn2 ) :
this.each(function(){
jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]
.apply( jQuery(this), args );
});
},
slideDown: function(speed,callback){
return this.animate({height: "show"}, speed, callback);
},
slideUp: function(speed,callback){
return this.animate({height: "hide"}, speed, callback);
},
slideToggle: function(speed, callback){
return this.each(function(){
var state = jQuery(this).is(":hidden") ? "show" : "hide";
jQuery(this).animate({height: state}, speed, callback);
});
},
fadeIn: function(speed, callback){
return this.animate({opacity: "show"}, speed, callback);
},
fadeOut: function(speed, callback){
return this.animate({opacity: "hide"}, speed, callback);
},
fadeTo: function(speed,to,callback){
return this.animate({opacity: to}, speed, callback);
},
animate: function( prop, speed, easing, callback ) {
return this.queue(function(){
this.curAnim = jQuery.extend({}, prop);
var opt = jQuery.speed(speed, easing, callback);
for ( var p in prop ) {
var e = new jQuery.fx( this, opt, p );
if ( prop[p].constructor == Number )
e.custom( e.cur(), prop[p] );
else
e[ prop[p] ]( prop );
}
});
},
queue: function(type,fn){
if ( !fn ) {
fn = type;
type = "fx";
}
return this.each(function(){
if ( !this.queue )
this.queue = {};
if ( !this.queue[type] )
this.queue[type] = [];
this.queue[type].push( fn );
if ( this.queue[type].length == 1 )
fn.apply(this);
});
}
});
jQuery.extend({
speed: function(speed, easing, fn) {
var opt = speed && speed.constructor == Object ? speed : {
complete: fn || !fn && easing ||
jQuery.isFunction( speed ) && speed,
duration: speed,
easing: fn && easing || easing && easing.constructor != Function && easing
};
opt.duration = (opt.duration && opt.duration.constructor == Number ?
opt.duration :
{ slow: 600, fast: 200 }[opt.duration]) || 400;
// Queueing
opt.old = opt.complete;
opt.complete = function(){
jQuery.dequeue(this, "fx");
if ( jQuery.isFunction( opt.old ) )
opt.old.apply( this );
};
return opt;
},
easing: {},
queue: {},
dequeue: function(elem,type){
type = type || "fx";
if ( elem.queue && elem.queue[type] ) {
// Remove self
elem.queue[type].shift();
// Get next function
var f = elem.queue[type][0];
if ( f ) f.apply( elem );
}
},
/*
* I originally wrote fx() as a clone of moo.fx and in the process
* of making it small in size the code became illegible to sane
* people. You've been warned.
*/
fx: function( elem, options, prop ){
var z = this;
// The styles
var y = elem.style;
// Store display property
var oldDisplay = jQuery.css(elem, "display");
// Make sure that nothing sneaks out
y.overflow = "hidden";
// Simple function for setting a style value
z.a = function(){
if ( options.step )
options.step.apply( elem, [ z.now ] );
if ( prop == "opacity" )
jQuery.attr(y, "opacity", z.now); // Let attr handle opacity
else if ( parseInt(z.now) ) // My hate for IE will never die
y[prop] = parseInt(z.now) + "px";
y.display = "block"; // Set display property to block for animation
};
// Figure out the maximum number to run to
z.max = function(){
return parseFloat( jQuery.css(elem,prop) );
};
// Get the current size
z.cur = function(){
var r = parseFloat( jQuery.curCSS(elem, prop) );
return r && r > -10000 ? r : z.max();
};
// Start an animation from one number to another
z.custom = function(from,to){
z.startTime = (new Date()).getTime();
z.now = from;
z.a();
z.timer = setInterval(function(){
z.step(from, to);
}, 13);
};
// Simple 'show' function
z.show = function(){
if ( !elem.orig ) elem.orig = {};
// Remember where we started, so that we can go back to it later
elem.orig[prop] = this.cur();
options.show = true;
// Begin the animation
z.custom(0, elem.orig[prop]);
// Stupid IE, look what you made me do
if ( prop != "opacity" )
y[prop] = "1px";
};
// Simple 'hide' function
z.hide = function(){
if ( !elem.orig ) elem.orig = {};
// Remember where we started, so that we can go back to it later
elem.orig[prop] = this.cur();
options.hide = true;
// Begin the animation
z.custom(elem.orig[prop], 0);
};
//Simple 'toggle' function
z.toggle = function() {
if ( !elem.orig ) elem.orig = {};
// Remember where we started, so that we can go back to it later
elem.orig[prop] = this.cur();
if(oldDisplay == "none") {
options.show = true;
// Stupid IE, look what you made me do
if ( prop != "opacity" )
y[prop] = "1px";
// Begin the animation
z.custom(0, elem.orig[prop]);
} else {
options.hide = true;
// Begin the animation
z.custom(elem.orig[prop], 0);
}
};
// Each step of an animation
z.step = function(firstNum, lastNum){
var t = (new Date()).getTime();
if (t > options.duration + z.startTime) {
// Stop the timer
clearInterval(z.timer);
z.timer = null;
z.now = lastNum;
z.a();
if (elem.curAnim) elem.curAnim[ prop ] = true;
var done = true;
for ( var i in elem.curAnim )
if ( elem.curAnim[i] !== true )
done = false;
if ( done ) {
// Reset the overflow
y.overflow = "";
// Reset the display
y.display = oldDisplay;
if (jQuery.css(elem, "display") == "none")
y.display = "block";
// Hide the element if the "hide" operation was done
if ( options.hide )
y.display = "none";
// Reset the properties, if the item has been hidden or shown
if ( options.hide || options.show )
for ( var p in elem.curAnim )
if (p == "opacity")
jQuery.attr(y, p, elem.orig[p]);
else
y[p] = "";
}
// If a callback was provided, execute it
if ( done && jQuery.isFunction( options.complete ) )
// Execute the complete function
options.complete.apply( elem );
} else {
var n = t - this.startTime;
// Figure out where in the animation we are and set the number
var p = n / options.duration;
// If the easing function exists, then use it
z.now = options.easing && jQuery.easing[options.easing] ?
jQuery.easing[options.easing](p, n, firstNum, (lastNum-firstNum), options.duration) :
// else use default linear easing
((-Math.cos(p*Math.PI)/2) + 0.5) * (lastNum-firstNum) + firstNum;
// Perform the next step of the animation
z.a();
}
};
}
});
}
yocto-reader/reader/rest.js 0000644 0000041 0000000 00000005201 10735421010 015472 0 ustar www-data root var REST_root = 'http://backend.yocto.aminche.com/';
var REST_user = 'test';
function encodeParams(opcode, params) {
if (!params)
params = {};
var paramStr = opcode + '?user=' + REST_user;
$.each(params, function(key, value) {
paramStr += '&' + key + '=' + escape(value);
});
return '/yocto-reader/rest/proxy.php?u=' + encodeURIComponent(REST_root + paramStr);
}
function REST_init() {
var context = new AsyncContext(function() {
alert('allDone');
});
context.addRequest(encodeParams('allFeeds'), function(json) {
alert('returned: ' + json);
});
context.fire();
}
function AsyncContext() {
this.requests = [];
this.doneCount = 0;
}
AsyncContext.prototype.addRequest = function(url, callback) {
this.requests.push({'url': url, 'callback' : callback});
}
AsyncContext.prototype.fire = function() {
var self = this;
$.each(this.requests, function(i, req) {
// alert(req.url);
loadUrl(req.url, self._onDone.bind(self, i));
})
}
AsyncContext.prototype.setOnComplete = function(fn) {
this.onComplete = fn;
}
AsyncContext.prototype._onDone = function(i, reply) {
this.requests[i].callback(reply.responseText);
this.doneCount++;
if (this.doneCount >= this.requests.length) {
if (this.onComplete)
this.onComplete();
}
}
function loadUrl (url, processingFunction, async)
{
async = true;
// enableMozillaAccess ()
var httpRequestObj = null
try {
if (window.XMLHttpRequest)
{
httpRequestObj = new XMLHttpRequest ()
}
else if (window.ActiveXObject)
{
httpRequestObj = new ActiveXObject ("Microsoft.XMLHTTP")
}
} catch(e) {
alert(e.message);
}
if (httpRequestObj == null)
{
alert("You need browser with XMLHTTPRequest support.")
throw("You need browser with XMLHTTPRequest support");
}
httpRequestObj.onreadystatechange = function () {stateChange (httpRequestObj, processingFunction)}
httpRequestObj.open ("GET", url, async)
httpRequestObj.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" );
httpRequestObj.send ("")
return httpRequestObj;
}
function stateChange (httpRequestObj, callBack)
{
if (httpRequestObj.readyState == 4)
{
if (httpRequestObj.status == 200 )
{
if (callBack)
callBack (httpRequestObj)
}
else
{
alert("Problem retrieving XML data " + httpRequestObj.status)
}
}
}
$(window).load(REST_init);
yocto-reader/reader/feeddata.js 0000644 0000041 0000000 00000130163 10735421005 016264 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
.
*/
function feed_load_dummy(url, fn) {
var data = FTC_feedData[url];
var result = {status: {code: 404}};
if (data) {
result.status.code = 200;
result.feed = data.feed;
}
fn(result);
}
var google = {};
google.dummy = true;
google.feeds = {};
google.feeds.Feed = Class.create();
google.feeds.Feed.prototype.initialize = function(feedurl) {
this.url = feedurl;
}
google.load = function() {
}
google.setOnLoadCallback = function(fn) {
$(window).load(reader_main);
}
google.feeds.findFeeds = function(query, callback) {
var result = FTC_feedSearchData;
result.status = {code: 200};
setTimeout(function(){callback(result)}, 200);
}
google.feeds.Feed.prototype.load = function(callback) {
var url = this.url;
setTimeout(function(){feed_load_dummy(url, callback)}, 200);
}
google.feeds.Feed.prototype.setNumEntries = function(num) {
}
var FTC_feedData = {};
/*
* Return a time thats 'hours' hours behind 'now'
*/
function getPast(hours) {
var d = new Date();
var dm = d.getTime();
var past = dm - hours*60*60*1000;
var pastd = new Date(past);
return pastd.toString();
}
// Get a date with a single digit min for code coverage
function getSpcDate() {
var ds = getPast(1);
var d = new Date(ds);
d.setMinutes(5);
return d.toString();
}
FTC_feedData['http://rss.cnn.com/rss/cnn_topstories.rss'] =
{"feed":
{"title":"CNN.com",
"link":"http://www.cnn.com/?eref\u003Drss_topstories",
"author":"",
"description":"CNN.com delivers up-to-the-minute news and information on the latest top stories, weather, entertainment, politics and more.",
"type":"rss20",
"entries":[
{"title":"Simpson: Casino incident overblown","link":"http://rss.cnn.com/~r/rss/cnn_topstories/~3/156999937/index.html","author":"",
// pubDate in recent past for testing (AM/PM)
"publishedDate":getPast(2),"contentSnippet":"Former NFL star O.J. Simpson says he and one of the alleged victims of a robbery have spoken by telephone and agree the ...","content":"Former NFL star O.J. Simpson says he and one of the alleged victims of a robbery have spoken by telephone and agree the incident was blown out of proportion. Las Vegas police say no arrests have been made.\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?a\u003D8Js1vt\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?i\u003D8Js1vt\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cdiv\u003E\n\u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DVuYro1as\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DVuYro1as\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DGDbEgwbK\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DGDbEgwbK\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DUeM5GH3B\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DUeM5GH3B\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DsV0zU32H\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DsV0zU32H\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DXIa7EegJ\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DXIa7EegJ\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\n\u003C/div\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~r/rss/cnn_topstories/~4/156999937\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E","categories":[]},
{"title":"Thousands protest Iraq war, 160 arrested","link":"http://rss.cnn.com/~r/rss/cnn_topstories/~3/157014496/index.html","author":"",
// pubDate in recent past for testing (PM/AM)
"publishedDate":getPast(14),"contentSnippet":"Read full story for latest details.\n\n \n","content":"Read full story for latest details.\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?a\u003Db8CJz3\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?i\u003Db8CJz3\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cdiv\u003E\n\u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003D5eZxq3Ab\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003D5eZxq3Ab\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DHqIbyoXU\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DHqIbyoXU\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DXi5LUQhL\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DXi5LUQhL\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DgbpS4QAa\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DgbpS4QAa\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DhB32UeUF\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DhB32UeUF\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\n\u003C/div\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~r/rss/cnn_topstories/~4/157014496\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E","categories":[]},
{"title":"Report: Retired judge may replace Gonzales","link":"http://rss.cnn.com/~r/rss/cnn_topstories/~3/156946485/index.html","author":"",
// Get a date with single hour / for code coverage
"publishedDate":getSpcDate(),"contentSnippet":"A retired federal judge is a leading candidate to replace Attorney General Alberto Gonzales, whose last day on the job was ...","content":"A retired federal judge is a leading candidate to replace Attorney General Alberto Gonzales, whose last day on the job was Friday, two sources told CNN on Saturday. Michael B. Mukasey was nominated to the bench in 1988 by President Ronald Reagan.\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?a\u003DAVDuJG\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?i\u003DAVDuJG\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cdiv\u003E\n\u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DCXNvBrOj\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DCXNvBrOj\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DXgTEyF76\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DXgTEyF76\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DJ9L5OSoF\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DJ9L5OSoF\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DP1slDKtt\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DP1slDKtt\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DQQRCo9cp\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DQQRCo9cp\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\n\u003C/div\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~r/rss/cnn_topstories/~4/156946485\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E","categories":[]},
{"title":"As hopes dim, Fossett search to be assessed","link":"http://rss.cnn.com/~r/rss/cnn_topstories/~3/157003819/index.html","author":"","publishedDate":"Sat, 15 Sep 2007 16:44:40 -0700","contentSnippet":"Read full story for latest details.\n\n \n","content":"Read full story for latest details.\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?a\u003Dc1eKV8\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~a/rss/cnn_topstories?i\u003Dc1eKV8\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cdiv\u003E\n\u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DYp3zmTiH\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DYp3zmTiH\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DPxj9NPLL\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DPxj9NPLL\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DfKxlsibE\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DfKxlsibE\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DyXULsz2i\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DyXULsz2i\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?a\u003DWosFhnlY\u0022\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~f/rss/cnn_topstories?i\u003DWosFhnlY\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\n\u003C/div\u003E\u003Cimg src\u003D\u0022http://rss.cnn.com/~r/rss/cnn_topstories/~4/157003819\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E","categories":[]}
]}};
FTC_feedData['http://technosophyunlimited.blogspot.com/atom.xml'] =
{"feed":
{"title":"Technosophy Unlimited",
"link":"http://technosophyunlimited.blogspot.com/",
"author":"Chandan Kudige",
"description":"",
"type":"atom10",
"entries":[{"title":"M$ - Microsoft ? Myspace ?",
"link":"http://technosophyunlimited.blogspot.com/2007/06/m-microsoft-myspace.html",
"author":"Chandan Kudige",
"publishedDate":"Tue, 26 Jun 2007 19:43:00 -0700",
"contentSnippet":"Myspace has still been holding up, against all odds and all the predictions by sensible people, just defying the logic - how ...",
"content":"Myspace has still been holding up, against all odds and all the predictions by sensible people, just defying the logic - how can something so crappy be still so popular ?\u003Cbr\u003E\u003Cbr\u003EAnd the moment we ask that question, we realize the error in our thinking. All it takes is to look back. But is being crappy the only thing thats similar between Myspace and Microsoft, or is there anything else we can learn and predict ?\u003Cbr\u003E\u003Cbr\u003EFirstly, believe it or not, both Microsoft and Myspace are in the same kind of business - building platforms. Microsoft built a desktop platform, whereas myspace built a networking platform. But on the technology front, Microsoft built a platform to run 3rd party applications, whereas myspace built a online platform to run 3rd party widgets. Niether of them started with that grand scheme, but rather their shortcomings prompted the developers to plug in the gaps and before we know there was a whole new market segment. Entrepernuers, whose forte was identifying all the limitations and building new companies just to fix it. All this is very similar between the two M$\u0027s.\u003Cbr\u003E\u003Cbr\u003ESo what does the future hold? If past lessons are anything to go by Myspace will continue to be very open (\u0022absolutely nothing worth keeping a secret\u0022), developer friendly (\u0022we are too lazy to fix our own bugs\u0022), will face a lot of security issues (\u0022users are not worth protecting\u0022) and continue building the money muscle (\u0022quality is nothing\u0022).\u003Cbr\u003E\u003Cbr\u003EBut the fatal mistake of Myspace unlike Microsoft is that they don\u0027t have a good plan to \u0027lock\u0027 users in, except for their over-hyped critical mass of users. But in this dynamic age critical mass just gives you a head start. Even the mighties like Google have started to realise (TODO: Add references to backup my bold claims!). Over time, (hopefully in less than a year or two), there will be an awesome addon to myspace which gets the users so hooked that they will forget to go back to myspace.",
"categories":["technology",
"prediction",
"microsoft",
"myspace"]},
{"title":"New take on Google\u0027s \u0022personal time\u0022",
"link":"http://technosophyunlimited.blogspot.com/2007/05/new-take-on-googles-personal-time.html",
"author":"Chandan Kudige",
"publishedDate":"Thu, 24 May 2007 17:12:00 -0700",
"contentSnippet":"As almost everyone knows, Google started an unique trend in the industry. At first they allowed, then encouraged, and now they ...",
"content":"As almost everyone knows, Google started an unique trend in the industry. At first they allowed, then encouraged, and now they require their employees to put aside one day of the week to work on their own pet projects. It was a revolutionary idea that attracted two kinds of reactions. The starry eyed programmers everywhere said what a noble company Google was, they had the employee\u0027s best interest in their heart. As we all suspected, Google has a heart of gold. On the other hand, industry veterans like Steve Balmer \u003Ca href\u003D\u0022http://searchengineland.com/070316-084008.php\u0022\u003Emocked google\u0027s personal time concept\u003C/a\u003E\u003Cbr\u003Ecalling it naive and insane.\u003Cbr\u003E\u003Cbr\u003EHowever what most people missed is that the motivation for this concept was neither altruistic nor misguided naivety. It was a carefully calculated, but bold move, that any entrepreneur would appreciate. Think what happens in most companies that attract great people. These people do their day job to earn a living and spend the rest of their free time thinking up other great ideas. If they come up with a hit, they take off, start their own venture and eventually make millions or move on to the next big thing. The company where they were earning their living didn\u0027t really gain much from this.\u003Cbr\u003E\u003Cbr\u003ECompanies do try throwing their lawyers\u003Ca href\u003D\u0022http://bp3.blogger.com/_FUBV2D4gbvc/RlYs9qoBh9I/AAAAAAAAALo/8h-ZCQsam_U/s1600-h/dilbert2006052442720.gif\u0022\u003E\u003Cimg style\u003D\u0022margin:0pt 0pt 10px 10px;float:right\u0022 src\u003D\u0022http://bp3.blogger.com/_FUBV2D4gbvc/RlYs9qoBh9I/AAAAAAAAALo/8h-ZCQsam_U/s320/dilbert2006052442720.gif\u0022 alt\u003D\u0022\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E at such ventures, trying to claim the intellectual property, but except for the fear factor they create, they rarely succeed. So how do you take advantage of such great ideas fomenting in the brains of their employees ? Why, encourage them to work on these in company\u0027s time. This is exactly what Google is saying, and I don\u0027t think its as evil as it sounds. If I were working for such a company, I would probably work on less spectacular ideas during the personal time, and still keep the more spectacular ones for after work, in the quiet comforts of my basement, ensuring no evil hands can ever reach them ...\u003Cbr\u003E\u003Cbr\u003EIt would be great to hear opinions of new and old Google engineers about this :)",
"categories":["steve balmer",
"google",
"personal time",
"microsoft",
"larry page"]},
{"title":"Yahoo! Widgets",
"link":"http://technosophyunlimited.blogspot.com/2005/12/yahoo-widgets.html",
"author":"Chandan Kudige",
"publishedDate":"Tue, 13 Dec 2005 08:06:00 -0800",
"contentSnippet":"Yahoo just announced their new version of Konfabulator - Yahoo! Widgets.For those of you who cared to read my previous rants, I ...",
"content":"\u003Cp\u003EYahoo just announced their new version of Konfabulator - Yahoo! Widgets.\u003C/p\u003E\u003Cp\u003EFor those of you who cared to read my previous rants, I must say, \u003Cbr\u003EYahoo! is eerily headed in the right direction. They even have one \u003Cbr\u003Ewidget (The 21st century sticky notes) which can be accessed from \u003Cbr\u003Eanywhere and the notes are stored at the server. This is such a classic \u003Cbr\u003Eexample of the desktop reinvention I have been going on about.\u003C/p\u003E\u003Cp\u003EI have to check their developer APIs to see if they support standard \u003Cbr\u003EHTML (like Tiger Dashboard) or some custom scripts. I bet its going to \u003Cbr\u003Ebe regular HTML\u003Cbr\u003E(just a I predicted).\u003C/p\u003E",
"categories":[]},
{"title":"An Interlude - Ajax Tutorial",
"link":"http://technosophyunlimited.blogspot.com/2005/12/interlude-ajax-tutorial.html",
"author":"Chandan Kudige",
"publishedDate":"Fri, 09 Dec 2005 01:36:00 -0800",
"contentSnippet":"After the ranting in the previous entries, I think its time to take a break from the philosophical side and get our hands ...",
"content":"\u003Cp\u003EAfter the ranting in the previous entries, I think its time to take a break from the philosophical side and get our hands dirty. I am going to put together a tutorial which explains how to you Ajax. I plan to start from the simplest tricks all the way to the most complex ones.\u003Cbr\u003EBut one step at a time.\u003C/p\u003E\u003Cp\u003ETo begin with I will demonstrate what I have been discussing - the \u0022world-wide-wait\u0022 syndrome everyone is so familiar with. In this demo I have two pages. The first one is a traditional template based web site and the second one is Ajax based. Both of them provide you the exact same information (reviews on 7 latest car models) but you can see thedifference for yourself! \u003C/p\u003E\u003Cp\u003EI call the first one Click-and-Wait. You click each link and you wait for the page to load up. The second one, in contrast, is Wait-and-Click-click-click. The page loads the data which is packaged in an XML file and after the initial wait, you are free to click asfast as you can! \u003C/p\u003E\u003Cp\u003E\u003Ca href\u003D\u0022http://kudang.com/users/chandan/blogget/click-and-wait/click-n-wait.php\u0022\u003EPage 1\u003C/a\u003E - The typical Click and Wait website\u003C/p\u003E\u003Cp\u003E\u003Ca href\u003D\u0022http://www.blogger.com/post-edit.g?blogID\u003D19538401\u0026amp;postID\u003D113412100928656554\u0022\u003EPage 2\u003C/a\u003E - Same information, but with nifty ajax at work.\u003C/p\u003E\u003Cp\u003E\u003Cspan style\u003D\u0022font-size:85%\u0022\u003ENext: I will dissect this demo and explain how it all works. This will be useful to anyone who wants to learn the nuts and bolts of ajax orwants to implement their own ajax code. \u003C/span\u003E\u003C/p\u003E",
"categories":[]}]}};
FTC_feedData['http://rss.slashdot.org/Slashdot/slashdot'] =
{"feed":{"title":"Slashdot",
"link":"http://slashdot.org/",
"author":"help@slashdot.org",
"description":"News for nerds, stuff that matters",
"type":"rss10",
"entries":[{"title":"PC Superstore Admits Linux Hinge Repair Mistake",
"link":"http://rss.slashdot.org/~r/Slashdot/slashdot/~3/157024083/article.pl",
"author":"Erris (posted by Zonk)",
"publishedDate":"Sat, 15 Sep 2007 18:29:00 -0700",
"contentSnippet":"Erris writes \u0022PC Superstore says their store manager was wrong to turn away a client with a broken hinge whose machine should ...",
"content":"Erris writes \u0022PC Superstore says their store manager was wrong to turn away a client with a broken hinge whose machine should have been repaired. \u0027El Reg put a call in to the DSGi-owned retail giant to get some clarification on PC World\u0027s Linux support policy. A spokesman told us that there had simply been a misunderstanding at the store and that, in fact, the normal procedure would be for the Tech Guys to provide a fix. [PC World] will provide a full repair once the firm has made contact with Tikka.\u0027\u003Cp\u003E\u003Ca href\u003D\u0022http://linux.slashdot.org/article.pl?sid\u003D07/09/15/2031231\u0026amp;from\u003Drss\u0022\u003ERead more of this story\u003C/a\u003E at Slashdot.\u003C/p\u003E\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?a\u003DdFhewl\u0022\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?i\u003DdFhewl\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~r/Slashdot/slashdot/~4/157024083\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["portables"]},{"title":"Impassable Northwest Passage Open For First Time In History",
"link":"http://rss.slashdot.org/~r/Slashdot/slashdot/~3/157024084/article.pl",
"author":"Zonk",
"publishedDate":"Sat, 15 Sep 2007 16:05:00 -0700",
"contentSnippet":"An anonymous reader writes \u0022The Northwest Passage, a normally ice-locked shortcut between Europe and Asia, is now passable for ...",
"content":"An anonymous reader writes \u0022The Northwest Passage, a normally ice-locked shortcut between Europe and Asia, is now passable for the first time in recorded history reports the European Space Agency. Leif Toudal Pedersen from the Danish National Space Centre said in the article: \u0027We have seen the ice-covered area drop to just around 3 million sq km which is about 1 million sq km less than the previous minima of 2005 and 2006. There has been a reduction of the ice cover over the last 10 years of about 100 000 sq km per year on average, so a drop of 1 million sq km in just one year is extreme.\u0027\u0022\u003Cp\u003E\u003Ca href\u003D\u0022http://science.slashdot.org/article.pl?sid\u003D07/09/15/2023212\u0026amp;from\u003Drss\u0022\u003ERead more of this story\u003C/a\u003E at Slashdot.\u003C/p\u003E\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?a\u003DAz9sHz\u0022\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?i\u003DAz9sHz\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~r/Slashdot/slashdot/~4/157024084\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["science"]},{"title":"Stealthy Windows Update Raises Serious Concerns",
"link":"http://rss.slashdot.org/~r/Slashdot/slashdot/~3/157024085/article.pl",
"author":"Zonk",
"publishedDate":"Sat, 15 Sep 2007 15:26:00 -0700",
"contentSnippet":"UniversalVM writes \u0022What is the single biggest issue that bothers open source advocates about proprietary software? It is ...",
"content":"UniversalVM writes \u0022What is the single biggest issue that bothers open source advocates about proprietary software? It is probably the ability of the vendor to pull stunts like Microsoft\u0027s recent stealth software update and subsequent downplaying of any concerns. Their weak explanation seems to be a great exercise in circular logic: \u0027Had we failed to update the service automatically, users would not have been able to successfully check for updates and, in turn, users would not have had updates installed automatically or received expected notifications.\u0027 News.com is reporting that all of the updated files on both XP and Vista appears to be in windows update itself. This is information that was independently uncovered by users and still not released by Microsoft.\u0022\u003Cp\u003E\u003Ca href\u003D\u0022http://it.slashdot.org/article.pl?sid\u003D07/09/15/2040259\u0026amp;from\u003Drss\u0022\u003ERead more of this story\u003C/a\u003E at Slashdot.\u003C/p\u003E\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?a\u003D1UNV7y\u0022\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?i\u003D1UNV7y\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~r/Slashdot/slashdot/~4/157024085\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["windows"]},{"title":"Google Calls for International Privacy Standards",
"link":"http://rss.slashdot.org/~r/Slashdot/slashdot/~3/157024086/article.pl",
"author":"Zonk",
"publishedDate":"Sat, 15 Sep 2007 14:18:00 -0700",
"contentSnippet":"HairyNevus writes \u0022The Washington Post has an article detailing Google\u0027s request for international privacy standards. Google is ...",
"content":"HairyNevus writes \u0022The Washington Post has an article detailing Google\u0027s request for international privacy standards. Google is taking this matter all the way to the U.N., arguing that a hodge-podge of privacy law unnecessarily burdens Internet-based companies while also failing to protect consumers. Although Google is currently under investigation by the EU for its privacy practices, the company claims it has been a crusader for protecting consumer privacy. Google\u0027s privacy counsel Peter Fleischer called America\u0027s privacy laws \u0027too complex and too much of a patchwork,\u0027 and the European Union\u0027s laws \u0027too bureaucratic and inflexible.\u0027 The alternative? Something closer to the Asia-Pacific Economic Cooperation\u0027s framework which \u0027balances very carefully information privacy with business needs and commercial interests\u0027, according to Fleischer.\u0022\u003Cp\u003E\u003Ca href\u003D\u0022http://yro.slashdot.org/article.pl?sid\u003D07/09/15/2014253\u0026amp;from\u003Drss\u0022\u003ERead more of this story\u003C/a\u003E at Slashdot.\u003C/p\u003E\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?a\u003DMUjpX1\u0022\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?i\u003DMUjpX1\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~r/Slashdot/slashdot/~4/157024086\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["google"]},{"title":"Internal Emails of An RIAA Attack Dog Leaked",
"link":"http://rss.slashdot.org/~r/Slashdot/slashdot/~3/157024087/article.pl",
"author":"Zonk",
"publishedDate":"Sat, 15 Sep 2007 13:24:00 -0700",
"contentSnippet":"qubezz writes \u0022The company MediaDefender works with the RIAA and MPAA against piracy, setting up fake torrents and trackers and ...",
"content":"qubezz writes \u0022The company MediaDefender works with the RIAA and MPAA against piracy, setting up fake torrents and trackers and disrupting p2p traffic. Previously, the TorrentFreak site accused them of setting up a fake internet video download site designed to catch and bust users. MediaDefender denied the entrapment charges. Now 700MB of MediaDefender\u0027s internal emails from the last 6 months have been leaked onto BitTorrent trackers. The emails detail their entire plan, including how they intended to distance themselves from the fake company they set up and future strategies. Other pieces of company information were included in the emails such as logins and passwords, wage negotiations, and numerous other aspect of their internal business.\u0022\u003Cp\u003E\u003Ca href\u003D\u0022http://it.slashdot.org/article.pl?sid\u003D07/09/15/1843234\u0026amp;from\u003Drss\u0022\u003ERead more of this story\u003C/a\u003E at Slashdot.\u003C/p\u003E\n\u003Cp\u003E\u003Ca href\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?a\u003DGLD4CC\u0022\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~a/Slashdot/slashdot?i\u003DGLD4CC\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\u003C/p\u003E\u003Cimg src\u003D\u0022http://rss.slashdot.org/~r/Slashdot/slashdot/~4/157024087\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["security"]}]}};
FTC_feedData['http://www.comedycentral.com/rss/colbertvideos.jhtml'] =
{"feed":{"title":"Colbert Report Videos",
"link":"http://www.comedycentral.com/shows/the_colbert_report/index.jhtml?rsspartner\u003DrssFeedfetcherGoogle",
"author":"",
"description":"Watch Stephen Colbert feel the news at you, anytime!",
"type":"rss20",
"entries":[{"title":"Are You There, God?",
"link":"http://www.comedycentral.com/extras/indecision2008/videos/indecision_colbert/index.jhtml?playVideo\u003D102735\u0026rsspartner\u003DrssFeedfetcherGoogle",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 00:00:00 -0700",
"contentSnippet":"Mother Teresa doubted the existence of God Boy, did she have a bad career counselor!",
"content":"Mother Teresa doubted the existence of God Boy, did she have a bad career counselor!",
"categories":[]},{"title":"Father James Martin",
"link":"http://www.comedycentral.com/shows/the_colbert_report/videos/celebrity_interviews/index.jhtml?playVideo\u003D102804\u0026rsspartner\u003DrssFeedfetcherGoogle",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 00:00:00 -0700",
"contentSnippet":"Father James Martin sets Stephen straight about Mother Teresa\u0027s crisis of faith.",
"content":"Father James Martin sets Stephen straight about Mother Teresa\u0027s crisis of faith.",
"categories":[]},{"title":"WristStrong",
"link":"http://www.comedycentral.com/videos/index.jhtml?playVideo\u003D102738\u0026rsspartner\u003DrssFeedfetcherGoogle",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 00:00:00 -0700",
"contentSnippet":"Stephen suggests that Matt Lauer slip his WristStrong bracelet to President Mahmoud Ahmadinejad.",
"content":"Stephen suggests that Matt Lauer slip his WristStrong bracelet to President Mahmoud Ahmadinejad.",
"categories":[]}]}};
FTC_feedData['http://www.quotationspage.com/data/qotd.rss'] =
{"feed":{"title":"Quotes of the Day",
"link":"http://www.quotationspage.com/qotd.html",
"author":"",
"description":"Four humorous quotations each day from The Quotations Page",
"type":"rss20",
"entries":[{"title":"Bernard M. Baruch",
"link":"http://www.quotationspage.com/quote/38809.html",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 17:00:00 -0700",
"contentSnippet":"\u0022Never answer a critic, unless he\u0027s right.\u0022",
"content":"\u0022Never answer a critic, unless he\u0027s right.\u0022",
"categories":[]},{"title":"Booth Tarkington",
"link":"http://www.quotationspage.com/quote/30199.html",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 17:00:00 -0700",
"contentSnippet":"\u0022There are two things that will be believed of any man whatsoever, and one of them is that he has taken to drink.\u0022",
"content":"\u0022There are two things that will be believed of any man whatsoever, and one of them is that he has taken to drink.\u0022",
"categories":[]},{"title":"C. E. Montague",
"link":"http://www.quotationspage.com/quote/26282.html",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 17:00:00 -0700",
"contentSnippet":"\u0022To be amused by what you read--that is the great spring of happy quotations.\u0022",
"content":"\u0022To be amused by what you read--that is the great spring of happy quotations.\u0022",
"categories":[]}]}};
FTC_feedData['http://www.theonion.com/content/feeds/daily'] =
{"feed":{"title":"The Onion",
"link":"http://www.theonion.com/content",
"author":"",
"description":"America\u0027s Finest News Source",
"type":"rss20",
"entries":[{"title":"[audio] Women Now Empowered By Everything A Woman Does",
"link":"http://feeds.theonion.com/~r/theonion/daily/~3/156725839/women_now_empowered_by",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 22:01:56 -0700",
"contentSnippet":"Onion Radio News - with Doyle Redland\n \n",
"content":"Onion Radio News - with Doyle Redland\u003Cdiv\u003E\n\u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003Dd927JcyN\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003Dd927JcyN\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003DTIPcv3mH\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003DTIPcv3mH\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003DaadR8zgH\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003DaadR8zgH\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\n\u003C/div\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~r/theonion/daily/~4/156725839\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["Onion_Radio_News"]},{"title":"Description Of Sexual Fantasy Changing With Girlfriend\u0027s Reaction",
"link":"http://feeds.theonion.com/~r/theonion/daily/~3/156725840/description_of_sexual_fantasy",
"author":"",
"publishedDate":"Fri, 14 Sep 2007 22:01:41 -0700",
"contentSnippet":"HOUSTON \u0022I put my finger up yourlips. Up to your lips. Like, to hush you, because the moment is so awe-inspiring,\u0022 said ...",
"content":"HOUSTON \u0026quot;I put my finger up yourlips. Up to your lips. Like, to hush you, because the moment is so awe-inspiring,\u0026quot; said Kendler, choking back his actual fantasy.\u003Cdiv\u003E\n\u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003DoviqivBi\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003DoviqivBi\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003DfsMMhXK4\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003DfsMMhXK4\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003DhqiyMuVE\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003DhqiyMuVE\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\n\u003C/div\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~r/theonion/daily/~4/156725840\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["Sex",
"couples",
"Bars",
"News",
"People"]},{"title":"[audio] Florida Town Mentally Prepares For Hurricane",
"link":"http://feeds.theonion.com/~r/theonion/daily/~3/156276304/florida_town_mentally",
"author":"",
"publishedDate":"Thu, 13 Sep 2007 22:01:58 -0700",
"contentSnippet":"Onion Radio News - with Doyle Redland\n \n",
"content":"Onion Radio News - with Doyle Redland\u003Cdiv\u003E\n\u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003D0B6fP3fh\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003D0B6fP3fh\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003DZs5JTOM2\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003DZs5JTOM2\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E \u003Ca href\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?a\u003DtPIwrFa8\u0022\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~f/theonion/daily?i\u003DtPIwrFa8\u0022 border\u003D\u00220\u0022\u003E\u003C/a\u003E\n\u003C/div\u003E\u003Cimg src\u003D\u0022http://feeds.theonion.com/~r/theonion/daily/~4/156276304\u0022 height\u003D\u00221\u0022 width\u003D\u00221\u0022\u003E",
"categories":["Onion_Radio_News"]}]}};
FTC_feedData['http://vitativeness.blogspot.com/feeds/posts/default'] =
{"feed":{"title":"Vitativeness","link":"http://vitativeness.blogspot.com/","author":"Vitativeness","description":"","type":"atom10","entries":[{"title":"Moved","link":"http://vitativeness.blogspot.com/2007/06/moved.html","author":"Vitativeness","publishedDate":"Tue, 26 Jun 2007 19:17:00 -0700","contentSnippet":"I\u0027ve moved! Here\u0027s my new addy: touchedbycolors","content":"I\u0027ve moved! Here\u0027s my new addy: \u003Ca href\u003D\u0022http://touchedbycolors.blogspot.com\u0022\u003Etouchedbycolors\u003C/a\u003E","categories":[]},{"title":"I am back!","link":"http://vitativeness.blogspot.com/2007/04/i-am-back.html","author":"Vitativeness","publishedDate":"Sat, 28 Apr 2007 04:54:00 -0700","contentSnippet":"I\u0027ve seen it all in these past couple of months, the Washington snow,the Boston chill, the California blue sky, Las Vegas hot ...","content":"I\u0027ve seen it all in these past couple of months, the Washington snow,\u003Cbr\u003E\u003Cbr\u003Ethe Boston chill, the California blue sky, Las Vegas hot sun,\u003Cbr\u003E\u003Cbr\u003ELos Angeles rain, and to think I used to complain about Melbourne\u0027s\u003Cbr\u003E\u003Cbr\u003Eweather!\u003Cbr\u003E\u003Cbr\u003EI\u0027ve collected enough paint on this trip to last me for a couple of\u003Cbr\u003E\u003Cbr\u003Eyears (no more excuses), and to those of you who have been\u003Cbr\u003E\u003Cbr\u003Epatiently waited for me to return, thank you! New posts are on the\u003Cbr\u003E\u003Cbr\u003Eway!\u003Cbr\u003E\u003Cbr\u003E(sorry, no photos from the trip. I am not much of a clicking tourist\u003Cbr\u003E\u003Cbr\u003Eperson, hate the dead weight of the camera and if I did carry it\u003Cbr\u003E\u003Cbr\u003Earound, too lazy to take any pic).","categories":[]},{"title":"Flick It","link":"http://vitativeness.blogspot.com/2006/07/flick-it.html","author":"Vitativeness","publishedDate":"Mon, 17 Jul 2006 22:23:00 -0700","contentSnippet":"Youre in a hallway, there are three switches.Two of these switches do not perform any function.Theres a door at the end of ...","content":"\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003EYoure in a hallway, there are three switches.\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003ETwo of these switches do not perform any function.\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003ETheres a door at the end of hallway leading to a room.\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003EThe third switch will turn on the light in that room.\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003EYou can flick the switches as many times as you like,\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003Ehowever, the door to the room can only be opened once.\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003EYou can not determine whether the light in that room is\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003Eon or off without opening the door. How do you establish\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003Ewhich switch\u003Cspan\u003E \u003C/span\u003Ewill light the room?\u003Cbr\u003E\u003C/span\u003E\u003C/p\u003E\u003Cp\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003E(None of the switches are dimmers \u003C/span\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022 style\u003D\u0022font-family:Wingdings\u0022\u003E\u003Cspan\u003E:)\u003C/span\u003E\u003C/span\u003E\u003Cspan lang\u003D\u0022EN-AU\u0022\u003E).\u003C/span\u003E\u003C/p\u003E","categories":[]}]}};
FTC_feedSearchData = {"query":"cnn","entries":[{"url":"http://rss.cnn.com/rss/cnn_topstories.rss","title":"\u003Cb\u003ECNN\u003C/b\u003E.com - Breaking News, U.S., World, Weather, Entertainment \u003Cb\u003E...\u003C/b\u003E","contentSnippet":"\u003Cb\u003ECNN\u003C/b\u003E.com delivers the latest breaking news and information on the latest top \u003Cbr\u003E stories, weather, \u003Cb\u003E...\u003C/b\u003E 2007 \u003Cb\u003ECable News Network\u003C/b\u003E LP, LLLP. A Time Warner Company. \u003Cb\u003E...\u003C/b\u003E","link":"http://www.cnn.com/"},
{"url":"http://rss.cnn.com/rss/cnn_tech.rss","title":"Technology - Computers, Internet and Personal Tech News from \u003Cb\u003ECNN\u003C/b\u003E.com","contentSnippet":"Find information about the latest advances in technology at \u003Cb\u003ECNN\u003C/b\u003E. \u003Cb\u003ECNN\u003C/b\u003E Technology \u003Cbr\u003E news and video covers the internet, business and personal tech, video games, \u003Cb\u003E...\u003C/b\u003E","link":"http://www.cnn.com/TECH/"},
{"url":"http://rss.cnn.com/rss/money_topstories.rss","title":"\u003Cb\u003ECNN\u003C/b\u003E/Money","contentSnippet":"\u003Cb\u003ECNN\u003C/b\u003E, FORTUNE, MONEY, BUSINESS 2.0 and Fortune Small Business magazines offer \u003Cbr\u003E business news and financial market coverage updated throughout the day, \u003Cb\u003E...\u003C/b\u003E","link":"http://money.cnn.com/"},
/* {"url":"http://rss.cnn.com/rss/edition.rss","title":"\u003Cb\u003ECNN\u003C/b\u003E.com International","contentSnippet":"World news, the latest world news headlines, weather, sport, business and \u003Cbr\u003E entertainment brought to you by \u003Cb\u003ECNN\u003C/b\u003E europe.","link":"http://edition.cnn.com/"},
{"url":"http://rss.cnn.com/rss/edition_asia.rss","title":"\u003Cb\u003ECNN\u003C/b\u003E.com International","contentSnippet":"Countdown Beijing. Countdown Beijing. \u003Cb\u003ECNN\u003C/b\u003E takes an in-depth look at China\u0026#39;s \u003Cbr\u003E preparations for the 2008 Olympic Games full story \u003Cb\u003E...\u003C/b\u003E","link":"http://edition.cnn.com/ASIA/"},
{"url":"http://rss.cnn.com/rss/si_topstories.rss","title":"\u003Cb\u003ECNN\u003C/b\u003E/SI Network Page","contentSnippet":"SI.com - sports news, scores, photos, columns and expert analysis from the world \u003Cbr\u003E of sports including NFL, NBA, NHL, MLB, NASCAR, college basketball, \u003Cb\u003E...\u003C/b\u003E","link":"http://sportsillustrated.cnn.com/"},
{"url":"http://rss.cnn.com/rss/si_topstories.rss","title":"SI.com - 2006 Winter Olympics","contentSnippet":"Cops put on leave after Tasering student. WEATHER. \u003Cb\u003ECNN\u003C/b\u003E CareerBuilder \u0026middot; SI.com. \u003Cbr\u003E STOCK QUOTE:. SUBSCRIBE TO SI \u0026middot; GIVE THE GIFT OF SI \u003Cb\u003E...\u003C/b\u003E","link":"http://sportsillustrated.cnn.com/olympics/"},
{"url":"http://rss.cnn.com/rss/cnn_politicalticker.rss","title":"\u003Cb\u003ECNN\u003C/b\u003E.com - \u003Cb\u003ECNN\u003C/b\u003E Political Ticker","contentSnippet":"WASHINGTON (\u003Cb\u003ECNN\u003C/b\u003E) Former Massachusetts Gov. Mitt Romney criticizes his fellow \u003Cbr\u003E Republicans for failing to control spending, neglecting to take action on \u003Cb\u003E...\u003C/b\u003E","link":"http://politicalticker.blogs.cnn.com/"},
*/ {"url":"http://twitter.com/statuses/user_timeline/428333.rss","title":"Twitter / cnnbrk","contentSnippet":"Name: \u003Cb\u003ECNN\u003C/b\u003E Breaking News; Bio: \u003Cb\u003ECNN\u003C/b\u003E.com is among the world\u0026#39;s leaders in online news \u003Cbr\u003E and \u003Cb\u003E...\u003C/b\u003E Location: Everywhere. Web: http://www.\u003Cb\u003Ecnn\u003C/b\u003E.com/; Joined: Jan 2007 \u003Cb\u003E...\u003C/b\u003E","link":"http://twitter.com/cnnbrk"},
{"url":"http://rss.cnn.com/rss/cnn_topstories.rss","title":"\u003Cb\u003ECNN\u003C/b\u003E.com - Breaking News, U.S., World, Weather, Entertainment \u003Cb\u003E...\u003C/b\u003E","contentSnippet":"\u003Cb\u003ECNN\u003C/b\u003E.com delivers the latest breaking news and information on the latest top \u003Cbr\u003E stories, weather, business, entertainment, politics, and more.","link":"http://cnn.org/"}]};
yocto-reader/reader/cache.js 0000644 0000041 0000000 00000010013 10735421005 015561 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
.
*/
/* Cache for feed items and their status
*
* (c) 2005-2007 Chandan Kudige
*
*
/*--------------------------------------------------------------------------*/
var FCV_cache = {};
var FCV_unread = {'_all' : 0};
function FC_cacheItem(entry) {
itemid = entry['entries-itemid'];
FCV_cache[itemid] = entry;
}
/*
function FC_lookupItem(feed, timestamp) {
return FC_lookupItemId(FC_makeItemId(feed, timestamp));
}
*/
function FC_lookupItemId(itemid) {
return FCV_cache[itemid];
}
function FC_makeItemId(feed, timestamp) {
return feed + FRC_joinstring + timestamp;
}
function FC_getItemFeed(itemid) {
try {
var t = itemid.split(FRC_joinstring);
if (t.length > 1)
return t[0];
} catch(e) {
}
}
function FC_clearUnread(feed) {
if (feed) {
if (FCV_unread[feed]) {
FCV_unread['_all'] -= parseInt(FCV_unread[feed]);
FCV_unread[feed] = 0;
}
} else {
// FCV_unread = {'_all' : 0};
}
}
function FC_updateUnread(feed, count) {
if (!FCV_unread[feed])
FCV_unread[feed] = 0;
FCV_unread[feed] += count;
FCV_unread['_all'] += count;
}
function FC_getUnread(feed) {
if (!FCV_unread[feed])
FCV_unread[feed] = 0;
return FCV_unread[feed];
}
function FC_getUnreadAll() {
return FCV_unread['_all'];
/* var total = 0;
$.each(FCV_unread, function(feed, num) {
total += num;
});
return total;
*/
}
function FC_setItemRead(itemid) {
var feed = FC_getItemFeed(itemid);
if (!feed || FR_isItemRead(itemid))
return;
FC_updateUnread(feed, -1);
FR_setItemRead(itemid);
Reader.updateFeedCount([feed], [itemid]);
}
function FC_setItemUnread(itemid) {
var feed = FC_getItemFeed(itemid);
if (feed && FR_isItemRead(itemid)) {
FC_updateUnread(feed, 1);
FR_setItemUnread(itemid);
Reader.updateFeedCount([feed], [itemid]);
}
}
var FC_lastCacheTime = 0;
var FC_cacheInterval = 60*1000; //msec (1 min)
var FC_updateInterval = 5*60*1000; // (5 mins)
var FC_numEntries = 100;
var FC_feedData = {};
function FC_cacheFeed(feedurl, entries) {
FC_feedData[feedurl] = {entries: entries,
cacheTime: currentTime()};
}
function FC_retreiveFeed(feedurl, callback) {
var result = FC_feedData[feedurl];
if (!result || timeExpired(result.cacheTime, FC_cacheInterval)) {
var feed = new google.feeds.Feed (feedurl);
feed.setNumEntries(FC_numEntries);
feed.load(FC_cacheAndCall.bind(null, callback, feedurl));
} else if (callback) {
// callback(result.entries);
setTimeout(function() {callback(result.entries);}, 100);
}
}
function FC_cacheAndCall(callback, feedurl, result) {
if (result.status.code == 200) {
var entries = GfeedToEntries(result.feed, feedurl);
FC_cacheFeed(feedurl, entries);
if (callback)
callback(entries);
} else {
if (callback) {
// XXX
callback([], "Feed could not be loaded - " + result.status.code);
}
}
}
yocto-reader/reader/template.js 0000644 0000041 0000000 00000016173 10735421010 016342 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
.
*/
/*
* Extensions to jQuery DOM wrapper to render javascript objects
* and arrays into appropriate HTML templated nodes.
*
* Author: Chandan Kudige (2007)
*/
jQuery.fn.extend({
/*
* Populate an HTML node with attributes from a javascript object.
* object can be an array or a dictionary
*
* For each attribute of the object, the dom elements whose
* classname contains the attribute name with a prefix ('fld-')
* are determined, and is populated by value of that attribute
*/
populate: function(object, template) {
if (typeof(object) == typeof([]) &&
object.length != undefined) {
return this.populateArray(object, template);
}
return this.populateObject(object);
},
/*
* Populate HTML template nodes with items from an array
* and append the nodes to 'this' node(s).
*
* Returns an array of bindings, one item for each element
* of the array.
* each binding has
* node - newly created HTML node for the element
* obj - corresponding element in the array
*/
populateArray: function(array_object, template) {
var node = this;
if (typeof(template) == typeof('')) {
template = $(template, $("#templates"));
}
var bindings = new Array;
$.each(array_object, function(i, prop) {
if (typeof(prop) != typeof(function(){})) {
var newnode = template.clone(true).
appendTo(node).populateObject(prop);
bindings.push({node: newnode, obj: prop});
}
});
return bindings;
},
/*
* Populate HTML node with the given object attributes.
*
* Returns the modified nodeset for chaining
*/
populateObject: function(json) {
node = this;
if (typeof(json) == typeof('')) {
json = {'name' : json};
}
for (property in json) {
var set;
if (node.is('.fld-' + property))
set = node;
else
set = $('.fld-' + property, node);
set.each(
function() {
var node = $(this);
if (property == 'icon') {
this.style.backgroundImage = 'url("themes/default/' +
json[property] + '")';
} else {
$(this).setdata(json[property]);
}
});
}
return node; // chain
},
/*
* This variant populates an HTML node with and item and an array of entries
* (item is the feed attributes, array is the feed entries.
* Used for the Summary View
*
* properties and rootpath are for internal use.
*/
populateFeed : function(obj, properties, rootpath) {
var target = this;
if (!properties)
properties = {};
if (!rootpath)
rootpath = '';
var path;
for (var p in obj) {
path = rootpath;
if (path)
path += '-';
path += p;
if (typeof (obj [p]) == typeof("")) {
properties[path] = obj[p];
}
}
target.populate(properties);
for (var p in obj) {
path = rootpath;
if (path)
path += '-';
path += p;
if (typeof (obj [p]) == "object") {
var ts = $('.fld-'+p, target);
var rt = ts.clone(true);
for (var i = 0, j = obj [p].length; i < j; i++) {
ts.populateFeed(obj[p][i], properties, path);
if (i < j - 1) {
ts.after(rt.clone(true));
ts = ts.next();
}
}
}
}
return target; // chain
}
});
/*
* Generic function to populate folders and tags
* for folder chooser dropdowns
*/
function populateFolders(topnode, feed, callback) {
var dropdown = $("ul.contents", topnode);
var folders = FR_folderForFeed(feed);
var allfolders = FR_allFolders();
$.merge(allfolders, FR_allTags());
dropdown.children().remove();
var addfolder = true;
// Function called when the user clicks on a folder/tag in the dropdown
var fn = function(event) {
event = jQuery.event.fix( event || window.event || {} );
var folder = event.target.innerHTML;
if (folder == FS_new_tag) {
folder = prompt(FS_enter_new_tag);
if (!folder)
return;
}
var remove = $(event.target).is('.chooser-item-selected');
if (remove) {
FR_removeFromFolder(feed, folder);
} else {
FR_copyToFolder(feed, folder);
}
Reader.refresh();
dropdown.addClass('hidden');
// Invoke the app callback if needed
if (callback) {
callback(feed, folder,
$(event.target).is('.chooser-item-selected'),
topnode);
}
// Re-populate the dropdown
populateFolders(topnode, feed, callback);
}
$.each(allfolders, function(i, folder) {
var li = $(document.createElement('li')).addClass('chooser-item')
.setdata(folder).appendTo(dropdown).click(fn);
if ($.indexOf(folders, folder) >= 0) {
li.addClass('chooser-item-selected');
addfolder = false;
}
});
$(document.createElement('li')).addClass('chooser-item')
.setdata(FS_new_tag).appendTo(dropdown).click(fn).addClass('newfolder');
var strprompt = FS_change_folders;
if (addfolder) {
strprompt = FS_add_to_folder;
}
$('.prompt', topnode).setdata(strprompt);
}
/*
* Just like jQuery extend function,
* but copy attributes with an optional prefix
*/
function objectCopy(dest, src, prefix) {
if (!prefix)
prefix = '';
for (p in src) {
if (typeof(src[p]) == typeof('')) {
dest[prefix + p] = src[p];
}
}
return dest;
}
yocto-reader/reader/rest.html 0000644 0000041 0000000 00000000651 10735421010 016026 0 ustar www-data root
REST TEST
TEST TEST
chandan
Last modified: Sun Dec 16 10:10:48 EST 2007
yocto-reader/reader/feed.js 0000644 0000041 0000000 00000016146 10735421005 015436 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
.
*/
/*
* FeedRenderer class
* Wrapper around Google Feed API to display feeds in different
* formats.
*/
function FeedRenderer () {
this.feeds = new Array ();
this.numEntries = 4;
}
FeedRenderer.prototype.add = function (url) {
if (typeof(url) != typeof([])) {
url = [url];
}
$.merge(this.feeds, [url]);
}
FeedRenderer.prototype.renderFeed = function (url, target, template) {
var fn = function (myurl, result) {
if (result.status.code == 200) {
result.feed.feed = myurl + '';
if (FC_getUnread(result.feed.feed))
result.feed.feedunread = '(' + FC_getUnread(result.feed.feed) + ')';
var folders = FR_folderForFeed(result.feed.feed);
var folder;
if (folders && folders.length>0) {
folder = folders[0];
result.feed.folder = '' + folders[0];
target.addClass('summary-with-folder');
var folderunread = 0;
$.each(FR_feedsInFolder(folders[0]), function(i, ffeed) {
folderunread += FC_getUnread(ffeed);
});
if (folderunread)
result.feed.folderunread = '(' + folderunread + ')';
}
target.populateFeed(result.feed).removeClass('hidden');
ReaderViewer.homeItemLoaded(target, result.feed.feed, folder);
}
else {
// error
}
}
fn = fn.bind(null, url);
var feed = new google.feeds.Feed (url);
feed.setNumEntries(this.numEntries);
feed.load(fn);
}
FeedRenderer.prototype.render = function (target, template) {
var bindings = [];
for (var i=0; i< this.feeds.length; i++) {
var rt = template.clone(true).addClass('hidden');
target.append(rt);
this.renderFeed (this.feeds[i], rt);
bindings.push({node: rt, feed: this.feeds[i]});
}
return bindings
}
FeedRenderer.prototype.renderSearchResult = function (query, target, template) {
google.feeds.findFeeds (query, function (result) {
if (result.status.code == 200) {
var rt = template.clone (true);
rt[0].id = "";
target.append (rt);
target.populateFeed(result);
Reader.hideLoading();
// Mark the entries whose feeds are already subscribed to
$(".tpl-search", $("#main")).each(function() {
var node = $(this);
var feed = $("input.fld-entries-url", node).getdata();
if (FR_feedInfo(feed)) {
node.addClass('result-subscribed');
}
populateFolders(node, feed);
});
}
else {
// error
}
});
}
FeedRenderer.prototype.startLoading = function (sink) {
for (var i=0; i< this.feeds.length; i++) {
var feedurl = this.feeds[i];
var fn = function(entries, error) {
if (error) {
alert(feedurl + ' error: ' + error);
} else if (entries) {
sink.inject(entries);
}
}
FC_retreiveFeed(feedurl, fn);
}
}
var MonthNames = [
'Jan', 'Feb', 'Mar',
'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'
];
function format_author(author) {
return "by " + author;
}
function format_date(datestr) {
var today = new Date();
var d = new Date(datestr);
var tm = today.getTime();
var dm = d.getTime();
if (dm > tm - 24*60*60*1000) {
var hh = d.getHours();
var mm = d.getMinutes();
var am = 'AM';
if (hh >= 12) {
hh -= 12;
am = 'PM';
}
if (mm < 10) {
mm = '0' + mm;
}
return hh + ':' + mm + ' ' + am;
} else {
return MonthNames[d.getMonth()] + ' ' + d.getDate() + ', ' + d.getFullYear();
}
}
function format_timestamp(str) {
var d = new Date(str);
return d.getTime();
}
function GfeedToEntries(gfeed, feedurl) {
var unread = 0;
var updated = false;
var entries = $.map(gfeed.entries,function(entry) {
var timestamp = 0;
var title = entry['title'];
if (entry['publishedDate']) {
timestamp = format_timestamp(entry['publishedDate']);
entry['formatDate'] = format_date(entry['publishedDate']);
}
if (entry['author']) {
entry['formatAuthor'] = format_author(entry['author']);
}
// Item ID format is decided here.
var itemid = entry['itemid'] =
FC_makeItemId(feedurl, timestamp+'/'+title);
if (!FR_isItemRead(itemid)) {
unread ++;
}
var property = objectCopy({feed: feedurl}, gfeed, '');
property = objectCopy(property, entry, 'entries-');
property.timestamp = timestamp;
if (!FC_lookupItemId(itemid)) {
FC_cacheItem(property);
updated = true;
}
return property;
});
FC_clearUnread(feedurl);
FC_updateUnread(feedurl, unread);
Reader.updateFeedCount([feedurl]);
if (updated) {
Reader.flashFeeds([feedurl]);
}
return entries;
}
/*
* Injector takes an array, 'inject' into a processing function
* slowly, with timeouts, so that the browser does not become
* unresponsive
*/
function Injector(callback, num, interval) {
this.callback = callback;
this.entries = [];
this.timer = false;
this.num = num;
this.interval = interval;
}
Injector.prototype = {
inject: function(items) {
/* if (typeof(items) != typeof([])) {
items = [items];
}
*/
$.merge(this.entries, items);
this.added();
},
added: function() {
if (!this.timer && this.entries.length > 0) {
this.pushout();
}
},
pushout: function() {
this.timer = false;
var current = this.entries.slice(0, this.num);
this.entries = this.entries.slice(this.num);
this.callback(current);
if (this.entries.length > 0) {
setTimeout(this.pushout.bind(this), this.interval);
this.timer = true;
}
}
}
yocto-reader/reader/strings.js 0000644 0000041 0000000 00000002171 10735421010 016211 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
.
*/
var FS_change_folders = 'Change folders ...';
var FS_add_to_folder = 'Add to folder ...';
var FS_new_tag = 'New tag ...';
var FS_enter_new_tag = 'Please enter a new tag';
yocto-reader/reader/mockapi.js 0000644 0000041 0000000 00000102111 11123730256 016145 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
* Copyright (C) 2008 Bradley M. Kuhn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
/*=======================================================
*
* DB Cache Variables
*
* All DB access is expected to be cached in these
* variables, and the application accesses the cache
* when calling the FR_* APIs
*
* APIs which modify the DB should update the cache immediately and
* return.
* The actual DB update should happen in background, hopefully
* with a request queue.
*
*=======================================================*/
/* Login Info:
* Details for the user logged in
*/
var FRV_logininfo;
/* Unique url for user's shared items */
var FRV_shareurl;
/* This is a list of all subscribed feeds */
var FRV_feedlist;
/* Internal to mock apis */
var FRV_feedinfo;
/* This is a hash keyed on feed url, value contains the title.
* This is used for speeding up the UI
*/
var FRV_feedhash;
/*
* Hashtable keyed on tagnames, and the values are arrays of
* itemids.
* itemid = feedurl + '::' + item publish timestamp
*/
var FRV_tagHash;
/* This dict stores the time stamp at which each item was tagged/branded
* a particular tag
*/
var FRV_tagTime;
/*
* Generalized list of item-level operations. Currently only
* 'Starred' and 'Shared' items are provided. Please see the
* note in FR_init() for format of this structure.
*/
var FRV_brands;
/*
* Hash table keyed on feed urls, and value is the foldername
* (if that feed is filed under any folder).
*/
var FRV_folderHash;
/*
* Hash table keyed on property name and values are property values.
* The DB should support storing whatever properties are passed
* by the application and retreive them back when requested.
*/
var FRV_properties;
/*
* List of items to be displayed when user 'browses' feeds.
* - Format yet to be specified -
*/
var FRV_browseFeeds;
/*
* Reading stats for the 'trends' display
*/
var FRV_trends;
/* Item status such as Starred, Shared and Read are stored as
* special tags in FRV_tagHash. The special names of the special tags
* start with this prefix
*/
var FRC_brandPrefix = '_';
/*
* Safe string to join item components to create an itemid
*/
var FRC_joinstring = ':@@:';
/*
* Property Prefixes:
* We use FR_get/setProperty for storing a lot of state information.
* Here are the prefixes used
*/
var FRP_FOLDER_STATE = 'folder-state-';
var FRP_FOLDER_SHARE = 'folder-share-';
var FRP_BUNDLE_STATE = 'bundle-state-';
/* This property determines the time for which an item should be open
* before its marked read
*/
var FRP_ITEM_READ_TIMEOUT = 'iv-read-timeout';
var FRP_REVERT = 'PrefsRevertFlag';
var FRP_START_PAGE = 'StartPage';
var FRP_SCROLL_TRACKING = 'ScrollTracking';
var FRP_EXPANDED_VIEW = 'ExpandedView';
var FRU_devBlog = "http://example.com/devBlog";
var FRU_tips = "http://example.com/tips";
var FRV_tips = [
{title: "Tip1",
content: "This is tip 1. This is tip 1. This is tip 1. This is tip 1. This is tip 1. This is tip 1. "
},
{title: "Tip2",
content: "This is tip 2. This is tip 2. This is tip 2. This is tip 2. This is tip 2. This is tip 2. This is tip 2. "
},
{title: "Tip3",
content: "This is tip 3.This is tip 3.This is tip 3.This is tip 3.This is tip 3.This is tip 3."
},
{title: "Tip4",
content: "This is tip 4. This is tip 4. This is tip 4. This is tip 4. This is tip 4. This is tip 4. This is tip 4. This is tip 4. "
}];
/*=======================================================
*
* DB APIs
*
*=======================================================*/
/*
* FR_init(callback)
*
* This should be called upon page load, and callback should be the application
* entry point.
*
* In real version, this call loads data from the server via REST and invoke
* the callback function. In mock version, it simply loads variables with
* static info and invokes the callback on a timer.
*/
function FR_init(onLoadCallback) {
FRV_logininfo = {'id': 'dummy@gmail.com',
'lastlogin': '0',
'name': "Big Dummy"};
FRV_shareurl = "http://www.example.com/user/reader/12345432";
FRV_feedlist = [
'http://rss.cnn.com/rss/cnn_topstories.rss', // TEST_FEED3
'http://www.comedycentral.com/rss/colbertvideos.jhtml',
'http://esperanto-usa.org/eusa/?q=node/feed',
'http://rss.slashdot.org/Slashdot/slashdot',
'http://www.quotationspage.com/data/qotd.rss',
'http://technosophyunlimited.blogspot.com/atom.xml', // TEST_FEED4
'http://www.theonion.com/content/feeds/daily', // TEST_FEED5
'http://vitativeness.blogspot.com/feeds/posts/default',
];
FRV_feedinfo = [
{title:'CNN.com',
feed:'http://rss.cnn.com/rss/cnn_topstories.rss',
lastupdated: '9/16/07',
unread : 5}, // TEST_FEED3
{title:'Colbert Report Videos',
feed:'http://www.comedycentral.com/rss/colbertvideos.jhtml',
lastupdated: '9/13/07',
unread : 6},
{title:'Esperanto-USA',
feed:'http://esperanto-usa.org/eusa/?q=node/feed',
lastupdated: '9/14/07',
unread : 7},
{title:'Slashdot',
feed:'http://rss.slashdot.org/Slashdot/slashdot',
lastupdated: '9/15/07',
unread : 8},
{title:'Quotes of the day',
feed:'http://www.quotationspage.com/data/qotd.rss',
lastupdated: '8/30/07',
unread : 9},
{title:'Technosophy Unlimited',
feed:'http://technosophyunlimited.blogspot.com/atom.xml',
lastupdated: '6/27/07',
unread : 10}, // TEST_FEED4
{title:'The Onion',
feed:'http://www.theonion.com/content/feeds/daily',
lastupdated: '9/16/07',
unread : 0},
{title:'Vitativeness',
feed:'http://vitativeness.blogspot.com/feeds/posts/default',
lastupdated: '6/28/07',
unread : 0}
];
// These items are for testing only
FRV_tagHash = {
'tag1' : ['item1', 'item2', 'item3'],
'tag2' : ['item2', 'item4', 'item5'],
'tag3' : ['item3'],
'tag4' : [],
'tag5' : ['item3', 'item1'],
'_starred' : ['item3', 'item1'],
'_shared' : ['item4', 'item5'],
'_read' : ['item3', 'item5']
};
FRV_tagTime = {
};
/*
* Currently google has two brandings - Starred and Shared.
* In our reader this is extended to any number of brandings.
*/
FRV_brands = [{display: 'Starred items',
brand: 'starred',
icon: 'icon-starred.png'},
{display: 'Shared items',
brand: 'shared',
icon: 'icon-shared.png'}];
FRV_folderHash = {
'http://rss.cnn.com/rss/cnn_topstories.rss':['news'],
'http://www.comedycentral.com/rss/colbertvideos.jhtml':['comedy'],
// 'http://esperanto-usa.org/eusa/?q=node/feed':['language'],
'http://rss.slashdot.org/Slashdot/slashdot':['news'],
'http://www.quotationspage.com/data/qotd.rss':['language'],
'http://technosophyunlimited.blogspot.com/atom.xml':['technology']
};
FRV_properties = {};
FRV_browseFeeds = FRV_googleBundles;
FRV_trends = FRV_sampleTrends;
FRV_feedhash = {};
FRI_feedInit(FRV_feedinfo);
/* --------------
* Simulate database loading by invoking the callback
* with a small delay.
*--------------*/
if (onLoadCallback && typeof onLoadCallback == 'function') {
onLoadCallback();
}
}
/*
* FR_loginInfo:
*
* Input
* none
*
*
* Output
* Object with fields =
* id : Login ID
* name: full name
* lastlogin: timestamp of last login
*/
function FR_loginInfo() {
return FRV_logininfo;
}
/*
* FR_getShareURL:
*
* Input
* none
*
*
* Output
* Full URL to the publicly accessible shared items
*/
function FR_getShareURL() {
return FRV_shareurl;
}
/*
* FR_feedInfo
*
* Input
* feed : URL for the feed
*
* Output
* Object with fields -
* feed : Url for this feed
* title : Display text for the feed
* unread : Number of items in this feed that the user has not read
* lastupdated : UNIX timestamp when the feed was last updated
* from the server perspective.
*/
function FR_feedInfo(feed) {
return FRV_feedhash[feed];
}
/*
* FR_allFeeds - List all subscribed feeds
*
* Input
* None
*
* Output
* Array of all subscribed feed URLs
*/
function FR_allFeeds() {
return FRV_feedlist;
}
/*
* FR_browseFeeds - Browse available feed bundles
*
* Input
* None
*
* Output
* Array of all available feed bundles
* See the structure of FRV_browseFeeds for return format
*/
function FR_browseFeeds() {
return FRV_browseFeeds;
}
/*
* FR_addFeed - Subscribe to a new feed
* (modifies DB)
*
* Input
* Feed URL
*
* Output
* None
*/
function FR_addFeed(feed) {
$.merge(FRV_feedlist, [feed])
}
/*
* FR_removeFeed - Unsubscribe an existing feed
* (modifies DB)
*
* Input
* Feed URL
*
* Output
* None
*/
function FR_removeFeed(feed) {
FRV_folderHash[feed] = undefined;
FRV_feedlist = $.grep(FRV_feedlist, function(f, i) {
return feed != f;});
}
/*
* FR_isFeedSubscribed - Check if a feed URL has been subscribed
*
* Input
* Feed URL
*
* Output
* true : Feed has already been subscribed to
* false : Feed has not been subscribed to
*/
function FR_isFeedSubscribed(feed) {
return ($.indexOf(FRV_feedlist,feed) >= 0);
}
/*
* FR_allTags - List all tags for the user
*
* Input
* None
*
* Output
* Array of unique tagnames
*/
function FR_allTags() {
return $.grep($.keys(FRV_tagHash), function(t) {
return t.match(/^[^_]/);});
}
/*
* FR_tagItem - Add a given tag to a given item
* (modifies DB)
*
* Input
* itemid : Item to be tagged
* tag : tag name (new or existing)
*
* Output
* None
*/
function FR_tagItem(itemid, tag) {
var d = new Date();
// update the tag time
FRV_tagTime[itemid + FRC_joinstring + tag] = d.getTime();
FRI_AddToList(FRV_tagHash, tag, itemid);
}
/*
* FR_untagItem - Removes a given tag from a given item
* (modifies DB)
*
* Input
* itemid : Item to be tagged
* tag : tag name to be removed
*
* Output
* None
*/
function FR_untagItem(itemid, tag) {
// update the tag time
FRV_tagTime[itemid + FRC_joinstring + tag] = undefined;
FRI_RemoveFromList(FRV_tagHash, tag, itemid);
if (FRV_tagHash[tag].length == 0) {
FRV_tagHash[tag] = undefined;
}
}
/*
* FR_untagAllForItem - Removes all user tags from a given item
* (modifies DB)
*
* Input
* itemid : Item to be untagged
*
* Output
* None
*/
function FR_untagAllForItem(itemid) {
$.each(FR_allTags(itemid), function(i, tag) {
FR_untagItem(itemid, tag);
});
}
/*
* Internal to mock api
*/
function FRI_tagsLookup(itemid) {
var alltags = $.keys(FRV_tagHash);
var tags = [];
return $.grep(alltags, function(tag, i) {
return ($.indexOf(FRV_tagHash[tag],itemid) >= 0);
});
}
/*
* FR_tagsForItem - List tags for a given item
*
* Input
* itemid : Item to be tagged
*
* Output
* Array of tag names
*/
function FR_tagsForItem(itemid) {
var tags = FRI_tagsLookup(itemid);
return $.grep(tags, function(t) {
return t.match(/^[^_]/);});
}
/*
* FR_taggedItems - Items tagged with a given tag
*
* Input
* tagname : string value
*
* Output
* Array of itemids which have been tagged with the tagname
*/
function FR_taggedItems(tagname) {
return FRV_tagHash[tagname] ? FRV_tagHash[tagname] : [];
}
/*
* FR_taggedTime - UNIX Time stamp at which the item was tagged
*
* Input
* item : Item to be looked up
* tag : tag to be looked up
*
* Output
* UNIX timestamp when the item was tagged.
* undefined if no timestamp
*
* NOTE: DO NOT check the timestamp to determine if an item has been
* tagged or not. Use FR_tagsForItem
*
*/
function FR_taggedTime(item, tagname) {
return FRV_tagTime[item + FRC_joinstring + tagname];
}
/* Brands:
* Starred and Shared items are implemented using special tags:
* _starred & _shared
*/
function FR_allBrands() {
return FRV_brands;
}
/*
* FR_brandedItems - Items which have been branded by a given brand
*
* Input
* brand : starred / shared / read
*
* Output
* Array of branded items
*/
function FR_brandedItems(brand) {
return FR_taggedItems(FRC_brandPrefix + brand);
}
/*
* FR_brandItem - Add a brand to a given item
* (modifies DB)
*
* Input
* itemid : Item to be branded
* brand : starred / shared / read
*
* Output
* None
*/
function FR_brandItem(itemid, brand) {
return FR_tagItem(itemid, FRC_brandPrefix + brand);
}
/*
* FR_unbrandItem - Remove a brand from a given item
* (modifies DB)
*
* Input
* itemid : Item to be unbranded
* brand : starred / shared / read
*
* Output
* None
*/
function FR_unbrandItem(itemid, brand) {
return FR_untagItem(itemid, FRC_brandPrefix + brand);
}
/*
* FR_isItemBranded - Check if an item has a given brand
*
* Input
* itemid : Item to be checked
* brand : starred/shared/read
*
* Output
* Array of itemids which have the brand
*/
function FR_isItemBranded(itemid, brand) {
var tags = FRI_tagsLookup(itemid);
return ($.indexOf(tags, FRC_brandPrefix + brand) >= 0);
}
/*
* FR_brandedTime - returns the timestamp when the item was branded (if it was)
*
* Input
* itemid : Item to be checked
* brand : starred/shared/read
*
* Output
* UNIX timestamp
*/
function FR_brandedTime(itemid, brand) {
return FR_taggedTime(itemid, FRC_brandPrefix + brand);
}
/* starred items */
/*
* FR_getStarredItems - List of items that have been starred
*
* Input
* None
*
* Output
* Array of itemids which have been starred
*/
function FR_getStarredItems() {
return FR_brandedItems('starred');
}
/*
* FR_starItem - Star a given item
* (modifies DB)
*
* Input
* itemid :
*
* Output
* None
*/
function FR_starItem(itemid) {
return FR_brandItem(itemid, 'starred');
}
/*
* FR_unstarItem - Unstar a given item
* (modifies DB)
*
* Input
* itemid :
*
* Output
* None
*/
function FR_unstarItem(itemid) {
return FR_unbrandItem(itemid, 'starred');
}
/*
* FR_isStarred - Check if an item is starred
*
* Input
* itemid :
*
* Output
* true : Itemid is starred
* false : Itemid is not starred
*/
function FR_isStarred(itemid) {
return FR_isItemBranded(itemid, 'starred');
}
function FR_starredTime(itemid) {
return FR_taggedTime(itemid, FRC_brandPrefix + 'starred');
}
/* shared items - APIs similar to "starred items"*/
function FR_getSharedItems() {
return FR_brandedItems('shared');
}
function FR_shareItem(itemid) {
return FR_brandItem(itemid, 'shared');
}
function FR_unshareItem(itemid) {
return FR_unbrandItem(itemid, 'shared');
}
function FR_isShared(itemid) {
return FR_isItemBranded(itemid, 'shared');
}
function FR_sharedTime(itemid) {
return FR_taggedTime(itemid, FRC_brandPrefix + 'shared');
}
/* read items - APIs similar to "starred items" */
function FR_getReadItems() {
return FR_brandedItems('read');
}
function FR_setItemRead(itemid) {
return FR_brandItem(itemid, 'read');
}
function FR_setItemUnread(itemid) {
return FR_unbrandItem(itemid, 'read');
}
function FR_isItemRead(itemid) {
return FR_isItemBranded(itemid, 'read');
}
function FR_itemReadTime(itemid) {
return FR_taggedTime(itemid, FRC_brandPrefix + 'read');
}
/* Folder */
/*
* FR_allFolders - List of all folders in the system
*
* Input
* None
*
* Output
* Array of folder names
*/
function FR_allFolders() {
var folders = [];
$.each($.values(FRV_folderHash), function(i, folderlist) {
if (folderlist)
$.merge(folders, folderlist);
});
return folders;
}
/*
* FR_moveToFolder - Move a feed into a different folder removing this
* feed from any folder(s) it is currently present
* (modifies DB)
*
* Input
* feed : feed URL
* folder : name of the folder to move into (new or existing)
*
* Output
* None
*/
function FR_moveToFolder(feed, foldername) {
FRV_folderHash[feed]= [foldername];
}
/*
* FR_copyToFolder - Copy a feed into a different folder leaving this
* feed in any other folder(s) it is currently present, intact
* (modifies DB)
*
* Input
* feed : feed URL
* folder : name of the folder to move into (new or existing)
*
* Output
* None
*/
function FR_copyToFolder(feed, foldername) {
if (!FRV_folderHash[feed]) {
FRV_folderHash[feed] = [];
}
$.merge(FRV_folderHash[feed], [foldername]);
}
/*
* FR_removeFromFolder - Remove a feed from its folder
* (modifies DB)
*
* Input
* feed : feed URL
* folder : name of the folder to remove from (new or existing)
*
* Output
* None
*/
function FR_removeFromFolder(feed, foldername) {
if (foldername && FRV_folderHash[feed]) {
var newhash = $.grep(FRV_folderHash[feed],
function(f, i) {
return (f != foldername);
});
if (newhash.length == 0)
newhash = undefined;
FRV_folderHash[feed] = newhash;
}
}
/*
* FR_feedsInFolder - List of feeds in a given folder
*
* Input
* folder : Name of the folder to list
*
* Output
* Array of feed URLs in this folder
*/
function FR_feedsInFolder(foldername) {
var feeds = [];
var str = '';
var allentries = $.keys(FRV_folderHash);
for (var i=0; i= 0)
$.merge(feeds, [f]);
}
return feeds;
}
/*
* FR_folderForFeed - Find the folder in which the feed resides
*
* Input
* feed : Feed URL
*
* Output
* list of folder names or [] (if feed is not under any folder)
*/
function FR_folderForFeed(feed) {
try {
if (FRV_folderHash[feed])
return FRV_folderHash[feed];
} catch(e) {
}
}
/*
* FR_getStats - Return the stats needed to display the reading trends
*
* Input
* None
*
* Output
* See the structure of FRV_sampleTrends for the return format
*/
function FR_getStats() {
return FRV_trends;
}
/*
* FR_sendEmail - allows sending an item from a given feed as an
* email to a friend
*
* Input
* to_address : Email address of the friend
* subject : Subject for email
* note : text message for the email
* feed : URL of the feed
* itemid : Item ID for the item being emailed
*
* Output
* None - Success
* String - error message
*/
function FR_sendEmail(to_address, subject, note, feed, itemid) {
// Do nothing
}
/* Property functions */
/*
* FR_getProperty - Get the value string for given property name
* (modifies DB)
*
* Input
* propname : Name of the property
*
* Output
* string value of the property or null (if property not found)
*/
function FR_getProperty(propname) {
try {
if (FRV_properties[propname])
return FRV_properties[propname];
} catch(e) {
}
return null;
}
/*
* FR_setProperty - Set the value string for given property name
* (modifies DB)
*
* Input
* propname : Name of the property to be set
* value : string value to be set
*
* Output
* None
*/
function FR_setProperty(propname, value) {
FRV_properties[propname] = value;
}
function FR_cacheFeed(feed, title, lastupdated, unread) {
FRV_feedhash[feed] = {feed:feed,
title:title,
lastupdated: lastupdated,
unread: unread};
}
/* Internal Functions */
function FRI_AddToList(obj, tag, feed) {
if (obj[tag]) {
$.merge(obj[tag], [feed]);
} else {
obj[tag] = [feed];
}
}
function FRI_RemoveFromList(obj, tag, feed) {
if (obj[tag]) {
obj[tag] = $.grep(obj[tag], function(f, i) {
return f != feed;});
}
}
function FRI_feedInit(feedlist) {
$.each(feedlist, function(i, feedInfo) {
FRV_feedhash[feedInfo.feed] = feedInfo;
});
/* FRV_feedhash =
feedlist.inject(FRV_feedhash, function(feedhash, feedInfo, index) {
feedhash[feedInfo.feed] = feedInfo;
return feedhash;
});
*/
}
var FRV_googleBundles = {"bundles":{"news":{"id":"news","title":"News","isadded":false,"subscriptions":[{"id":"feed/http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml","title":"BBC News (World)"},{"id":"feed/http://www.csmonitor.com/rss/top.rss","title":"Christian Science Monitor"},{"id":"feed/http://sports.espn.go.com/espn/rss/news","title":"ESPN.com"},{"id":"feed/http://news.google.com/?output\u003Drss","title":"Google News"},{"id":"feed/http://www.marketwatch.com/rss/topstories","title":"MarketWatch.com"},{"id":"feed/http://www.npr.org/rss/podcast.php?id\u003D500001","title":"NPR Podcast (7AM EST)"}]},"sports":{"id":"sports","title":"Sports","isadded":false,"subscriptions":[{"id":"feed/http://sports.espn.go.com/espn/rss/news","title":"ESPN.com"},{"id":"feed/http://newsrss.bbc.co.uk/rss/sportonline_world_edition/front_page/rss.xml","title":"BBC Sport"},{"id":"feed/http://sports.espn.go.com/keyword/search?searchString\u003Dbill_simmons\u0026feed\u003Drss\u0026src\u003Drss\u0026rT\u003Dsports","title":"Bill Simmons"},{"id":"feed/http://www.ericmcerlain.com/offwingopinion/index.rdf","title":"Off Wing Opinion"},{"id":"feed/http://www.themightymjd.com/feed/","title":"the mighty mjd sports blog"},{"id":"feed/http://www.sportsfrog.com/feed.xml","title":"The Sports Frog"},{"id":"feed/http://www.truehoop.com/atom.xml","title":"True Hoop"},{"id":"feed/http://yanksfansoxfan.typepad.com/ysfs/atom.xml","title":"Yanksfan vs Soxfan"},{"id":"feed/http://www.footbag.org/index2/index.rss","title":"Footbag WorldWide"}]},"fun":{"id":"fun","title":"Fun","isadded":false,"subscriptions":[{"id":"feed/http://www.comedycentral.com/rss/colbertvideos.jhtml","title":"Colbert Report Videos"},{"id":"feed/http://www.comedycentral.com/rss/tdsvideos.jhtml","title":"Daily Show Videos"},{"id":"feed/http://video.google.com/videofeed?type\u003Dtop100new","title":"Google Video Top 100"},{"id":"feed/http://www.quotationspage.com/data/qotd.rss","title":"Quotes of the Day"},{"id":"feed/http://www.theonion.com/content/feeds/daily","title":"The Onion"},{"id":"feed/http://youtube.com/rss/global/top_viewed_today.rss","title":"YouTube Most Viewed"}]},"thinkers":{"id":"thinkers","title":"Thinkers","isadded":false,"subscriptions":[{"id":"feed/http://www.freakonomics.com/blog/feed/","title":"Freakonomics Blog"},{"id":"feed/http://gladwell.typepad.com/gladwellcom/atom.xml","title":"Malcolm Gladwell\u0027s Blog"},{"id":"feed/http://www.kottke.org/remainder/index.rdf","title":"kottke.org remaindered links"},{"id":"feed/http://itre.cis.upenn.edu/~myl/languagelog/index.rdf","title":"Language Log"},{"id":"feed/http://www.languagehat.com/index.rdf","title":"LanguageHat"},{"id":"feed/http://www.marginalrevolution.com/marginalrevolution/index.rdf","title":"Marginal Revolution"},{"id":"feed/http://www.npr.org/rss/podcast.php?id\u003D4538138","title":"NPR: This I Believe"},{"id":"feed/http://feeds.salon.com/salon/index","title":"Salon"},{"id":"feed/http://tedblog.typepad.com/tedblog/atom.xml","title":"TED Blog"}]},"celebrities":{"id":"celebrities","title":"Celebrities","isadded":false,"subscriptions":[{"id":"feed/http://www.defamer.com/index.xml","title":"Defamer"},{"id":"feed/http://www.gawker.com/index.xml","title":"Gawker"},{"id":"feed/http://www.perezhilton.com/index.xml","title":"PerezHilton"},{"id":"feed/http://feeds.feedburner.com/popsugar","title":"PopSugar"},{"id":"feed/http://www.thesuperficial.com/index.xml","title":"The Superficial"}]},"geeky":{"id":"geeky","title":"Geeky","isadded":false,"subscriptions":[{"id":"feed/http://feeds.feedburner.com/CoolTools","title":"Cool Tools"},{"id":"feed/http://lifehacker.com/index.xml","title":"Lifehacker"},{"id":"feed/http://www.makezine.com/blog/index.xml","title":"MAKE Magazine"},{"id":"feed/http://www.penny-arcade.com/rss.xml","title":"Penny-Arcade"},{"id":"feed/http://www.pvrblog.com/pvr/index.rdf","title":"PVRblog"}]},"video":{"id":"video","title":"Video","isadded":false,"subscriptions":[{"id":"feed/http://feeds.feedburner.com/AskANinja","title":"Ask A Ninja"},{"id":"feed/http://video.google.com/videofeed?type\u003Dtop100new","title":"Google Video Top 100"},{"id":"feed/http://feeds.feedburner.com/hotair/vent","title":"Hot Air TV"},{"id":"feed/http://www.rocketboom.com/vlog/atom.xml","title":"Rocketboom"},{"id":"feed/http://www.zefrank.com/theshow/atom.xml","title":"The Show with zefrank"},{"id":"feed/http://feeds.feedburner.com/TikiBarTV","title":"Tiki Bar TV"},{"id":"feed/http://youtube.com/rss/global/top_viewed_today.rss","title":"YouTube Most Viewed"}]},"food":{"id":"food","title":"Food","isadded":false,"subscriptions":[{"id":"feed/http://chocolateandzucchini.com/index.rdf","title":"Chocolate \u0026 Zucchini"},{"id":"feed/http://dinersjournal.blogs.nytimes.com/?feed\u003Drss2","title":"Diner\u0027s Journal"},{"id":"feed/http://www.megnut.com/index.xml","title":"Megnut"},{"id":"feed/http://feeds.feedburner.com/PurpleLiquidAWineAndFoodDiary","title":"Purple Liquid"},{"id":"feed/http://www.amateurgourmet.com/the_amateur_gourmet/atom.xml","title":"The Amateur Gourmet"},{"id":"feed/http://www.thefoodsection.com/foodsection/index.rdf","title":"The Food Section"}]},"finance":{"id":"finance","title":"Finance","isadded":false,"subscriptions":[{"id":"feed/http://rss.cnn.com/rss/money_topstories.rss","title":"CNNMoney.com"},{"id":"feed/http://www.iwillteachyoutoberich.com/atom.xml","title":"I Will Teach You To Be Rich"},{"id":"feed/http://www.marketwatch.com/rss/topstories","title":"MarketWatch.com"},{"id":"feed/http://www.pfblog.com/index.xml","title":"Personal Finance Blog"},{"id":"feed/http://www.fool.com/About/headlines/rss_headlines.asp","title":"The Motley Fool"},{"id":"feed/http://www.thestreet.com/feeds/rss/index.xml","title":"TheStreet.com"}]},"google-related":{"id":"google-related","title":"Google-related","isadded":false,"subscriptions":[{"id":"feed/http://blog.outer-court.com/rss.xml","title":"Google Blogoscoped"},{"id":"feed/http://googlesightseeing.com/feed/","title":"Google Sightseeing"},{"id":"feed/http://battellemedia.com/index.xml","title":"John Battelle\u0027s Searchblog"},{"id":"feed/http://googleblog.blogspot.com/atom.xml","title":"Official Google Blog"},{"id":"feed/http://googlereader.blogspot.com/atom.xml","title":"Official Google Reader Blog"},{"id":"feed/http://googlevideo.blogspot.com/atom.xml","title":"Official Google Video Blog"}]},"technology":{"id":"technology","title":"Technology","isadded":false,"subscriptions":[{"id":"feed/http://digg.com/rss/index.xml","title":"Digg"},{"id":"feed/http://www.engadget.com/rss.xml","title":"Engadget"},{"id":"feed/http://slashdot.org/index.rss","title":"Slashdot"},{"id":"feed/http://feeds.feedburner.com/Techcrunch","title":"TechCrunch"},{"id":"feed/http://www.wired.com/news/feeds/rss2/0,2610,,00.xml","title":"Wired News"}]},"small-business":{"id":"small-business","title":"Small-business","isadded":false,"subscriptions":[{"id":"feed/http://www.businesspundit.com/index.rdf","title":"Businesspundit"},{"id":"feed/http://exacttarget.typepad.com/chrisbaggott/atom.xml","title":"Email Marketing Best Practices"},{"id":"feed/http://www.churchofthecustomer.com/blog/index.rdf","title":"Church of the Customer Blog"},{"id":"feed/http://feeds.feedburner.com/ducttapemarketing/nRUD","title":"Duct Tape Marketing"},{"id":"feed/http://sethgodin.typepad.com/seths_blog/atom.xml","title":"Seth\u0027s Blog"},{"id":"feed/http://feeds.feedburner.com/SmallBusinessTrends","title":"Small Business Trends"},{"id":"feed/http://forum.belmont.edu/cornwall/atom.xml","title":"The Entrepreneurial Mind"}]},"science":{"id":"science","title":"Science","isadded":false,"subscriptions":[{"id":"feed/http://scienceblogs.com/cognitivedaily/atom.xml","title":"Cognitive Daily"},{"id":"feed/http://cosmicvariance.com/feed/","title":"Cosmic Variance"},{"id":"feed/http://news.nationalgeographic.com/index.rss","title":"National Geographic News"},{"id":"feed/http://www.nature.com/news/rss.rdf","title":"Nature.com"},{"id":"feed/http://www.realclimate.org/feed/rss2/","title":"RealClimate"},{"id":"feed/http://www.sciam.com/xml/sciam.xml","title":"Scientific American"}]},"photography":{"id":"photography","title":"Photography","isadded":false,"subscriptions":[{"id":"feed/http://www.durhamtownship.com/index.rdf","title":"A Walk Through Durham Township, Pennsylvania"},{"id":"feed/http://wvs.topleftpixel.com/index_fullfeed.rdf","title":"[daily dose of imagery]"},{"id":"feed/http://www.dpreview.com/news/dpr.rdf","title":"Digital Photography Review"},{"id":"feed/http://www.filemagazine.com/thecollection/atom.xml","title":"FILE Magazine"},{"id":"feed/http://www.greyscalegorilla.com/index.php?x\u003Drss","title":"greyscalegorilla"},{"id":"feed/http://groundglass.ca/index.xml","title":"groundglass"},{"id":"feed/http://www.mylalaland.com/hello/index.xml","title":"HELLO"},{"id":"feed/http://feeds.feedburner.com/ngpod","title":"National Geographic Photo of the Day"},{"id":"feed/http://www.photoflavor.com/index.xml","title":"photoflavor"},{"id":"feed/http://www.photojojo.com/content/feed","title":"Photojojo"},{"id":"feed/http://vitrineenillumina.zerosun6.com/index.php?x\u003Drss","title":"vitrine en illumina"}]},"cars":{"id":"cars","title":"Cars","isadded":false,"subscriptions":[{"id":"feed/http://www.autoblog.com/rss.xml","title":"Autoblog"},{"id":"feed/http://carscarscars.blogs.com/index/atom.xml","title":"Cars! Cars! Cars!"},{"id":"feed/http://www.jalopnik.com/index.xml","title":"Jalopnik"},{"id":"feed/http://feeds.popularmechanics.com/pm/blogs/automotive_news","title":"PopularMechanics Automotive News"},{"id":"feed/http://www.thetruthaboutcars.com/?feed\u003Drss2","title":"The Truth About Cars"}]}}};
var FRV_sampleTrends = {
period : {
/* Last 30 days : Array of 30 numbers, one for item count each day */
month : [
0, 10, 0, 0, 0, 0, 10, 5, 2, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 20
],
/* Time of day : Array of 24 numbers, one for each hourly period
* starting with index 0 = midnight - 1AM
*/
day : [
0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 0, 0,
2, 1, 1, 1, 0, 0, 2, 0, 0, 0, 0, 2
],
/* Day of week : Array of 7 numbers, one for each day of week
* starting with index 0 = Sunday*/
week : [
8, 2, 1, 0, 2, 0, 4
]
},
/*
* For each feed, stats like number of items read, percent read,
* number of items shared, starred, emailed, read on mobile
*/
itemstats :
[// Feed 1
{feed: 'http://rss.cnn.com/rss/cnn_topstories.rss',
link: "http://www.cnn.com/?eref\u003Drss_topstories",
nread: 6,
percentread: 22,
shared: 0,
starred: 3,
emailed: 1,
readonmobile: 1
},
// Feed 2
{feed: 'http://www.comedycentral.com/rss/colbertvideos.jhtml',
link:"http://www.comedycentral.com/shows/the_colbert_report/index.jhtml?rsspartner\u003DrssFeedfetcherGoogle",
nread: 4,
percentread: 16,
shared: 1,
starred: 0,
emailed: 3,
readonmobile: 0
}
// More feeds
],
/*
* ordered list of feeds which are frequently updated
* and those which are inactive
*/
update_frequency: {
frequent: [
{feed: 'http://www.comedycentral.com/rss/colbertvideos.jhtml',
items_per_day: 8,
percent_read: 16
},
{feed: 'http://rss.cnn.com/rss/cnn_topstories.rss',
items_per_day: 4,
percent_read: 12
}
// More feeds
],
inactive: [
// least active
'http://www.comedycentral.com/rss/colbertvideos.jhtml',
// next least active
'http://rss.cnn.com/rss/cnn_topstories.rss'
// More feeds
]
}
}
/*
* Return a given tip by its number
* Internal to mockapi
*/
function FR_getTips(num) {
if (!num) {
num = Math.round(FRV_tips.length*Math.random());
}
return FRV_tips[num];
}
yocto-reader/reader/reader.js 0000644 0000041 0000000 00000253410 10735421010 015766 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
/*
* Element naming conventions:
* id=''
*
* Prefix: ol (Operation list box in left margin)
* af (Add Feed box in left margin)
* fl (Feed list box in left margin)
* sfl (Sub folder)
* hm (Home View)
* lv (List View)
* tpl (Template container)
*
* class='-'
* Type: fld (Templated element field)
*
*/
/* --------------------------------------------
* State Variables.
* If any of these variables are changed,
* dont forget to call the corresponding
* update function(s)
*--------------------------------------------*/
var FRS_folders = []; // List of folders
var FRS_feedinfo_list = []; // List of all subscribed feeds
var FRS_tags = []; // List of all tags
var FRS_current_item = null;
var FEEDLOAD_NUMENTRIES = 7;
var FEEDLOAD_INTERVAL = 150;
var ALL_VIEWS = '#listview,#searchview,#settingsview,' +
'#browsefeedsview,#home,#trendsview';
var SETTING_TABS = ['subscriptions','labels','goodies','importexport','extras'];
//Container for all dom element references
var DOM = {};
function reader_main(initCallback) {
// Init subsystems
FR_init(initCallback);
FR_setProperty(FRP_SCROLL_TRACKING, '');
//FR_setProperty(FRP_START_PAGE, '?tag/tag1');
// FR_setProperty(FRP_EXPANDED_VIEW, 'true');
Reader.init();
// Reload the feeds periodically
Reader.reloadFeeds();
setInterval(Reader.reloadFeeds.bind(this), FC_updateInterval);
ReaderViewer.init();
Settings.init();
Reader.hideLoading();
handle_resize();
var start_page = location.search.length > 0? location.search : (
FR_getProperty(FRP_START_PAGE));
handle_permalinks(start_page);
$(document).keyup(handle_keycuts);
}
function handle_resize() {
var winh, winw;
var sizeElements = {};
sizeElements['msie'] = {obj: document.documentElement,
fieldHeight: 'clientHeight',
fieldWidth: 'clientWidth'};
sizeElements['opera'] =
sizeElements['safari'] =
sizeElements['mozilla'] = {obj: window,
fieldHeight: 'innerHeight',
fieldHeight: 'innerWidth'};
$.each(sizeElements, function(browsertype, info) {
if ($.browser[browsertype]) {
if (!winh) {
winh = info.obj[info.fieldHeight];
winw = info.obj[info.fieldWidth];
}
}
});
if ($.browser.mozilla) {
winh = window.innerHeight; winw = window.innerWidth;
}
if ($.browser.mozilla) {
var pos = $("#nav-toggler").positionedOffset();
var delh = winh - pos[1];
$("#nav-toggler").css('height', delh + 'px');
}
if (ReaderViewer.state == stateListView) {
var pos = $("#entries").positionedOffset();
var delh = winh - pos[1] - $("#chrome-footer-container")[0].offsetHeight;
var delw = winw - pos[0];
$("#entries").css('width', delw + 'px');
$("#entries").css('height', delh + 'px');
}
var node;
try {
node = $("#browsefeedsview");
var pos = node.positionedOffset();
var delh = winh - pos[1];
var delw = winw - pos[0];
node.css('height', delh + 'px');
} catch(e) {
// alert(e.message);
}
if (!$.browser.msie) {
if (ReaderViewer.viewtype == 'TrendsView') {
var pos = $("#trends").positionedOffset();
var delh = winh - pos[1];
var delw = winw - pos[0];
$("#trends").css('width', delw + 'px');
$("#trends").css('height', delh + 'px');
}
var elem = $("#sub-tree-resizer");
var rpos = elem.positionedOffset();
var rdelh = winh - rpos[1] - 15 - $("#sub-tree-footer")[0].offsetHeight;
elem.css('height', rdelh + 'px');
}
}
// Create state machines
var Reader = new StateMachine(stateList, ReaderFSM);
var ReaderViewer = new StateMachine(stateListView, RVFSM);
var Settings = new StateMachine(stateSubs, STFSM);
/*
* Reload data from backend
*/
Reader.init = function(evt) {
this.state = 'List';
this.buttonClicked($('#ol-home'));
if (!this.domLoaded) {
this.domLoaded = true;
// Setup DOM by browser and version
var body = $(document.body);
if ($.browser.mozilla) {
body.addClass('mozilla');
} else if ($.browser.msie) {
body.addClass('ie');
var ver = parseFloat($.browser.version);
if (ver <= 6.0) {
body.addClass('ie6');
}
} else if ($.browser.opera) {
body.addClass('opera');
} else if ($.browser.safari) {
body.addClass('safari');
}
DOM.quickadd = $("#quickadd");
DOM.recentStarred = $("#recent-activity-star");
DOM.recentShared = $("#recent-activity-share");
$(document.body).click(body_clicked);
$(window).resize(handle_resize);
/*
DOM.navToggler = $("#nav-toggler");
DOM.navToggler.hover(
DOM.navToggler.addClass.bind(DOM.navToggler, 'hover'),
DOM.navToggler.removeClass.bind(DOM.navToggler, 'hover')),
*/
}
// Initially populate unread counts from cached value
// from database
$.each(FR_allFeeds(), function(i, feed) {
try {
FC_updateUnread(feed, FR_feedInfo(feed).unread);
} catch(e) {}
});
Reader.handleEvent("evOpen");
Reader.handleEvent("evHome", $("#ol-home")[0]);
}
Reader.toggleNav = function() {
if ($(document.body).is(".hide-nav"))
this.handleEvent('evOpen');
else
this.handleEvent('evClose');
}
Reader.close = function(evt) {
$(document.body).addClass("hide-nav");
}
Reader.open = function(evt) {
$(document.body).removeClass("hide-nav");
Reader.handleEvent('evRefresh');
}
/*
* Fetch all the feeds and see if there are any new items,
* If so update the counts and flash the corresponding feed/folder
* in Reader view.
*/
Reader.reloadFeeds = function() {
$.each(FR_allFeeds(), function(i, feed) {
FC_retreiveFeed(feed);
});
}
/*
* Redraw the UI with the latest data
*/
Reader.refresh = function(evt) {
this.brands = FR_allBrands();
var folders = this.folders = FR_allFolders();
this.feedlist = FR_allFeeds();
this.orphans = $.grep(this.feedlist, function(feed) {
return (!FR_folderForFeed(feed));
});
this.tags = $.grep(FR_allTags(), function(tag) {
return ($.indexOf(folders,tag) < 0);
});
this.folderNodes = {};
this.brandNodes = {};
// Populate the brands
var brand_bindings = $('#ol-brandlist').clear().populate(this.brands, '#tpl-brandlist');
$.each(brand_bindings, function(i, bind) {
Reader.brandNodes[bind.obj.brand] = bind.node;
if (Reader.brand) {
if (bind.obj.brand == Reader.brand) {
Reader.buttonClicked(bind.node[0], true);
}
}
});
// Populate the folders
var folder_bindings = $('#fl-folderlist').clear().populate(this.folders,
'#tpl-folder');
Reader.folderNodes = new Object;
Reader.feedNodes = new Object;
Reader.tagNodes = new Object;
var feed_bindings;
// For each folder, populate the feeds in that folder
$.each(folder_bindings, function(i, binding) {
var node = binding.node;
var folder = binding.obj;
// Store the UI node displaying this folder in folderNodes
Reader.folderNodes[folder] = node;
var feeds_in_folder = FR_feedsInFolder(folder);
var feed_infos = $.map(feeds_in_folder,FR_feedInfo);
node.attr("name", folder);
feed_bindings = $('.sfl-container',node).populate(feed_infos,
'#tpl-feed');
// For each feed in the folder, hash the UI node in feedNodes
$.each(feed_bindings, function (i, info) {
var fnode = Reader.feedNodes[info.obj.feed];
if (fnode) {
Reader.feedNodes[info.obj.feed] = fnode.addnodes(info.node);
} else {
Reader.feedNodes[info.obj.feed] = info.node;
}
});
// Remember if this folder was collapsed last time.
if (FR_getProperty(FRP_FOLDER_STATE + folder) == 'open') {
Reader.toggleFolder(folder);
}
});
if(this.folder && this.folderNodes[this.folder]) {
this.buttonClicked($('.folder-selector',
this.folderNodes[this.folder]), true);
}
// Populate the feeds not part of any folder
feed_bindings = $('#fl-feedlist').clear().populate(
$.map(this.orphans,FR_feedInfo),'#tpl-feed');
// For each feed at top level, hash the UI node in feedNodes
$.each(feed_bindings, function (i, info) {
Reader.feedNodes[info.obj.feed] = info.node;
});
if (this.feed && this.feedNodes[this.feed]) {
this.buttonClicked($('.feed-selector',
this.feedNodes[this.feed]), true);
}
// Populate the tag list
var tag_bindings = $('#fl-taglist').clear().populate(this.tags, '#tpl-tagfolder');
$.each(tag_bindings, function(i, info) {
Reader.tagNodes[info.obj] = info.node;
});
this.updateFeedCount(this.feedlist);
}
Reader.buttonClicked = function(node, from_code) {
if (node) {
if (!from_code)
this.feed = this.brand = this.folder = this.tag = undefined;
this.elem = node;
}
if (this.selectedNode) {
this.selectedNode.removeClass('selected');
}
this.selectedNode = $(this.elem);
if (this.selectedNode) {
this.selectedNode.addClass('selected');
}
$('.navigated').removeClass('navigated');
}
/*
// XXX
Reader.buttonClicked1 = function(node) {
if (node) {
this.feed = this.brand = this.folder = undefined;
this.elem = node;
}
if (this.selectedNode) {
this.selectedNode.removeClass('selected');
}
if (this.elem) {
this.selectedNode = $(this.elem);
}
this.selectedNode.addClass('selected');
}
*/
Reader.allitems = function(evt) {
this.buttonClicked();
if (ReaderViewer.viewtype != 'AllItemsView') {
ReaderViewer.listLoaded = false;
ReaderViewer.viewtype = 'AllItemsView';
}
ReaderViewer.handleEvent('evListView');
}
Reader.home = function(evt) {
this.buttonClicked();
ReaderViewer.viewtype = 'HomeView';
ReaderViewer.handleEvent('evListView');
}
Reader.trends = function(evt) {
this.buttonClicked();
ReaderViewer.viewtype = 'TrendsView';
ReaderViewer.handleEvent('evListView');
}
Reader.quickadd = function (evt) {
var s = $('#add-box');
var o = s.positionedOffset();
var s = $('#quick-add-bubble-holder');
s.css('top', o [1] + "px");
s.css('left', o [0] + "px");
s.show();
try {
DOM.quickadd.setdata('cnn')[0].focus();
} catch(e) {}
}
Reader.browse = function(evt) {
ReaderViewer.viewtype = 'FeedDiscoveryView';
ReaderViewer.handleEvent('evListView');
}
Reader.bundleAdded = function(bundle_name) {
FR_setProperty(FRP_BUNDLE_STATE + bundle_name, 'added');
}
Reader.openFolder = function(folder) {
var node = Reader.folderNodes[folder];
if (node)
Reader.buttonClicked($('.folder-selector', node));
this.folder = folder;
ReaderViewer.viewtype = 'SubscriptionView';
ReaderViewer.listLoaded = false;
Reader.feedFilter = FR_feedsInFolder(folder);
ReaderViewer.handleEvent('evListView');
}
Reader.expandFolder = function(folder) {
var node = Reader.folderNodes[folder];
if (node && node.is(".collapsed"))
this.toggleFolder(folder)
}
Reader.collapseFolder = function(folder) {
var node = Reader.folderNodes[folder];
if (node && node.is(".expanded"))
this.toggleFolder(folder)
}
Reader.openTagEvent = function(evt, data) {
return this.openTag(data);
}
Reader.openTag = function(tag) {
this.buttonClicked($('.tag-selector', this.tagNodes[tag]));
this.tag = tag;
ReaderViewer.viewtype = 'TagView';
ReaderViewer.listLoaded = false;
ReaderViewer.handleEvent('evListView');
}
Reader.openStarredEvent = function(evt) {
return Reader.openBrand('starred');
}
Reader.openSharedEvent = function(evt) {
return Reader.openBrand('shared');
}
Reader.openBrand = function(brand) {
if (this.brandNodes[brand])
this.buttonClicked(this.brandNodes[brand]);
this.brand = brand;
ReaderViewer.viewtype = "BrandView";
ReaderViewer.listLoaded = false;
ReaderViewer.handleEvent('evListView');
}
Reader.showSettings = function(evt) {
// Switch to settings state
this.state = 'Settings';
Settings.show();
}
Reader.displaySubList = function(evt) {
Settings.showsubscriptions();
}
Reader.displayTagList = function(evt) {
Settings.showlabels();
}
/*
* These events dont make sense since they are dependant on
* a sequence of actions not captured in the state diagrams.
* Example - rename involves displaying the rename box and
* pressing OK.
* So instead of blindly implementing these event handles
* that dont make sense, I have indicated the events in the
* actual UI handles.
*/
/*
Reader.subsFilter = function(evt) {
Settings.filterSubs();
}
Reader.subsRename = function(evt) {
// #subs-rename-button
save_rename_clicked(this.elem);
}
Reader.subsAddTag = function(evt) {
}
Reader.subsDelete = function(evt) {
}
Reader.subsTagSelected = function(evt) {
}
Reader.subsDeleteSelected = function(evt) {
}
Reader.subsSelect = function(evt) {
}
*/
/* Prefs Pane */
Reader.prefsRevert = function(evt) {
FR_setProperty(FRP_REVERT, 'true');
}
Reader.prefsSetHome = function(evt, data) {
FR_setProperty(FRP_START_PAGE, data);
}
Reader.prefsScrollTracking = function(evt, data) {
FR_setProperty(FRP_SCROLL_TRACKING, data?'true':null);
}
/* Import Export Pane - best done at server */
Reader.importExport = function(evt) {
}
/* Goodies Pane - cool links */
Reader.goodies = function(evt) {
}
Reader.toggleFolder = function(folder) {
var node = Reader.folderNodes[folder];
if (node) {
node = $(node);
node.toggleClass('expanded');
node.toggleClass('collapsed');
// Save State
if (node.is('.expanded')) {
FR_setProperty(FRP_FOLDER_STATE + folder, 'open');
} else {
FR_setProperty(FRP_FOLDER_STATE + folder, 'closed');
}
}
}
Reader.openFeedEvent = function(evt, data) {
return Reader.openFeed(data);
}
Reader.openFeed = function(feedurl) {
var node = Reader.feedNodes[feedurl];
if (node)
Reader.buttonClicked($('.feed-selector', node));
this.feed = feedurl;
ReaderViewer.viewtype = 'SubscriptionView';
ReaderViewer.listLoaded = false;
Reader.feedFilter = [];
Reader.feedFilter.push(feedurl);
var folders = FR_folderForFeed(feedurl);
if (folders && folders.length > 0) {
$.each(folders, function(i, folder) {
Reader.expandFolder(folder);
});
}
// alert('[' + folder + '] ' + ReaderViewer.feedFilter.length);
ReaderViewer.handleEvent('evListView');
}
Reader.removeFeed = function(feed) {
FR_removeFeed(feed);
FC_clearUnread(feed);;
this.handleEvent('evRefresh');
}
Reader.flashNode = function(anode) {
anode.addClass('updated');
setTimeout(function() {
anode.removeClass('updated');
anode.addClass('updated-intermediate');
setTimeout(function() {
anode.removeClass('updated-intermediate');
}, 500);
}, 500);
}
Reader.flashFeeds = function(feeds) {
var folders = [];
$.each(feeds, function(i, feed) {
if (FR_folderForFeed(feed))
$.merge(folders, FR_folderForFeed(feed));
var node = Reader.feedNodes[feed];
if (node)
Reader.flashNode($(".feed-selector", node));
});
$.each(folders, function(i, folder) {
var node = Reader.folderNodes[folder];
if (node)
Reader.flashNode($(".folder-selector", node));
});
}
/*
* Updated the unread count for given feeds, their folders & All Items
*/
Reader.updateFeedCount = function(feeds, items) {
var folders = [];
var unread = 0;
if (!items)
items = [];
$.each(feeds, function(i, feed) {
if (FR_folderForFeed(feed))
$.merge(folders, FR_folderForFeed(feed));
if (Reader.feedNodes[feed]) {
unread = FC_getUnread(feed);
Reader.setUnreadNode('feed', feed, unread);
}
});
$.each(items, function(i, itemid) {
$.merge(folders, FR_tagsForItem(itemid));
});
$.each(folders, function(i, folder) {
unread = 0;
$.each(FR_feedsInFolder(folder), function(i, feed) {
unread += FC_getUnread(feed);
});
// Folder can also be a tag ... handle this.
$.each(FR_taggedItems(folder), function(i, itemid) {
if (!FR_isItemRead(itemid)) {
unread++;
}
});
Reader.setUnreadNode('folder', folder, unread);
});
$.each(['starred', 'shared'], function(i, brand) {
var items = FR_brandedItems(brand);
var bunread = 0;
$.each(items, function(i, item) {
var feed = FC_getItemFeed(item);
if (feed && !FR_isItemRead(item)) {
bunread++;
}
});
Reader.setUnreadNode('brand', brand, bunread);
});
unread = FC_getUnreadAll(); // check
Reader.setUnreadNode('allitems', 'allitems', unread);
}
Reader.setUnreadNode = function(nodetype, name, unread) {
var node, expr;
switch (nodetype) {
case 'feed':
expr = ".fld-unread";
node = this.feedNodes[name];
break;
case 'folder':
expr = ".fld-folder_unread";
node = this.folderNodes[name];
break;
case 'brand':
expr = ".fld-brand_unread";
node = this.brandNodes[name];
break;
case 'allitems':
expr = ".fld-all_unread";
node = $("#ol-allitems");
break;
// case 'tag':
// break;
}
if (node) {
$(expr, node).setdata(unread);
if (unread > 0)
node.addClass('unread');
else
node.removeClass('unread');
}
ReaderViewer.displayUnreadCount(nodetype, name, unread)
}
/*
* In ther reader feedlist, toggle between showing all feeds/folders
* and showing only updated feeds/folders
*/
Reader.showUpdatedOnly = function() {
$("#ol-feedlist").addClass("updatedonly");
}
Reader.showAll = function() {
$("#ol-feedlist").removeClass("updatedonly");
}
Reader.sortUpdatedOrAll = function() {
$("#ol-feedlist").toggleClass("updatedonly");
}
Reader.showLoading = function() {
$('#loading-area').removeClass('hidden');
}
Reader.hideLoading = function() {
$('#loading-area').addClass('hidden');
}
Reader.settingsSubTab = function(evt) {
Settings.viewtype = 'SubView';
$("#setting-subscriptions").click();
Reader.handleEvent('evSettingsView');
}
Reader.settingsPrefTab = function(evt) {
Settings.viewtype = 'PrefView';
$("#setting-extra").click();
Reader.handleEvent('evSettingsView');
}
Reader.settingsTagTab = function(evt) {
Settings.viewtype = 'TagView';
$("#setting-labels").click();
Reader.handleEvent('evSettingsView');
}
Reader.settingsGoodiesTab = function(evt) {
Settings.viewtype = 'GoodiesView';
$("#setting-goodies").click();
Reader.handleEvent('evSettingsView');
}
Reader.settingsImexportTab = function(evt) {
Settings.viewtype = 'ImexportView';
$("#setting-importexport").click();
Reader.handleEvent('evSettingsView');
}
Reader.returnToReader = function(evt) {
this.state = 'List';
StateVars.PreviousView = true;
Settings.hide();
ReaderViewer.handleEvent('evListView');
}
ReaderViewer.init = function() {
this.expandedView = false;
if (FR_getProperty(FRP_EXPANDED_VIEW) == 'true') {
this.handleEvent('evToggleExpanded'); // coverage
}
this.SortMode = 'newest';
this.listLoaded = false;
this.homeLoaded = false;
this.generation = 0;
this.viewtype = 'HomeView';
this.homeviewFeeds = {};
this.homeviewFolders = {};
if (!this.domLoaded) {
// Dont barf if init is called more than once
this.domLoaded = true;
// Tag edit form setup
$("#hover-tags-edit//input.iv-addtags-input").
enter(ReaderViewer.saveTags.bind(ReaderViewer, null));
// Trendview setup
$("#trends-period-tab").maketab('tab-header', 'tab-contents');
$("#trends-brand-tab").maketab('tab-header', 'tab-contents');
$("#trends-freq-tab").maketab('tab-header', 'tab-contents');
DOM.quickadd.enter(function() {
ReaderViewer.viewtype = 'SearchResultsView';
ReaderViewer.handleEvent('evListView');
});
$("#entries").scroll(this.handleScroll.bind(this));
}
// this.refresh();
}
ReaderViewer.refresh = function(evt) {
switch(this.state) {
case stateListView:
this.listview();
break;
/* case stateHomeView:
this.homeview();
break;
case stateTrendsView:
this.trendsview();
break;
*/
}
}
ReaderViewer.setStatus = function(str) {
$('#lv-status').setdata(str);
}
ReaderViewer.setTitle = function(str) {
$('#lv-title').setdata(str);
}
ReaderViewer.renameCurrentFeed = function(evt) {
if (this.viewtype == 'SubscriptionView') {
var newname = prompt('Enter new name for feed:');
if (!newname.match(/^\s*$/))
FR_cacheFeed(Reader.feed, newname);
ReaderViewer.handleEvent('evRefresh');
}
}
ReaderViewer.deleteCurrentFeed = function(evt) {
if (this.viewtype == 'SubscriptionView') {
FR_removeFeed(Reader.feed);
Reader.handleEvent("evHome", $("#ol-home")[0]);
}
}
ReaderViewer.openFeedForItem = function(evt) {
var feed = $('.fld-feed', this.elem).getdata();
Reader.openFeed(feed);
}
ReaderViewer.openItemSite = function(evt) {
// Nothing to do, html takes care of it
}
ReaderViewer.openItemEmail = function(evt) {
// Nothing to do, html takes care of it
}
/*
* Change the Settings dropdown menu in listview, at the top right
*/
ReaderViewer.setMenu = function(kind) {
this.menuKind = kind;
$("#lv-settings-menu,#lv-settings-menu-contents").removeClass("allitems-menu");
$("#lv-settings-menu,#lv-settings-menu-contents").removeClass("folder-menu");
$("#lv-settings-menu,#lv-settings-menu-contents").removeClass("single-feed-menu");
$("#lv-settings-menu,#lv-settings-menu-contents").removeClass("brand-menu");
$("#lv-settings-menu,#lv-settings-menu-contents").addClass(kind + "-menu");
if (kind == 'single-feed') {
var node = $("#lv-settings-menu-contents");
populateFolders(node, Reader.feed, function() {
$("ul.contents", node).removeClass('hidden');
node.addClass('hidden');
});
}
$("#order-by-newest,#order-by-oldest,$order-by-magic",
$("#lv-settings-menu-contents")).removeClass("chooser-item-selected");
$("#order-by-" + this.SortMode, $("#lv-settings-menu-contents")).
addClass("chooser-item-selected");
}
ReaderViewer.homeview = function(evt) {
// All views
$(ALL_VIEWS).hide();
$('body,html').addClass('homeview');
$('#home').show();
make_permalink('home');
// Not in spec
// if (this.homeLoaded) {
// return;
// }
this.displayTips();
this.displayRecently();
var container = $('#hm-container').clear();
var fr = new FeedRenderer ();
$.each(Reader.feedlist, function(i, feed) {
fr.add(feed);
});
fr.numEntries = 3;
Reader.showLoading();
var bindings = fr.render(container, $('.tpl-summary', $("#templates")));
/* Cache the nodes for filling in feed & folder unread count */
ReaderViewer.homeviewFolders = {};
ReaderViewer.homeviewFeeds = {};
/*
$.each(bindings, function(i, bind) {
var node = bind.node;
var feed = bind.feed;
var folder = $('.fld-folder', node).getdata();
if (feed) {
ReaderViewer.homeviewFeeds[feed] = $('.fld-feedunread', node);
}
if (folder) {
ReaderViewer.homeviewFolders[folder] = $('.fld-folderunread', node);
}
alert(node[0].innerHTML);
});
*/
this.homeLoaded = true;
}
ReaderViewer.homeItemLoaded = function(node, feed, folder) {
if (feed) {
ReaderViewer.homeviewFeeds[feed] = $('.fld-feedunread', node);
}
if (folder) {
var fnode = ReaderViewer.homeviewFolders[folder];
if (fnode)
ReaderViewer.homeviewFolders[folder] = fnode.addnodes($('.fld-folderunread', node));
else
ReaderViewer.homeviewFolders[folder] = $('.fld-folderunread', node);
}
Reader.hideLoading();
}
ReaderViewer.listview = function(evt) {
// We call listview for the sake of correctness against specs.
// for everything (homeview, searchfeedsview) etc.
if (this.viewtype == 'HomeView') {
Reader.page = 'home';
return this.homeview();
}
if (this.viewtype == 'SearchResultsView') {
Reader.page = 'search';
return this.searchfeedsview();
}
if (this.viewtype == 'FeedDiscoveryView') {
Reader.page = 'browse';
return this.browseFeeds();
}
if (this.viewtype == 'TrendsView') {
Reader.page = 'trends';
return this.trendsview();
}
// The real list view begins here
$(ALL_VIEWS).hide();
$('body,html').removeClass('homeview');
$('#listview').show();
// not in specs - removing
// if (this.state == stateListView && this.listLoaded)
// return;
FRS_current_item = undefined;
// Switch RV state to list view
this.state = stateListView;
handle_resize();
this.generation++;
var container = $('#entries').clear();
var fr = new FeedRenderer ();
fr.numEntries = 100;
Reader.showLoading();
this.setLVCount('');
this.setStatus('loading ...');
this.itemNodes = [];
var sink = this.sink = new Injector(this.feedLoaded.bind(this, this.generation),
FEEDLOAD_NUMENTRIES, FEEDLOAD_INTERVAL);
switch (this.viewtype) {
case 'AllItemsView':
Reader.page = 'allitems';
this.setTitle("All Items");
this.setMenu('allitems');
make_permalink('allitems');
$.each(Reader.feedlist,function(i,feed) {
fr.add(feed);
});
break;
case 'SubscriptionView':
if (Reader.folder)
make_permalink('folder', Reader.folder);
else
make_permalink('feed', Reader.feed);
this.setTitle(Reader.folder ? Reader.folder :
FR_feedInfo(Reader.feed).title);
this.setMenu(Reader.folder?'folder': 'single-feed');
$.each(Reader.feedFilter, function(i, feed) {
fr.add(feed);
});
// Folder can also be a tag for items - so load these too
sink.inject($.map(FR_taggedItems(Reader.folder), FC_lookupItemId));
break;
case 'BrandView':
make_permalink(Reader.brand);
this.setTitle("Your " + Reader.brand +" items");
this.setMenu('brand');
/* In Shared View, we need a text section in the top explaining
* what the shared view is and how to share */
if (Reader.brand == 'shared')
container.append($('.tpl-sharedview-hdr',
$("#templates")).clone(true));
sink.inject($.map(FR_brandedItems(Reader.brand), FC_lookupItemId));
Reader.hideLoading();
this.listLoaded = true;
return;
case 'TagView':
make_permalink('tag', Reader.tag);
this.setTitle(Reader.tag);
this.setMenu('folder');
sink.inject($.map(FR_taggedItems(Reader.tag), FC_lookupItemId));
Reader.hideLoading();
this.listLoaded = true;
return;
}
Reader.showLoading();
this.numItems = 0;
this.numUnread = 0;
fr.startLoading(sink);
this.listLoaded = true;
}
ReaderViewer.sortBy = function(how) {
this.SortMode = how;
this.handleEvent('evRefresh');
}
ReaderViewer.showUnreadOnly = function() {
$("#listview").addClass("unreadonly");
}
ReaderViewer.showAll = function() {
$("#listview").removeClass("unreadonly");
}
ReaderViewer.updateLVCount = function() {
var read = $("#entries//.brand-read").length;
var unread = $("#entries//.entry").length - read;
this.setLVCount(unread);
}
ReaderViewer.setLVCount = function(count) {
var node = $(".lv-unread-count");
if (count < 10) {
node.setdata(count);
return;
} else if (count < 100) {
factor = 10;
} else if (count < 1000) {
factor = 100;
} else {
factor = 1000;
}
node.setdata(parseInt(count/factor) * factor + '+');
}
ReaderViewer.nextItem = function(scanOnly) {
var rows;
if (!FRS_current_item) {
rows = $("#entries//.entry");
} else {
rows = $(FRS_current_item).parent().next().children('.entry');
}
if (rows.length > 0) {
if (scanOnly) {
item_select(rows[0]);
} else {
item_clicked(rows[0]);
}
card_recenter($(rows[0]));
}
}
ReaderViewer.prevItem = function(scanOnly) {
var rows;
if (!FRS_current_item) {
rows = $("#entries//.entry");
} else {
rows = $(FRS_current_item).parent().prev().children('.entry');
}
if (rows.length > 0) {
if (scanOnly) {
item_select(rows[0]);
} else {
item_clicked(rows[0]);
}
card_recenter($(rows[0]));
}
}
ReaderViewer.toggleItemOpen = function() {
if (FRS_current_item) {
$(FRS_current_item).toggleClass('expanded');
}
}
ReaderViewer.starCurrentItem = function() {
if (FRS_current_item) {
star_clicked($(".item-star", $(FRS_current_item))[0]);
}
}
ReaderViewer.shareCurrentItem = function() {
if (FRS_current_item) {
$(".item-share", $(FRS_current_item)).click();
}
}
ReaderViewer.toggleItemRead = function() {
if (FRS_current_item) {
var node = $(FRS_current_item);
var itemid = $(".fld-entries-itemid", node);
if (itemid.length) {
var id = itemid[0].value;
if (!FR_isItemRead(id)) {
FC_setItemRead(id);
node.addClass('brand-read');
} else {
FC_setItemUnread(id);
node.removeClass('brand-read');
}
}
}
}
ReaderViewer.tagItem = function() {
if (FRS_current_item) {
var node = $(FRS_current_item);
var tagger = $(".iv-edittags", node);
ReaderViewer.handleEvent('evAddTag', tagger[0]);
}
}
ReaderViewer.viewOriginal = function() {
if (FRS_current_item) {
var link_a = $("a.fld-entries-link", $(FRS_current_item));
if (link_a.length) {
window.open(link_a[0].href, 'yacto-reader-newsitem');
}
}
}
ReaderViewer.trendsview = function(evt) {
$(ALL_VIEWS).hide();
$('body,html').removeClass('homeview');
// this.state = stateTrendsView;
$('#trendsview').show();
handle_resize();
make_permalink('trends');
var stats = FR_getStats();
var dayscaling = get_scaling(stats.period.month)
var hourscaling = get_scaling(stats.period.day);
var dowscaling = get_scaling(stats.period.week);
/* Handle periodic tab */
var day = $("#day-bucket-chart-contents").populate(dayscaling);
var hour = $("#hour-bucket-chart-contents").populate(hourscaling);
var dow = $("#dow-bucket-chart-contents").populate(dowscaling);
populateGraph(day, ".tpl-day-bucket-cell", dayscaling, stats.period.month);
populateGraph(hour, ".tpl-hour-bucket-cell", hourscaling, stats.period.day);
populateGraph(dow, ".tpl-dow-bucket-cell", dowscaling, stats.period.week);
/* Handle reading trends tabs */
populateTrends("#trends-most-read-sorting-contents//tbody",
".tpl-reading-trends-read",
stats.itemstats, 'nread');
populateTrends("#trends-most-starred-sorting-contents//tbody",
".tpl-reading-trends-starred",
stats.itemstats, 'starred');
populateTrends("#trends-most-shared-sorting-contents//tbody",
".tpl-reading-trends-shared",
stats.itemstats, 'shared');
populateTrends("#trends-most-emailed-sorting-contents//tbody",
".tpl-reading-trends-emailed",
stats.itemstats, 'emailed');
populateTrends("#trends-mobile-sorting-contents//tbody",
".tpl-reading-trends-mobile",
stats.itemstats, 'readonmobile');
/* Handle subscription trends tabs */
populateTrends('#trends-most-updated-sorting-contents//tbody',
'.tpl-subs-trends-freq',
stats.update_frequency.frequent, 'items_per_day', true);
populateTrends('#trends-least-updated-sorting-contents//tbody',
'.tpl-subs-trends-inactive',
$.map(stats.update_frequency.inactive,
FR_feedInfo), undefined, true);
var totalstats = {
nfeeds : 0,
nread : 0,
nstarred: 0,
nshared : 0,
nemailed : 0
};
$.each(stats.itemstats, function(i, stat) {
totalstats.nfeeds++;
totalstats.nread += stat.nread;
totalstats.nstarred += stat.starred;
totalstats.nshared += stat.shared;
totalstats.nemailed += stat.emailed;
});
$("#trends-item-count-header").populateObject(totalstats);
var tagcloud = $("#trends-tag-cloud");
tagcloud.children().remove();
var tagtemp = $(".tpl-tag-cloud", $("#templates"));
var clouds = tagcloud.populateArray(FR_allFolders(), tagtemp);
var tagstats = {};
var max_items = 0;
var max_readitems = 0;
$.each(clouds, function(i, binding) {
var items = 0;
var readitems = 0;
var feeds = FR_feedsInFolder(binding.obj);
if (feeds) {
items = feeds.length;
$.each(stats.itemstats, function(i, stat) {
if ($.indexOf(feeds, stat.feed) >= 0) {
readitems += stat.nread;
}
});
}
tagstats[binding.obj] = {items: items, readitems: readitems,
node:binding.node};
if (items > max_items)
max_items = items;
if (readitems > max_readitems)
max_readitems = readitems;
});
$.each(tagstats, function(tag, tagstat) {
var notch = Math.round(5.0 * tagstat.items / max_items);
tagstat.node.addClass("x" + notch);
var notch1 = Math.round(5.0 * tagstat.readitems / max_readitems);
tagstat.node.addClass("y" + notch1);
});
}
Reader.navNext = function() {
var node = $('.navigated');
if (!node || !node.length)
node = Reader.selectedNode;
var saved = node;
// If this not a folder,feed or tag node ...
if (!node || !node.parents('#fl-folderlist,#fl-feedlist,#fl-taglist').length) {
node = $('span.link', $("#fl-folderlist"));
if (node.length > 1)
node = $(node[0]);
} else {
node = $('span.link', node.parents('li').next());
}
if (!node || !node.length) {
node = $('span.link', saved.parents('#fl-folderlist,#fl-feedlist,#fl-taglist').next());
}
if (node.length > 1)
node = $(node[0]);
$('.navigated').removeClass('navigated');
if (node && node.length) {
node.addClass('navigated');
}
}
Reader.navPrev = function() {
var node = $('.navigated');
if (!node || !node.length)
node = Reader.selectedNode;
var saved = node;
// If this not a folder,feed or tag node ...
if (!node || !node.parents('#fl-folderlist,#fl-feedlist,#fl-taglist').length) {
node = $("#fl-taglist").children('li').children('span.link');
if (node.length > 1)
node = $(node[node.length-1]);
} else {
node = node.parents('li').prev().children('span.link');
}
if (!node || !node.length) {
node = saved.parents('#fl-folderlist,#fl-feedlist,#fl-taglist').prev().children('li').children('span.link');
if (node.length > 1)
node = $(node[node.length-1]);
}
$('.navigated').removeClass('navigated');
if (node && node.length) {
node.addClass('navigated');
}
}
Reader.navOpenSelected = function() {
var node = $('.navigated');
if (node.length > 0) {
if (node.is('.tag-selector')) {
node.parents('li.tag').click();
} else {
$('.folder-invoke,.feed-invoke', node).andSelf().click();
}
}
}
Reader.navToggleExpand = function() {
var node = $('.navigated');
if (node.length > 0)
$('div.toggle', node.parent('li.folder')).click();
}
Reader.toggleFullScreen = function() {
if ($(document.body).is('.hide-nav')) {
Reader.open();
} else {
Reader.close();
}
}
Reader.openPromptedFeed = function() {
var feed = prompt('Feed to open:');
$("#fl-feedlist//span.fld-title:contains('" + feed+ "')").parents('.feed-invoke').click();
}
/*
* Function to populate the bar graph for trends
*/
function populateGraph(node, expr, scaling, statlist) {
$(".bucket-scale-dyncell", node).remove();
$.each(statlist, function(i, val) {
var cell = $(expr, $("#templates")).clone(true);
cell.attr('title', val); // XXX add a prefix
$(".bucket", cell).css('height', parseInt(1+100*val/scaling.scalemax) + 'px');
cell.appendTo($(".bucket-scale-dynrow", node));
});
}
/*
* Function to populate the entrie trends screen
*/
function populateTrends(expr, template, orgstats, field, nosort) {
var tmpstats;
if (field) {
tmpstats = $.grep($.clone(orgstats), function(stat) {
return stat[field] > 0;
});
} else {
tmpstats = $.clone(orgstats);
}
/* Sort if needed */
var stats;
if (!nosort) {
stats = [];
$.each(tmpstats, function(i, stat) {
var found = false;
for (var j=0; j= 3)
rt.addClass('bundle-extra');
bundlesData[p].feedcount = ''+bundlesData[p].subscriptions.length;
// FeedRenderer.prototype.renderObject (bundlesData[p], rt, template);
rt.populateFeed(bundlesData[p]);
var link = $(".bundle-invoke", rt);
var title = bundlesData[p].title;
link.click(function(event){
event = jQuery.event.fix( event || window.event || {} );
ReaderViewer.handleEvent('evTag', event.target);
return false;});
if (FR_getProperty(FRP_BUNDLE_STATE + title) == 'added') {
rt.addClass('bundle-added');
}
var bi = $(".feeds-bundle-data", rt);
bi.each(function(i) {this.bundleData = bundlesData[p];});
bnum++;
}
}
Reader.hideLoading();
// fr.renderSearchResult ($('#quickadd')[0].value, container, $('#tpl-search'));
this.searchLoaded = true;
}
ReaderViewer.showbundle = function(evt) {
if (this.viewtype == 'FeedDiscoveryView') {
var node = this.elem;
var topnode = $(node).parents('.tpl-bundle-news');
var inp = $(".feeds-bundle-data", topnode);
var folder = inp[0].bundleData.title;
// var folder= node.href;
if (folder.match(/([^\/]+)$/)) {
folder = RegExp.$1;
}
Reader.openFolder(folder);
}
return false;
}
ReaderViewer.showImport = function(evt) {
if (this.viewtype == 'FeedDiscoveryView') {
Reader.settingsImexportTab();
}
}
ReaderViewer.searchfeedsview = function (evt) {
$(ALL_VIEWS).hide();
$('body,html').removeClass('homeview');
$('#quick-add-bubble-holder').hide();
$('#searchview').show();
Reader.showLoading ();
var container = $('#sr-container');
container.children().remove();
var fr = new FeedRenderer ();
Reader.showLoading();
var keyword = DOM.quickadd.getdata();
$("#sv-keyword").setdata(keyword);
make_permalink('search', keyword);
fr.renderSearchResult (keyword, container, $('#tpl-search'));
this.searchLoaded = true;
}
ReaderViewer.searchInBrowse = function(evt) {
DOM.quickadd.setdata($('#directory-search-query').getdata());
this.viewtype = 'SearchResultsView';
this.handleEvent('evListView');
}
ReaderViewer.toggleExpanded = function(evt) {
this.expandedView = !this.expandedView;
if (this.expandedView) {
$("#view-cards").addClass('tab-header-selected');
$("#view-list").removeClass('tab-header-selected');
FR_setProperty(FRP_EXPANDED_VIEW, 'true');
} else {
$("#view-list").addClass('tab-header-selected');
$("#view-cards").removeClass('tab-header-selected');
FR_setProperty(FRP_EXPANDED_VIEW, null);
}
this.handleEvent('evListView');
}
ReaderViewer.setExpanded = function(expanded) {
if (expanded != this.expandedView)
this.handleEvent('evToggleExpanded');
}
ReaderViewer.feedLoaded = function(generation, entries) {
// There is no way to STOP a feed being loaded.
// So we use this trick
if (generation != this.generation)
return;
if (this.expandedView) {
$("#entries")[0].className = 'expanded';
} else {
$("#entries")[0].className = 'list';
}
var feeds = [];
$.each(entries, function(i, property) {
var itemid = property['entries-itemid'];
var node = $(ReaderViewer.expandedView?'.tpl-entry-exp':'.tpl-entry',
$("#templates")).clone(true);
var itemnode = {node:node,
timestamp:property.timestamp};
var placed = false;
switch (ReaderViewer.SortMode) {
case 'newest':
$.each(ReaderViewer.itemNodes, function(i, item) {
if (item.timestamp < property.timestamp) {
node.insertBefore(item.node);
var newnodes = ReaderViewer.itemNodes.slice(0,i);
newnodes.push(itemnode);
$.merge(newnodes, ReaderViewer.itemNodes.slice(i));
ReaderViewer.itemNodes = newnodes;
placed = true;
return false;
}
});
break;
case 'oldest':
$.each(ReaderViewer.itemNodes, function(i, item) {
if (item.timestamp > property.timestamp) {
node.insertBefore(item.node);
var newnodes = ReaderViewer.itemNodes.slice(0,i);
newnodes.push(itemnode);
$.merge(newnodes, ReaderViewer.itemNodes.slice(i));
ReaderViewer.itemNodes = newnodes;
placed = true;
return false;
}
});
break;
default:
break;
}
if (!placed) {
node.appendTo($('#entries'));
ReaderViewer.itemNodes.push(itemnode);
placed = true;
}
node.populate(property);
$(".user-tags-list", node).populateArray(FR_tagsForItem(itemid),
$("#tpl-iv-tag-list", $("#templates")));
setBranding(node, property);
$.merge(feeds, [property.feed]);
if (itemid == ReaderViewer.current_itemid) {
FRS_current_item = $(".entry", node).addClass('expanded').attr('id', 'current-entry')[0];
}
});
if (this.expandedView) {
$("#entries//.entry").click(card_clicked);
}
Reader.updateFeedCount(feeds);
this.numItems += entries.length;
this.setLVCount(this.numItems);
this.setStatus(' ' + this.numItems + ' items');
Reader.hideLoading();
}
ReaderViewer.searchAddFolder = function(node, event) {
var topnode = $(node); //".sv-folder-menu");
var dropdown = $(".sv-folder-menu-contents", topnode);
var inactive = dropdown.is('.hidden');
if (inactive) {
dropdown.removeClass('hidden');
// var bc = $('.button-container', topnode);
// dropdown[0].style.width = bc[0].offsetWidth + 'px';
} else {
dropdown.addClass('hidden');
}
}
ReaderViewer.searchFolderHide = function() {
$(".sv-folder-menu-contents").addClass('hidden');
}
ReaderViewer.searchViewFeed = function(node, event) {
var feed = $("input.fld-entries-url", node.parentNode).getdata();
var folders = FR_folderForFeed(feed);
if (folders && folders.length > 0) {
Reader.expandFolder(folders[0]);
}
Reader.openFeed(feed);
}
ReaderViewer.searchRemoveFeed = function(node, event) {
if (!confirm("Are you sure you want to unsubscribe this feed?")) {
return;
}
// Unsubscribe the feed
var feed = $("input.fld-entries-url", node.parentNode).getdata();
Reader.removeFeed(feed);
// Mark this search entry as unsubscribed
$(node).parents(".tpl-search").removeClass("result-subscribed");
}
ReaderViewer.removeSubscribedFeed = function(evt) {
return this.searchRemoveFeed(this.elem);
}
ReaderViewer.settingsClicked = function(node, event) {
var topnode = $("#lv-settings-menu");
var dropdown = $("#lv-settings-menu-contents");
var inactive = dropdown.is('.hidden');
if (inactive) {
dropdown.removeClass('hidden');
// var bc = $('.button-container', topnode);
// dropdown[0].style.width = bc[0].offsetWidth + 'px';
} else {
dropdown.addClass('hidden');
}
}
ReaderViewer.settingsHide = function() {
var dropdown = $("#lv-settings-menu-contents");
dropdown.addClass('hidden');
}
ReaderViewer.itemEditTags = function(evt) {
return this.editTags(this.elem);
}
ReaderViewer.editTags = function(node, event) {
node = $(node);
var topnode = node.parents(".entry");
var itemid = $(".fld-entries-itemid", topnode).getdata();
if(itemid.length > 0) {
this.currentItem = itemid;
this.currentItemNode = node.parents(".iv-main");
var tpl = $("#hover-tags-edit");
var pos = node.positionedOffset();
var l = (pos[0]+node[0].offsetWidth+2)+'px';
var t = (pos[1]-15)+'px';
// alert(l + ',' + t);
tpl.css('left', l).
css('top', t).show();
/* populate with current tags */
var tags = FR_tagsForItem(itemid).join(', ');
$("input.iv-addtags-input", tpl).setdata(tags)[0].focus();
}
}
ReaderViewer.saveTags = function(node, event) {
var tpl = $("#hover-tags-edit")
if (this.currentItem) {
var itemid = this.currentItem;
var node = this.currentItemNode;
this.currentItem = this.currentItemNode = undefined;
var tags = $.map($("input.iv-addtags-input", tpl).getdata().split(','), $.trim);
FR_untagAllForItem(itemid);
$.each(tags, function(i, tag) {
FR_tagItem(itemid, tag);
});
var taglist = $(".user-tags-list", node);
taglist.children().remove();
taglist.populateArray(FR_tagsForItem(itemid),
$("#tpl-iv-tag-list", $("#templates")));
Reader.refresh();
}
tpl.hide();
}
ReaderViewer.close = function() {
// Huh ??
}
ReaderViewer.cancelTags = function(node, event) {
var tpl = $("#hover-tags-edit")
tpl.hide();
this.currentItem = undefined;
}
ReaderViewer.openDevBlog = function(evt) {
window.open(FRU_devBlog);
}
ReaderViewer.openTips = function(evt) {
window.open(FRU_tips);
}
ReaderViewer.displayTips = function(evt) {
$(".hv-tips-container").populateObject(FR_getTips());
}
ReaderViewer.displayBundles = function(evt) {
// Bundles are displayed as part of the main refresh
// So nothing to do here
}
ReaderViewer.displayUnread = function(evt) {
// Unread is displayed as part of the main refresh
// So nothing to do here
}
var dbg = true;
ReaderViewer.displayUnreadCount = function(nodetype, name, unread) {
if (nodetype == 'feed') {
try {
this.homeviewFeeds[name].setdata('('+unread+')');
} catch(e){}
} else if (nodetype == 'folder') {
try {
// alert(unread);
this.homeviewFolders[name].setdata('('+unread+')');
} catch(e){}
}
}
ReaderViewer.displayRecently = function(evt) {
var entries = FR_getStarredItems();
var node = DOM.recentStarred;
if (entries && entries.length>0) {
entries = entries.slice(entries.length-3);
node.show().children('.tpl-recent').remove();
node.populateArray($.map(entries, FC_lookupItemId), ".tpl-recent");
} else {
node.hide();
}
entries = FR_getSharedItems();
entries = entries.slice(entries.length-3);
node = DOM.recentShared;
if (entries && entries.length>0) {
entries = entries.slice(entries.length-3);
node.show().children('.tpl-recent').remove();
node.populateArray($.map(entries, FC_lookupItemId), ".tpl-recent");
} else {
node.hide();
}
}
Settings.init = function() {
this.viewtype = 'SubView';
this.currentTab = 'subscriptions';
DOM.subsFilterInput = $("#subs-filter-input");
if (!this.domLoaded) {
// Dont barf if init is called more than once
this.domLoaded = true;
DOM.subsFilterInput.enter(this.filterSubs.bind(this)).
keyup(this.filterSubs.bind(this));
}
DOM.settings = $("#settings");
}
Settings.show = function() {
// Show the settings section and hide everything else
$('#main').hide();
DOM.settings.show();
$("body,html").addClass('settings');
switch(Settings.viewtype) {
case 'SubView':
make_permalink('settings', 'subs');
this.currentTab = 'subscriptions';
break;
case 'PrefView':
make_permalink('settings', 'prefs');
this.currentTab = 'extras';
break;
case 'TagView':
make_permalink('settings', 'labels');
this.currentTab = 'labels';
break;
case 'ImexportView':
make_permalink('settings', 'imexport');
this.currentTab = 'importexport';
break;
case 'GoodiesView':
make_permalink('settings', 'goodies');
this.currentTab = 'goodies';
break;
}
$.each(SETTING_TABS, function(i, tab) {
$('#setting-' + tab).removeClass('selected');
$('.setting-tab-' + tab).removeClass('selected');
});
$('#setting-' + this.currentTab).addClass('selected');
$('.setting-tab-' + this.currentTab).addClass('selected');
this['show' + this.currentTab]();
}
/* Settings.showtab = function(newtab) {
this.currentTab = newtab;
this.show();
} */
Settings.showextras = function() {
var folders = FR_allFolders();
var tags = FR_allTags();
var select = $("#settings-prefs-dropdown");
select.children(".dynamic").remove();
$.each(folders, function(i, folder) {
var option = $(document.createElement('option')).addClass('dynamic').setdata(folder).appendTo(select);
option[0].value = '?folder/' + folder;
});
$.each(tags, function(i, tag) {
var option = $(document.createElement('option')).addClass('dynamic').setdata(tag).appendTo(select);
option[0].value = '?tag/' + tag;
});
select[0].value = FR_getProperty(FRP_START_PAGE);
var scrollchk = $('#settings-prefs-scroll');
scrollchk.attr('checked', FR_getProperty(FRP_SCROLL_TRACKING));
}
Settings.showimportexport = function() {
}
Settings.showgoodies = function() {
}
Settings.showsubscriptions = function() {
if (!this.selectedFeeds)
this.selectedFeeds = [];
var subs = $.map(Reader.feedlist, FR_feedInfo);
$.each(subs, function(i, sub) {
var folders = FR_folderForFeed(sub.feed);
if (folders) {
sub.folders = folders.join(', ');
}
});
var subsnode = $('#subscriptions');
subsnode.children().each(function() {$(this).remove();});
var bindings = subsnode.populateArray(subs,
$('.tpl-settings-row,.tpl-settings-row1',
$("#templates")));
$.each(bindings, function(i, b) {
if ($.indexOf(Settings.selectedFeeds, b.obj.feed)>=0) {
$(".chkbox", b.node).attr('checked', 'checked');
}
populateFolders(b.node, b.obj.feed,
Settings.subsUpdateTags.bind(Settings, b.node, b.obj.feed));
});
$("#subs-total").setdata(subs.length);
if (this.selectedFeeds.length > 0) {
this.updateFolders([]);
}
}
Settings.subsUpdateTags = function(topnode, feed) {
var folders = FR_folderForFeed(feed);
if (!folders)
folders = [];
$(".fld-folders", topnode).setdata(folders.join(", "));
}
Settings.hide = function() {
DOM.settings.hide();
$('#main').show();
$("body,html").removeClass('settings');
}
/* -- Subscriptions tab -- */
Settings.show_folders_dropdown = function (topnode) {
var feed = $(".feedid", topnode)[0].value;
var dropdown = $("ul.contents", topnode);
var inactive = dropdown.is('.hidden');
/* Close all open dropdowns */
this.hide_folder_dropdowns();
if (inactive) {
dropdown.removeClass('hidden');
var bc = $('.button-container', topnode);
dropdown[0].style.width = bc[0].offsetWidth + 'px';
} else {
dropdown.addClass('hidden');
}
}
Settings.hide_folder_dropdowns = function() {
$(".tpl-settings-row//ul.contents").addClass('hidden');
}
/*
Settings.choice_clicked = function(feed, folder, remove, topnode) {
if (remove) {
FR_removeFromFolder(feed, folder);
} else {
FR_copyToFolder(feed, folder);
}
Reader.refresh();
this.show();
}
*/
Settings.show_rename = function(topnode) {
var feed = $(".feedid", topnode)[0].value;
var feedinfo = FR_feedInfo(feed);
if (feedinfo) {
return $("#hover-form", $("#globalnodes")).
populateObject(feedinfo);
}
}
Settings.do_rename = function(feed, newtitle) {
FR_cacheFeed(feed, newtitle);
Reader.refresh();
this.show();
}
Settings.remove_feed = function(topnode) {
var feed = $(".feedid", topnode)[0].value;
ReaderViewer.homeLoaded = false;
Reader.removeFeed(feed);
this.show();
}
Settings.select_all = function() {
var settings = DOM.settings;
var folders = [];
this.selectedFeeds = FR_allFeeds();
$('.tpl-settings-row//.chkbox', settings).attr('checked', 'checked');
$('.tpl-settings-row//.fld-folders', settings).each(
function() {
$.merge(folders, $(this).getdata().split(','));
});
this.updateFolders(folders);
}
Settings.select_none = function() {
var settings = DOM.settings;
this.selectedFeeds = [];
$('.tpl-settings-row//.chkbox', settings).attr('checked', '');
this.updateFolders([]);
}
Settings.select_unassigned = function() {
var settings = DOM.settings;
this.selectedFeeds = [];
$('.tpl-settings-row', settings).each(function() {
if ($('.fld-folders', $(this)).getdata() == '') {
Settings.selectedFeeds.push($('.fld-feed', $(this)).getdata());
$('.chkbox', $(this)).attr('checked', 'checked');
} else {
$('.chkbox', $(this)).attr('checked', '');
}
});
this.updateFolders([]);
}
Settings.unsubscribeSelected = function() {
if (!this.selectedFeeds || this.selectedFeeds.length == 0) {
alert("Please select the feeds you want to unsubscribe from");
return;
}
if (!confirm("Are you sure you want to unsubscribe from selected feeds?")) {
return;
}
Reader.showLoading();
ReaderViewer.homeLoaded = false;
$.each(this.selectedFeeds, function(i, feed) {
Reader.removeFeed(feed);
});
Reader.hideLoading();
this.selectedFeeds = [];
this.show();
}
Settings.filterSubs = function() {
var key = DOM.subsFilterInput.getdata();
var settings = $("#settings");
$('.tpl-settings-row', settings).each(function() {
var feed = $('.fld-feed', $(this)).getdata()
var folders = FR_folderForFeed(feed);
var feedinfo = FR_feedInfo(feed);
if (feed.indexOf(key) >= 0 ||
feedinfo.title.indexOf(key) >= 0 ||
(folders && folders.join('___').indexOf(key) >= 0)) {
$(this).removeClass('hidden').next(".tpl-settings-row1").removeClass('hidden');
} else {
$(this).addClass('hidden').next(".tpl-settings-row1").addClass('hidden');
}
});
}
Settings.checkChanged = function() {
var settings = DOM.settings;
var folders = [];
this.selectedFeeds = [];
$('.tpl-settings-row', settings).each(function() {
if ($('.chkbox', $(this)).attr('checked')) {
Settings.selectedFeeds.push($('.fld-feed', $(this)).getdata());
var fstr = $('.fld-folders', $(this)).getdata();
if (fstr)
$.merge(folders, fstr.split(','));
}
});
this.updateFolders(folders);
}
Settings.updateFolders = function(remove_list) {
remove_list = $.uniq($.map(remove_list, $.trim));
var options = $('#subs-folder-options', DOM.settings).setdata('');
var allfolders = FR_allFolders();
$.merge(allfolders, FR_allTags());
var option = $(document.createElement('option')).attr('value', '0');
option[0].innerHTML = 'More actions...';
options.append(option);
option = $(document.createElement('option')).
attr('disabled', 'disabled').attr('value', '0');
option[0].innerHTML = 'Add tag...';
options.append(option);
// Add all folders
$.each(allfolders, function(i, f) {
option = $(document.createElement('option')).
attr('value', f).addClass('a').addClass('label');
option[0].innerHTML = f;
options.append(option);
});
if (remove_list && remove_list.length > 0) {
option = $(document.createElement('option')).
attr('disabled', 'disabled');
option[0].innerHTML = 'Remove tag...';
options.append(option);
// Add remove_list
$.each(remove_list, function(i, f) {
option = $(document.createElement('option')).
attr('value', f).addClass('a').addClass('label').
addClass('remove');
option[0].innerHTML = f;
options.append(option);
});
}
// options.change(Settings.folderChanged.bind(Settings, options[0]));
}
Settings.folderChanged = function(node, event) {
var settings = DOM.settings;
var opt = $(node.options[node.selectedIndex]);
var remove = false;
var folder = opt[0].value;
if (folder != '0') {
if (opt.is('.remove')) {
remove = true;
}
$('.tpl-settings-row', settings).each(function() {
var feed = $('.fld-feed', $(this))[0].value;
if ($('.chkbox', $(this)).attr('checked')) {
if (remove) {
FR_removeFromFolder(feed, folder);
} else
FR_copyToFolder(feed, folder);
}
});
Reader.refresh();
this.show();
}
}
/* -- Tag tab -- */
Settings.showlabels = function() {
if (!this.selectedLabels)
this.selectedLabels = [];
var allfolders = FR_allFolders();
$.merge(allfolders, FR_allTags());
var topnode = $("#settings");
var tbody = $('#labels-list', topnode);
tbody.children('.tpl-tags-row').remove();
$(".labels-change-sharing")[0].selectedIndex = 0;
var finfos = $.map(allfolders, function(f) {
var info = {folder: f};
return info;
});
var bindings = tbody.populateArray(finfos,
$('.tpl-tags-row', $("#templates")));
bindings.push({node: $(".labels-list-starred"),
obj: {folder : "_starred"}});
bindings.push({node: $(".labels-list-shared"),
obj: {folder : "_shared"}});
$.each(bindings, function(i, bind) {
if (FR_getProperty(FRP_FOLDER_SHARE + bind.obj.folder) ==
'public') {
bind.node.addClass('is-public');
}
if ($.indexOf(Settings.selectedLabels,bind.obj.folder) >= 0) {
$(".chkbox", bind.node).attr('checked', 'checked');
} else {
$(".chkbox", bind.node).attr('checked', '');
}
});
if (FR_getProperty(FRP_FOLDER_SHARE + "_starred") =='public')
$(".labels-list-starred").addClass("is-public");
else
$(".labels-list-starred").removeClass("is-public");
$("#labels-total").setdata(bindings.length);
}
Settings.togglepublic_clicked = function(event) {
event = jQuery.event.fix( event || window.event || {} );
var topnode = $(event.target).parents(".data-row");
if (!topnode.is(".labels-list-shared")) {
var isPublic = topnode.is(".is-public");
var folder = $(".fld-folder", topnode).getdata();
if (isPublic) {
FR_setProperty(FRP_FOLDER_SHARE + folder, null);
topnode.removeClass('is-public');
} else {
FR_setProperty(FRP_FOLDER_SHARE + folder, 'public');
topnode.addClass('is-public');
}
}
}
Settings.removefolder_clicked = function(event) {
event = jQuery.event.fix( event || window.event || {} );
var topnode = $(event.target).parents(".data-row");
var folder = $(".fld-folder", topnode).getdata();
if (confirm('Are you sure you want to remove the "' + folder
+ '" label ?')) {
this.removeFolder(topnode);
$("#labels-total").setdata($(".data-row",
$("#setting-labels")).length);
}
}
Settings.removeFolder = function(topnode) {
var folder = $(".fld-folder", topnode).getdata();
if (!folder.match(/^_/)) {
var feeds = FR_feedsInFolder(folder);
if (feeds)
$.each(feeds, function(i, f) {FR_removeFromFolder(f, folder);});
var items = FR_taggedItems(folder);
if (items)
$.each(items, function(i, item) {FR_untagItem(item, folder);});
topnode.remove();
Reader.refresh();
}
}
Settings.removeSelectedTags = function() {
if ($.grep(this.selectedLabels, function(label) {
return label.match(/^_/);}).length > 0) {
alert("You cannot remove your starred or shared items");
return;
}
if (confirm("Are you sure you want to remove the selected labels?")) {
$(".chkbox", $("#setting-labels")).each(function() {
var opt = $(this);
if (opt.attr('checked')) {
var topnode = opt.parents(".data-row");
Settings.removeFolder(topnode);
}
});
$("#labels-total").setdata($(".data-row", $("#setting-labels")).length);
}
}
Settings.tagCheckChanged = function(node) {
node = $(node);
var folder = $(".fld-folder",
node.parents(".data-row")).getdata();
if (node.attr('checked')) {
this.selectedLabels.push(folder);
this.selectedLabels = $.uniq(this.selectedLabels);
} else {
this.selectedLabels = $.grep(this.selectedLabels, function(l) {
return l != folder;
});
}
}
Settings.shareOptionChanged = function(node) {
var makePrivate = true;
if (node.value != '0') {
if (node.value == 'public') {
makePrivate = false;
}
$(".chkbox", $("#setting-labels")).each(function() {
var opt = $(this);
if (opt.attr('checked')) {
var topnode = opt.parents(".data-row");
var isPublic = topnode.is(".is-public");
var folder = $(".fld-folder", topnode).getdata();
if (makePrivate && !topnode.is('.labels-list-shared')) {
FR_setProperty(FRP_FOLDER_SHARE + folder, null);
topnode.removeClass('is-public');
} else {
FR_setProperty(FRP_FOLDER_SHARE + folder, 'public');
topnode.addClass('is-public');
}
}
});
node.selectedIndex = 0;
}
}
Settings.select_alltags = function() {
$(".chkbox", $("#setting-labels")).attr('checked', 'checked');
var allfolders = FR_allFolders();
$.merge(allfolders, FR_allTags());
this.selectedLabels = allfolders;
}
Settings.select_notags = function() {
$(".chkbox", $("#setting-labels")).attr('checked', '');
this.selectedLabels = [];
}
Settings.select_publictags = function() {
this.selectedLabels = [];
$(".chkbox", $("#setting-labels")).each(function() {
var topnode = $(this).parents(".data-row");
if (topnode.is(".is-public")) {
Settings.selectedLabels.push($(".fld-folder", topnode).getdata());
$(this).attr('checked', 'checked');
} else {
$(this).attr('checked', '');
}
});
}
Settings.select_privatetags = function() {
this.selectedLabels = [];
$(".chkbox", $("#setting-labels")).each(function() {
var topnode = $(this).parents(".data-row");
if (topnode.is(".is-public")) {
$(this).attr('checked', '');
} else {
Settings.selectedLabels.push($(".fld-folder", topnode).getdata());
$(this).attr('checked', 'checked');
}
});
}
//-- UI state manipulation code --
function setBranding(node, property) {
var itemid = property['entries-itemid'];
if (itemid) {
if (FR_isStarred(itemid)) {
node.addClass('brand-starred');
} else {
node.removeClass('brand-starred');
}
if (FR_isShared(itemid)) {
node.addClass('brand-shared');
} else {
node.removeClass('brand-shared');
}
if (FR_isItemRead(itemid)) {
node.addClass('brand-read');
} else {
node.removeClass('brand-read');
// FC_updateUnread(property.feed, 1);
}
}
}
//-- Reader UI callbacks --
/*function home_clicked(node) {
Reader.handleEvent('evHome', node);
}
function allitems_clicked(node) {
Reader.handleEvent('evAllItems', node);
}
function quickadd_clicked (node) {
Reader.handleEvent('evQuickAdd', node);
}
function browse_clicked (node) {
ReaderViewer.handleEvent('evBrowse', node);
}
function searchfeeds_clicked (node) {
ReaderViewer.handleEvent ('evSearchFeeds', node);
}
*/
function quickadd_close_clicked(node) {
$("#quick-add-bubble-holder").hide();
}
function subscribeFeed_clicked (node) {
var inp = $("input.fld-entries-url", node);
var feed = {title: '', feed: ''};
feed.feed = inp[0].value;
inp = $("input.fld-entries-title", node);
feed.title = inp[0].value;
FR_cacheFeed(feed.feed, feed.title);
FR_addFeed(feed.feed);
// Start retreiving the items
FC_retreiveFeed(feed.feed);
ReaderViewer.handleEvent('evSubSubscribed', node);
Reader.handleEvent('evRefresh', node);
}
ReaderViewer.addBundleOrFeed = function(evt) {
if (this.viewtype == 'FeedDiscoveryView') {
return subscribeBundle_clicked(this.elem);
} else if (this.viewtype == 'SearchResultsView') {
subscribeFeed_clicked(this.elem);
}
}
ReaderViewer.doSearch = function() {
// Search results are displayed as part of the main refresh
// So nothing to do here
}
ReaderViewer.returnToFD = function() {
if(this.viewtype == 'SearchResultsView') {
Reader.handleEvent('evBrowse');
}
}
ReaderViewer.searchFeedSubscribed = function(evt) {
var node = this.elem;
// markup the search and switch button display
var topnode = $(node).parents(".tpl-search");
topnode.addClass('result-subscribed');
}
ReaderViewer.openSubscribedFeed = function(evt) {
this.searchViewFeed(this.elem);
}
ReaderViewer.handleScroll = function() {
if (this.expandedView) {
var scrollTop = $("#entries")[0].scrollTop;
var done = false;
$("#entries//.entry").each(function(i, entry) {
if (!done) {
if ($(entry).positionedOffset()[1] >= scrollTop) {
done = true;
item_clicked(entry);
}
}
});
}
}
function subscribeBundle_clicked (node) {
var inp = $(".feeds-bundle-data", node);
var bundle = inp[0].bundleData;
for (var i = 0; i < bundle.subscriptions.length; i++) {
var feed = {title: '', feed: ''};
feed.title = bundle.subscriptions [i].title;
feed.feed = bundle.subscriptions [i].id;
feed.feed = feed.feed.replace (/^feed\//, "");
FR_cacheFeed(feed.feed, feed.title);
FR_addFeed(feed.feed);
// Start retreiving the items
FC_retreiveFeed(feed.feed);
FR_copyToFolder(feed.feed, bundle.title);
}
Reader.bundleAdded(bundle.title);
$(node).addClass('bundle-added');
Reader.handleEvent('evRefresh', node);
Reader.expandFolder(bundle.title);
}
function morebundles_clicked(node) {
$("#directory-box").addClass("bundles-only");
make_permalink('browse', 'more');
}
function lessbundles_clicked(node) {
$("#directory-box").removeClass("bundles-only");
make_permalink('browse');
}
function folder_clicked(node, e) {
var elem = node.parentNode;
Reader.buttonClicked(elem);
Reader.openFolder($(".fld-name",node).getdata());
return false;
}
function tag_clicked(node, e) {
Reader.openTag($(".fld-name", node).getdata());
}
function feed_clicked(elem, e) {
Reader.openFeed($("input.fld-feed", elem).getdata());
}
function refresh_clicked(node, e) {
ReaderViewer.listLoaded = false;
ReaderViewer.homeLoaded = false;
ReaderViewer.refresh();
}
function card_clicked(event) {
event = jQuery.event.fix( event || window.event || {} );
var node = $(event.target);
var topnode = node.parents(".entry");
item_clicked(topnode[0]);
card_recenter(topnode);
}
function card_recenter(topnode) {
// Move this item to the top
$("#entries")[0].scrollTop = topnode.positionedOffset()[1] - 2;
}
function item_select(node) {
if (FRS_current_item != node) {
if (FRS_current_item) {
$(FRS_current_item).removeClass('expanded');
FRS_current_item.id = '';
}
FRS_current_item = node;
FRS_current_item.id = 'current-entry';
// $(FRS_current_item).addClass('expanded');
}
}
function item_clicked(node, e) {
if (FRS_current_item == node) {
$(node).toggleClass('expanded');
} else {
if (FRS_current_item) {
$(FRS_current_item).removeClass('expanded');
FRS_current_item.id = '';
}
FRS_current_item = node;
FRS_current_item.id = 'current-entry';
$(FRS_current_item).addClass('expanded');
}
if (ReaderViewer.expandedView) {
return;
}
node = $(node);
var topnode = node.parents(".tpl-entry");
var itemid = $(".fld-entries-itemid", topnode);
if($(node).is('.expanded') && itemid.length > 0) {
var ci = FRS_current_item;
var timeout = FR_getProperty(FRP_ITEM_READ_TIMEOUT);
if (timeout == null) {
timeout = 1000;
}
setTimeout(function() {
if (ci == FRS_current_item) {
FC_setItemRead(itemid[0].value);
topnode.addClass('brand-read');
}
}, timeout);
make_permalink_item(itemid.getdata());
} else {
make_permalink_item();
}
ReaderViewer.updateLVCount();
}
function itemread_clicked(node, event) {
node = $(node);
var topnode = node.parents(".entry").parent();
var itemid = $(".fld-entries-itemid", topnode);
if(itemid.length > 0) {
if (!FR_isItemRead(itemid[0].value)) {
FC_setItemRead(itemid[0].value);
topnode.addClass('brand-read');
} else {
FC_setItemUnread(itemid[0].value);
topnode.removeClass('brand-read');
}
}
}
function markall_clicked(node, event) {
Reader.showLoading();
var top = $(".entry");
// Set the status of currently displayed entries
top.each(function() {
var itemid = $(".fld-entries-itemid", $(this));
if (itemid.length > 0) {
FC_setItemRead(itemid[0].value);
$(this).addClass('brand-read');
}
});
$.each(ReaderViewer.sink.entries, function(i, entry) {
FC_setItemRead(entry['entries-itemid']);
});
ReaderViewer.updateLVCount();
Reader.hideLoading();
}
function star_clicked(node, event) {
node = $(node);
var topnode = node.parents(".entry").parent();
var itemid = $(".fld-entries-itemid", topnode);
if(itemid.length > 0) {
if (!FR_isStarred(itemid[0].value)) {
FR_starItem(itemid[0].value);
topnode.addClass('brand-starred');
} else {
FR_unstarItem(itemid[0].value);
topnode.removeClass('brand-starred');
/* Not in spec, not needed
// If we are in the star view we need to refresh
if (ReaderViewer.state == stateListView &&
ReaderViewer.viewtype == 'BrandView' &&
Reader.brand == 'starred') {
refresh_clicked(node, event);
}
*/
}
}
Reader.updateFeedCount([]);
event = jQuery.event.fix( event || window.event || {} );
event.preventDefault();
event.stopPropagation();
}
function share_clicked(node, e) {
node = $(node);
var topnode = node.parents(".entry").parent();
var itemid = $(".fld-entries-itemid", topnode);
if(itemid.length > 0) {
if (!FR_isShared(itemid[0].value)) {
FR_shareItem(itemid[0].value);
topnode.addClass('brand-shared');
} else {
FR_unshareItem(itemid[0].value);
topnode.removeClass('brand-shared');
}
}
Reader.updateFeedCount([]);
}
function listbrand_clicked(node, e) {
node = $(node);
var brand = $(".fld-brand", node)[0].value;
Reader.buttonClicked(node);
Reader.openBrand(brand);
}
/*
* Dropdown which allows users to change the folders
*/
function change_folders_clicked(node, event) {
node = $(node);
var topnode = node.parents(".tpl-settings-row");
Settings.show_folders_dropdown(topnode);
}
function choose_folder_clicked(node) {
if (node.parents('.button-container').length > 0)
return true;
return false;
}
function subs_rename_clicked(node, event) {
var rform = Settings.show_rename($(node).parents(".tpl-settings-row"));
var pos = $(node).positionedOffset();
rform.css('left', (pos[0]-4) + 'px').
css('top', (pos[1]-4) + 'px').show();
}
function cancel_rename_clicked(node, event) {
$("#hover-form").hide();
}
function save_rename_clicked(node, event) {
$("#hover-form").hide();
node = $(node);
Settings.do_rename(node.siblings("input.fld-feed").getdata(),
node.siblings("input.fld-title").getdata());
}
function subs_remove_feed(node, event) {
var topnode = $(node).parents(".tpl-settings-row");
if (confirm("Are you sure you want to unsubscribe from " +
$(".fld-title", topnode).getdata())) {
Settings.remove_feed(topnode);
}
}
function lv_settings_clicked(node) {
}
function body_clicked(event) {
event = jQuery.event.fix( event || window.event || {} );
if (!choose_folder_clicked($(event.target))) {
Settings.hide_folder_dropdowns();
ReaderViewer.settingsHide();
ReaderViewer.searchFolderHide();
}
}
function make_permalink_item(itemid) {
var args = [Reader.page];
switch (args[0]) {
/* case 'allitems':
case 'starred':
case 'shared':
break;*/
case 'folder':
case 'feed':
case 'tag':
args.push(Reader.page_args[0]);
break;
}
if (itemid)
args.push(itemid);
make_permalink.apply(null, args);
}
function make_permalink() {
var args = [];
$.merge(args, arguments);
var page = args.shift();
Reader.page = page;
Reader.page_args = $.makeArray(args);
args = $.map(args, encodeURIComponent);
args.unshift(page);
$("#permalink").setdata(location.protocol + '//' + location.hostname + (location.port?':':'') + location.port + location.pathname + '?' + args.join('/'));
}
function handle_permalinks(srch) {
var page, args = [];
if (srch && srch.length > 0) {
page = srch.substring(1);;
if (page.match(/^([a-z]+)\/(.*)$/)) {
page = RegExp.$1;
args = $.map(RegExp.$2.split('/'), decodeURIComponent);
}
}
switch (page) {
case 'allitems':
if (args)
ReaderViewer.current_itemid = args[0];
Reader.handleEvent('evAllItems', $("#ol-allitems")[0]);
break;
case 'starred':
if (args)
ReaderViewer.current_itemid = args[0];
listbrand_clicked($("#ol-brandlist//.tpl-brandlist")[0]);
break;
case 'shared':
if (args)
ReaderViewer.current_itemid = args[0];
listbrand_clicked($("#ol-brandlist//.tpl-brandlist")[1]);
break;
case 'trends':
Reader.handleEvent('evTrends', $("#trends-selector")[0]);
break;
case 'browse':
Reader.handleEvent('evBrowse');
if (args.length && args[0] == 'more')
$("#show-more-bundles-link").click();
break;
case 'search':
DOM.quickadd.setdata(args);
DOM.quickadd.enter();
break;
case 'folder':
var folder = args.shift();
if (args)
ReaderViewer.current_itemid = args[0];
Reader.openFolder(folder);
break
case 'feed':
var feed = args.shift();
if (args)
ReaderViewer.current_itemid = args[0];
Reader.openFeed(feed);
break
case 'tag':
var tag = args.shift();
if (args)
ReaderViewer.current_itemid = args[0];
Reader.openTag(tag);
break
case 'settings':
var subpage = args.shift();
switch (subpage) {
case 'labels':
Reader.handleEvent('evSettings');
Reader.handleEvent('evTagTab');
break;
case 'goodies':
Reader.handleEvent('evSettings');
Reader.handleEvent('evGoodiesTab');
break;
case 'prefs':
Reader.handleEvent('evSettings');
Reader.handleEvent('evPrefTab');
break;
case 'imexport':
Reader.handleEvent('evSettings');
Reader.handleEvent('evImexportTab');
break;
default:
case 'subs':
Reader.handleEvent('evSettings');
Reader.handleEvent('evSubTab');
break;
}
break;
}
}
var KeyTable = {};
var table;
/* Global Keys */
table = KeyTable['Global'] = {};
table[with_shift(keycode('n'))] = Reader.navNext;
table[with_shift(keycode('p'))] = Reader.navPrev;
table[with_shift(keycode('x'))] = Reader.navToggleExpand;
table[with_shift(keycode('o'))] = Reader.navOpenSelected;
table[keycode('u')] = Reader.toggleFullScreen;
table[keycode('g')] = function() {gotoMode = true;}
table[with_shift(keycode('g'))] = function() {gotoMode = true;}
/* List View Keys */
table = KeyTable['ListView'] = {};
table[keycode('j')] = ReaderViewer.nextItem;
table[keycode('k')] = ReaderViewer.prevItem;
table[keycode('n')] = function(){
ReaderViewer.nextItem(true);
};
table[keycode('p')] = function() {
ReaderViewer.prevItem(true)
};
table[keycode('o')] = ReaderViewer.toggleItemOpen;
table[KEY_ENTER] = ReaderViewer.toggleItemOpen;
table[keycode('s')] = ReaderViewer.starCurrentItem;
table[with_shift(keycode('s'))] = ReaderViewer.shareCurrentItem;
table[keycode('m')] = ReaderViewer.toggleItemRead;
table[keycode('t')] = ReaderViewer.tagItem;
table[keycode('v')] = ReaderViewer.viewOriginal;
table[with_shift(keycode('a'))] = markall_clicked;
table[keycode('1')] = function() {ReaderViewer.setExpanded(true)};
table[keycode('2')] = function() {ReaderViewer.setExpanded(false)};
table[keycode('r')] = ReaderViewer.refresh;
/* Goto Keys */
table = KeyTable['Goto'] = {};
table[keycode('h')] = function() {$("#ol-home").click()};
table[keycode('a')] = function() {$("#ol-allitems").click()};
table[keycode('s')] = function() {Reader.brandNodes['starred'].click()};
table[with_shift(keycode('s'))] = function() {Reader.brandNodes['shared'].click()};
table[with_shift(keycode('t'))] = function() {$("#trends-selector").click()};
table[keycode('t')] = function() {Reader.openTag(prompt('Tag name:'))}
table[keycode('u')] = Reader.openPromptedFeed;
var ViewXform = {
'SubscriptionView' : 'ListView',
'AllItemsView' : 'ListView',
'BrandView' : 'ListView',
'TagView' : 'ListView'
};
/*
var gShiftDown = false;
function handle_shiftdown(event) {
event = jQuery.event.fix( event || window.event || {} );
if (event.keyCode == KEY_SHIFT) {
gShiftDown = true;
}
}
function handle_shiftup(event) {
event = jQuery.event.fix( event || window.event || {} );
if (event.keyCode == KEY_SHIFT) {
gShiftDown = false;
}
}
*/
var gotoMode = false;
function handle_keycuts(event) {
event = jQuery.event.fix( event || window.event || {} );
var code = event.keyCode;
var mod = MOD_NONE;
if (event.shiftKey)
mod |= MOD_SHIFT;
/*
* We dont use alt and control keys right now
if (event.altKey)
mod |= MOD_ALT;
if (event.ctrlKey)
mod |= MOD_CTRL;
*/
if (mod == MOD_NONE)
mod = '';
else
mod = '_' + mod;
// First look in the global key table
var table, fn;
if (gotoMode) {
table = KeyTable['Goto'];
gotoMode = false;
fn = table[code + mod];
if (fn)
return fn();
}
table = KeyTable['Global'];
fn = table[code + mod];
if (fn)
return fn();
// If not found, look in state specific key table
if (Reader.state == 'List') { // List
var viewtype = ViewXform[ReaderViewer.viewtype] || ReaderViewer.viewtype;
table = KeyTable[viewtype];
if (table) {
fn = table[code + mod];
}
if (fn)
fn();
else {
// alert(code);
}
} else { // Settings
}
}
// App Initialization
google.load("feeds", "1");
google.setOnLoadCallback(function() {reader_main();});
yocto-reader/reader/common.js 0000644 0000041 0000000 00000015462 10735421005 016023 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
/*--------------------------------------------------------------------------
* Basic JavaScript extensions
* for common array constructs.
*
* Author: Chandan Kudige (2007)
/*--------------------------------------------------------------------------*/
var KEY_ENTER= 13;
var KEY_ESC = 27;
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT= 39;
var KEY_DOWN = 40;
var KEY_F1 = 112;
var KEY_PLUS = 43;
var KEY_MINUS= 45;
var KEY_DELETE = 46;
var KEY_BACKSPACE = 8;
var KEY_TAB = 9;
var KEY_DOT = 46;
var KEY_A = 65;
var KEY_0 = 48;
var KEY_SHIFT = 16;
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
Function.prototype.bind = function() {
var __method = this, args = $.clone(arguments), object = args.shift();
return function() {
return __method.apply(object, args.concat($.clone(arguments)));
}
}
jQuery.fn.extend({
enter: function(fn){
if (!fn) {
return this[0].onkeypress({type: 'keypress',
target: node[0], keyCode: KEY_ENTER});
}
this.keypress(function(event) {
event = jQuery.event.fix( event || window.event || {} );
var code = event.keyCode? event.keyCode : event.charCode;
if (code == KEY_ENTER) {
event.preventDefault();
event.stopPropagation();
fn(event);
return false;
}
return true;
});
return this;
},
positionedOffset: function() {
var element = this[0];
var valueT = 0, valueL = 0;
do {
valueT += element.offsetTop || 0;
valueL += element.offsetLeft || 0;
element = element.offsetParent;
if (element) {
if(element.tagName=='BODY') break;
var p = this.css('position');
if (p == 'relative' || p == 'absolute') break;
}
} while (element);
return [valueL, valueT];
},
datafield: function() {
var anchor = this[0];
switch (anchor.nodeName) {
case 'INPUT':
case 'input':
return 'value';
case 'a':
case 'A':
return 'href';
/* // We dont use this
case 'IMG':
return 'src';
*/
default:
return 'innerHTML';
}
},
getdata: function() {
return this[0][this.datafield()];
},
setdata: function(value) {
var node = this;
try {
node.each(function() {this[$(this).datafield()] = value});
} catch(e) {
}
return this; // chain
},
clear: function() {
var node = this;
node.each(function() {$(this).setdata('');});
return node;
},
maketab: function(header_expr, content_expr) {
var node = this;
$('.'+content_expr, node).hide();
var hdrs = $('.'+header_expr, this);
hdrs.click(function(event) {
event = jQuery.event.fix( event || window.event || {} );
$('.'+content_expr, node).hide();
$('.'+header_expr, node).removeClass(header_expr + "-selected");
var hdr = $(event.target);
if ($(event.target).is('.'+header_expr))
hdr = $(event.target);
else
hdr = $(event.target).parents('.'+header_expr);
$("#" + hdr.addClass(header_expr + "-selected").
attr('id') + '-contents').show();
});
$(hdrs[0]).click();
},
addnodes: function(node) {
var arr = [];
this.each(function() {arr.push(this);});
node.each(function() {arr.push(this);});
return $(arr);
}
});
jQuery.extend({
uniq: function(first) {
var second = [];
jQuery.each(first, function(i,v) {
jQuery.merge(second, [v]);
});
return second;
},
keys: function(object) {
var keys = [];
for (var property in object) {
if (object[property] != undefined)
keys.push(property);
}
return keys;
},
values: function(object) {
var values = [];
for (var property in object)
values.push(object[property]);
return values;
},
indexOf: function(obj, value) {
try {
for ( var i = 0, ol = obj.length; i < ol; i++ )
if (obj[i] == value) return i;
} catch(e) {
}
return -1;
},
clone: function(iterable) {
if (!iterable) return [];
var results = [];
for (var i = 0; i < iterable.length; i++)
results.push(iterable[i]);
return results;
}
});
function get_scaling(arr) {
var max = -1;
$.each(arr, function(i, val) {
if (max < val)
max = val;
});
return {scalemax: max,
scale2: parseInt(2*max/3),
scale1: parseInt(1*max/3),
scale0: 0};
}
function currentTime() {
var d = new Date();
return d.getTime();
}
function timeExpired(timestamp, interval) {
return currentTime() - timestamp > interval;
}
Array.prototype.toArray = Array.prototype.clone;
var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead');
function keycode(letter) {
if (letter.match(/[a-zA-Z]/)) {
return KEY_A + (letter.charCodeAt(0) - 'a'.charCodeAt(0));
}
if (letter.match(/[0-9]/)) {
return KEY_0 + (letter.charCodeAt(0) - '0'.charCodeAt(0));
}
}
function with_shift(str) {
return str + '_' + MOD_SHIFT;
}
const MOD_NONE = 0;
const MOD_SHIFT = 1;
const MOD_ALT = 2;
const MOD_CTRL = 4;
yocto-reader/tests/ 0000755 0000041 0000000 00000000000 10735421013 014064 5 ustar www-data root yocto-reader/tests/testcases_common.js 0000644 0000041 0000000 00000013645 10735421012 020000 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
function testBasics() {
var Myclass = Class.create();
Myclass.prototype.initialize = function(arg1, arg2) {
testflags["0.0"] = [arg1, arg2].join(',');
}
Myclass.prototype.test1 = function(arg1, arg2) {
testflags["0.1"] = [this.id, arg1, arg2].join(',');
}
var Myvar = new Myclass('a','b');
assertEquals("0.0", "a,b", testflags["0.0"]);
Myvar.id = "testid";
var fn = Myvar.test1.bind(Myvar, "testarg1");
fn("testarg2");
assertEquals("0.1", "testid,testarg1,testarg2", testflags["0.1"]);
}
function testDomExt() {
var node = $("#c-test1//input");
node.enter(function() {
testflags["1.0.1"] = true;
});
node[0].onkeypress({type: 'keypress', target: node[0], keyCode: KEY_ESC});
assertEquals("1.0.0", undefined, testflags['1.0.1']);
node[0].onkeypress({type: 'keypress', target: node[0], keyCode: KEY_ENTER});
assertEquals("1.0.1", true, testflags['1.0.1']);
var node1 = $("#c-test2//.top");
var node2 = $("#c-test2//.bottom");
var node3 = $("#c-test2//.abs1");
var pos1 = node1.positionedOffset();
var pos2 = node2.positionedOffset();
var pos3 = node3.positionedOffset();
assert("1.1.0", pos2[1] > pos1[1]);
assert("1.1.1", pos2[0] == pos1[0]);
assertEquals("1.1.2", 100, pos3[1]);
assertEquals("1.1.3", 250, pos3[0]);
var input = $("#c-test3//input");
var anchor = $("#c-test3//a");
var img = $("#c-test3//img");
var span = $("#c-test3//span");
// test get data
assertEquals("1.2.1", 'abcd', input.getdata());
assertEquals("1.2.2", 'http://www.example.com/', anchor.getdata());
assertEquals("1.2.3", 'http://www.example.com/image.gif', img.getdata());
assertEquals("1.2.4", 'span test string', span.getdata());
// test set data
var str = "http://www.example.com/test";
input.setdata(str);
anchor.setdata(str);
img.setdata(str);
span.setdata(str);
assertEquals("1.3.1", str, input[0].value);
assertEquals("1.3.2", str, anchor[0].href);
assertEquals("1.3.3", str, img[0].src);
assertEquals("1.3.4", str, span[0].innerHTML);
input.clear();
anchor.clear();
img.clear();
span.clear();
assertEquals("1.4.1", '', input[0].value);
//these two are urls and when empty, the DOM returns the
// path of the script.
// assertEquals("1.4.2", '', anchor[0].href);
// assertEquals("1.4.3", '', img[0].src);
assertEquals("1.4.4", '', span[0].innerHTML);
// Simple Tab functions
node = $("#c-test4");
node.maketab('tab-header', 'tab-contents');
assertEquals("1.5.0", "none", $(".tab-contents",node).css('display'));
$("#tab1", node).click();
assertEquals("1.5.1", "block", $("#tab1-contents",node).css('display'));
assert("1.5.2", $("#tab1", node).is('.tab-header-selected'));
$("#tab2", node)[0].onclick({type: 'click', target: $("#tab2/a")[0]});
assertEquals("1.5.3", "none", $("#tab1-contents",node).css('display'));
assert("1.5.4", !$("#tab1", node).is('.tab-header-selected'));
assertEquals("1.5.5", "block", $("#tab2-contents",node).css('display'));
assert("1.5.6", $("#tab2", node).is('.tab-header-selected'));
// addnodes()
var n1 = $(".node1,.node2", $("#c-test5"));
var n2 = $(".node3,.node4,.node5", $("#c-test5"));
var n3 = n1.addnodes(n2);
assertEquals("1.6.1", 2, n1.length);
assertEquals("1.6.2", 3, n2.length);
assertEquals("1.6.3", 5, n3.length);
assert("1.6.4", n3.is(".node1"));
assert("1.6.5", n3.is(".node2"));
assert("1.6.6", n3.is(".node3"));
assert("1.6.7", n3.is(".node4"));
assert("1.6.8", n3.is(".node5"));
}
function testUtils() {
// uniq()
var arr1 = [1,2,4,2,3,1,6];
var arr2 = $.uniq(arr1);
assertEquals("2.0", 5, arr2.length);
assert("2.1.1", $.indexOf(arr2, 1) >= 0);
assert("2.1.2", $.indexOf(arr2, 2) >= 0);
assert("2.1.3", $.indexOf(arr2, 3) >= 0);
assert("2.1.4", $.indexOf(arr2, 4) >= 0);
assert("2.1.5", $.indexOf(arr2, 5) < 0);
assert("2.1.6", $.indexOf(arr2, 6) >= 0);
// keys
var obj = {key1: 'val1', key2: 'val2', key3: 'val3'};
var keys = $.keys(obj);
assertEquals("2.2.1", "key1,key2,key3", keys.join(','));
var vals = $.values(obj);
assertEquals("2.2.2", "val1,val2,val3", vals.join(','));
var arr3 = $.clone(arr1);
assertEquals("2.2.3", '1,2,4,2,3,1,6', arr3.join(','));
// get_scaling
var scale = get_scaling([1,2,3,4,5,6,7,8,9,10]);
assertEquals("2.3.1", 10, scale.scalemax);
assertEquals("2.3.2", 6, scale.scale2);
assertEquals("2.3.3", 3, scale.scale1);
assertEquals("2.3.4", 0, scale.scale0);
// current time test - pretty lame
var t1 = currentTime();
var t2 = currentTime();
assert("2.4.0", t2 >= t1);
// time expired
var t3 = t1 - 10000;
assert("2.4.1", timeExpired(t3, 9000));
assert("2.4.2", !timeExpired(t3, 20000));
}
testlist.push('testBasics');
testlist.push('testDomExt');
testlist.push('testUtils');
yocto-reader/tests/tlib.js 0000644 0000041 0000000 00000006774 10735421013 015372 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
var testlist = {};
var testflags = {};
var TEST_FEED1 = 'http://kudang.com/myfeed1.xml';
var TEST_FEED2 = 'http://kudang.com/myfeed2.xml';
var TEST_FEED3 = 'http://rss.cnn.com/rss/cnn_topstories.rss';
var TEST_TITLE3 = 'CNN.com';
var TEST_FEED4 = 'http://technosophyunlimited.blogspot.com/atom.xml';
var TEST_FEED5 = 'http://www.theonion.com/content/feeds/daily';
var TEST_FOLDER1 = 'some';
var TEST_FOLDER2 = 'folder';
var TEST_FOLDER3 = 'news';
var TEST_FOLDER4 = 'technology';
var TEST_TAG1 = 'testtag1';
var TEST_TAG2 = 'testtag2';
var obj1 = {'url1':"http://www.example.com/",
'url2':"http://www.example.com/image.gif",
'field1': "string1",
'field2':"string2",
'field3':"string3"};
var obj2 = {'icon' : 'test.gif'};
var arr1 = [{'field1' : 'string1',
'field2' : 'string2'},
{'field1' : 'newstring1',
'field2' : 'newstring2'}];
var feed1 = {'attr1' : 'text1',
'url' : 'http://www.example.com/image.gif',
'array1': [
{'name1' : 'test1.1',
'name2' : 'test string 1.2'},
{'name1' : 'test2.1',
'name2' : 'test string 2.2'}],
'array2': [
{'name3' : 'obj1.1',
'name4' : 'obj string 1.2'},
{'name3' : 'obj2.1',
'name4' : 'obj string 2.2'},
{'name3' : 'obj3.1',
'name4' : 'test string 3.2'}]
};
var obj3 = {'field1' : 'apple',
'field2' : 'orange',
'field3' : 'peach'};
var obj4 = {'attr1' : 'existing'};
function testflag_incr(flagname) {
if (!testflags[flagname])
testflags[flagname] = 0;
testflags[flagname]++;
}
function testflag_resetall(flagname) {
testflags = {};
}
function testflag_set(flagname) {
testflags[flagname] = true;
}
function assertFlag(casenum, flag) {
assertEquals(casenum, true, testflags[flag]);
}
function assertNoflag(casenum, flag) {
assertEquals(casenum, undefined, testflags[flag]);
}
var testevents = {};
var dbg = true;
// Get the state machine to log events
StateMachine.prototype.logEvent = function(evt, elem, data) {
testevents[evt] = {fsm: this.table._name, data: data, elem: elem};
}
// Clear event log
function clearEventLog() {
testevents = {};
}
function assertEvent(testcase, evt) {
assert(testcase + ': [' + evt + ']', testevents[evt] != undefined);
}
function assertNoevent(testcase, evt) {
assert(testcase + ': [!' + evt + ']', testevents[evt] == undefined);
}
yocto-reader/tests/tlibui.js 0000644 0000041 0000000 00000006361 10735421013 015720 0 ustar www-data root /*
* yocto-reader - A light-weight RSS reader aggregator prototype, version 0.2
* (http://yocto-reader.flouzo.net/)
*
* Copyright (C) 2007 Loic Dachary (loic@dachary.org)
* Copyright (C) 2007 Chandan Kudige (chandan@nospam.kudige.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
var testlist = [];
var TestQueue;
var TestPaused = false;
var ConfirmYes = true;
var PromptResponse = 'default';
function initTests() {
document.f1.tgroups.value = "";
startTests();
}
function startTests() {
doTest($.clone(testlist));
}
function TestPause() {
TestPaused = true;
}
function TestResume() {
TestPaused = false;
var mylist = TestQueue;
TestQueue = null;
setTimeout(function(){doTest(mylist);}, 10);
}
// Make sure Wait is the last call in the calling function
function Wait(msecs) {
TestPause();
setTimeout(function(){TestResume();}, msecs);
}
function SetConfirm(bool) {
ConfirmYes = bool;
}
function SetPromptResponse(str) {
PromptResponse = str;
}
function confirm(str) {
AddStatus(" confirm('" + str + "') -> " + ConfirmYes);
return ConfirmYes;
}
function alert(str) {
AddStatus(" alert('" + str + "')");
}
function prompt(str) {
AddStatus(" prompt('" + str + "') -> " + PromptResponse);
return PromptResponse;
}
function doTest(mylist) {
if (TestPaused) {
TestQueue = mylist;
return;
}
var status = document.getElementById('tStatus');
var x = mylist.shift();
if (typeof(window[x]) == 'function') {
try {
window[x]();
AddStatus(x + " OK");
} catch(jse) {
if (jse.isJsUnitException) {
AddStatus(x + " failed ***");
AddStatus(' ' + jse.comment + ': ' + jse.jsUnitMessage + "\n");
} else {
jsUnitAllCases++;
AddStatus(x + " (JS error) ***");
AddStatus(' Error: ' + jse.message?jse.message:jse + "\n");
AddStatus(jse.stack);
}
}
}
status.innerHTML = "Finished: " + x + " Passed:" +
jsUnitPassedCases+'/' + jsUnitAllCases;
if (mylist.length > 0) {
setTimeout(doTest.bind(null, mylist), 200);
} else {
status.innerHTML = "All Done " + " Passed:" +
jsUnitPassedCases+'/' + jsUnitAllCases;
AddStatus("\n\nAll Testcases Completed\n");
}
}
function AddStatus(str) {
document.f1.tgroups.value += "\n" + str;
}
google.setOnLoadCallback = function(fn) {
}
window.uitest = true;
$(window).load(startTests);
yocto-reader/tests/start_uitest.html 0000644 0000041 0000000 00000007205 10735421011 017506 0 ustar www-data root
JSCoverage
JSCoverage (working ...)
File
Statements
Executed
Coverage
Missing
This is version 0.2 of JSCoverage, a program that calculates code
coverage statistics for JavaScript.
See http://siliconforks.com/jscoverage/ for more information.
Copyright © 2007 siliconforks.com
yocto-reader/tests/jsUnitCore.js 0000644 0000041 0000000 00000043701 10735421011 016512 0 ustar www-data root var JSUNIT_UNDEFINED_VALUE;
var JSUNIT_VERSION = 2.2;
var isTestPageLoaded = false;
var jsUnitErrorCases = 0;
var jsUnitPassedCases = 0;
var jsUnitAllCases = 0;
//hack for NS62 bug
function jsUnitFixTop() {
var tempTop = top;
if (!tempTop) {
tempTop = window;
while (tempTop.parent) {
tempTop = tempTop.parent;
if (tempTop.top && tempTop.top.jsUnitTestSuite) {
tempTop = tempTop.top;
break;
}
}
}
try {
window.top = tempTop;
} catch (e) {
}
}
jsUnitFixTop();
/**
+ * A more functional typeof
+ * @param Object o
+ * @return String
+ */
function _trueTypeOf(something) {
var result = typeof something;
try {
switch (result) {
case 'string':
case 'boolean':
case 'number':
break;
case 'object':
case 'function':
switch (something.constructor)
{
case String:
result = 'String';
break;
case Boolean:
result = 'Boolean';
break;
case Number:
result = 'Number';
break;
case Array:
result = 'Array';
break;
case RegExp:
result = 'RegExp';
break;
case Function:
result = 'Function';
break;
default:
var m = something.constructor.toString().match(/function\s*([^( ]+)\(/);
if (m)
result = m[1];
else
break;
}
break;
}
}
finally {
result = result.substr(0, 1).toUpperCase() + result.substr(1);
return result;
}
}
function _displayStringForValue(aVar) {
var result = '<' + aVar + '>';
if (!(aVar === null || aVar === top.JSUNIT_UNDEFINED_VALUE)) {
result += ' (' + _trueTypeOf(aVar) + ')';
}
return result;
}
function fail(failureMessage) {
throw new JsUnitException("Call to fail()", failureMessage);
}
function error(errorMessage) {
var errorObject = new Object();
errorObject.description = errorMessage;
errorObject.stackTrace = getStackTrace();
throw errorObject;
}
function argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) {
return args.length == expectedNumberOfNonCommentArgs + 1;
}
function commentArg(expectedNumberOfNonCommentArgs, args) {
if (argumentsIncludeComments(expectedNumberOfNonCommentArgs, args))
return 'Test Case '+args[0];
return null;
}
function nonCommentArg(desiredNonCommentArgIndex, expectedNumberOfNonCommentArgs, args) {
return argumentsIncludeComments(expectedNumberOfNonCommentArgs, args) ?
args[desiredNonCommentArgIndex] :
args[desiredNonCommentArgIndex - 1];
}
function _validateArguments(expectedNumberOfNonCommentArgs, args) {
if (!( args.length == expectedNumberOfNonCommentArgs ||
(args.length == expectedNumberOfNonCommentArgs + 1 && typeof(args[0]) == 'string') ))
error('Incorrect arguments passed to assert function');
}
function _assert(comment, booleanValue, failureMessage) {
jsUnitAllCases++;
if (!booleanValue) {
jsUnitErrorCases++;
throw new JsUnitException(comment, failureMessage);
}
jsUnitPassedCases++;
}
function assert() {
_validateArguments(1, arguments);
var booleanValue = nonCommentArg(1, 1, arguments);
if (typeof(booleanValue) != 'boolean')
error('Bad argument to assert(boolean)');
_assert(commentArg(1, arguments), booleanValue === true, 'Call to assert(boolean) with false');
}
function assertTrue() {
_validateArguments(1, arguments);
var booleanValue = nonCommentArg(1, 1, arguments);
if (typeof(booleanValue) != 'boolean')
error('Bad argument to assertTrue(boolean)');
_assert(commentArg(1, arguments), booleanValue === true, 'Call to assertTrue(boolean) with false');
}
function assertFalse() {
_validateArguments(1, arguments);
var booleanValue = nonCommentArg(1, 1, arguments);
if (typeof(booleanValue) != 'boolean')
error('Bad argument to assertFalse(boolean)');
_assert(commentArg(1, arguments), booleanValue === false, 'Call to assertFalse(boolean) with true');
}
function assertEquals() {
_validateArguments(2, arguments);
var var1 = nonCommentArg(1, 2, arguments);
var var2 = nonCommentArg(2, 2, arguments);
_assert(commentArg(2, arguments), var1 === var2, 'Expected ' + _displayStringForValue(var1) + ' but was ' + _displayStringForValue(var2));
}
function assertNotEquals() {
_validateArguments(2, arguments);
var var1 = nonCommentArg(1, 2, arguments);
var var2 = nonCommentArg(2, 2, arguments);
_assert(commentArg(2, arguments), var1 !== var2, 'Expected not to be ' + _displayStringForValue(var2));
}
function assertNull() {
_validateArguments(1, arguments);
var aVar = nonCommentArg(1, 1, arguments);
_assert(commentArg(1, arguments), aVar === null, 'Expected ' + _displayStringForValue(null) + ' but was ' + _displayStringForValue(aVar));
}
function assertNotNull() {
_validateArguments(1, arguments);
var aVar = nonCommentArg(1, 1, arguments);
_assert(commentArg(1, arguments), aVar !== null, 'Expected not to be ' + _displayStringForValue(null));
}
function assertUndefined() {
_validateArguments(1, arguments);
var aVar = nonCommentArg(1, 1, arguments);
_assert(commentArg(1, arguments), aVar === top.JSUNIT_UNDEFINED_VALUE, 'Expected ' + _displayStringForValue(top.JSUNIT_UNDEFINED_VALUE) + ' but was ' + _displayStringForValue(aVar));
}
function assertNotUndefined() {
_validateArguments(1, arguments);
var aVar = nonCommentArg(1, 1, arguments);
_assert(commentArg(1, arguments), aVar !== top.JSUNIT_UNDEFINED_VALUE, 'Expected not to be ' + _displayStringForValue(top.JSUNIT_UNDEFINED_VALUE));
}
function assertNaN() {
_validateArguments(1, arguments);
var aVar = nonCommentArg(1, 1, arguments);
_assert(commentArg(1, arguments), isNaN(aVar), 'Expected NaN');
}
function assertNotNaN() {
_validateArguments(1, arguments);
var aVar = nonCommentArg(1, 1, arguments);
_assert(commentArg(1, arguments), !isNaN(aVar), 'Expected not NaN');
}
function assertObjectEquals() {
_validateArguments(2, arguments);
var var1 = nonCommentArg(1, 2, arguments);
var var2 = nonCommentArg(2, 2, arguments);
var type;
var msg = commentArg(2, arguments)?commentArg(2, arguments):'';
var isSame = (var1 === var2);
//shortpath for references to same object
var isEqual = ( (type = _trueTypeOf(var1)) == _trueTypeOf(var2) );
if (isEqual && !isSame) {
switch (type) {
case 'String':
case 'Number':
isEqual = (var1 == var2);
break;
case 'Boolean':
case 'Date':
isEqual = (var1 === var2);
break;
case 'RegExp':
case 'Function':
isEqual = (var1.toString() === var2.toString());
break;
default: //Object | Array
var i;
if (isEqual = (var1.length === var2.length))
for (i in var1)
assertObjectEquals(msg + ' found nested ' + type + '@' + i + '\n', var1[i], var2[i]);
}
_assert(msg, isEqual, 'Expected ' + _displayStringForValue(var1) + ' but was ' + _displayStringForValue(var2));
}
}
assertArrayEquals = assertObjectEquals;
function assertEvaluatesToTrue() {
_validateArguments(1, arguments);
var value = nonCommentArg(1, 1, arguments);
if (!value)
fail(commentArg(1, arguments));
}
function assertEvaluatesToFalse() {
_validateArguments(1, arguments);
var value = nonCommentArg(1, 1, arguments);
if (value)
fail(commentArg(1, arguments));
}
function assertHTMLEquals() {
_validateArguments(2, arguments);
var var1 = nonCommentArg(1, 2, arguments);
var var2 = nonCommentArg(2, 2, arguments);
var var1Standardized = standardizeHTML(var1);
var var2Standardized = standardizeHTML(var2);
_assert(commentArg(2, arguments), var1Standardized === var2Standardized, 'Expected ' + _displayStringForValue(var1Standardized) + ' but was ' + _displayStringForValue(var2Standardized));
}
function assertHashEquals() {
_validateArguments(2, arguments);
var var1 = nonCommentArg(1, 2, arguments);
var var2 = nonCommentArg(2, 2, arguments);
for (var key in var1) {
assertNotUndefined("Expected hash had key " + key + " that was not found", var2[key]);
assertEquals(
"Value for key " + key + " mismatch - expected = " + var1[key] + ", actual = " + var2[key],
var1[key], var2[key]
);
}
for (var key in var2) {
assertNotUndefined("Actual hash had key " + key + " that was not expected", var1[key]);
}
}
function assertRoughlyEquals() {
_validateArguments(3, arguments);
var expected = nonCommentArg(1, 3, arguments);
var actual = nonCommentArg(2, 3, arguments);
var tolerance = nonCommentArg(3, 3, arguments);
assertTrue(
"Expected " + expected + ", but got " + actual + " which was more than " + tolerance + " away",
Math.abs(expected - actual) < tolerance
);
}
function assertContains() {
_validateArguments(2, arguments);
var contained = nonCommentArg(1, 2, arguments);
var container = nonCommentArg(2, 2, arguments);
assertTrue(
"Expected '" + container + "' to contain '" + contained + "'",
container.indexOf(contained) != -1
);
}
function standardizeHTML(html) {
var translator = document.createElement("DIV");
translator.innerHTML = html;
return translator.innerHTML;
}
function isLoaded() {
return isTestPageLoaded;
}
function setUp() {
}
function tearDown() {
}
function getFunctionName(aFunction) {
var regexpResult = aFunction.toString().match(/function(\s*)(\w*)/);
if (regexpResult && regexpResult.length >= 2 && regexpResult[2]) {
return regexpResult[2];
}
return 'anonymous';
}
function getStackTrace() {
var result = '';
if (typeof(arguments.caller) != 'undefined') { // IE, not ECMA
for (var a = arguments.caller; a != null; a = a.caller) {
result += '> ' + getFunctionName(a.callee) + '\n';
if (a.caller == a) {
result += '*';
break;
}
}
}
else { // Mozilla, not ECMA
// fake an exception so we can get Mozilla's error stack
var testExcp;
try
{
foo.bar;
}
catch(testExcp)
{
var stack = parseErrorStack(testExcp);
for (var i = 1; i < stack.length; i++)
{
result += '> ' + stack[i] + '\n';
}
}
}
return result;
}
function parseErrorStack(excp)
{
var stack = [];
var name;
if (!excp || !excp.stack)
{
return stack;
}
var stacklist = excp.stack.split('\n');
for (var i = 0; i < stacklist.length - 1; i++)
{
var framedata = stacklist[i];
name = framedata.match(/^(\w*)/)[1];
if (!name) {
name = 'anonymous';
}
stack[stack.length] = name;
}
// remove top level anonymous functions to match IE
while (stack.length && stack[stack.length - 1] == 'anonymous')
{
stack.length = stack.length - 1;
}
return stack;
}
function JsUnitException(comment, message) {
this.isJsUnitException = true;
this.comment = comment;
this.jsUnitMessage = message;
this.stackTrace = getStackTrace();
}
function warn() {
if (top.tracer != null)
top.tracer.warn(arguments[0], arguments[1]);
}
function inform() {
if (top.tracer != null)
top.tracer.inform(arguments[0], arguments[1]);
}
function info() {
inform(arguments[0], arguments[1]);
}
function debug() {
if (top.tracer != null)
top.tracer.debug(arguments[0], arguments[1]);
}
function setJsUnitTracer(aJsUnitTracer) {
top.tracer = aJsUnitTracer;
}
function trim(str) {
if (str == null)
return null;
var startingIndex = 0;
var endingIndex = str.length - 1;
while (str.substring(startingIndex, startingIndex + 1) == ' ')
startingIndex++;
while (str.substring(endingIndex, endingIndex + 1) == ' ')
endingIndex--;
if (endingIndex < startingIndex)
return '';
return str.substring(startingIndex, endingIndex + 1);
}
function isBlank(str) {
return trim(str) == '';
}
// the functions push(anArray, anObject) and pop(anArray)
// exist because the JavaScript Array.push(anObject) and Array.pop()
// functions are not available in IE 5.0
function push(anArray, anObject) {
anArray[anArray.length] = anObject;
}
function pop(anArray) {
if (anArray.length >= 1) {
delete anArray[anArray.length - 1];
anArray.length--;
}
}
function jsUnitGetParm(name)
{
if (typeof(top.jsUnitParmHash[name]) != 'undefined')
{
return top.jsUnitParmHash[name];
}
return null;
}
if (top && typeof(top.xbDEBUG) != 'undefined' && top.xbDEBUG.on && top.testManager)
{
top.xbDebugTraceObject('top.testManager.containerTestFrame', 'JSUnitException');
// asserts
top.xbDebugTraceFunction('top.testManager.containerTestFrame', '_displayStringForValue');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'error');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'argumentsIncludeComments');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'commentArg');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'nonCommentArg');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', '_validateArguments');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', '_assert');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assert');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertTrue');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertEquals');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotEquals');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNull');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotNull');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertUndefined');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotUndefined');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNaN');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'assertNotNaN');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'isLoaded');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'setUp');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'tearDown');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'getFunctionName');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'getStackTrace');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'warn');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'inform');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'debug');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'setJsUnitTracer');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'trim');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'isBlank');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'newOnLoadEvent');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'push');
top.xbDebugTraceFunction('top.testManager.containerTestFrame', 'pop');
}
function newOnLoadEvent() {
isTestPageLoaded = true;
}
function jsUnitSetOnLoad(windowRef, onloadHandler)
{
var isKonqueror = navigator.userAgent.indexOf('Konqueror/') != -1 ||
navigator.userAgent.indexOf('Safari/') != -1;
if (typeof(windowRef.attachEvent) != 'undefined') {
// Internet Explorer, Opera
windowRef.attachEvent("onload", onloadHandler);
} else if (typeof(windowRef.addEventListener) != 'undefined' && !isKonqueror) {
// Mozilla, Konqueror
// exclude Konqueror due to load issues
windowRef.addEventListener("load", onloadHandler, false);
} else if (typeof(windowRef.document.addEventListener) != 'undefined' && !isKonqueror) {
// DOM 2 Events
// exclude Mozilla, Konqueror due to load issues
windowRef.document.addEventListener("load", onloadHandler, false);
} else if (typeof(windowRef.onload) != 'undefined' && windowRef.onload) {
windowRef.jsunit_original_onload = windowRef.onload;
windowRef.onload = function() {
windowRef.jsunit_original_onload();
onloadHandler();
};
} else {
// browsers that do not support windowRef.attachEvent or
// windowRef.addEventListener will override a page's own onload event
windowRef.onload = onloadHandler;
}
}
jsUnitSetOnLoad(window, newOnLoadEvent);
yocto-reader/tests/jscoverage.js 0000644 0000041 0000000 00000032150 10735421011 016551 0 ustar www-data root /*
jscoverage.js - code coverage for JavaScript
Copyright (C) 2007 siliconforks.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
if (!('_$jscoverage' in window)) {
window._$jscoverage = {};
}
var gCurrentFile = null;
var gCurrentLine = null;
var gCurrentSource = null;
var gCurrentLines = null;
// http://www.quirksmode.org/js/findpos.html
function findPos(obj) {
var result = 0;
do {
result += obj.offsetTop;
obj = obj.offsetParent;
}
while (obj);
return result;
}
// http://www.quirksmode.org/viewport/compatibility.html
function getViewportHeight() {
if (self.innerHeight) {
// all except Explorer
return self.innerHeight;
}
else if (document.documentElement && document.documentElement.clientHeight) {
// Explorer 6 Strict Mode
return document.documentElement.clientHeight;
}
else if (document.body) {
// other Explorers
return document.body.clientHeight;
}
else {
throw "Couldn't calculate viewport height";
}
}
function lengthyOperation(f) {
var body = document.getElementsByTagName('body').item(0);
body.className = 'busy';
setTimeout(function() {
try {
f();
}
finally {
body.className = '';
body = null;
}
}, 0);
}
function setSize() {
var viewportHeight = getViewportHeight();
/*
padding-top: 10px
border-top-width: 1px
border-bottom-width: 1px
padding-bottom: 10px
margin-bottom: 10px
----
32px
*/
var tabPages = document.getElementById('tabPages');
var tabPagesHeight = (viewportHeight - findPos(tabPages) - 32) + 'px';
tabPages.style.height = tabPagesHeight;
var browserIframe = document.getElementById('browserIframe');
browserIframe.height = viewportHeight - findPos(browserIframe) - 23;
var coverageSummaryDiv = document.getElementById('summaryDiv');
coverageSummaryDiv.style.height = tabPagesHeight;
var sourceDiv = document.getElementById('sourceDiv');
var sourceDivHeight = (viewportHeight - findPos(sourceDiv) - 23) + 'px';
sourceDiv.style.height = sourceDivHeight;
}
function body_load() {
initTabControl();
setSize();
// check if a URL was passed in the query string
if (location.search.length > 0) {
var url = location.search.substring(1);
// this will automatically propagate to the input field
frames[0].location = url;
} else if (test_url) {
frames[0].location = test_url;
}
}
function body_resize() {
setSize();
}
/*******************************************************************************
tab 1
*/
function updateBrowser() {
var input = document.getElementById("location");
frames[0].location = input.value;
}
function updateInput() {
var input = document.getElementById("location");
input.value = frames[0].location;
}
function input_keypress(e) {
if (e.keyCode === 13) {
updateBrowser();
}
}
function button_click() {
updateBrowser();
}
function browser_load() {
updateInput();
}
/*******************************************************************************
tab 2
*/
function createLink(file, line) {
var link = document.createElement("a");
var url;
var call;
var text;
if (line) {
url = file + ".jscoverage.html?" + line;
call = "get('" + file + "', " + line + ");";
text = line.toString();
}
else {
url = file + ".jscoverage.html";
call = "get('" + file + "');";
text = file;
}
link.setAttribute('href', 'javascript:' + call);
link.appendChild(document.createTextNode(text));
return link;
}
function recalculateSummaryTab(cc) {
if (! cc) {
cc = window._$jscoverage;
}
if (! cc) {
throw "No coverage information found.";
}
var tbody = document.getElementById("summaryTbody");
while (tbody.hasChildNodes()) {
tbody.removeChild(tbody.firstChild);
}
for (var file in cc) {
var i;
var num_statements = 0;
var num_executed = 0;
var missing = [];
var length = cc[file].length;
for (i = 0; i < length; i++) {
if (cc[file][i] === undefined) {
continue;
}
else if (cc[file][i] === 0) {
missing.push(i);
}
else {
num_executed++;
}
num_statements++;
}
var percentage = parseInt(100 * num_executed / num_statements);
var row = document.createElement("tr");
var cell = document.createElement("td");
var link = createLink(file);
cell.appendChild(link);
row.appendChild(cell);
cell = document.createElement("td");
cell.className = 'numeric';
cell.appendChild(document.createTextNode(num_statements));
row.appendChild(cell);
cell = document.createElement("td");
cell.className = 'numeric';
cell.appendChild(document.createTextNode(num_executed));
row.appendChild(cell);
cell = document.createElement("td");
cell.className = 'numeric';
cell.appendChild(document.createTextNode(percentage + '%'));
row.appendChild(cell);
cell = document.createElement("td");
for (i = 0; i < missing.length; i++) {
if (i !== 0) {
cell.appendChild(document.createTextNode(", "));
}
link = createLink(file, missing[i]);
cell.appendChild(link);
}
row.appendChild(cell);
tbody.appendChild(row);
}
}
/*******************************************************************************
tab 3
*/
function makeTable() {
var rows = [];
var coverage = _$jscoverage[gCurrentFile];
var lines = gCurrentLines;
var i;
for (i = 0; i < lines.length; i++) {
var lineNumber = i + 1;
var row = '';
row += '' + lineNumber + ' ';
if (lineNumber in coverage) {
var timesExecuted = coverage[lineNumber];
if (timesExecuted === 0) {
row += '';
}
else {
row += ' ';
}
row += timesExecuted;
row += ' ';
}
else {
row += ' ';
}
row += '' + lines[i] + ' ';
row += ' ';
row += '\n';
rows[i] = row;
}
var result = rows.join('');
var sourceDiv = document.getElementById('sourceDiv');
while (sourceDiv.hasChildNodes()) {
sourceDiv.removeChild(sourceDiv.firstChild);
}
sourceDiv.innerHTML = '';
}
function highlightSource() {
// set file name
var fileDiv = document.getElementById('fileDiv');
fileDiv.innerHTML = gCurrentFile;
// highlight source and break into lines
var pre = document.createElement('pre');
pre.appendChild(document.createTextNode(gCurrentSource));
sh_highlightElement(document, pre, sh_languages['javascript']);
var source = pre.innerHTML;
var length = source.length;
var endOfLinePattern = /\r\n|\r|\n/g;
endOfLinePattern.lastIndex = 0;
var lines = [];
var i = 0;
while (i < length) {
var start = i;
var end;
var startOfNextLine;
var endOfLineMatch = endOfLinePattern.exec(source);
if (endOfLineMatch === null) {
end = length;
startOfNextLine = length;
}
else {
end = endOfLineMatch.index;
startOfNextLine = endOfLinePattern.lastIndex;
}
var line = source.substring(start, end);
lines.push(line);
i = startOfNextLine;
}
gCurrentLines = lines;
// coverage
recalculateSourceTab();
}
function scrollToLine() {
setSize();
selectTab(2);
if (! window.gCurrentLine) {
return;
}
var div = document.getElementById('sourceDiv');
if (gCurrentLine === 1) {
div.scrollTop = 0;
}
else {
var cell = document.getElementById('line-' + gCurrentLine);
var divOffset = findPos(div);
var cellOffset = findPos(cell);
div.scrollTop = cellOffset - divOffset;
}
gCurrentLine = 0;
}
function setThrobber() {
var throbberImg = document.getElementById('throbberImg');
throbberImg.style.visibility = 'visible';
}
function clearThrobber() {
var throbberImg = document.getElementById('throbberImg');
throbberImg.style.visibility = 'hidden';
}
function httpError(file) {
gCurrentFile = null;
clearThrobber();
var fileDiv = document.getElementById('fileDiv');
fileDiv.innerHTML = '';
var sourceDiv = document.getElementById('sourceDiv');
sourceDiv.innerHTML = "Error retrieving document " + file + ".";
selectTab(2);
}
/**
Loads the given file (and optional line) in the source tab.
*/
function get(file, line) {
if (file === gCurrentFile) {
selectTab(2);
gCurrentLine = line;
lengthyOperation(recalculateSourceTab);
}
else {
if (gCurrentFile === null) {
var tab = document.getElementById('sourceTab');
tab.className = '';
tab.onclick = tab_click;
}
selectTab(2);
setThrobber();
// Note that the IE7 XMLHttpRequest does not support file URL's.
// http://xhab.blogspot.com/2006/11/ie7-support-for-xmlhttprequest.html
// http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx
var request;
if (window.ActiveXObject) {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
else {
request = new XMLHttpRequest();
}
request.open("GET", file + ".jscoverage.js", true);
request.onreadystatechange = function(event) {
if (request.readyState === 4) {
if (request.status === 0 || request.status === 200) {
var response = request.responseText;
// opera returns status zero even if there is a missing file???
if (response === '') {
httpError(file);
}
else {
clearThrobber();
gCurrentFile = file;
gCurrentLine = line || 1;
gCurrentSource = response;
lengthyOperation(highlightSource);
}
}
else {
httpError(file);
}
}
};
if ('onerror' in request) {
request.onerror = function(event) {
httpError(file);
};
}
try {
request.send(null);
}
catch (e) {
httpError(file);
}
}
}
/**
Calculates coverage statistics for the current source file.
*/
function recalculateSourceTab() {
if (! gCurrentFile) {
return;
}
makeTable();
scrollToLine();
}
/*******************************************************************************
tabs
*/
function initTabControl() {
var tabs = document.getElementById('tabs');
var i;
var child;
var tabNum = 0;
for (i = 0; i < tabs.childNodes.length; i++) {
child = tabs.childNodes.item(i);
if (child.nodeType === 1) {
if (child.className !== 'disabled') {
child.onclick = tab_click;
}
tabNum++;
}
}
selectTab(0);
}
function selectTab(tab) {
if (typeof tab !== 'number') {
tab = tabIndexOf(tab);
}
var tabControl = document.getElementById("tabControl");
var tabs = document.getElementById('tabs');
var tabPages = document.getElementById('tabPages');
var i;
var child;
var tabNum = 0;
for (i = 0; i < tabs.childNodes.length; i++) {
child = tabs.childNodes.item(i);
if (child.nodeType === 1) {
if (child.className !== 'disabled') {
child.className = tabNum === tab? 'selected': '';
}
tabNum++;
}
}
tabNum = 0;
for (i = 0; i < tabPages.childNodes.length; i++) {
child = tabPages.childNodes.item(i);
if (child.nodeType === 1) {
child.style.display = tabNum === tab? 'block': 'none';
tabNum++;
}
}
setSize();
}
function tabIndexOf(tab) {
var tabs = document.getElementById('tabs');
var i;
var child;
var tabNum = 0;
for (i = 0; i < tabs.childNodes.length; i++) {
child = tabs.childNodes.item(i);
if (child.nodeType === 1) {
if (child === tab) {
return tabNum;
}
tabNum++;
}
}
throw "Tab not found";
}
function tab_click(e) {
var target;
if (e) {
target = e.target;
}
else if (window.event) {
// IE
target = window.event.srcElement;
}
selectTab(target);
if (target.id === 'summaryTab') {
lengthyOperation(recalculateSummaryTab);
}
else if (target.id === 'sourceTab') {
lengthyOperation(recalculateSourceTab);
}
}
yocto-reader/tests/uitest.patch 0000644 0000041 0000000 00000005742 11123730256 016436 0 ustar www-data root --- feedread.html 2008-12-20 20:34:46.063421900 -0500
+++ uitest.html 2008-12-20 20:41:15.977641845 -0500
@@ -30,28 +30,39 @@
+
+
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
JavaScript must be enabled in order for you to use
Reader. However, it seems JavaScript is either disabled or not
supported by your browser. To use Reader, enable JavaScript by changing
your browser options, then try again .
Yocto Reader
Source Code
|
dummy@example.com
|
Permalink
|
Keyboard Shortcuts
|
Settings
|
My Account
|
Help
|
Sign Out
3 weeks ago
2 weeks ago
1 week ago
Today
Items read, day by day, over the past 30 days
Items read by time of day
Items read by day of the week
null
null
Reading trends
Your item reading trends for the last 30 days
Subscription
# Read
% Read
Show:
top 10
-
top 20
-
top 40
Show:
top 10
-
top 20
-
top 40
Show:
top 10
-
top 20
-
top 40
Show:
top 10
-
top 20
-
top 40
You have not read any items on a mobile device. Visit Yocto Reader on your phone to try it.
Subscription trends
Your subscription trends for the last 30 days
Subscription
Items/Day
% Read
Show:
top 10
-
top 20
-
top 40
Subscription
Last Updated
Show:
top 10
-
top 20
-
top 40
null
null
null
Tags
The more items a tag has, the bigger it appears. The more of those items you have read, the darker it is.
Show:
new items
-
all items
Show:
new items
-
all items
You have subscribed to "All items ."
<< Return to feed discovery
Already using a feed reader?
Import your subscriptions »
Welcome to Yocto Reader!
Browse and discover feeds
Get started quickly with feed bundles
The easiest way to add subscriptions is to subscribe to one of our pre-packaged bundles. They have lots of interesting content in them, and you can always add or remove individual feeds later on.
« Return to feed discovery
Stay close to friends and family!
Do your friends use Blogger, Flickr or MySpace? We've made it easy to keep up with users of these and other social sites.
Search and browse
You can also search for feeds by using keywords:
Still looking? Get started with these category searches:
Recently starred
Recently shared
If you find yourself repeatedly visiting a
website to check for updates, or if you just stumble across a page you
want to keep track of, you can easily subscribe to it in Yocto Reader
using the subscribe bookmark .
To use the subscribe bookmark , simply drag the link below to
your bookmarks bar. Then, when you're on a web page, you can click the
bookmark to view it in Yocto Reader.
Once you see the feed preview, confirm your subscription by clicking the "Subscribe" button within Reader.
Some of our users, like Robert Scoble, can go through 600 feeds in less time
than it takes to say "mark all as read":
(Thanks Tim for this video!)
For those of you who don't have supernatural powers and would like a quick
and easy way to go ...
See more »