/*!
* jQuery Lifestream Plug-in
* Show a stream of your online activity
* @version 0.5.5
* @author Christian Vuerings et al.
* @copyright Copyright 2014, Christian Vuerings - http://denbuzze.com
* @license https://github.com/christianvuerings/jquery-lifestream/blob/master/LICENSE MIT
*/
/*global jQuery */
;(function( $ ){
"use strict";
/**
* 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 ) {
$('').data( "name", item.config.service )
.data( "url", item.url || "#" )
.data( "time", item.date )
.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(
'//ajax.aspnetcdn.com/ajax/jquery.templates/beta1/' +
'jquery.tmpl.min.js',
load);
} else {
load();
}
});
};
/**
* 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
*/
$.fn.lifestream.createYqlUrl = function( query ) {
return ( ('https:' === document.location.protocol ? 'https' : 'http') +
'://query.yahooapis.com/v1/public/yql?q=__QUERY__' +
'&env=' + 'store://datatables.org/alltableswithkeys&format=json')
.replace( "__QUERY__" , encodeURIComponent( query ) );
};
/**
* A big container which contains all available feeds
*/
$.fn.lifestream.feeds = $.fn.lifestream.feeds || {};
/**
* Add compatible Object.keys support in older environments that do not natively support it
* https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys#section_6
*/
if(!Object.keys) {
Object.keys = function(o){
if (o !== Object(o)) {
throw new TypeError('Object.keys called on non-object');
}
var ret=[],p;
for(p in o) {
if(Object.prototype.hasOwnProperty.call(o,p)) {
ret.push(p);
}
}
return ret;
};
}
}( jQuery ));
(function($) {
$.fn.lifestream.feeds.atom = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted ${title.content}'
},
config.template),
/**
* Parse the input from atom feed
*/
parseAtom = function( input ) {
var output = [], list = [], i = 0, j = 0;
if(input.query && input.query.count && input.query.count > 0) {
list = input.query.results.feed.entry;
j = list.length;
for( ; icommitted at ${owner}/${name}',
pullrequest_fulfilled: 'fulfilled a pull request at ${owner}/${name}',
pullrequest_rejected: 'rejected a pull request at ${owner}/${name}',
pullrequest_created: 'created a pull request at ${owner}/${name}',
create: 'created a new project at ${owner}/${name}',
fork: 'forked ${owner}/${name}'
},
config.template),
supported_events = [
"commit",
"pullrequest_fulfilled",
"pullrequest_rejected",
"pullrequest_created",
"create",
"fork"
],
parseBitbucketStatus = function( status ) {
if ($.inArray(status.event, supported_events) !== -1) {
//bb generates some weird create events, check for repository
if (status.repository) {
if (status.event === "commit") {
return $.tmpl( template.commit, {
owner: status.repository.owner,
name: status.repository.name,
node: status.node
});
} else {
return $.tmpl( template[status.event], {
owner: status.repository.owner,
name: status.repository.name
});
}
}
}
},
parseBitbucket = function( input ) {
var output = [];
if (input.query && input.query.count && input.query.count > 0) {
$.each(input.query.results.json, function () {
output.push({
date: new Date(this.events.created_on.replace(/-/g, '/')),
config: config,
html: parseBitbucketStatus(this.events)
});
});
}
return output;
};
$.ajax({
url: $.fn.lifestream.createYqlUrl('select events.event,' +
'events.node, events.created_on,' +
'events.repository.name, events.repository.owner ' +
'from json where url = "https://api.bitbucket.org/1.0/users/' +
config.user + '/events/"'),
dataType: 'jsonp',
success: function( data ) {
callback(parseBitbucket(data));
}
});
return {
'template' : template
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.bitly = function( config, callback ) {
var template = $.extend({},
{
created: 'created URL ' +
'${short_url}'
},
config.template);
$.ajax({
url: $.fn.lifestream.createYqlUrl('select data.short_url, data.created, '+
'data.title from json where url="' +
'http://bitly.com/u/' + config.user + '.json"'),
dataType: "jsonp",
success: function( input ) {
var output = [], i = 0, j, list;
if ( input.query && input.query.count && input.query.results.json ) {
list = input.query.results.json;
j = list.length;
for( ; i < j; i++) {
var item = list[i].data;
output.push({
date: new Date(item.created * 1000),
config: config,
html: $.tmpl( template.created, item )
});
}
}
callback(output);
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);(function($) {
$.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, k, l;
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];
if( !item.origLink ) {
k = 0;
l = item.link.length;
for ( ; k < l ; k++ ) {
if( item.link[k].rel === 'alternate' ) {
item.origLink = item.link[k].href;
}
}
}
// ignore items that have no link.
if ( item.origLink ){
if( item.title.content ) {
item.title = item.title.content;
}
output.push({
date: new Date( item.published ),
config: config,
html: $.tmpl( template.posted, item )
});
}
}
}
return output;
};
$.ajax({
url: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.citeulike = function( config, callback ) {
var template = $.extend({},
{
saved: 'saved ${title} by ${authors}'
},
config.template),
parseCiteulike = function( data ) {
var output = [], i = 0, j;
if(data && data.length && data.length > 0) {
j = data.length;
for( ; i${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: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.delicious = function( config, callback ) {
var template = $.extend({},
{
bookmarked: 'bookmarked ${d}'
},
config.template);
$.ajax({
url: "https://api.del.icio.us/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
};
};
})(jQuery);
(function($) {
$.fn.lifestream.feeds.deviantart = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted ${title}'
},
config.template);
$.ajax({
url: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.disqus = function( config, callback ) {
var template = $.extend({},
{
post: 'commented on ${thread.title}',
thread_like: 'liked ${thread.title}'
},
config.template),
parseDisqus = function( input ) {
var output = [], i = 0, j, item;
if(input) {
j = input.length;
for( ; i${title}'
},
config.template);
$.ajax({
url: "https://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${text}'
},
config.template);
/**
* Parse the input from facebook
*/
var parseFacebooky = function(response) {
var output = [];
if (!response.posts || !response.posts.length) {
return output;
}
for (var i = 0 ;i < response.posts.length; i++){
var post = response.posts[i];
output.push({
"date": new Date(post.time * 1000),
"config": config,
"html": $.tmpl(template.wall_post, post)
});
}
callback(output);
};
$.ajax({
url: 'https://facebooky.herokuapp.com/page/' + config.user,
success: parseFacebooky
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);
(function($) {
'use strict';
$.fn.lifestream.feeds.fancy = function( config, callback ) {
var template = $.extend({},
{
fancied: 'fancy\'d ${title}'
},
config.template),
parseFancy = 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);
$.ajax({
url: "https://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(/-/g, '/') ),
config: config,
html: $.tmpl( template.bookmarked, item )
});
}
}
callback( output );
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);
(function($) {
$.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: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.forrst = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted a ${post_type} ${title}'
},
config.template);
$.ajax({
url: "https://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
};
};
})(jQuery);
(function($) {
$.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( ; i${title}'
},
config.template);
$.ajax({
url: "https://gimmebar.com/api/v0/public/assets/" + config.user + ".json?jsonp_callback=?",
dataType: "json",
success: function( data ) {
data = data.records;
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.date * 1000),
config: config,
html: $.tmpl( template.bookmarked, item )
});
}
}
callback(output);
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);
(function($) {
$.fn.lifestream.feeds.github = function( config, callback ) {
var template = $.extend({},
{
commitCommentEvent: 'commented on ${status.repo.name}',
createBranchEvent: 'created branch ' +
'${status.payload.ref} at ${status.repo.name}',
createRepositoryEvent: 'created repository ' +
'${status.repo.name}',
createTagEvent: 'created tag ' +
'${status.payload.ref} at ${status.repo.name}',
deleteBranchEvent: 'deleted branch ${status.payload.ref} at ' +
'' +
'${status.repo.name}',
deleteTagEvent: 'deleted tag ${status.payload.ref} at ' +
'' +
'${status.repo.name}',
followEvent: 'started following ${status.payload.target.login}',
forkEvent: 'forked ' +
'${status.repo.name}',
gistEvent: '${status.payload.action} gist ' +
'' +
'${status.payload.gist.id}',
issueCommentEvent: 'commented on issue ' +
'${status.payload.issue.number} on ${status.repo.name}',
issuesEvent: '${status.payload.action} issue ' +
'${status.payload.issue.number} '+
'on ' +
'${status.repo.name}',
pullRequestEvent: '${status.payload.action} pull request ' +
'${status.payload.number} on ' +
'' +
'${status.repo.name}',
pushEvent: 'pushed to ${status.payload.ref} at ' +
'' +
'${status.repo.name}',
watchEvent: 'started watching ${status.repo.name}'
},
config.template),
parseGithubStatus = function( status ) {
if (status.type === 'CommitCommentEvent' ) {
return $.tmpl( template.commitCommentEvent, {status: status} );
}
else if (status.type === 'CreateEvent' &&
status.payload.ref_type === 'branch') {
return $.tmpl( template.createBranchEvent, {status: status} );
}
else if (status.type === 'CreateEvent' &&
status.payload.ref_type === 'repository') {
return $.tmpl( template.createRepositoryEvent, {status: status} );
}
else if (status.type === 'CreateEvent' &&
status.payload.ref_type === 'tag') {
return $.tmpl( template.createTagEvent, {status: status} );
}
else if (status.type === 'DeleteEvent' &&
status.payload.ref_type === 'branch') {
return $.tmpl( template.deleteBranchEvent, {status: status} );
}
else if (status.type === 'DeleteEvent' &&
status.payload.ref_type === 'tag') {
return $.tmpl( template.deleteTagEvent, {status: status} );
}
else if (status.type === 'FollowEvent' ) {
return $.tmpl( template.followEvent, {status: status} );
}
else if (status.type === 'ForkEvent' ) {
return $.tmpl( template.forkEvent, {status: status} );
}
else if (status.type === 'GistEvent' ) {
if (status.payload.action === 'create') {
status.payload.action = 'created';
} else if (status.payload.action === 'update') {
status.payload.action = 'updated';
}
return $.tmpl( template.gistEvent, {status: status} );
}
else if (status.type === 'IssueCommentEvent' ) {
return $.tmpl( template.issueCommentEvent, {status: status} );
}
else if (status.type === 'IssuesEvent' ) {
return $.tmpl( template.issuesEvent, {status: status} );
}
else if (status.type === 'PullRequestEvent' ) {
return $.tmpl( template.pullRequestEvent, {status: status} );
}
else if (status.type === 'PushEvent' ) {
status.payload.ref = status.payload.ref.split('/')[2];
return $.tmpl( template.pushEvent, {status: status} );
}
else if (status.type === 'WatchEvent' ) {
return $.tmpl( template.watchEvent, {status: 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${actor.displayName}' +
' has posted a new entry ${title} ' +
'${object.replies.totalItems} replies, ' +
'${object.plusoners.totalItems} +1s, ' +
'${object.resharers.totalItems} Reshares'
},
config.template),
parseGooglePlus = function( input ) {
var output = [], i = 0, j, item;
if(input && input.items) {
j = input.items.length;
for( ; i${title} by ${artist}',
history: 'listened to ${title} by ${artist}'
},
config.template);
$.ajax({
url: "http://hypem.com/playlist/" + config.type + "/" + config.user + "/json/1/data.js",
dataType: "json",
success: function( data ) {
var output = [], i = 0, j = -1;
for (var k in data) {
if (data.hasOwnProperty(k)) {
j++;
}
}
if (data && j > 0) {
for( ; i < j; i++) {
var item = data[i];
output.push({
date: new Date( (config.type === "history" ? item.dateplayed : item.dateloved) * 1000 ),
config: config,
html: $.tmpl( (config.type === "history" ? template.history : template.loved) , item )
});
}
}
callback(output);
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.instapaper = function( config, callback ) {
var template = $.extend({},
{
loved: 'loved ${title}'
},
config.template),
parseInstapaper = 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${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: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.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' +
'${book.title} by ${book.author_fl} to my library'
},
config.template),
parseLibraryThing = function( input ) {
var output = [], i = "";
if(input.books) {
// LibraryThing returns a hash that maps id to Book objects
// which leads to the following slightly weird for loop.
for (i in input.books) {
if (input.books.hasOwnProperty(i)) {
var book = input.books[i];
output.push({
date : new Date(book.entry_stamp * 1000),
config : config,
html : $.tmpl(template.book, {book : book}),
url : 'http://www.librarything.com/profile/' + config.user
});
}
}
}
return output;
};
$.ajax({
url: 'https://www.librarything.com/api_getdata.php?booksort=entry_REV&userid=' + config.user,
dataType: 'jsonp',
success: function( data ) {
callback(parseLibraryThing(data));
}
});
return {
"template" : template
};
};
})(jQuery);
(function($) {
'use strict';
$.fn.lifestream.feeds.linkedin = function( config, callback ) {
var template = $.extend({},
{
'posted': '${title}'
}, config.template),
jsonpCallbackName = 'jlsLinkedinCallback' + config.user,
createYql = function(){
var query = 'SELECT * FROM feed WHERE url="' + config.url + '"';
// I bet some will not read the instructions
if(config.user) {
query += ' AND link LIKE "%' + config.user + '%"';
}
return query;
},
parseLinkedinItem = function(item) {
return {
'date': new Date(item.pubDate),
'config': config,
'html': $.tmpl(template.posted, item)
};
};
// !!! Global function for jsonp callback
window[jsonpCallbackName] = function(input) {
var output = [], i = 0;
if(input.query && input.query.count && input.query.count > 0) {
if (input.query.count === 1) {
output.push(parseLinkedinItem(input.query.results.item));
} else {
for(i; i < input.query.count; i++) {
var item = input.query.results.item[i];
output.push(parseLinkedinItem(item));
}
}
}
callback(output);
};
$.ajax({
'url': $.fn.lifestream.createYqlUrl(createYql()),
'cache': true,
'data': {
// YQL will cache this for 5 minutes
'_maxage': 300
},
'dataType': 'jsonp',
// let YQL cache
'jsonpCallback': jsonpCallbackName
});
// Expose the template.
// We use this to check which templates are available
return {
'template': template
};
};
})(jQuery);
(function($) {
$.fn.lifestream.feeds.mendeley = function( config, callback ) {
var template = $.extend({},
{
flagged1: 'flagged ${title}',
flagged2: 'flagged ${title}'
},
config.template),
parseMendeley = function( input ) {
var output = [], list, i = 0, j;
if(input.query && input.query.count && input.query.count > 0) {
list = input.query.results.rss.channel.item;
j = list.length;
for( ; i${title}'
},
config.template),
/**
* Parse the input from rss feed
*/
parseMiso = function( input ) {
var output = [], list, i = 0, j;
if(input.query && input.query.count && input.query.count > 0) {
list = input.query.results.rss.channel.item;
j = list.length;
for( ; i${title}'
},
config.template);
var parseMlkshk = 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: $.fn.lifestream.createYqlUrl('select * from xml where ' +
'url="http://mlkshk.com/user/' + config.user + '/rss"'),
dataType: "jsonp",
success: function ( data ) {
callback(parseMlkshk(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);(function($) {
$.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: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.pocket = function( config, callback ) {
var template = $.extend({},
{
pocketed: 'pocketed ${title}'
},
config.template),
parsePocket = function( input ) {
var output = [], list, i = 0, j;
if(input.query && input.query.results) {
list = input.query.results.rss.channel.item;
j = list.length;
for( ; i${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: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.quora = function( config, callback ) {
var template = $.extend({},
{
posted: '${title}'
},
config.template),
/**
* Get the link
* Straigth copy from RSS
*
* @param {Object} channel
* @return {String}
*/
getChannelUrl = function(channel){
var i = 0, j = channel.link.length;
for( ; i < j; i++) {
var link = channel.link[i];
if( typeof link === 'string' ) {
return link;
}
}
return '';
},
/**
* Parse the input from quora feed
*/
parseRSS = function( input ) {
var output = [], list = [], i = 0, j = 0, url = '';
if(input.query && input.query.count && input.query.count > 0) {
list = input.query.results.rss.channel.item;
j = list.length;
url = getChannelUrl(input.query.results.rss.channel);
for( ; icommented ' +
'(${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: "https://pay.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),
/**
* Get the link
* @param {Object} channel
* @return {String}
*/
getChannelUrl = function(channel){
var i = 0, j = channel.link.length;
for( ; i < j; i++) {
var link = channel.link[i];
if( typeof link === 'string' ) {
return link;
}
}
return '';
},
/**
* Parse the input from rss feed
*/
parseRSS = function( input ) {
var output = [], list = [], i = 0, j = 0, url = '';
if(input.query && input.query.count && input.query.count > 0) {
list = input.query.results.rss.channel.item;
j = list.length;
url = getChannelUrl(input.query.results.rss.channel);
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: $.fn.lifestream.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
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.snipplr = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted a snippet ${title}'
},
config.template);
var parseSnipplr = 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: $.fn.lifestream.createYqlUrl('select * from xml where ' +
'url="http://snipplr.com/rss/users/' + config.user + '"'),
dataType: "jsonp",
success: function ( data ) {
callback(parseSnipplr(data));
}
});
};
})(jQuery);(function($) {
$.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") {
link = stackoverflow_link + "?tab=reputation";
}
text = item.timeline_type;
title = item.title || item.detail || "";
link = link || question_link + item.post_id;
return {
link: link,
title: title,
text: text
};
},
convertDate = function( date ) {
return new Date(date * 1000);
};
$.ajax({
url: "https://api.stackexchange.com/2.1/users/" + config.user +
"/timeline?site=stackoverflow",
dataType: "jsonp",
jsonp: 'jsonp',
success: function( data ) {
var output = [];
if(data && data.items) {
for(var i = 0 ; i < data.items.length; i++) {
var item = data.items[i];
output.push({
date: convertDate(item.creation_date),
config: config,
html: $.tmpl( template.global, parseStackoverflowItem(item) )
});
}
}
callback(output);
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);
(function($) {
$.fn.lifestream.feeds.tumblr = function( config, callback ) {
var template = $.extend({},
{
posted: 'posted a ${type} ${title}'
},
config.template),
limit = config.limit || 20,
getImage = function( post ) {
switch(post.type) {
case 'photo':
var images = post['photo-url'];
return $('')
.attr({
src: images[images.length - 1].content,
title: getTitle(post),
alt: getTitle(post)
}).wrap('').parent().html(); // generate an HTML string
case 'video':
var videos = post['video-player'];
var video = videos[videos.length - 1].content;
// Videos hosted on Tumblr use JavaScript to render the
// video, but the JavaScript doesn't work when we call it
// from a lifestream - so don't try to embed these.
if (video.match(/<\s*script/)) { return null; }
return video;
case 'audio':
// Unlike photo and video, audio gives you no visual indication
// of what it contains, so we append the "title" text.
return post['audio-player'] + ' ' +
// HTML-escape the text.
$('').text(getTitle(post)).html();
default:
return null;
}
},
getFirstElementOfBody = function( post, bodyAttribute ) {
return $(post[bodyAttribute]).filter(':not(:empty):first').text();
},
getTitleForPostType = function( post ) {
var title;
switch(post.type) {
case 'regular':
return post['regular-title'] ||
getFirstElementOfBody(post, 'regular-body');
case 'link':
title = post['link-text'] ||
getFirstElementOfBody(post, 'link-description');
if (title === '') { title = post['link-url']; }
return title;
case 'video':
return getFirstElementOfBody(post, 'video-caption');
case 'audio':
return getFirstElementOfBody(post, 'audio-caption');
case 'photo':
return getFirstElementOfBody(post, 'photo-caption');
case 'quote':
return '"' + post['quote-text'].replace(/<.+?>/g, ' ').trim() + '"';
case 'conversation':
title = post['conversation-title'];
if (!title) {
title = post.conversation.line;
if (typeof(title) !== 'string') {
title = title[0].label + ' ' + title[0].content + ' ...';
}
}
return title;
case 'answer':
return post.question;
default:
return post.type;
}
},
/**
* get title text
*/
getTitle = function( post ) {
var title = getTitleForPostType(post) || '';
// 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.replace('regular', 'blog entry'),
url: post.url,
image: getImage(post),
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: $.fn.lifestream.createYqlUrl('select *' +
' from tumblr.posts where username="' + config.user + '"' +
' and num="' + limit + '"'),
dataType: 'jsonp',
success: function( data ) {
callback(parseTumblr(data));
}
});
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);(function($) {
"use strict";
$.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
*/
var linkify = function( tweet ) {
var link = function( t ) {
return t.replace(
/([a-z]+:\/\/)([-A-Z0-9+&@#\/%?=~_|(\)!:,.;]*[-A-Z0-9+&@#\/%=~_|(\)])/ig,
function( m, m1, m2 ) {
return $("").attr("href", m).text(
( ( m2.length > 35 ) ? m2.substr( 0, 34 ) + '...' : m2 )
)[0].outerHTML;
}
);
},
at = function( t ) {
return t.replace(
/(^|[^\w]+)\@([a-zA-Z0-9_]{1,15})/g,
function( m, m1, m2 ) {
var elem = ($("")
.attr("href", "https://twitter.com/" + m2)
.text("@" + m2))[0].outerHTML;
return m1 + elem;
}
);
},
hash = function( t ) {
return t.replace(/(pic\.twitter\.com\/.*)/g, '').replace(
/|(^|\r?\n|\r|\n|)(#|\$)([a-zA-Z0-9ÅåÄäÖöØøÆæÉéÈèÜüÊêÛûÎî_]+)(\r?\n|\r|\n||$)/g,
function( m, m1, m2, m3, m4 ) {
if (typeof m3 == "undefined") return m;
var elem = "";
if (m2 == "#") {
elem = ($("")
.attr("href",
"https://twitter.com/hashtag/" + m3 + "?src=hash")
.text("#" + m3))[0].outerHTML;
} else if (m2 == "$") {
elem = ($("")
.attr("href",
"https://twitter.com/search?q=%24" + m3 + "&src=hash")
.text("$" + m3))[0].outerHTML;
}
return (m1 + elem + m4);
}
);
};
return hash(at(link(tweet)));
},
/**
* Parse the input from twitter
* @private
* @param {Object[]} items
* @return {Object[]} Array of Twitter status messages.
*/
parseTwitter = function(response) {
var output = [];
if (!response.tweets) {
return output;
}
for(var i = 0; i < response.tweets.length; i++ ) {
var status = response.tweets[i];
output.push({
"date": new Date(status.createdAt * 1000), // unix time
"config": config,
"html": $.tmpl( template.posted, {
"tweet": linkify($('').html(status.text).text()),
"complete_url": 'https://twitter.com/' + config.user +
"/status/" + status.id
} ),
"url": 'https://twitter.com/' + config.user
});
}
callback(output);
};
$.ajax({
"url": 'https://twittery.herokuapp.com/' + config.user,
"cache": false
}).success(parseTwitter);
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);
(function($) {
$.fn.lifestream.feeds.vimeo = function( config, callback ) {
var template = $.extend({},
{
liked: 'liked ${title}',
posted: 'posted ${title}'
},
config.template),
parseVimeo = function( input, item_type ) {
var output = [], i = 0, j, item, type = item_type || 'liked', date, description;
if (input) {
j = input.length;
for( ; i < j; i++) {
item = input[i];
if (type === 'posted') {
date = new Date( item.upload_date.replace(' ', 'T') );
} else {
date = new Date( item.liked_on.replace(' ', 'T') );
}
if (item.description) {
description = item.description.replace(/"/g, "'").replace( /<.+?>/gi, '');
} else {
description = '';
}
output.push({
date: date,
config: config,
html: $.tmpl( template[type], {
url: item.url,
description: item.description ? item.description
.replace(/"/g, "'")
.replace( /<.+?>/gi, '') : '',
title: item.title
})
});
}
}
return output;
};
$.ajax({
url: $.fn.lifestream.createYqlUrl('SELECT * FROM xml WHERE ' +
'url="http://vimeo.com/api/v2/' + config.user + '/likes.xml" OR ' +
'url="http://vimeo.com/api/v2/' + config.user + '/videos.xml"'),
dataType: 'jsonp',
success: function( response ) {
var output = [];
// check for likes & parse
if ( response.query.results.videos[0] != null &&
response.query.results.videos[0].video.length > 0 ) {
output = output.concat(parseVimeo(
response.query.results.videos[0].video
));
}
// check for uploads & parse
if ( response.query.results.videos[1] != null &&
response.query.results.videos[1].video.length > 0 ) {
output = output.concat(
parseVimeo(response.query.results.videos[1].video, 'posted')
);
}
callback(output);
}
});
// Expose the template.
// We use this to check which templates are available
return {
'template' : template
};
};
})(jQuery);(function($) {
$.fn.lifestream.feeds.wikipedia = function( config, callback ) {
// default to english if no language was set
var language = config.language || 'en',
template = $.extend({},
{
contribution: 'contributed to ${title}'
},
config.template);
$.ajax({
url: "https://" + language +
".wikipedia.org/w/api.php?action=query&ucuser=" +
config.user + "&list=usercontribs&ucdir=older&format=json",
dataType: "jsonp",
success: function( data ) {
var output = [], i = 0, j;
if(data && data.query.usercontribs) {
j = data.query.usercontribs.length;
for( ; i${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;
};
var url = "";
if ( config.user ){
// If the config.user property starts with http:// we assume that is the
// full url to the user his blog. We append the /feed to the url.
url = (config.user.indexOf('http://') === 0 ?
config.user + '/feed' :
'http://' + config.user + '.wordpress.com/feed');
$.ajax({
url: $.fn.lifestream.createYqlUrl('select * from xml where ' +
'url="' + url + '"'),
dataType: "jsonp",
success: function ( data ) {
callback(parseWordpress(data));
}
});
}
// Expose the template.
// We use this to check which templates are available
return {
"template" : template
};
};
})(jQuery);(function($) {
"use strict";
$.fn.lifestream.feeds.youtube = function( config, callback ) {
var template = $.extend({},
{
"uploaded": 'uploaded ${title}'
},
config.template);
var parseYoutube = function(response) {
var output = [];
if(!response.videos) {return output;}
for (var i=0; i${title} by ${creatorSummary}'
},
config.template),
parseZotero = 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