forked from scala/docs.scala-lang
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtweetMachine-update.js
executable file
·414 lines (364 loc) · 19.7 KB
/
tweetMachine-update.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
/*
* jQuery TweetMachine v0.2.1b
* GitHub: https://github.com/ryangiglio/jquery-tweetMachine
* Copyright (c) 2013 Ryan Giglio (@ryangiglio)
*/
(function ($) {
// Plugin body
$.fn.tweetMachine = function (query, options, callback) {
// For each instance of the plugin
$(this).each(function () {
var settings, tweetMachine;
// If this.tweetMachine is already initialized, just change the settings
if (this.tweetMachine) {
// Overwrite the initialized/default settings
settings = $.extend(this.tweetMachine.settings, options);
this.tweetMachine.settings = settings;
// If a new query has been passed
if (query) {
// Replace the old query
this.tweetMachine.query = query;
}
// If a tweet interval is already set up
if (this.tweetMachine.interval) {
// Refresh now so the new settings can kick in
this.tweetMachine.refresh();
}
// If a new callback was passed
if (callback) {
// Replace the old callback
this.tweetMachine.callback = callback;
}
} else { // It's not initialized, so let's do that
settings = $.extend({
backendScript: '/webscripts/ajax/getFromTwitter.php', // Path to your backend script that holds your Twitter credentials and calls the API
endpoint: 'statuses/user_timeline', // Twitter API endpoint to call. Currently only search/tweets is supported
user_name: 'scala_lang', // Set your username
include_retweets: true, // Set to true or false if you want to include retweets
exclude_replies: false, // Set to true or false if you want to exclude replies
rate: 5000, // Rate in ms to refresh the tweets. Any higher than 5000 for search/tweets will get you rate limited
limit: 5, // Number of tweets to display at a time
autoRefresh: true, // CURRENTLY REQUIRED. Auto-refresh the tweets
animateOut: false, // NOT YET SUPPORTED. Animate out old tweets.
animateIn: true, // Fade in new tweets.
pageLimit: 0, // Number of tweets per page. If equals 0, tweets won't be paginated.
tweetFormat: "<li class='tweet'><img class='avatar' src=''/><div class='meta'><a href='' class='username'></a><a href='' class='time'></a></div><p class='content'></p></li>", // Format for each tweet
localization: { // Verbiage to use for timestamps
seconds: 'seconds ago',
minute: 'a minute ago',
minutes: 'minutes ago',
hour: 'an hour ago',
hours: 'hours ago',
day: 'a day ago',
days: 'days ago'
},
filter: false // Function to filter tweet results.
}, options);
this.tweetMachine = {
settings: settings, // Set the settings object
query: query, // Set the query to search for
interval: false, // This will hold the refresh interval when it is created
container: this, // Set the object that contains the tweets
lastTweetID: null, // This will hold the ID of the last tweet displayed
callback: callback, // This callback will run after each refresh
/*
* Function to generate a relative timestamp from Twitter's time string
*/
relativeTime: function (timeString) {
var delta, parsedDate, r;
// Create a Date object
parsedDate = Date.parse(timeString);
// Get the number of seconds ago that the tweet was created
delta = (Date.parse(Date()) - parsedDate) / 1000;
// String to hold the relative time
r = '';
// If it was less than a minute ago
if (delta < 60) {
r = delta + " " + settings.localization.seconds;
// If it was less than 2 minutes ago
} else if (delta < 120) {
r = settings.localization.minute;
// If it was less than 45 minutes ago
} else if (delta < (45 * 60)) {
r = (parseInt(delta / 60, 10)).toString() + " " + settings.localization.minutes;
// If it was less than 90 minutes ago
} else if (delta < (90 * 60)) {
r = settings.localization.hour;
// If it was less than a day ago
} else if (delta < (24 * 60 * 60)) {
r = '' + (parseInt(delta / 3600, 10)).toString() + " " + settings.localization.hours;
// If it was less than 2 days ago
} else if (delta < (48 * 60 * 60)) {
r = settings.localization.day;
} else {
r = (parseInt(delta / 86400, 10)).toString() + " " + settings.localization.days;
}
return r;
},
/*
* Function to update the timestamps of each tweet
*/
updateTimestamps: function () {
var tweetMachine;
tweetMachine = this;
// Loop over each timestamp
$(tweetMachine.container).find('.time').each(function () {
var originalTime, timeElement;
// Save a reference to the time element
timeElement = $(this);
// Get the original time from the data stored on the timestamp
originalTime = timeElement.data('timestamp');
// Generate and show a new time based on the original time
timeElement.html(tweetMachine.relativeTime(originalTime));
});
},
/*
* Function to parse the text of a tweet and and add links to links, hashtags, and usernames
*/
parseText: function (text) {
// Links
text = text.replace(/[A-Za-z]+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+/g, function (m) {
return '<a href="' + m + '" target="_blank">' + m + '</a>';
});
// Usernames
text = text.replace(/@[A-Za-z0-9_]+/g, function (u) {
return '<a href="https://twitter.com/#!/' + u.replace(/^@/, '') + '" target="_blank">' + u + '</a>';
});
// Hashtags
text = text.replace(/#[A-Za-z0-9_\-]+/g, function (u) {
return '<a href="https://twitter.com/#!/search?q=' + u.replace(/^#/, '%23') + '" target="_blank">' + u + '</a>';
});
return text;
},
/*
* Function to build the tweet as a jQuery object
*/
buildTweet: function (tweet) {
var tweetMachine, tweetObj;
tweetMachine = this;
var actualTweet = /^RT/.test(tweet.text) ? tweet.retweeted_status : tweet;
// Create the tweet from the tweetFormat setting
tweetObj = $(tweetMachine.settings.tweetFormat);
// Set the avatar. NOTE: reasonably_small is Twitter's suffix for the largest square avatar that they store
tweetObj.find('.avatar')
.attr('src', actualTweet.user.profile_image_url_https.replace("normal", "reasonably_small"));
// Set the user screen name
var usernameLink = "<a target=\"_blank\" href=\""
+ "https://twitter.com/"
+ actualTweet.user.screen_name
+ "\">"
+ "@"
+ actualTweet.user.screen_name
+ "</a>";
tweetObj.find('.username').html("" + usernameLink);
// Set the username:
var userLink = "<a target=\"_blank\" href=\""
+ "https://twitter.com/"
+ actualTweet.user.screen_name
+ "\">"
+ actualTweet.user.name
+ "</a>";
tweetObj.find('.user').html("" + userLink);
// Set the timestamp
var dateLink = "<a target=\"_blank\" href=\"" + "https://twitter.com/"
+ actualTweet.user.screen_name + "/status/"
+ actualTweet.id_str + "\">"
+ tweetMachine.relativeTime(actualTweet.created_at)
+ "</a>";
tweetObj.find('.date')
.html("" + dateLink)
// Save the created_at time as jQuery data so we can update it later
.data('timestamp', actualTweet.created_at);
// Set the text
tweetObj.find('.main-tweet')
.html("<p>" + tweetMachine.parseText(actualTweet.text) + "</p>");
// If we are animating in the new tweets
if (tweetMachine.settings.animateIn) {
// Set the opacity to 0 so it can fade in
tweetObj.css('opacity', '0');
}
return tweetObj;
},
/*
* Function to handle the reloading of tweets
*/
refresh: function (firstLoad) {
var queryParams, tweetMachine;
tweetMachine = this;
// If it is the first load or we're refreshing automatically
if (firstLoad || tweetMachine.settings.autoRefresh) {
// Set the query parameters that the endpoint needs
/*
* Twitter feed for search through tweets only
* API Reference: https://dev.twitter.com/docs/api/1.1/get/search/tweets
*/
if (tweetMachine.settings.endpoint === "search/tweets") {
queryParams = {
q: tweetMachine.query,
count: (this.settings.requestLimit) ? this.settings.requestLimit: this.settings.limit,
since_id: tweetMachine.lastTweetID
};
}
/*
* Twitter feed for username only
* API Reference: https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
*/
if (tweetMachine.settings.endpoint === "statuses/user_timeline") {
queryParams = {
screen_name: settings.user_name,
count: (this.settings.requestLimit) ? this.settings.requestLimit: this.settings.limit,
include_rts: settings.include_retweets,
exclude_replies: settings.exclude_replies
};
}
// Call your backend script to get JSON back from Twitter
$.getJSON(tweetMachine.settings.backendScript, {
endpoint: tweetMachine.settings.endpoint,
queryParams: queryParams
}, function (tweets) {
var tweetsDisplayed;
var pagesDisplayed;
// If we got a response from Twitter
if ( tweets[0] ) {
// If there is an error message
if ( tweets[0].message ) {
// If there is already an error displayed
if ( $('.twitter-error').length ) {
// Update the error message
$('.twitter-error').html('<p class="tweet-machine-error">Error ' + tweets[0].code + ': ' + tweets[0].message + '</p>');
}
else { // There isn't an error displayed yet
// Display an error message above the container
$(tweetMachine.container).before('<p class="twitter-error">Error ' + tweets[0].code + ': ' + tweets[0].message + '</p>');
}
}
// There are tweets
else {
// If there was an error before
if ( $('.twitter-error').length ) {
// Remove it
$('.twitter-error').remove();
}
// Reverse them so they are added in the correct order
tweets.reverse();
// Count the number of tweets displayed
tweetsDisplayed = 0;
// Count the pages:
pagesDisplayed = 0;
// Loop through each tweet
$.each(tweets, function () {
var tweet, tweetObj;
tweet = this;
// If there is no filter, or this tweet passes the filter
if (!tweetMachine.settings.filter || tweetMachine.settings.filter(this)) {
// Build the tweet as a jQuery object
tweetObj = tweetMachine.buildTweet(tweet);
if (tweetMachine.settings.pageLimit > 0) {
tweetObj.addClass("page" + pagesDisplayed);
}
//// If there are already tweets on the screen
//if (!firstLoad) {
//
// // If we are animating out the old tweets
// if (tweetMachine.settings.animateOut) {
// /*
// * TODO Support this feature
// */
// } else { // We are not animating the old tweets
// // Remove them
// $(tweetMachine.container).children(':last-child').remove();
// }
//}
// Prepend the new tweet
$(tweetMachine.container).prepend(tweetObj);
// If we are animating in the new tweets
//if (tweetMachine.settings.animateIn) {
// // Fade in the new tweet
// /*
// * TODO Figure out why .fadeIn() doesn't work
// */
// $(tweetMachine.container).children(':first-child').animate({
// opacity: 1
// });
//}
// Increment the tweets diplayed
tweetsDisplayed++;
// Increase page number and wrap tweets if pagination is enabled and we're finishing a page:
if (tweetMachine.settings.pageLimit > 0 && tweetsDisplayed % tweetMachine.settings.pageLimit == 0) {
$(".page" + pagesDisplayed).wrapAll("<li></li>");
pagesDisplayed++;
}
// Save this tweet ID so we only get newer noes
tweetMachine.lastTweetID = tweet.id_str;
// If we've reached the limit of tweets to display
if (tweetsDisplayed > tweetMachine.settings.limit) {
// Quit the loop
return false;
}
}
});
}
}
//Callback function
if (typeof tweetMachine.callback === "function") {
if(typeof tweets === 'undefined' || typeof tweetsDisplayed === 'undefined' ) {
tweets = null;
tweetsDisplayed = 0;
}
tweetMachine.callback(tweets, tweetsDisplayed);
}
});
}
/* TODO: Implement an "x new Tweets, click to refresh" link if auto refresh is turned off
else {
}
*/
},
// Start refreshing
start: function () {
var tweetMachine;
tweetMachine = this;
// If there's no interval yet
if (!this.interval) {
// Create an interval to refresh after the rate has passed
this.interval = setInterval(function () {
tweetMachine.refresh();
}, tweetMachine.settings.rate);
// Start refreshing with the firstLoad flag = true
this.refresh(true);
}
},
// Stop refreshing
stop: function () {
var tweetMachine;
tweetMachine = this;
// If there is an interval
if (tweetMachine.interval) {
// Clear it
clearInterval(tweetMachine.interval);
// Remove the reference to it
tweetMachine.interval = false;
}
},
// Clear all tweets
clear: function () {
var tweetMachine;
tweetMachine = this;
// Remove all tweets
$(tweetMachine.container).find('.tweet').remove();
// Set the lastTweetID to null so we start clean next time
tweetMachine.lastTweetID = null;
}
};
// Save a global tweetMachine object
tweetMachine = this.tweetMachine;
// Create an interval to update the timestamps
this.timeInterval = setInterval(function () {
tweetMachine.updateTimestamps();
}, tweetMachine.settings.rate);
// Start the Machine!
this.tweetMachine.start();
}
});
};
})(jQuery);