/*!
* jQuery Lifestream Plug-in
* @version 0.1.2
* Show a stream of your online activity
*
* Copyright 2011, Christian Vuerings - http://denbuzze.com
*/
/*globals jQuery, $ */
;(function( $ ){
/**
* Create a valid YQL URL by passing in a query
* @param {String} query The query you want to convert into a valid yql url
* @return {String} A valid YQL URL
*/
var createYqlUrl = function( query ) {
return ( "http://query.yahooapis.com/v1/public/yql?q=__QUERY__&env=" +
"store://datatables.org/alltableswithkeys&format=json")
.replace( "__QUERY__" , encodeURIComponent( query ) );
};
/**
* Initialize the lifestream plug-in
* @param {Object} config Configuration object
*/
$.fn.lifestream = function( config ) {
// Make the plug-in chainable
return this.each(function() {
// The element where the lifestream is linked to
var outputElement = $(this),
// Extend the default settings with the values passed
settings = jQuery.extend({
// The name of the main lifestream class
// We use this for the main ul class e.g. lifestream
// and for the specific feeds e.g. lifestream-twitter
classname: "lifestream",
// Callback function which will be triggered when a feed is loaded
feedloaded: null,
// The amount of feed items you want to show
limit: 10,
// An array of feed items which you want to use
list: []
}, config),
// The data object contains all the feed items
data = {
count: settings.list.length,
items: []
},
// We use the item settings to pass the global settings variable to
// every feed
itemsettings = jQuery.extend( true, {}, settings ),
/**
* This method will be called every time a feed is loaded. This means
* that several DOM changes will occur. We did this because otherwise it
* takes to look before anything shows up.
* We allow 1 request per feed - so 1 DOM change per feed
* @private
* @param {Array} inputdata an array containing all the feeditems for a
* specific feed.
*/
finished = function( inputdata ) {
// Merge the feed items we have from other feeds, with the feeditems
// from the new feed
$.merge( data.items, inputdata );
// Sort the feeditems by date - we want the most recent one first
data.items.sort( function( a, b ) {
return ( b.date - a.date );
});
var items = data.items,
// We need to check whether the amount of current feed items is
// smaller than the main limit. This parameter will be used in the
// for loop
length = ( items.length < settings.limit ) ?
items.length :
settings.limit,
i = 0, item,
// We create an unordered list which will create all the feed
// items
ul = $('
');
// Run over all the feed items + add them as list items to the
// unordered list
for ( ; i < length; i++ ) {
item = items[i];
if ( item.html ) {
$('').append( item.html )
.appendTo( ul );
}
}
// Change the innerHTML with a list of all the feeditems in
// chronological order
outputElement.html( ul );
// Trigger the feedloaded callback, if it is a function
if ( $.isFunction( settings.feedloaded ) ) {
settings.feedloaded();
}
},
/**
* Fire up all the feeds and pass them the right arugments.
* @private
*/
load = function() {
var i = 0, j = settings.list.length;
// We don't pass the list array to each feed because this will create
// a recursive JavaScript object
delete itemsettings.list;
// Run over all the items in the list
for( ; i < j; i++ ) {
var config = settings.list[i];
// Check whether the feed exists, if the feed is a function and if a
// user has been filled in
if ( $.fn.lifestream.feeds[config.service] &&
$.isFunction( $.fn.lifestream.feeds[config.service] )
&& config.user) {
// You'll be able to get the global settings by using
// config._settings in your feed
config._settings = itemsettings;
// Call the feed with a config object and finished callback
$.fn.lifestream.feeds[config.service]( config, finished );
}
}
};
// Load the jQuery templates plug-in if it wasn't included in the page.
// At then end we call the load method.
if( !jQuery.tmpl ) {
jQuery.getScript(
"https://raw.github.com/jquery/jquery-tmpl/master/"
+ "jquery.tmpl.min.js",
load);
} else {
load();
}
});
};
/**
* A big container which contains all available feeds
*/
$.fn.lifestream.feeds = $.fn.lifestream.feeds || {};
$.fn.lifestream.feeds.blogger = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted ${title}'
},
config.template),
parseBlogger = function ( input ) {
var output = [], list, i = 0, j, item;
if ( input.query && input.query.count && input.query.count > 0
&& input.query.results.feed.entry ) {
list = input.query.results.feed.entry;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
output.push({
date: new Date( item.published ),
config: config,
html: $.tmpl( template.posted, item )
});
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where url="http://'
+ config.user + '.blogspot.com/feeds/posts/default"'),
dataType: "jsonp",
success: function ( data ) {
callback(parseBlogger(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.dailymotion = function( config, callback ) {
var template = $.extend({},
{
uploaded: 'uploaded a video ${title[0]}'
},
config.template),
parseDailymotion = function( input ) {
var output = [], list, i = 0, j, item;
if ( input.query && input.query.count && input.query.count > 0
&& input.query.results.rss.channel.item ) {
list = input.query.results.rss.channel.item;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
output.push({
date: new Date ( item.pubDate ),
config: config,
html: $.tmpl( template.uploaded, item )
});
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where '
+ 'url="http://www.dailymotion.com/rss/user/' + config.user + '"'),
dataType: "jsonp",
success: function( data ) {
callback(parseDailymotion(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.delicious = function( config, callback ) {
var template = $.extend({},
{
bookmarked: 'bookmarked ${d}'
},
config.template);
$.ajax({
url: "http://feeds.delicious.com/v2/json/" + config.user,
dataType: "jsonp",
success: function( data ) {
var output = [], i = 0, j;
if (data && data.length && data.length > 0) {
j = data.length;
for( ; i < j; i++) {
var item = data[i];
output.push({
date: new Date(item.dt),
config: config,
html: $.tmpl( template.bookmarked, item )
});
}
}
callback(output);
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.deviantart = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted ${title}'
},
config.template);
$.ajax({
url: createYqlUrl(
'select title,link,pubDate from rss where '
+ 'url="http://backend.deviantart.com/rss.xml?q=gallery%3A'
+ encodeURIComponent(config.user)
+ '&type=deviation'
+ '" | unique(field="title")'
),
dataType: 'jsonp',
success: function( resp ) {
var output = [],
items, item,
i = 0, j;
if (resp.query && resp.query.count > 0) {
items = resp.query.results.item;
j = items.length;
for ( ; i < j; i++) {
item = items[i];
output.push({
date: new Date(item.pubDate),
config: config,
html: $.tmpl( template.posted, item )
});
}
}
callback(output);
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.dribbble = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted a shot ${title}'
},
config.template);
$.ajax({
url: "http://api.dribbble.com/players/" + config.user + "/shots",
dataType: "jsonp",
success: function( data ) {
var output = [], i = 0, j;
if(data && data.total) {
j = data.shots.length;
for( ; i${title}'
},
config.template);
$.ajax({
url: "http://api.flickr.com/services/feeds/photos_public.gne?id="
+ config.user + "&lang=en-us&format=json",
dataType: "jsonp",
jsonp: 'jsoncallback',
success: function( data ) {
var output = [], i = 0, j;
if(data && data.items && data.items.length > 0) {
j = data.items.length;
for( ; i${url}'
},
config.template);
$.ajax({
url: "http://api.foomark.com/urls/list/",
data: {
format: "jsonp",
username: config.user
},
dataType: "jsonp",
success: function( data ) {
var output = [], i=0, j;
if( data && data.length && data.length > 0 ) {
j = data.length;
for( ; i < j; i++ ) {
var item = data[i];
output.push({
date: new Date( item.created_at.replace(' ', 'T') ),
config: config,
html: $.tmpl( template.bookmarked, item )
});
}
}
callback( output );
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.formspring = function( config, callback ) {
var template = $.extend({},
{
answered: 'answered a question ${title}'
},
config.template);
var parseFormspring = function ( input ) {
var output = [], list, i = 0, j, item;
if ( input.query && input.query.count && input.query.count > 0
&& input.query.results.rss.channel.item ) {
list = input.query.results.rss.channel.item;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
output.push({
date: new Date( item.pubDate ),
config: config,
html: $.tmpl( template.answered, item )
});
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where '
+ 'url="http://www.formspring.me/profile/' + config.user + '.rss"'),
dataType: "jsonp",
success: function ( data ) {
callback(parseFormspring(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.forrst = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted a ${post_type} '
+ '${title}'
},
config.template);
$.ajax({
url: "http://forrst.com/api/v2/users/posts?username=" + config.user,
dataType: "jsonp",
success: function( data ) {
var output = [], i=0, j;
if( data && data.resp.length && data.resp.length > 0 ) {
j = data.resp.length;
for( ; i < j; i++ ) {
var item = data.resp[i];
output.push({
date: new Date( item.created_at.replace(' ', 'T') ),
config: config,
html: $.tmpl( template.posted, item )
});
}
}
callback( output );
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.foursquare = function( config, callback ) {
var template = $.extend({},
{
checkedin: 'checked in @ ${title}'
},
config.template),
parseFoursquare = function( input ) {
var output = [], i = 0, j;
if(input.query && input.query.count && input.query.count >0) {
j = input.query.count;
for( ; ipushed to '
+'${repo}',
gist: '${status.payload.name}',
commented: 'commented on '
+'${repo}',
pullrequest: '${status.payload.action} '
+'pull request on ${repo}',
created: 'created ${status.payload.ref_type || status.payload.object}'
+' ${status.payload.ref || '
+'status.payload.object_name} for '
+'${repo}',
createdglobal: 'created ${status.payload.object} '
+'${title}',
deleted: 'deleted ${status.payload.ref_type} '
+'status.payload.ref'
},
config.template);
var returnRepo = function( status ) {
return status.payload.repo
|| ( status.repository ? status.repository.owner + "/"
+ status.repository.name : null )
|| status.url.split("/")[3] + "/" + status.url.split("/")[4];
},
parseGithubStatus = function( status ) {
var repo, title;
if(status.type === "PushEvent") {
title = status.payload && status.payload.shas
&& status.payload.shas.json
&& status.payload.shas.json[2];
repo = returnRepo(status);
return $.tmpl( template.pushed, {
status: status,
title: title,
author: title ? status.payload.shas.json[3] : "",
repo: returnRepo(status)
} );
}
else if (status.type === "GistEvent") {
return $.tmpl( template.gist, status );
}
else if (status.type === "CommitCommentEvent" ||
status.type === "IssueCommentEvent") {
repo = returnRepo(status);
return $.tmpl( template.commented, {
repo: repo,
status: status
} );
}
else if (status.type === "PullRequestEvent") {
repo = returnRepo(status);
return $.tmpl( template.pullrequest, {
repo: repo,
status: status
} );
}
// Github has several syntaxes for create tag events
else if (status.type === "CreateEvent" &&
(status.payload.ref_type === "tag" ||
status.payload.ref_type === "branch" ||
status.payload.object === "tag")) {
repo = returnRepo(status);
return $.tmpl( template.created, {
repo: repo,
status: status
} );
}
else if (status.type === "CreateEvent") {
title = (status.payload.object_name === "null")
? status.payload.name
: status.payload.object_name;
return $.tmpl( template.createdglobal, {
title: title,
status: status
} );
}
else if (status.type === "DeleteEvent") {
return $.tmpl( template.deleted, status );
}
},
parseGithub = function( input ) {
var output = [], i = 0, j;
if(input.query && input.query.count && input.query.count >0) {
j = input.query.count;
for( ; i${title.content}'
},
config.template),
/**
* Parse the input from google reader
*/
parseReader = function( input ) {
var output = [], list, i = 0, j;
if(input.query && input.query.count && input.query.count >0) {
list = input.query.results.feed.entry;
j = list.length;
for( ; i${what} on (${os})'
},
config.template);
var parseIusethis = function( input ) {
var output = [], list, i, j, k, l, m = 0, n, item, title, actions,
action, what, os, oss = ["iPhone", "OS X", "Windows"];
if (input.query && input.query.count && input.query.count > 0
&& input.query.results.rss) {
n = input.query.results.rss.length;
actions = ['started using', 'stopped using', 'stopped loving',
'Downloaded', 'commented on', 'updated entry for',
'started loving', 'registered'];
l = actions.length;
for( ; m < n; m++) {
os = oss[m];
list = input.query.results.rss[m].channel.item;
i = 0;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
title = item.title.replace(config.user + ' ', '');
k = 0;
for( ; k < l; k++) {
if(title.indexOf(actions[k]) > -1) {
action = actions[k];
break;
}
}
what = title.split(action);
output.push({
date: new Date(item.pubDate),
config: config,
html: $.tmpl( template.global, {
action: action.toLowerCase(),
link: item.link,
what: what[1],
os: os
} )
});
}
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where '
+ 'url="http://iphone.iusethis.com/user/feed.rss/' + config.user
+ '" or '
+ 'url="http://osx.iusethis.com/user/feed.rss/' + config.user
+ '" or '
+ 'url="http://win.iusethis.com/user/feed.rss/' + config.user + '"'),
dataType: "jsonp",
success: function( data ) {
callback(parseIusethis(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.lastfm = function( config, callback ) {
var template = $.extend({},
{
loved: 'loved ${name} by '
+ '${artist.name}'
},
config.template),
parseLastfm = function( input ) {
var output = [], list, i = 0, j;
if(input.query && input.query.count && input.query.count > 0
&& input.query.results.lovedtracks
&& input.query.results.lovedtracks.track) {
list = input.query.results.lovedtracks.track;
j = list.length;
for( ; i${title}'
},
config.template);
$.ajax({
url: "http://picplz.com/api/v2/user.json?username="
+ config.user + "&include_pics=1",
dataType: "jsonp",
success: function( data ) {
var output = [], i=0, j, images;
images = data.value.users[0].pics;
if( images && images.length && images.length > 0 ) {
j = images.length;
for( ; i < j; i++ ) {
var item = images[i];
output.push({
date: new Date( ( item.date ) * 1000 ),
config: config,
html: $.tmpl( template.uploaded, {
url: item.pic_files["640r"].img_url,
title: item.caption || item.id
} )
});
}
}
callback( output );
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.pinboard = function( config, callback ) {
var template = $.extend({},
{
bookmarked: 'bookmarked ${title}'
},
config.template);
var parsePinboard = function( input ) {
var output = [], list, i = 0, j, item;
if (input.query && input.query.count && input.query.count > 0) {
list = input.query.results.RDF.item;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
output.push({
date: new Date(item.date),
config: config,
html: $.tmpl( template.bookmarked, item )
});
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where '
+ 'url="http://feeds.pinboard.in/rss/u:' + config.user + '"'),
dataType: "jsonp",
success: function( data ) {
callback(parsePinboard(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.posterous = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted ${title}'
},
config.template);
var parsePosterous = function ( input ) {
var output = [], list, i = 0, j, item;
if ( input.query && input.query.count && input.query.count > 0
&& input.query.results.rss.channel.item ) {
list = input.query.results.rss.channel.item;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
output.push({
date: new Date( item.pubDate ),
config: config,
html: $.tmpl( template.posted, item )
});
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where '
+ 'url="http://' + config.user + '.posterous.com/rss.xml"'),
dataType: "jsonp",
success: function ( data ) {
callback(parsePosterous(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.reddit = function( config, callback ) {
var template = $.extend({},
{
commented: 'commented '
+ '(${score}) in ${item.data.subreddit}',
created: ''
+ 'created new thread (${score}) in '
+ ''
+ '${item.data.subreddit}'
},
config.template);
/**
* Parsed one item from the Reddit API.
* item.kind == t1 is a reply, t2 is a new thread
*/
var parseRedditItem = function( item ) {
var score = item.data.ups - item.data.downs,
pass = {
item: item,
score: (score > 0) ? "+" + score : score
};
// t1 = reply, t3 = new thread
if (item.kind === "t1") {
return $.tmpl( template.commented, pass );
}
else if (item.kind === "t3") {
return $.tmpl( template.created, pass );
}
},
/**
* Reddit date's are simple epochs.
* seconds*1000 = milliseconds
*/
convertDate = function( date ) {
return new Date(date * 1000);
};
$.ajax({
url: "http://www.reddit.com/user/" + config.user + ".json",
dataType: "jsonp",
jsonp:"jsonp",
success: function( data ) {
var output = [], i = 0, j;
if(data && data.data && data.data.children
&& data.data.children.length > 0) {
j = data.data.children.length;
for( ; i${title}'
},
config.template);
var parseSlideshare = function( input ) {
var output = [], list, i = 0, j, item;
if (input.query && input.query.count && input.query.count > 0) {
list = input.query.results.rss.channel.item;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
output.push({
date: new Date(item.pubDate),
config: config,
html: $.tmpl( template.uploaded, item )
});
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where '
+ 'url="http://www.slideshare.net/rss/user/' + config.user + '"'),
dataType: "jsonp",
success: function( data ) {
callback(parseSlideshare(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.stackoverflow = function( config, callback ) {
var template = $.extend({},
{
global: '${text} - ${title}'
},
config.template);
var parseStackoverflowItem = function( item ) {
var text="", title="", link="",
stackoverflow_link = "http://stackoverflow.com/users/" + config.user,
question_link = "http://stackoverflow.com/questions/";
if(item.timeline_type === "badge") {
text = item.timeline_type + " " + item.action + ": "
+ item.description;
title = item.detail;
link = stackoverflow_link + "?tab=reputation";
}
else if (item.timeline_type === "revision"
|| item.timeline_type === "comment"
|| item.timeline_type === "accepted"
|| item.timeline_type === "askoranswered") {
text = item.post_type + " " + item.action;
title = item.detail || item.description || "";
link = question_link + item.post_id;
}
return {
link: link,
title: title,
text: text
};
},
convertDate = function( date ) {
return new Date(date * 1000);
};
$.ajax({
url: "http://api.stackoverflow.com/1.1/users/" + config.user
+ "/timeline?"
+ "jsonp",
dataType: "jsonp",
jsonp: 'jsonp',
success: function( data ) {
var output = [], i = 0, j;
if(data && data.total && data.total > 0 && data.user_timelines) {
j = data.user_timelines.length;
for( ; i${title}'
},
config.template),
/**
* get title text
*/
getTitle = function( post ) {
var title = post["regular-title"]
|| post["quote-text"]
|| post["conversation-title"]
|| post["photo-caption"]
|| post["video-caption"]
|| post["audio-caption"]
|| post["regular-body"]
|| post["link-text"]
|| post.type
|| "";
// remove tags
return title.replace( /<.+?>/gi, " ");
},
createTumblrOutput = function( config, post ) {
return {
date: new Date(post.date),
config: config,
html: $.tmpl( template.posted, {
type: post.type,
url: post.url,
title: getTitle(post)
} )
};
},
parseTumblr = function( input ) {
var output = [], i = 0, j, post;
if(input.query && input.query.count && input.query.count > 0) {
// If a user only has one post, post is a plain object, otherwise it
// is an array
if ( $.isArray(input.query.results.posts.post) ) {
j = input.query.results.posts.post.length;
for( ; i < j; i++) {
post = input.query.results.posts.post[i];
output.push(createTumblrOutput(config, post));
}
}
else if ( $.isPlainObject(input.query.results.posts.post) ) {
output.push(createTumblrOutput(config,input.query.results.posts.post));
}
}
return output;
};
$.ajax({
url: createYqlUrl('select *'
+ ' from tumblr.posts where username="'+ config.user +'"'),
dataType: 'jsonp',
success: function( data ) {
callback(parseTumblr(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.twitter = function( config, callback ) {
var template = $.extend({},
{
posted: '{{html tweet}}'
},
config.template),
/**
* Add links to the twitter feed.
* Hashes, @ and regular links are supported.
* @private
* @param {String} tweet A string of a tweet
* @return {String} A linkified tweet
*/
linkify = function( tweet ) {
var link = function( t ) {
return t.replace(
/[a-z]+:\/\/[a-z0-9-_]+\.[a-z0-9-_:~%&\?\/.=]+[^:\.,\)\s*$]/ig,
function( m ) {
return ''
+ ( ( m.length > 25 ) ? m.substr( 0, 24 ) + '...' : m )
+ '';
}
);
},
at = function( t ) {
return t.replace(
/(^|[^\w]+)\@([a-zA-Z0-9_]{1,15})/g,
function( m, m1, m2 ) {
return m1 + '@'
+ m2 + '';
}
);
},
hash = function( t ) {
return t.replace(
/(^|[^\w'"]+)\#([a-zA-Z0-9_]+)/g,
function( m, m1, m2 ) {
return m1 + '#' + m2 + '';
}
);
};
return hash(at(link(tweet)));
},
/**
* Parse the input from twitter
*/
parseTwitter = function( input ) {
var output = [], i = 0, j;
if(input.query && input.query.count && input.query.count >0) {
j = input.query.count;
for( ; i${title}'
},
config.template),
parseVimeo = function( input ) {
var output = [], i = 0, j, item;
if (input) {
j = input.length;
for( ; i < j; i++) {
item = input[i];
output.push({
date: new Date( item.upload_date.replace(' ', 'T') ),
config: config,
html: $.tmpl( template.posted, {
url: item.url,
description: item.description.replace(/"/g, "'")
.replace( /<.+?>/gi, ""),
title: item.title
} )
});
}
}
return output;
};
$.ajax({
url: "http://vimeo.com/api/v2/" + config.user + "/videos.json",
dataType: "jsonp",
crossDomain: true,
success: function( data ) {
callback(parseVimeo(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.wordpress = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted ${title}'
},
config.template);
var parseWordpress = function ( input ) {
var output = [], list, i = 0, j, item;
if ( input.query && input.query.count && input.query.count > 0
&& input.query.results.rss.channel.item ) {
list = input.query.results.rss.channel.item;
j = list.length;
for ( ; i < j; i++) {
item = list[i];
output.push({
date: new Date( item.pubDate ),
config: config,
html: $.tmpl( template.posted, item )
});
}
}
return output;
};
$.ajax({
url: createYqlUrl('select * from xml where '
+ 'url="http://' + config.user + '.wordpress.com/feed"'),
dataType: "jsonp",
success: function ( data ) {
callback(parseWordpress(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
$.fn.lifestream.feeds.youtube = function( config, callback ) {
var template = $.extend({},
{
favorited: 'favorited ${video.title}'
},
config.template),
parseYoutube = function( input ) {
var output = [], i = 0, j, item;
if(input.data && input.data.items) {
j = input.data.items.length;
for( ; i