Skip to content

Commit 0aa3520

Browse files
author
Dan Drinkard
committed
sync w/ wpost; fixed encapsulation hole, var cleanup
1 parent b7d058c commit 0aa3520

5 files changed

+204
-72
lines changed

jquery.json-feed.js

+67-54
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/**
22
* jquery-json-feed
33
* ================
4-
* JSONP -> html with recursive parsing
4+
* JSONP -> html with recursive parsing, source polling and pagination
5+
* Copyright (c) 2011 Dan Drinkard
6+
* MIT License.
57
*
68
* Usage:
79
* ------
@@ -53,15 +55,16 @@
5355
* `data`
5456
*
5557
*/
56-
(function($, window, undefined){
58+
(function($, window){
5759
$.fn.JSONFeed = function(opts){
58-
5960
var defaults = {
60-
url: 'http://projects.washingtonpost.com/moderation/twitter-feed/washington-post-tweets/recent.json',
61+
url: 'http://api.twitter.com/1/statuses/public_timeline.json',
6162
jsonp: 'callback',
6263
jsonpCallback: '?',
6364
iterator: function(data){ return data; },
6465
num: 5,
66+
avatar_width: 48,
67+
avatar_height: 48,
6568
poll: 0,
6669
pollUrlGenerator: function(prev_url, prev_response, options){
6770
return prev_url;
@@ -70,25 +73,26 @@
7073
paginationUrlGenerator: function(prev_url, prev_response, options){
7174
return prev_url;
7275
},
73-
spinner: '<span>Loading...</span>',
74-
newTweetsMessage: '<a href="#">Click to show new tweets.</a>',
76+
spinner: '<span class="jf-loading">Loading...</span>',
77+
newContentMessage: '<a href="#">Click to show new tweets.</a>',
7578
paginationButton: '<a href="#">Load more...</a>',
7679
template: '<p style="color:#a00">You haven&apos;t set a template for this feed!</p>',
7780
jsonVarP: /\{\{([^\}]+)\}\}/gm,
7881
optionP: /\{%([^%]+)%\}/gm,
79-
renderCallback: function(str){return str},
82+
renderCallback: function(str){return str;},
8083
appendCallback: function(){}
81-
},
82-
options = $.extend({}, defaults, opts),
84+
}, is_unique, request, render, pageFactory, poll, paginate;
85+
// confirms uniqueness of generated element for pagination & polling
8386
is_unique = function(el){
8487
if($(el).attr('id')){
8588
return !$('#'+$(el).attr('id')).length;
8689
}else{
8790
// always unique if no ids
88-
return true
91+
return true;
8992
}
90-
},
91-
request = function(url, ctx){
93+
};
94+
// gets a resource and fires a success callback
95+
request = function(url, ctx, options){
9296
var self = $(ctx),
9397
action = (self.attr('className').match(/page-/)!== null ? 'poll': 'page'),
9498
num = self.parent().attr('data-num') || options.num,
@@ -100,30 +104,35 @@
100104
var objs = options.iterator(data);
101105
$.each(objs, function(idx, item){
102106
// exempt from limit if this is a polling request
103-
if(idx<num || action=='poll'){
104-
var el = $(render(item));
107+
if(idx<num || action==='poll'){
108+
var el = $(render(item, options));
105109
if(is_unique(el)){
106110
self.append(el);
107111
}
108112
}else{
109113
return false;
110114
}
111115
});
116+
// handle empty
117+
if(!options.paginate && objs.length === 0 && typeof options.empty !== 'undefined'){
118+
self.append(options.empty);
119+
}
112120
// handle buttons & data cache
113-
if(action=='poll'){
121+
if(action === 'poll'){
114122
if(self.children().length && self.is(':hidden')){
115123
var showBtn = self.siblings('.jf-show-new');
116124
if(showBtn.length){
117125
self.before(showBtn);
118126
}else{
119-
self.before(options.newTweetsMessage).prev().addClass('jf-show-new');
127+
self.before(options.newContentMessage).prev().addClass('jf-show-new')
128+
.hide().slideDown();
120129
}
121130
}
122131
var _poll = self.parent().data('_poll');
123132
_poll['data'] = data;
124133
self.parent().data('_poll', _poll);
125-
}else{
126-
if(objs.length == 0){ // last page
134+
}else{ // this is pagination or first call
135+
if(objs.length === 0){ // last page
127136
self.siblings('.jf-show-more').remove();
128137
}else{
129138
self.siblings('.jf-show-more').removeClass('disabled');
@@ -134,13 +143,12 @@
134143
}
135144
}
136145
}
137-
138146
self.each(options.appendCallback);
139147
}
140-
}
148+
};
141149

142150
if(options.jsonpCallback){
143-
if(options.jsonpCallback != '?'){
151+
if(options.jsonpCallback !== '?'){
144152
ajaxOpts.jsonpCallback = options.jsonpCallback;
145153
ajaxOpts.jsonp = options.jsonp;
146154
}else{
@@ -154,14 +162,15 @@
154162
}else{
155163
ajaxOpts.success([], 'skipped');
156164
}
157-
},
158-
render = function(data){
165+
};
166+
// renders a feed item against the template
167+
render = function(data, options){
159168
// data
160169
var str = options.template.replace(options.jsonVarP, function($0,$1){
161170
var keys = $1.split('.'),
162171
response = data;
163172
$.each(keys, function(idx, key){
164-
if(typeof response[key] != 'undefined'){
173+
if(typeof response[key] !== 'undefined'){
165174
response = response[key];
166175
}else{ response=''; }
167176
});
@@ -172,18 +181,21 @@
172181
var keys = $1.split('.'),
173182
response = options;
174183
$.each(keys, function(idx, key){
175-
if(typeof options[key] != 'undefined'){
184+
if(typeof options[key] !== 'undefined'){
176185
response = response[key];
177-
}else{ response = '' }
186+
}else{ response = ''; }
178187
});
179188
return response;
180189
});
181190
return options.renderCallback(str);
182-
},
191+
};
192+
// returns a page div
183193
pageFactory = function(num){
184194
return '<div class="jf-page page'+num+'"></div>';
185-
}
186-
poll = function(ctx){
195+
};
196+
// generates a request for new content
197+
poll = function(ctx, options){
198+
console.log(ctx, options);
187199
var self = $(ctx),
188200
locals = self.data('_poll');
189201
locals.count += 1;
@@ -196,60 +208,61 @@
196208
}
197209
locals.lastUrl = options.pollUrlGenerator(locals.lastUrl, locals['data'], options);
198210
self.data('_poll', locals);
199-
request(locals.lastUrl, page);
200-
window.setTimeout(function(){poll(self)}, locals.interval*1000);
201-
},
202-
paginate = function(ctx){
211+
request(locals.lastUrl, page, options);
212+
window.setTimeout(function(){poll(self, options);}, locals.interval*1000);
213+
};
214+
// generates a request for old content
215+
paginate = function(ctx, options){
203216
var self = $(ctx),
204217
locals = self.data('_page');
205218
locals.page += 1;
206219
var page = self.find('.jf-page').eq(-1).after(pageFactory(locals.page)).next();
207220
locals.lastUrl = options.paginationUrlGenerator(locals.lastUrl, locals['data'], options);
208221
self.data('_page', locals);
209-
request(locals.lastUrl, page);
222+
request(locals.lastUrl, page, options);
210223
};
211-
224+
// plugin constructor/closure
212225
return $(this).each(function(){
213226
var self = $(this),
214-
locals = {
215-
url: self.attr('data-url') || options.url,
216-
poll: self.attr('data-poll') || options.poll,
217-
paginate: self.attr('data-paginate') || options.paginate
218-
},
227+
options = $.extend({}, defaults, opts, {
228+
url: self.attr('data-url') || opts.url,
229+
poll: self.attr('data-poll') || opts.poll,
230+
paginate: self.attr('data-paginate') || opts.paginate
231+
}),
219232
page = self.append(pageFactory(0)).find('.page0').eq(0);
220-
request(locals.url, page);
233+
request(options.url, page, options);
221234
$(this).delegate('a.jf-show-new', 'click', function(e){
222235
e.preventDefault();
223236
e.stopPropagation();
224-
$(this).nextAll('.jf-page').filter(':hidden').show()
237+
$(this).nextAll('.jf-page').filter(':hidden').show();
225238
$(this).remove();
226239
});
227-
if(locals.poll > 0){
240+
if(options.poll > 0){
228241
self.data('_poll', {
229-
lastUrl: locals.url,
242+
lastUrl: options.url,
230243
lastTime: new Date(),
231-
interval: locals.poll,
244+
interval: options.poll,
232245
count: 0,
233246
page:0
234247
});
235-
window.setTimeout(function(){poll(self)}, locals.poll*1000);
248+
window.setTimeout(function(){poll(self, options);}, options.poll*1000);
236249
}
237-
if(locals.paginate == 'true'){
250+
if(options.paginate === 'true'){
238251
self.data('_page', {
239-
lastUrl: locals.url,
240-
page: 0,
252+
lastUrl: options.url,
253+
page: 0
241254
});
242255
self.append($(options.paginationButton).addClass('jf-show-more').click(function(e){
243256
e.preventDefault();
244-
if(!$(this).hasClass('.disabled')){
257+
if(!$(this).hasClass('disabled')){
245258
$(this).addClass('disabled');
246-
paginate(self);
259+
paginate(self, options);
247260
}
248261
}));
249262
}
250263
});
251-
}
264+
};
252265
$.fn.JSONFeed.docsURL = 'http://github.com/dandrinkard/jquery-json-feed/';
253-
$.fn.JSONFeed.presets = {};
254-
$.fn.JSONFeed.utils = {};
266+
$.fn.JSONFeed.presets = $.fn.JSONFeed.presets || {};
267+
$.fn.JSONFeed.utils = $.fn.JSONFeed.utils || {};
255268
})(jQuery, window);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
(function($){
2+
$.extend($.fn.JSONFeed.presets, {
3+
'tweetriverPaginatedOembed': {
4+
/**
5+
* Twitter User Feed, oEmbed via embedly
6+
* @requires embedly-jquery <https://github.com/embedly/embedly-jquery>
7+
* @requires utils.activateLinks
8+
* @requires utils.hoverCardsWithUsernames
9+
*/
10+
template: '<div class="jf-tweet clearfix" id="tweet-{{id_str}}">\
11+
<a class="jf-avatar" href="http://twitter.com/intent/user?screen_name={{user.screen_name}}"><img src="{{user.profile_image_url}}" alt="{{user.screen_name}}" width="{%avatar_width%}" height="{%avatar_height%}" /></a>\
12+
<p class="jf-tweet"><a class="anywhere-username" href="http://twitter.com/intent/user?screen_name={{user.screen_name}}">{{user.screen_name}}</a> - <span class="tweet-text">{{text}}</span></p>\
13+
<p class="jf-meta"><a class="jf-timestamp tweet-permalink" href="http://twitter.com/{{user.screen_name}}/status/{{id_str}}" title="{{created_at}}"></a>\
14+
<a class="twitter-intent tweet-reply" href="http://twitter.com/intent/tweet?in_reply_to={{id_str}}"><span class="icon"></span> Reply</a>\
15+
<a class="twitter-intent tweet-retweet" href="http://twitter.com/intent/retweet?tweet_id={{id_str}}"><span class="icon"></span> Retweet</a>\
16+
<a class="twitter-intent tweet-favorite" href="http://twitter.com/intent/favorite?tweet_id={{id_str}}"><span class="icon"></span> Favorite</a></p>\
17+
</div>',
18+
iterator: function(data){ return data; },
19+
pollUrlGenerator: function(url, data, options){
20+
var objs = options.iterator(data);
21+
if(objs && objs.length){
22+
var since_id = objs[0].order_id;
23+
if(url.match('since_id') !== null){
24+
url = url.replace(/since_id=[0-9]+/g, 'since_id=' + since_id);
25+
}else{
26+
if(url.match(/\?/) !== null){
27+
url += '&since_id=' + since_id;
28+
}else{
29+
url += '?since_id=' + since_id;
30+
}
31+
}
32+
}
33+
window.console && console.log && console.log('polling:', url);
34+
return url;
35+
},
36+
paginationUrlGenerator: function(url, data, options){
37+
var objs = options.iterator(data);
38+
if(objs && objs.length){
39+
var start = objs[objs.length - 1].order_id;
40+
if(url.match('start') !== null){
41+
url = url.replace(/(&|\?)start=([\d]+)/g, function($0, $1, $2){return $1+'start='+start});
42+
}else{
43+
start = objs[objs.length - 1].order_id;
44+
if(url.match(/\?/) !== null){
45+
url += '&start=' + start;
46+
}else{
47+
url += '?start=' + start;
48+
}
49+
}
50+
}
51+
window.console && console.log && console.log('paginating:', url);
52+
return url;
53+
},
54+
renderCallback: function(str){
55+
var str = $(this).JSONFeed.utils.activateLinks(str);
56+
return $(this).JSONFeed.utils.activateTwitterHashTags(str);
57+
},
58+
appendCallback: function(){
59+
$(this).parent().find('.jf-timestamp').each(function() {
60+
var date = new Date($(this).attr('title').replace('+0000', 'GMT'));
61+
$(this).text(date.toUTCString()).relativeDate();
62+
});
63+
$(this).find('p.jf-tweet a').embedly();
64+
}
65+
}
66+
});
67+
})(jQuery);

presets/jf.preset.twitter-paginated-oembed.js renamed to presets/jf.preset.twitter-paginated.js

+14-17
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
(function($){
22
$.extend($.fn.JSONFeed.presets, {
3-
'twitterPaginatedOembed': {
3+
'twitterPaginated': {
44
/**
5-
* Twitter User Feed, oEmbed via embedly
6-
* @requires twttr.anywhere <http://dev.twitter.com/anywhere>
7-
* @requires embedly-jquery <https://github.com/embedly/embedly-jquery>
5+
* Twitter User Feed
86
* @requires utils.activateLinks
97
* @requires utils.hoverCardsWithUsernames
108
*/
11-
template: '<div class="jf-tweet" id="tweet-{{id_str}}">\
12-
<a href="http://twitter.com/{{user.screen_name}}"><img src="{{user.profile_image_url}}" alt="{{user.screen_name}}" width="{%avatar_width%}" height="{%avatar_height%}" /></a>\
13-
<p class="jf-meta">\
14-
<a class="anywhere-username" href="http://twitter.com/{{user.screen_name}}">{{user.screen_name}}</a> - \
15-
<a class="jf-timestamp" href="http://twitter.com/{{user.screen_name}}/status/{{id_str}}" title="{{created_at}}"></a></p>\
16-
<p class="jf-tweet">{{text}}</p>\
9+
template: '<div class="jf-tweet clearfix" id="tweet-{{id_str}}">\
10+
<a class="jf-avatar" href="http://twitter.com/intent/user?screen_name={{user.screen_name}}"><img src="{{user.profile_image_url}}" alt="{{user.screen_name}}" width="{%avatar_width%}" height="{%avatar_height%}" /></a>\
11+
<p class="jf-tweet"><a class="anywhere-username" href="http://twitter.com/intent/user?screen_name={{user.screen_name}}">{{user.screen_name}}</a> - <span class="tweet-text">{{text}}</span></p>\
12+
<p class="jf-meta"><a class="jf-timestamp tweet-permalink" href="http://twitter.com/{{user.screen_name}}/status/{{id_str}}" title="{{created_at}}"></a>\
13+
<a class="twitter-intent tweet-reply" href="http://twitter.com/intent/tweet?in_reply_to={{id_str}}"><span class="icon"></span> Reply</a>\
14+
<a class="twitter-intent tweet-retweet" href="http://twitter.com/intent/retweet?tweet_id={{id_str}}"><span class="icon"></span> Retweet</a>\
15+
<a class="twitter-intent tweet-favorite" href="http://twitter.com/intent/favorite?tweet_id={{id_str}}"><span class="icon"></span> Favorite</a></p>\
1716
</div>',
1817
iterator: function(data){ return data; },
1918
pollUrlGenerator: function(url, data, options){
2019
var objs = options.iterator(data);
2120
if(objs && objs.length){
2221
var since_id = objs[0].id_str;
2322
if(url.match('since_id') !== null){
24-
url = url.replace(/since_id=[0-9]+/, 'since_id=' + since_id);
23+
url = url.replace(/since_id=[\d]+/g, 'since_id=' + since_id);
2524
}else{
2625
if(url.match(/\?/) !== null){
2726
url += '&since_id=' + since_id;
@@ -36,10 +35,11 @@
3635
paginationUrlGenerator: function(url, data, options){
3736
var objs = options.iterator(data);
3837
if(objs && objs.length){
39-
var max_id = objs[objs.length-1].id_str;
38+
var max_id = objs[objs.length - 1].id_str;
4039
if(url.match('max_id') !== null){
41-
url = url.replace(/max_id=[0-9]+/, 'max_id=' + max_id);
40+
url = url.replace(/(&|\?)max_id=([\d]+)/g, function($0, $1, $2){return $1+'max_id='+max_id});
4241
}else{
42+
max_id = objs[objs.length - 1].id_str;
4343
if(url.match(/\?/) !== null){
4444
url += '&max_id=' + max_id;
4545
}else{
@@ -53,15 +53,12 @@
5353
renderCallback: function(str){
5454
var str = $(this).JSONFeed.utils.activateLinks(str);
5555
return $(this).JSONFeed.utils.activateTwitterHashTags(str);
56-
return str;
5756
},
5857
appendCallback: function(){
5958
$(this).parent().find('.jf-timestamp').each(function() {
60-
var date = new Date(Date.parse($(this).attr('title')));
59+
var date = new Date($(this).attr('title').replace('+0000', 'GMT'));
6160
$(this).text(date.toUTCString()).relativeDate();
6261
});
63-
$(this).JSONFeed.utils.hovercardsWithUsernames(this);
64-
$(this).find('p.jf-tweet a').embedly();
6562
}
6663
}
6764
});

0 commit comments

Comments
 (0)