2014-04-24 03:38:53 +00:00
/*jshint bitwise:true, curly:true, forin:false, noarg:true, noempty:true, nonew:true, undef:true, strict:false, browser:true, jquery:true */
2012-01-16 01:35:36 +00:00
// jquery.tweet.js - See http://tweet.seaofclouds.com/ or https://github.com/seaofclouds/tweet for more info
// Copyright (c) 2008-2011 Todd Matthews & Steve Purcell
( function ( $ ) {
$ . fn . tweet = function ( o ) {
var s = $ . extend ( {
username : null , // [string or array] required unless using the 'query' option; one or more twitter screen names (use 'list' option for multiple names, where possible)
list : null , // [string] optional name of list belonging to username
favorites : false , // [boolean] display the user's favorites instead of his tweets
query : null , // [string] optional search query (see also: http://search.twitter.com/operators)
avatar _size : null , // [integer] height and width of avatar if displayed (48px max)
count : 3 , // [integer] how many tweets to display?
fetch : null , // [integer] how many tweets to fetch via the API (set this higher than 'count' if using the 'filter' option)
page : 1 , // [integer] which page of results to fetch (if count != fetch, you'll get unexpected results)
retweets : true , // [boolean] whether to fetch (official) retweets (not supported in all display modes)
intro _text : null , // [string] do you want text BEFORE your your tweets?
outro _text : null , // [string] do you want text AFTER your tweets?
join _text : null , // [string] optional text in between date and tweet, try setting to "auto"
auto _join _text _default : "i said," , // [string] auto text for non verb: "i said" bullocks
auto _join _text _ed : "i" , // [string] auto text for past tense: "i" surfed
auto _join _text _ing : "i am" , // [string] auto tense for present tense: "i was" surfing
auto _join _text _reply : "i replied to" , // [string] auto tense for replies: "i replied to" @someone "with"
auto _join _text _url : "i was looking at" , // [string] auto tense for urls: "i was looking at" http:...
loading _text : null , // [string] optional loading text, displayed while tweets load
refresh _interval : null , // [integer] optional number of seconds after which to reload tweets
twitter _url : "twitter.com" , // [string] custom twitter url, if any (apigee, etc.)
twitter _api _url : "api.twitter.com" , // [string] custom twitter api url, if any (apigee, etc.)
twitter _search _url : "search.twitter.com" , // [string] custom twitter search url, if any (apigee, etc.)
template : "{avatar}{time}{join}{text}" , // [string or function] template used to construct each tweet <li> - see code for available vars
comparator : function ( tweet1 , tweet2 ) { // [function] comparator used to sort tweets (see Array.sort)
2014-04-24 04:55:14 +00:00
return tweet2 . tweet _time - tweet1 . tweet _time ;
2012-01-16 01:35:36 +00:00
} ,
filter : function ( tweet ) { // [function] whether or not to include a particular tweet (be sure to also set 'fetch')
return true ;
}
} , o ) ;
// See http://daringfireball.net/2010/07/improved_regex_for_matching_urls
var url _regexp = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/gi ;
// Expand values inside simple string templates with {placeholders}
function t ( template , info ) {
if ( typeof template === "string" ) {
var result = template ;
for ( var key in info ) {
var val = info [ key ] ;
result = result . replace ( new RegExp ( '{' + key + '}' , 'g' ) , val === null ? '' : val ) ;
}
return result ;
2014-04-24 04:55:14 +00:00
} else { return template ( info ) ; }
2012-01-16 01:35:36 +00:00
}
// Export the t function for use when passing a function as the 'template' option
$ . extend ( { tweet : { t : t } } ) ;
function replacer ( regex , replacement ) {
return function ( ) {
var returning = [ ] ;
this . each ( function ( ) {
returning . push ( this . replace ( regex , replacement ) ) ;
} ) ;
return $ ( returning ) ;
} ;
}
function escapeHTML ( s ) {
return s . replace ( /</g , "<" ) . replace ( />/g , "^>" ) ;
}
$ . fn . extend ( {
linkUser : replacer ( /(^|[\W])@(\w+)/gi , "$1@<a href=\"http://" + s . twitter _url + "/$2\">$2</a>" ) ,
// Support various latin1 (\u00**) and arabic (\u06**) alphanumeric chars
linkHash : replacer ( /(?:^| )[\#]+([\w\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u00ff\u0600-\u06ff]+)/gi ,
2014-04-24 04:55:14 +00:00
' <a href="http://' + s . twitter _search _url + '/search?q=&tag=$1&lang=all' + ( ( s . username && s . username . length === 1 && ! s . list ) ? '&from=' + s . username . join ( "%2BOR%2B" ) : '' ) + '">#$1</a>' ) ,
2012-01-16 01:35:36 +00:00
capAwesome : replacer ( /\b(awesome)\b/gi , '<span class="awesome">$1</span>' ) ,
capEpic : replacer ( /\b(epic)\b/gi , '<span class="epic">$1</span>' ) ,
makeHeart : replacer ( /(<)+[3]/gi , "<tt class='heart'>♥</tt>" )
} ) ;
function linkURLs ( text , entities ) {
return text . replace ( url _regexp , function ( match ) {
var url = ( /^[a-z]+:/i ) . test ( match ) ? match : "http://" + match ;
var text = match ;
for ( var i = 0 ; i < entities . length ; ++ i ) {
var entity = entities [ i ] ;
2014-04-24 04:55:14 +00:00
if ( entity . url === url && entity . expanded _url ) {
2012-01-16 01:35:36 +00:00
url = entity . expanded _url ;
text = entity . display _url ;
break ;
}
}
return "<a href=\"" + escapeHTML ( url ) + "\">" + escapeHTML ( text ) + "</a>" ;
} ) ;
}
function parse _date ( date _str ) {
// The non-search twitter APIs return inconsistently-formatted dates, which Date.parse
// cannot handle in IE. We therefore perform the following transformation:
// "Wed Apr 29 08:53:31 +0000 2009" => "Wed, Apr 29 2009 08:53:31 +0000"
return Date . parse ( date _str . replace ( /^([a-z]{3})( [a-z]{3} \d\d?)(.*)( \d{4})$/i , '$1,$2$4$3' ) ) ;
}
function relative _time ( date ) {
var relative _to = ( arguments . length > 1 ) ? arguments [ 1 ] : new Date ( ) ;
var delta = parseInt ( ( relative _to . getTime ( ) - date ) / 1000 , 10 ) ;
var r = '' ;
if ( delta < 1 ) {
r = 'just now' ;
} else if ( delta < 60 ) {
r = delta + ' seconds ago' ;
} else if ( delta < 120 ) {
r = 'a minute ago' ;
} else if ( delta < ( 45 * 60 ) ) {
r = ( parseInt ( delta / 60 , 10 ) ) . toString ( ) + ' minutes ago' ;
} else if ( delta < ( 2 * 60 * 60 ) ) {
r = 'an hour ago' ;
} else if ( delta < ( 24 * 60 * 60 ) ) {
r = '' + ( parseInt ( delta / 3600 , 10 ) ) . toString ( ) + ' hours ago' ;
} else if ( delta < ( 48 * 60 * 60 ) ) {
r = 'a day ago' ;
} else {
r = ( parseInt ( delta / 86400 , 10 ) ) . toString ( ) + ' days ago' ;
}
return 'about ' + r ;
}
function build _auto _join _text ( text ) {
if ( text . match ( /^(@([A-Za-z0-9-_]+)) .*/i ) ) {
return s . auto _join _text _reply ;
} else if ( text . match ( url _regexp ) ) {
return s . auto _join _text _url ;
} else if ( text . match ( /^((\w+ed)|just) .*/im ) ) {
return s . auto _join _text _ed ;
} else if ( text . match ( /^(\w*ing) .*/i ) ) {
return s . auto _join _text _ing ;
} else {
return s . auto _join _text _default ;
}
}
function build _api _url ( ) {
2014-04-24 04:55:14 +00:00
var proto = ( 'https:' === document . location . protocol ? 'https:' : 'http:' ) ;
2012-01-16 01:35:36 +00:00
var count = ( s . fetch === null ) ? s . count : s . fetch ;
var common _params = '&include_entities=1&callback=?' ;
if ( s . list ) {
return proto + "//" + s . twitter _api _url + "/1/" + s . username [ 0 ] + "/lists/" + s . list + "/statuses.json?page=" + s . page + "&per_page=" + count + common _params ;
} else if ( s . favorites ) {
return proto + "//" + s . twitter _api _url + "/favorites/" + s . username [ 0 ] + ".json?page=" + s . page + "&count=" + count + common _params ;
2014-04-24 04:55:14 +00:00
} else if ( s . query === null && s . username . length === 1 ) {
2012-01-16 01:35:36 +00:00
return proto + '//' + s . twitter _api _url + '/1/statuses/user_timeline.json?screen_name=' + s . username [ 0 ] + '&count=' + count + ( s . retweets ? '&include_rts=1' : '' ) + '&page=' + s . page + common _params ;
} else {
var query = ( s . query || 'from:' + s . username . join ( ' OR from:' ) ) ;
return proto + '//' + s . twitter _search _url + '/search.json?&q=' + encodeURIComponent ( query ) + '&rpp=' + count + '&page=' + s . page + common _params ;
}
}
function extract _avatar _url ( item , secure ) {
if ( secure ) {
return ( 'user' in item ) ?
item . user . profile _image _url _https :
extract _avatar _url ( item , false ) .
replace ( /^http:\/\/[a-z0-9]{1,3}\.twimg\.com\// , "https://s3.amazonaws.com/twitter_production/" ) ;
} else {
return item . profile _image _url || item . user . profile _image _url ;
}
}
// Convert twitter API objects into data available for
// constructing each tweet <li> using a template
function extract _template _data ( item ) {
var o = { } ;
o . item = item ;
o . source = item . source ;
o . screen _name = item . from _user || item . user . screen _name ;
o . avatar _size = s . avatar _size ;
o . avatar _url = extract _avatar _url ( item , ( document . location . protocol === 'https:' ) ) ;
2014-04-24 04:55:14 +00:00
o . retweet = typeof ( item . retweeted _status ) !== 'undefined' ;
2012-01-16 01:35:36 +00:00
o . tweet _time = parse _date ( item . created _at ) ;
2014-04-24 04:55:14 +00:00
o . join _text = s . join _text === "auto" ? build _auto _join _text ( item . text ) : s . join _text ;
2012-01-16 01:35:36 +00:00
o . tweet _id = item . id _str ;
o . twitter _base = "http://" + s . twitter _url + "/" ;
o . user _url = o . twitter _base + o . screen _name ;
o . tweet _url = o . user _url + "/status/" + o . tweet _id ;
o . reply _url = o . twitter _base + "intent/tweet?in_reply_to=" + o . tweet _id ;
o . retweet _url = o . twitter _base + "intent/retweet?tweet_id=" + o . tweet _id ;
o . favorite _url = o . twitter _base + "intent/favorite?tweet_id=" + o . tweet _id ;
o . retweeted _screen _name = o . retweet && item . retweeted _status . user . screen _name ;
o . tweet _relative _time = relative _time ( o . tweet _time ) ;
o . entities = item . entities ? ( item . entities . urls || [ ] ) . concat ( item . entities . media || [ ] ) : [ ] ;
o . tweet _raw _text = o . retweet ? ( 'RT @' + o . retweeted _screen _name + ' ' + item . retweeted _status . text ) : item . text ; // avoid '...' in long retweets
o . tweet _text = $ ( [ linkURLs ( o . tweet _raw _text , o . entities ) ] ) . linkUser ( ) . linkHash ( ) [ 0 ] ;
o . tweet _text _fancy = $ ( [ o . tweet _text ] ) . makeHeart ( ) . capAwesome ( ) . capEpic ( ) [ 0 ] ;
// Default spans, and pre-formatted blocks for common layouts
o . user = t ( '<a class="tweet_user" href="{user_url}">{screen_name}</a>' , o ) ;
o . join = s . join _text ? t ( ' <span class="tweet_join">{join_text}</span> ' , o ) : ' ' ;
o . avatar = o . avatar _size ?
t ( '<a class="tweet_avatar" href="{user_url}"><img src="{avatar_url}" height="{avatar_size}" width="{avatar_size}" alt="{screen_name}\'s avatar" title="{screen_name}\'s avatar" border="0"/></a>' , o ) : '' ;
o . time = t ( '<span class="tweet_time"><a href="{tweet_url}" title="view tweet on twitter">{tweet_relative_time}</a></span>' , o ) ;
o . text = t ( '<span class="tweet_text">{tweet_text_fancy}</span>' , o ) ;
o . reply _action = t ( '<a class="tweet_action tweet_reply" href="{reply_url}">reply</a>' , o ) ;
o . retweet _action = t ( '<a class="tweet_action tweet_retweet" href="{retweet_url}">retweet</a>' , o ) ;
o . favorite _action = t ( '<a class="tweet_action tweet_favorite" href="{favorite_url}">favorite</a>' , o ) ;
return o ;
}
return this . each ( function ( i , widget ) {
var list = $ ( '<ul class="tweet_list">' ) ;
var intro = '<p class="tweet_intro">' + s . intro _text + '</p>' ;
var outro = '<p class="tweet_outro">' + s . outro _text + '</p>' ;
var loading = $ ( '<p class="loading">' + s . loading _text + '</p>' ) ;
if ( s . username && typeof ( s . username ) == "string" ) {
s . username = [ s . username ] ;
}
$ ( widget ) . bind ( "tweet:load" , function ( ) {
2014-04-24 04:55:14 +00:00
if ( s . loading _text ) { $ ( widget ) . empty ( ) . append ( loading ) ; }
2012-01-16 01:35:36 +00:00
$ . getJSON ( build _api _url ( ) , function ( data ) {
$ ( widget ) . empty ( ) . append ( list ) ;
2014-04-24 04:55:14 +00:00
if ( s . intro _text ) { list . before ( intro ) ; }
2012-01-16 01:35:36 +00:00
list . empty ( ) ;
var tweets = $ . map ( data . results || data , extract _template _data ) ;
tweets = $ . grep ( tweets , s . filter ) . sort ( s . comparator ) . slice ( 0 , s . count ) ;
list . append ( $ . map ( tweets , function ( o ) { return "<li>" + t ( s . template , o ) + "</li>" ; } ) . join ( '' ) ) .
children ( 'li:first' ) . addClass ( 'tweet_first' ) . end ( ) .
children ( 'li:odd' ) . addClass ( 'tweet_even' ) . end ( ) .
children ( 'li:even' ) . addClass ( 'tweet_odd' ) ;
2014-04-24 04:55:14 +00:00
if ( s . outro _text ) { list . after ( outro ) ; }
2012-01-16 01:35:36 +00:00
$ ( widget ) . trigger ( "loaded" ) . trigger ( ( tweets . length === 0 ? "empty" : "full" ) ) ;
if ( s . refresh _interval ) {
window . setTimeout ( function ( ) { $ ( widget ) . trigger ( "tweet:load" ) ; } , 1000 * s . refresh _interval ) ;
}
} ) ;
} ) . trigger ( "tweet:load" ) ;
} ) ;
} ;
} ) ( jQuery ) ;