root / drupal7 / sites / all / themes / simplecorp / js / plugins / jquery.jtweetsanywhere-1.3.1.js @ bad93dab
1 | b9383c72 | Julien Enselme | /**
|
---|---|---|---|
2 | * jTweetsAnywhere V1.3.1
|
||
3 | * http://thomasbillenstein.com/jTweetsAnywhere/
|
||
4 | *
|
||
5 | * Copyright 2011, Thomas Billenstein
|
||
6 | * Licensed under the MIT license.
|
||
7 | * http://thomasbillenstein.com/jTweetsAnywhere/license.txt
|
||
8 | */
|
||
9 | |||
10 | |||
11 | /**
|
||
12 | * The code below is used as supplied by Twitter (https://dev.twitter.com/docs/intents)
|
||
13 | *
|
||
14 | * Twitter says:
|
||
15 | |||
16 | * "Some sites may prefer to embed the unobtrusive Web Intents pop-up Javascript inline
|
||
17 | * or without a dependency to platform.twitter.com. The snippet below will offer the
|
||
18 | * equivalent functionality without the external dependency."
|
||
19 | */
|
||
20 | (function()
|
||
21 | { |
||
22 | if (window.__twitterIntentHandler)
|
||
23 | return;
|
||
24 | |||
25 | var intentRegex = /twitter\.com(\:\d{2,4})?\/intent\/(\w+)/, |
||
26 | windowOptions = 'scrollbars=yes,resizable=yes,toolbar=no,location=yes',
|
||
27 | width = 550,
|
||
28 | height = 420,
|
||
29 | winHeight = screen.height, |
||
30 | winWidth = screen.width; |
||
31 | |||
32 | |||
33 | function handleIntent(e) |
||
34 | { |
||
35 | e = e || window.event; |
||
36 | |||
37 | var target = e.target || e.srcElement,
|
||
38 | m, left, top; |
||
39 | |||
40 | while (target && target.nodeName.toLowerCase() !== 'a') |
||
41 | { |
||
42 | target = target.parentNode; |
||
43 | } |
||
44 | |||
45 | if (target && target.nodeName.toLowerCase() === 'a' && target.href) |
||
46 | { |
||
47 | m = target.href.match(intentRegex); |
||
48 | if (m)
|
||
49 | { |
||
50 | left = Math.round((winWidth / 2) - (width / 2)); |
||
51 | top = 0;
|
||
52 | |||
53 | if (winHeight > height)
|
||
54 | { |
||
55 | top = Math.round((winHeight / 2) - (height / 2)); |
||
56 | } |
||
57 | |||
58 | window.open(target.href, 'intent', windowOptions + ',width=' + width + ',height=' + height + ',left=' + left + ',top=' + top); |
||
59 | e.returnValue = false;
|
||
60 | e.preventDefault && e.preventDefault(); |
||
61 | } |
||
62 | } |
||
63 | } |
||
64 | |||
65 | if (document.addEventListener)
|
||
66 | { |
||
67 | document.addEventListener('click', handleIntent, false); |
||
68 | } |
||
69 | else if (document.attachEvent) |
||
70 | { |
||
71 | document.attachEvent('onclick', handleIntent);
|
||
72 | } |
||
73 | |||
74 | window.__twitterIntentHandler = true;
|
||
75 | }()); |
||
76 | |||
77 | |||
78 | /**
|
||
79 | * JTA_I18N is based on SimpleI18N V0.1.0
|
||
80 | *
|
||
81 | * SimpleI18N.js is a tiny library for simple i18n support in Javascript.
|
||
82 | * Currently only translation is supported.
|
||
83 | */
|
||
84 | (function()
|
||
85 | { |
||
86 | if (window.__JTA_I18N)
|
||
87 | { |
||
88 | return;
|
||
89 | } |
||
90 | |||
91 | JTA_I18N = function() |
||
92 | { |
||
93 | var _resources = {};
|
||
94 | |||
95 | function ResourceBundle(locale, resources) |
||
96 | { |
||
97 | this.getLocale = function() |
||
98 | { |
||
99 | return locale;
|
||
100 | }; |
||
101 | |||
102 | this.get = function(key, params) |
||
103 | { |
||
104 | return xlate(key, 1, params); |
||
105 | }; |
||
106 | |||
107 | this._ = this.get; |
||
108 | |||
109 | this.nget = function(singular, plural, count, params) |
||
110 | { |
||
111 | return count === 1 ? xlate(singular, 1, params) : xlate(plural, count, params); |
||
112 | }; |
||
113 | |||
114 | this.__ = this.nget; |
||
115 | |||
116 | function xlate(key, count, params) |
||
117 | { |
||
118 | var resource = getValue(key);
|
||
119 | |||
120 | if (count !== 1 && typeof resource === "object") |
||
121 | { |
||
122 | resource = evalMulti(key, resource, count); |
||
123 | } |
||
124 | |||
125 | if (resource && params)
|
||
126 | { |
||
127 | for (p in params) |
||
128 | { |
||
129 | resource = resource.replace(p, getValue(params[p])); |
||
130 | } |
||
131 | } |
||
132 | |||
133 | return resource;
|
||
134 | }; |
||
135 | |||
136 | function getValue(resource) |
||
137 | { |
||
138 | return resources ? (resources[resource] || resource) : resource;
|
||
139 | }; |
||
140 | |||
141 | function evalMulti(key, resource, count) |
||
142 | { |
||
143 | for (pat in resource) |
||
144 | { |
||
145 | var re = /(\d+)\s*-\s*(\d+)/, |
||
146 | match = re.exec(pat); |
||
147 | |||
148 | if (match)
|
||
149 | { |
||
150 | var from = match[1]; |
||
151 | var to = match[2]; |
||
152 | if (count >= from && count <= to)
|
||
153 | { |
||
154 | return resource[pat];
|
||
155 | } |
||
156 | } |
||
157 | |||
158 | re = /([<>]=?)\s*(\d+)/;
|
||
159 | match = re.exec(pat); |
||
160 | |||
161 | if (match)
|
||
162 | { |
||
163 | var op = match[1]; |
||
164 | var num = match[2]; |
||
165 | if (op === '>' && count > num) |
||
166 | { |
||
167 | return resource[pat];
|
||
168 | } |
||
169 | else if (op === '>=' && count >= num) |
||
170 | { |
||
171 | return resource[pat];
|
||
172 | } |
||
173 | else if (op === '<' && count < num) |
||
174 | { |
||
175 | return resource[pat];
|
||
176 | } |
||
177 | else if (op === '<=' && count <= num) |
||
178 | { |
||
179 | return resource[pat];
|
||
180 | } |
||
181 | } |
||
182 | |||
183 | re = /\s*,\s*/;
|
||
184 | match = pat.split(re); |
||
185 | |||
186 | if (match)
|
||
187 | { |
||
188 | for (var i = 0; i < match.length; i++) |
||
189 | { |
||
190 | if (count === ~~match[i])
|
||
191 | { |
||
192 | return resource[pat];
|
||
193 | } |
||
194 | } |
||
195 | } |
||
196 | } |
||
197 | |||
198 | return key;
|
||
199 | } |
||
200 | }; |
||
201 | |||
202 | return {
|
||
203 | |||
204 | addResourceBundle: function(project, locale, resources) |
||
205 | { |
||
206 | if (!_resources[project])
|
||
207 | { |
||
208 | _resources[project] = {}; |
||
209 | } |
||
210 | |||
211 | _resources[project][locale] = resources; |
||
212 | }, |
||
213 | |||
214 | getResourceBundle: function(project, locale) |
||
215 | { |
||
216 | return new ResourceBundle(locale, _resources[project] ? _resources[project][locale] : null); |
||
217 | } |
||
218 | }; |
||
219 | }(); |
||
220 | |||
221 | window.__JTA_I18N = true;
|
||
222 | }()); |
||
223 | |||
224 | JTA_I18N.addResourceBundle('jTweetsAnywhere', 'en', |
||
225 | { |
||
226 | '$$monthNames': [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ] |
||
227 | }); |
||
228 | |||
229 | (function($) |
||
230 | { |
||
231 | $.fn.jTweetsAnywhere = function(config) |
||
232 | { |
||
233 | // setup the default options
|
||
234 | var options = $.extend( |
||
235 | { |
||
236 | /**
|
||
237 | * The user's name who's tweet feed or list feed is displayed. This
|
||
238 | * param is also used when a Twitter "Follow Button" is displayed. Usually
|
||
239 | * this param is a string, but can also be an array of strings. If an array
|
||
240 | * is supplied (and the params 'list' and 'searchParams' are null), a
|
||
241 | * combined feed of all users is displayed.
|
||
242 | *
|
||
243 | * Sample: 'tbillenstein' or ['twitterapi', '...', '...']
|
||
244 | */
|
||
245 | username: 'morethanthemes', |
||
246 | |||
247 | /**
|
||
248 | * The name of a user's list where the tweet feed is generated from. The special
|
||
249 | * list name 'favorites' can be used to display a user's favorited tweets.
|
||
250 | */
|
||
251 | list: null, |
||
252 | |||
253 | /**
|
||
254 | * A single search param string or an array of search params, to be used in
|
||
255 | * a Twitter search call. All Twitter Search Params are supported
|
||
256 | * See here for the details:
|
||
257 | * http://apiwiki.twitter.com/Twitter-Search-API-Method%3A-search
|
||
258 | *
|
||
259 | * Sample: 'q=twitter' or ['q=twitter', 'geocode=48.856667,2.350833,30km']
|
||
260 | */
|
||
261 | searchParams: null, |
||
262 | |||
263 | /**
|
||
264 | * The number of tweets shown in the tweet feed. If this param is 0, no feed
|
||
265 | * is displayed. For user or list feeds the maximum count is 20, for search
|
||
266 | * results the maximum count is 100.
|
||
267 | *
|
||
268 | * Unlike in previous releases, since 1.2.0 jTweetsAnywhere is based on a
|
||
269 | * tweets caching algorithm that will always deliver the requested count of
|
||
270 | * tweets accepting that this request can only be fullfilled by calling Twitter
|
||
271 | * more than once.
|
||
272 | *
|
||
273 | * IMPORTANT: Please always keep in mind, that the use of the Twitter API is
|
||
274 | * rate limited. Non-authenticated users are rated IP-based and you have only
|
||
275 | * 150 calls per hour available. Every retrieval of tweets counts and so does
|
||
276 | * for example hovering over a profile image to show the hovercard.
|
||
277 | * jTweetsAnywhere will always check the remaining count of free API calls before
|
||
278 | * actually calling Twitter to avoid black listing your visitor's IP.
|
||
279 | */
|
||
280 | count: 0, |
||
281 | |||
282 | /**
|
||
283 | * A flag (true/false) that specifies whether to display a profile image in
|
||
284 | * tweets. If the param is set to null (the default value), a profile image
|
||
285 | * is displayed only if the feed represents a user's list or the result of a
|
||
286 | * Twitter search.
|
||
287 | *
|
||
288 | * THIS OPTION IS DEPRECATED. You should use showTweetFeed.showProfileImages
|
||
289 | * instead.
|
||
290 | */
|
||
291 | tweetProfileImagePresent: null, |
||
292 | |||
293 | /**
|
||
294 | * Each tweet that is loaded from Twitter will pass the tweetFilter. if
|
||
295 | * the filter returns true, the tweet will be added to the tweets cache
|
||
296 | * otherwise it is ignored. The defaultTweetFilter alsways retruns true
|
||
297 | * but you can supply your own tweet filter to customize the tweet feed.
|
||
298 | */
|
||
299 | tweetFilter: defaultTweetFilter,
|
||
300 | |||
301 | /**
|
||
302 | * A flag (true/false) that specifies whether to display a Tweet Feed
|
||
303 | * or an object literal representing the configuration options for the
|
||
304 | * Tweet Feed. This flag works in conjunction with the count parameter:
|
||
305 | * - if count equals 0, no feed is displayed, ignoring showTweetFeed
|
||
306 | * - if count not equals 0 and showTweetFeed equals false, no feed
|
||
307 | * is displayed
|
||
308 | * {
|
||
309 | * autoConformToTwitterStyleguide: false,
|
||
310 | * // Boolean - as the name implies, sets all options to confirm to Twitter's
|
||
311 | * // styleguide regulations. Implies:
|
||
312 | * // showTweetFeed: {
|
||
313 | * // showUserFullNames: null, // null means: if usernames are shown, show
|
||
314 | * // // fullnames too
|
||
315 | * // showTwitterBird: true,
|
||
316 | * // showActionReply: true,
|
||
317 | * // showActionRetweet: true,
|
||
318 | * // showActionFavorite: true
|
||
319 | * // }
|
||
320 | *
|
||
321 | * showTwitterBird: true, // Boolean - show Twitter bird icon beneath the timestamp of a tweet, linking to
|
||
322 | * // the tweeter's MiniProfile Web Intent
|
||
323 | *
|
||
324 | * showTimestamp: true, // A flag (true/false) that specifies whether to display a tweet's timestamp
|
||
325 | * // or an object literal representing the configuration options for the
|
||
326 | * // timestamp.
|
||
327 | * // {
|
||
328 | * // refreshInterval: 0, // Time in seconds to be waited until the
|
||
329 | * // // timestamps of the displayed tweets get refreshed
|
||
330 | * // // 0 means no refreshing.
|
||
331 | * // }
|
||
332 | *
|
||
333 | * showSource: false, // Boolean - Show info about the source of the tweet.
|
||
334 | *
|
||
335 | * showGeoLocation: true, // Boolean - Show geolocation info and link to Google maps.
|
||
336 | *
|
||
337 | * showInReplyTo: true, // Boolean - Show link to the "replied to" tweet (if available).
|
||
338 | *
|
||
339 | * showActionReply: false, // Boolean - Show tweet's 'Reply' action (supplies a link to popup the tweet's
|
||
340 | * // Reply Web Intent)
|
||
341 | *
|
||
342 | * showActionRetweet: false, // Boolean - Show tweet's 'Retweet' action (supplies a link to popup the tweet's
|
||
343 | * // Retweet Web Intent)
|
||
344 | *
|
||
345 | * showActionFavorite: false, // Boolean - Show tweet's 'Favorite' action (supplies a link to popup the tweet's
|
||
346 | * // Favorite Web Intent)
|
||
347 | *
|
||
348 | * showProfileImages: null, // A flag (true/false) that specifies whether to display a profile image in
|
||
349 | * // tweets. If the param is set to null (the default value), a profile image
|
||
350 | * // is displayed only if the feed represents a user's list or the result of a
|
||
351 | * // Twitter search.
|
||
352 | *
|
||
353 | * showUserScreenNames: null, // A flag (true/false/null) that specifies whether to display a username in
|
||
354 | * // tweets. If the param is set to null (the default value), a username
|
||
355 | * // is displayed only if the feed represents a user's list or the result of a
|
||
356 | * // Twitter search.
|
||
357 | *
|
||
358 | * showUserFullNames: false, // A flag (true/false/null) that specifies whether to display a user's full name
|
||
359 | * // in tweets. If the param is set to null, a user's full name
|
||
360 | * // is displayed only if the feed represents a user's list or the result of a
|
||
361 | * // Twitter search.
|
||
362 | *
|
||
363 | * expandHovercards: false, // Boolean - Show Hovercards in expanded mode.
|
||
364 | *
|
||
365 | * includeRetweets: true, // Boolean - Include native retweets in a user's tweet feed
|
||
366 | *
|
||
367 | * paging: // An object literal representing the configuration options for the
|
||
368 | * { // paging support, that specifies how more/earlier tweets can be loaded
|
||
369 | * mode: "none" // by using the supplied UI controls (more/next buttons, scrollbar).
|
||
370 | * }, // Accepted values for mode are: "none" | "more" | "prev-next" | "endless-scroll"
|
||
371 | * // if mode equals "endless-scroll" you have to set the height of the tweet feed
|
||
372 | * // element (.jta-tweet-list) in your CSS to get a scrollbar! You should also set
|
||
373 | * // the "overflow" attribute to "auto".
|
||
374 | *
|
||
375 | * autorefresh: // An object literal representing the configuration options for the
|
||
376 | * { // autorefresh behaviour.
|
||
377 | *
|
||
378 | * // IMPORTANT: Please always keep in mind, that using the Twitter API is rate
|
||
379 | * // limited. Non-authenticated users are rated IP-based and you have only 150
|
||
380 | * // calls per hour available. Every retrieval of tweets counts and so does for
|
||
381 | * // example hovering over a profile image to show the hovercard. jTweetsAnywhere will
|
||
382 | * // always check the remaining count of free API calls before actually calling
|
||
383 | * // Twitter to avoid black listing your visitor's IP.
|
||
384 | *
|
||
385 | * // However - choose your settings wisely to keep your visitors happy. An update
|
||
386 | * // interval of 30 seconds on a feed that is updated averaged once per hour
|
||
387 | * // does not make sense and is a total waste of remaining API calls!
|
||
388 | *
|
||
389 | * mode: "none", // Accepted values for mode are: "none" | "auto-insert" | "trigger-insert"
|
||
390 | * // "none" (the default value) - disables the autorefresh feature
|
||
391 | * // "auto-insert" - automatically insert the new tweets on top of the tweet feed
|
||
392 | * // "trigger-insert" - if new tweets arrived, show or update a button that displays
|
||
393 | * // the number of new tweets. These new tweets are inserted on top of the tweet
|
||
394 | * // feed, if the user clicks on the button.
|
||
395 | *
|
||
396 | * interval: 60, // Time in seconds to be waited until the next request for new tweets. Minimum
|
||
397 | * // value is 30.
|
||
398 | *
|
||
399 | * duration: 3600 // Time in seconds for how long the autorefresh will be active. After
|
||
400 | * // this period of time, autorefreshing will stop. A value of -1 means
|
||
401 | * // autorefresh for ever.
|
||
402 | * }
|
||
403 | * }
|
||
404 | */
|
||
405 | showTweetFeed: true, |
||
406 | |||
407 | /**
|
||
408 | * A flag (true/false) that specifies whether to display a Twitter "Follow
|
||
409 | * Button".
|
||
410 | */
|
||
411 | showFollowButton: false, |
||
412 | |||
413 | /**
|
||
414 | * A flag (true/false) that specifies whether to display a Twitter "Connect
|
||
415 | * Button" or an object literal representing the configuration options for
|
||
416 | * the "Tweet Box".
|
||
417 | * {
|
||
418 | * size: 'medium' // String - The size of the Connect Button. Valid values are: small, medium, large, xlarge
|
||
419 | * }
|
||
420 | */
|
||
421 | showConnectButton: false, |
||
422 | |||
423 | /**
|
||
424 | * A flag (true/false) that specifies whether to display Login Infos.
|
||
425 | */
|
||
426 | showLoginInfo: false, |
||
427 | |||
428 | /**
|
||
429 | * A flag (true/false) that specifies whether to display a Twitter "Tweet
|
||
430 | * Box" or an object literal representing the configuration options for
|
||
431 | * the "Tweet Box".
|
||
432 | * {
|
||
433 | * counter: true, // Boolean - Display a counter in the Tweet Box for counting characters
|
||
434 | * width: 515, // Number - The width of the Tweet Box in pixels
|
||
435 | * height: 65, // Number - The height of the Tweet Box in pixels
|
||
436 | * label: "What's happening?", // String - The text above the Tweet Box, a call to action
|
||
437 | * defaultContent: <none>, // String - Pre-populated text in the Tweet Box. Useful for an @mention, a #hashtag, a link, etc.
|
||
438 | * onTweet: <none> // Function - Specify a listener for when a tweet is sent from the Tweet Box. The listener receives two arguments: a plaintext tweet and an HTML tweet
|
||
439 | * }
|
||
440 | */
|
||
441 | showTweetBox: false, |
||
442 | |||
443 | /**
|
||
444 | * Identifies the locale for I18N support. The default locale is 'en'. To use this option you have to inlude the
|
||
445 | * adequate locale script, jtweetsanywhere-{language}-{version}.js, e.g. jtweetsanywhere-de-1.3.0.js
|
||
446 | */
|
||
447 | locale: 'en', |
||
448 | |||
449 | /**
|
||
450 | * A dataProvider is a function that delivers the "raw" Twitter data in
|
||
451 | * JSON format. ATM internal use only!
|
||
452 | */
|
||
453 | tweetDataProvider:
|
||
454 | defaultTweetDataProvider, |
||
455 | //mockedTweetDataProvider,
|
||
456 | rateLimitDataProvider:
|
||
457 | defaultRateLimitDataProvider, |
||
458 | //mockedRateLimitDataProvider,
|
||
459 | |||
460 | /**
|
||
461 | * A decorator is a function that is responsible for constructing a certain
|
||
462 | * element of the widget. Most of the decorators return a HTML string.
|
||
463 | * Exceptions are the mainDecorator, which defines the basic sequence of
|
||
464 | * the widget's components, plus the linkDecorator, the usernameDecorator
|
||
465 | * and the hashtagDecorator which return the string that is supplied as a
|
||
466 | * function param, enriched with the HTML tags.
|
||
467 | *
|
||
468 | * For details, see the implementations of the default decorators. Each
|
||
469 | * default decorator can be overwritten by your own implementation.
|
||
470 | */
|
||
471 | mainDecorator: defaultMainDecorator,
|
||
472 | |||
473 | tweetFeedDecorator: defaultTweetFeedDecorator,
|
||
474 | |||
475 | tweetDecorator: defaultTweetDecorator,
|
||
476 | tweetProfileImageDecorator: defaultTweetProfileImageDecorator,
|
||
477 | tweetBodyDecorator: defaultTweetBodyDecorator,
|
||
478 | tweetUsernameDecorator: defaultTweetUsernameDecorator,
|
||
479 | tweetTextDecorator: defaultTweetTextDecorator,
|
||
480 | |||
481 | tweetAttributesDecorator: defaultTweetAttributesDecorator,
|
||
482 | tweetTwitterBirdDecorator: defaultTweetTwitterBirdDecorator,
|
||
483 | tweetTimestampDecorator: defaultTweetTimestampDecorator,
|
||
484 | tweetSourceDecorator: defaultTweetSourceDecorator,
|
||
485 | tweetGeoLocationDecorator: defaultTweetGeoLocationDecorator,
|
||
486 | tweetInReplyToDecorator: defaultTweetInReplyToDecorator,
|
||
487 | tweetRetweeterDecorator: defaultTweetRetweeterDecorator,
|
||
488 | |||
489 | tweetActionsDecorator: defaultTweetActionsDecorator,
|
||
490 | tweetActionReplyDecorator: defaultTweetActionReplyDecorator,
|
||
491 | tweetActionRetweetDecorator: defaultTweetActionRetweetDecorator,
|
||
492 | tweetActionFavoriteDecorator: defaultTweetActionFavoriteDecorator,
|
||
493 | |||
494 | tweetFeedControlsDecorator: defaultTweetFeedControlsDecorator,
|
||
495 | tweetFeedControlsMoreBtnDecorator: defaultTweetFeedControlsMoreBtnDecorator,
|
||
496 | tweetFeedControlsPrevBtnDecorator: defaultTweetFeedControlsPrevBtnDecorator,
|
||
497 | tweetFeedControlsNextBtnDecorator: defaultTweetFeedControlsNextBtnDecorator,
|
||
498 | |||
499 | tweetFeedAutorefreshTriggerDecorator: defaultTweetFeedAutorefreshTriggerDecorator,
|
||
500 | tweetFeedAutorefreshTriggerContentDecorator: defaultTweetFeedAutorefreshTriggerContentDecorator,
|
||
501 | |||
502 | connectButtonDecorator: defaultConnectButtonDecorator,
|
||
503 | |||
504 | loginInfoDecorator: defaultLoginInfoDecorator,
|
||
505 | loginInfoContentDecorator: defaultLoginInfoContentDecorator,
|
||
506 | |||
507 | followButtonDecorator: defaultFollowButtonDecorator,
|
||
508 | |||
509 | tweetBoxDecorator: defaultTweetBoxDecorator,
|
||
510 | |||
511 | linkDecorator: defaultLinkDecorator,
|
||
512 | usernameDecorator: defaultUsernameDecorator,
|
||
513 | hashtagDecorator: defaultHashtagDecorator,
|
||
514 | |||
515 | loadingDecorator: defaultLoadingDecorator,
|
||
516 | errorDecorator: defaultErrorDecorator,
|
||
517 | noDataDecorator: defaultNoDataDecorator,
|
||
518 | |||
519 | /**
|
||
520 | * Formatters are currently used for date format processing only.
|
||
521 | *
|
||
522 | * The tweetTimestampFormatter formats the tweet's timestamp to be shown
|
||
523 | * in the tweet attributes section
|
||
524 | *
|
||
525 | * For details, see the implementation of the defaultTweetTimestampFormatter.
|
||
526 | */
|
||
527 | tweetTimestampFormatter : defaultTweetTimestampFormatter,
|
||
528 | |||
529 | /**
|
||
530 | * The tweetTimestampTooltipFormatter formats the tweet's timestamp to be shown
|
||
531 | * in the tooltip when hovering over the timestamp link.
|
||
532 | */
|
||
533 | tweetTimestampTooltipFormatter : defaultTweetTimestampTooltipFormatter,
|
||
534 | |||
535 | /**
|
||
536 | * A visualizer is a function that is responsible for adding one or more
|
||
537 | * elements to the DOM and thereby making them visible to the user.
|
||
538 | * A visualizer might also be responsible to do the opposite effect:
|
||
539 | * To remove one or more elements from the DOM.
|
||
540 | *
|
||
541 | * The tweetVisualizer gets called each time a tweet element should be
|
||
542 | * appended or prepended to the tweet feed element.
|
||
543 | *
|
||
544 | * For details, see the implementation of the defaultTweetVisualizer.
|
||
545 | *
|
||
546 | * Each default visualizer can be overwritten by your own implementation.
|
||
547 | */
|
||
548 | tweetVisualizer: defaultTweetVisualizer,
|
||
549 | |||
550 | /**
|
||
551 | * The loadingIndicatorVisualizer gets called each time data is retrieved
|
||
552 | * from Twitter to visualize the loading indicator. This visualizer is also
|
||
553 | * used to hide the loading indicator.
|
||
554 | *
|
||
555 | * For details, see the implementation of the defaultLoadingIndicatorVisualizer.
|
||
556 | */
|
||
557 | loadingIndicatorVisualizer: defaultLoadingIndicatorVisualizer,
|
||
558 | |||
559 | /**
|
||
560 | * The autorefreshTriggerVisualizer will be called if the autorefresh
|
||
561 | * trigger should be visualized or hidden.
|
||
562 | *
|
||
563 | * For details, see the implementation of the autorefreshTriggerVisualizer.
|
||
564 | */
|
||
565 | autorefreshTriggerVisualizer: defaultAutorefreshTriggerVisualizer,
|
||
566 | |||
567 | /**
|
||
568 | * An event handler is a function that gets called whenever the event you
|
||
569 | * are interested in, occurs.
|
||
570 | *
|
||
571 | * The onDataRequest event handler will be called immediatly before calling
|
||
572 | * Twitter to retrieve new data and gives you the opportunity to deny
|
||
573 | * the call by returning false from the function.
|
||
574 | *
|
||
575 | * This feature might be used in conjunction with the paging feature,
|
||
576 | * especially when using the "endless-scroll" paging mode, to avoid the
|
||
577 | * exhaustion of remaining Twitter API calls, before the rate limit is
|
||
578 | * reached. The stats parameter contains statistical infos and counters
|
||
579 | * that you can examine to base your decision whether to return true or
|
||
580 | * false.
|
||
581 | */
|
||
582 | onDataRequestHandler: defaultOnDataRequestHandler,
|
||
583 | |||
584 | /**
|
||
585 | * The onRateLimitData event handler is called each time
|
||
586 | * jTweetsAnywhere retrieved the rate limit data from Twitter. The actual
|
||
587 | * rate limit data is contained in the stats object.
|
||
588 | */
|
||
589 | onRateLimitDataHandler: defaultOnRateLimitDataHandler,
|
||
590 | |||
591 | /**
|
||
592 | * The OnOptionsInitializingHandler event handler is called before initializing
|
||
593 | * the user options
|
||
594 | */
|
||
595 | onOptionsInitializingHandler: defaultOnOptionsInitializingHandler,
|
||
596 | |||
597 | _tweetFeedConfig:
|
||
598 | { |
||
599 | autoConformToTwitterStyleguide: false, |
||
600 | showTwitterBird: true, |
||
601 | showTimestamp:
|
||
602 | { |
||
603 | refreshInterval: 0 |
||
604 | }, |
||
605 | showSource: false, |
||
606 | showGeoLocation: true, |
||
607 | showInReplyTo: true, |
||
608 | showActionReply: false, |
||
609 | showActionRetweet: false, |
||
610 | showActionFavorite: false, |
||
611 | showProfileImages: null, |
||
612 | showUserScreenNames: null, |
||
613 | showUserFullNames: false, |
||
614 | expandHovercards: false, |
||
615 | includeRetweets: true, |
||
616 | paging:
|
||
617 | { |
||
618 | mode: "none", |
||
619 | _limit: 0, |
||
620 | _offset: 0 |
||
621 | }, |
||
622 | autorefresh:
|
||
623 | { |
||
624 | mode: "none", |
||
625 | interval: 60, |
||
626 | duration: 3600, |
||
627 | max: -1, |
||
628 | _startTime: null, |
||
629 | _triggerElement: null |
||
630 | }, |
||
631 | _pageParam: 0, |
||
632 | _maxId: null, |
||
633 | _recLevel: 0, |
||
634 | _noData: false, |
||
635 | _clearBeforePopulate: false |
||
636 | }, |
||
637 | _tweetBoxConfig:
|
||
638 | { |
||
639 | counter: true, |
||
640 | width: 515, |
||
641 | height: 65, |
||
642 | label: null, |
||
643 | defaultContent: '', |
||
644 | onTweet: function(textTweet, htmlTweet) {} |
||
645 | }, |
||
646 | _connectButtonConfig:
|
||
647 | { |
||
648 | size: "medium" |
||
649 | }, |
||
650 | _baseSelector: null, |
||
651 | _baseElement: null, |
||
652 | _tweetFeedElement: null, |
||
653 | _tweetFeedControlsElement: null, |
||
654 | _followButtonElement: null, |
||
655 | _loginInfoElement: null, |
||
656 | _connectButtonElement: null, |
||
657 | _tweetBoxElement: null, |
||
658 | _loadingIndicatorElement: null, |
||
659 | _noDataElement: null, |
||
660 | _tweetsCache: [],
|
||
661 | _autorefreshTweetsCache: [],
|
||
662 | _stats:
|
||
663 | { |
||
664 | dataRequestCount: 0, |
||
665 | rateLimitPreventionCount: 0, |
||
666 | rateLimit:
|
||
667 | { |
||
668 | remaining_hits: 150, |
||
669 | hourly_limit: 150 |
||
670 | } |
||
671 | }, |
||
672 | _resourceBundle: null |
||
673 | }, config); |
||
674 | |||
675 | // save the plugin's base selector
|
||
676 | options._baseSelector = this.selector;
|
||
677 | |||
678 | options.onOptionsInitializingHandler(options); |
||
679 | setupOptions(options); |
||
680 | |||
681 | // no main decorator? nothing to do!
|
||
682 | if (!options.mainDecorator)
|
||
683 | { |
||
684 | return;
|
||
685 | } |
||
686 | |||
687 | $.ajaxSetup({ cache: true }); |
||
688 | |||
689 | return this.each(function() |
||
690 | { |
||
691 | // the DOM element, where to display the widget
|
||
692 | options._baseElement = $(this); |
||
693 | |||
694 | // create the widget's necessary sub DOM elements
|
||
695 | options._tweetFeedElement = options.tweetFeedDecorator ? $(options.tweetFeedDecorator(options)) : null; |
||
696 | options._tweetFeedControlsElement = options.tweetFeedControlsDecorator ? $(options.tweetFeedControlsDecorator(options)) : null; |
||
697 | options._followButtonElement = options.followButtonDecorator ? $(options.followButtonDecorator(options)) : null; |
||
698 | options._tweetBoxElement = options.tweetBoxDecorator ? $(options.tweetBoxDecorator(options)) : null; |
||
699 | options._connectButtonElement = options.connectButtonDecorator ? $(options.connectButtonDecorator(options)): null; |
||
700 | options._loginInfoElement = options.loginInfoDecorator ? $(options.loginInfoDecorator(options)) : null; |
||
701 | |||
702 | // add the widget to the DOM
|
||
703 | options.mainDecorator(options); |
||
704 | |||
705 | populateTweetFeed(options); |
||
706 | populateAnywhereControls(options); |
||
707 | |||
708 | bindEventHandlers(options); |
||
709 | |||
710 | setupAutorefresh(options); |
||
711 | }); |
||
712 | }; |
||
713 | defaultMainDecorator = function(options) |
||
714 | { |
||
715 | // defines the default sequence of the widget's elements
|
||
716 | if (options._tweetFeedElement)
|
||
717 | { |
||
718 | options._baseElement.append(options._tweetFeedElement); |
||
719 | } |
||
720 | |||
721 | if (options._tweetFeedControlsElement)
|
||
722 | { |
||
723 | options._baseElement.append(options._tweetFeedControlsElement); |
||
724 | } |
||
725 | |||
726 | if (options._connectButtonElement)
|
||
727 | { |
||
728 | options._baseElement.append(options._connectButtonElement); |
||
729 | } |
||
730 | |||
731 | if (options._loginInfoElement)
|
||
732 | { |
||
733 | options._baseElement.append(options._loginInfoElement); |
||
734 | } |
||
735 | |||
736 | if (options._followButtonElement)
|
||
737 | { |
||
738 | options._baseElement.append(options._followButtonElement); |
||
739 | } |
||
740 | |||
741 | if (options._tweetBoxElement)
|
||
742 | { |
||
743 | options._baseElement.append(options._tweetBoxElement); |
||
744 | } |
||
745 | }; |
||
746 | defaultTweetFeedControlsDecorator = function(options) |
||
747 | { |
||
748 | // the default tweet feed's paging controls
|
||
749 | var html = ''; |
||
750 | |||
751 | if (options._tweetFeedConfig.paging.mode == 'prev-next') |
||
752 | { |
||
753 | if (options.tweetFeedControlsPrevBtnDecorator)
|
||
754 | { |
||
755 | html += options.tweetFeedControlsPrevBtnDecorator(options); |
||
756 | } |
||
757 | |||
758 | if (options.tweetFeedControlsNextBtnDecorator)
|
||
759 | { |
||
760 | html += options.tweetFeedControlsNextBtnDecorator(options); |
||
761 | } |
||
762 | } |
||
763 | else if (options._tweetFeedConfig.paging.mode == 'endless-scroll') |
||
764 | { |
||
765 | // nothing to do here
|
||
766 | } |
||
767 | else
|
||
768 | { |
||
769 | if (options.tweetFeedControlsMoreBtnDecorator)
|
||
770 | { |
||
771 | html += options.tweetFeedControlsMoreBtnDecorator(options); |
||
772 | } |
||
773 | } |
||
774 | |||
775 | return '<div class="jta-tweet-list-controls">' + html + '</div>'; |
||
776 | }; |
||
777 | defaultTweetFeedControlsMoreBtnDecorator = function(options) |
||
778 | { |
||
779 | return '<span class="jta-tweet-list-controls-button jta-tweet-list-controls-button-more">' + options._resourceBundle._('More') + '</span>'; |
||
780 | }; |
||
781 | defaultTweetFeedControlsPrevBtnDecorator = function(options) |
||
782 | { |
||
783 | return '<span class="jta-tweet-list-controls-button jta-tweet-list-controls-button-prev">' + options._resourceBundle._('Prev') + '</span>'; |
||
784 | }; |
||
785 | defaultTweetFeedControlsNextBtnDecorator = function(options) |
||
786 | { |
||
787 | return '<span class="jta-tweet-list-controls-button jta-tweet-list-controls-button-next">' + options._resourceBundle._('Next') + '</span>'; |
||
788 | }; |
||
789 | defaultTweetFeedAutorefreshTriggerDecorator = function(count, options) |
||
790 | { |
||
791 | var html = ''; |
||
792 | |||
793 | if (options.tweetFeedAutorefreshTriggerContentDecorator)
|
||
794 | { |
||
795 | html = options.tweetFeedAutorefreshTriggerContentDecorator(count, options); |
||
796 | } |
||
797 | |||
798 | return '<li class="jta-tweet-list-autorefresh-trigger">' + html + '</li>'; |
||
799 | }; |
||
800 | defaultTweetFeedAutorefreshTriggerContentDecorator = function(count, options) |
||
801 | { |
||
802 | var content = options._resourceBundle.__('%count% new tweet', '%count% new tweets', count, { '%count%' : count }); |
||
803 | |||
804 | return '<span class="jta-tweet-list-autorefresh-trigger-content">' + content + '</span>'; |
||
805 | }; |
||
806 | defaultTweetFeedDecorator = function(options) |
||
807 | { |
||
808 | // the default placeholder for the tweet feed is an unordered list
|
||
809 | return '<ul class="jta-tweet-list"></ul>'; |
||
810 | }; |
||
811 | defaultTweetDecorator = function(tweet, options) |
||
812 | { |
||
813 | // the default tweet is made of the optional user's profile image and the
|
||
814 | // tweet body inside a list item element
|
||
815 | var html = ''; |
||
816 | |||
817 | if (options._tweetFeedConfig.showProfileImages)
|
||
818 | { |
||
819 | html += options.tweetProfileImageDecorator(tweet, options); |
||
820 | } |
||
821 | |||
822 | if (options.tweetBodyDecorator)
|
||
823 | { |
||
824 | html += options.tweetBodyDecorator(tweet, options); |
||
825 | } |
||
826 | |||
827 | html += '<div class="jta-clear"> </div>';
|
||
828 | |||
829 | return '<li class="jta-tweet-list-item">' + html + '</li>'; |
||
830 | }; |
||
831 | defaultTweetProfileImageDecorator = function(tweet, options) |
||
832 | { |
||
833 | // if tweet is a native retweet, use the retweet's profile
|
||
834 | var t = tweet.retweeted_status || tweet;
|
||
835 | |||
836 | // the default profile image decorator simply adds a link to the user's Twitter profile
|
||
837 | var screenName = getScreenName(tweet);
|
||
838 | var imageUrl = t.user ? t.user.profile_image_url : false || t.profile_image_url; |
||
839 | |||
840 | var html =
|
||
841 | '<a class="jta-tweet-profile-image-link" href="http://twitter.com/' + screenName + '" target="_blank">' + |
||
842 | '<img src="' + imageUrl + '" alt="' + screenName + '"' + |
||
843 | (isAnywherePresent() ? '' : (' title="' + screenName + '"')) + |
||
844 | '/>' +
|
||
845 | '</a>';
|
||
846 | |||
847 | return '<div class="jta-tweet-profile-image">' + html + '</div>'; |
||
848 | }; |
||
849 | defaultTweetBodyDecorator = function(tweet, options) |
||
850 | { |
||
851 | // the default tweet body contains the tweet text and the tweet's creation date
|
||
852 | var html = ''; |
||
853 | |||
854 | if (options.tweetTextDecorator)
|
||
855 | { |
||
856 | html += options.tweetTextDecorator(tweet, options); |
||
857 | } |
||
858 | |||
859 | if (options.tweetAttributesDecorator)
|
||
860 | { |
||
861 | html += options.tweetAttributesDecorator(tweet, options); |
||
862 | } |
||
863 | |||
864 | if (options.tweetActionsDecorator)
|
||
865 | { |
||
866 | html += options.tweetActionsDecorator(tweet, options); |
||
867 | } |
||
868 | |||
869 | return '<div class="jta-tweet-body ' + |
||
870 | (options._tweetFeedConfig.showProfileImages ? 'jta-tweet-body-list-profile-image-present' : '') + '">' + |
||
871 | html + |
||
872 | '</div>';
|
||
873 | }; |
||
874 | defaultTweetTextDecorator = function(tweet, options) |
||
875 | { |
||
876 | var tweetText = tweet.text;
|
||
877 | |||
878 | // if usernames should be visible and tweet is a native retweet, use
|
||
879 | // the original tweet text
|
||
880 | if (tweet.retweeted_status &&
|
||
881 | ( |
||
882 | options._tweetFeedConfig.showUserScreenNames || |
||
883 | options._tweetFeedConfig.showUserScreenNames == null ||
|
||
884 | options._tweetFeedConfig.showUserFullNames || |
||
885 | options._tweetFeedConfig.showUserFullNames == null
|
||
886 | ) |
||
887 | ) |
||
888 | { |
||
889 | tweetText = tweet.retweeted_status.text; |
||
890 | } |
||
891 | |||
892 | // the default tweet text decorator optionally marks links, @usernames,
|
||
893 | // and #hashtags
|
||
894 | if (options.linkDecorator)
|
||
895 | { |
||
896 | tweetText = options.linkDecorator(tweetText, options); |
||
897 | } |
||
898 | |||
899 | if (options.usernameDecorator)
|
||
900 | { |
||
901 | tweetText = options.usernameDecorator(tweetText, options); |
||
902 | } |
||
903 | |||
904 | if (options.hashtagDecorator)
|
||
905 | { |
||
906 | tweetText = options.hashtagDecorator(tweetText, options); |
||
907 | } |
||
908 | |||
909 | if (options._tweetFeedConfig.showUserScreenNames ||
|
||
910 | options._tweetFeedConfig.showUserFullNames || |
||
911 | tweet.retweeted_status && |
||
912 | ( |
||
913 | options._tweetFeedConfig.showUserScreenNames == null ||
|
||
914 | options._tweetFeedConfig.showUserFullNames == null
|
||
915 | ) |
||
916 | ) |
||
917 | { |
||
918 | tweetText = options.tweetUsernameDecorator(tweet, options) + ' ' + tweetText;
|
||
919 | } |
||
920 | |||
921 | return '<span class="jta-tweet-text">' + tweetText + '</span>'; |
||
922 | }; |
||
923 | defaultTweetUsernameDecorator = function(tweet, options) |
||
924 | { |
||
925 | // if tweet is a native retweet, use the retweet's profile
|
||
926 | var screenName = getScreenName(tweet);
|
||
927 | var fullName = getFullName(tweet);
|
||
928 | |||
929 | var htmlScreenName = null; |
||
930 | if (screenName && (options._tweetFeedConfig.showUserScreenNames || (options._tweetFeedConfig.showUserScreenNames == null && tweet.retweeted_status))) |
||
931 | { |
||
932 | htmlScreenName = |
||
933 | '<span class="jta-tweet-user-screen-name">' +
|
||
934 | '<a class="jta-tweet-user-screen-name-link" href="http://twitter.com/' + screenName + '" target="_blank">' + |
||
935 | screenName + |
||
936 | '</a>' +
|
||
937 | '</span>';
|
||
938 | } |
||
939 | |||
940 | var htmlFullName = null; |
||
941 | if (fullName && (options._tweetFeedConfig.showUserFullNames || (options._tweetFeedConfig.showUserFullNames == null && tweet.retweeted_status))) |
||
942 | { |
||
943 | htmlFullName = |
||
944 | '<span class="jta-tweet-user-full-name">' +
|
||
945 | (htmlScreenName ? ' ' : '') + |
||
946 | '<a class="jta-tweet-user-full-name-link" href="http://twitter.com/' + screenName + '" name="' + screenName + '" target="_blank">' + |
||
947 | fullName + |
||
948 | '</a>' +
|
||
949 | '</span>';
|
||
950 | } |
||
951 | |||
952 | var html = ''; |
||
953 | |||
954 | if (htmlScreenName)
|
||
955 | { |
||
956 | html += htmlScreenName; |
||
957 | } |
||
958 | |||
959 | if (htmlFullName)
|
||
960 | { |
||
961 | if (htmlScreenName)
|
||
962 | { |
||
963 | html += ' ';
|
||
964 | } |
||
965 | |||
966 | html += htmlFullName; |
||
967 | } |
||
968 | |||
969 | if (htmlScreenName || htmlFullName)
|
||
970 | { |
||
971 | html = |
||
972 | '<span class="jta-tweet-user-name">' +
|
||
973 | (tweet.retweeted_status ? 'RT ' : '') + |
||
974 | html + |
||
975 | '</span>';
|
||
976 | } |
||
977 | |||
978 | return html;
|
||
979 | }; |
||
980 | defaultTweetAttributesDecorator = function(tweet, options) |
||
981 | { |
||
982 | var html = ''; |
||
983 | |||
984 | if (options.tweetTwitterBirdDecorator ||
|
||
985 | options.tweetTimestampDecorator || |
||
986 | options.tweetSourceDecorator || |
||
987 | options.tweetGeoLocationDecorator || |
||
988 | options.tweetInReplyToDecorator || |
||
989 | (tweet.retweeted_status && options.tweetRetweeterDecorator) |
||
990 | ) |
||
991 | { |
||
992 | html += '<span class="jta-tweet-attributes">';
|
||
993 | |||
994 | if (options.tweetTwitterBirdDecorator)
|
||
995 | { |
||
996 | html += options.tweetTwitterBirdDecorator(tweet, options); |
||
997 | } |
||
998 | |||
999 | if (options.tweetTimestampDecorator)
|
||
1000 | { |
||
1001 | html += options.tweetTimestampDecorator(tweet, options); |
||
1002 | } |
||
1003 | |||
1004 | if (options.tweetSourceDecorator)
|
||
1005 | { |
||
1006 | html += options.tweetSourceDecorator(tweet, options); |
||
1007 | } |
||
1008 | |||
1009 | if (options.tweetGeoLocationDecorator)
|
||
1010 | { |
||
1011 | html += options.tweetGeoLocationDecorator(tweet, options); |
||
1012 | } |
||
1013 | |||
1014 | if (options.tweetInReplyToDecorator)
|
||
1015 | { |
||
1016 | html += options.tweetInReplyToDecorator(tweet, options); |
||
1017 | } |
||
1018 | |||
1019 | if (tweet.retweeted_status && options.tweetRetweeterDecorator)
|
||
1020 | { |
||
1021 | html += options.tweetRetweeterDecorator(tweet, options); |
||
1022 | } |
||
1023 | |||
1024 | html += '</span>';
|
||
1025 | } |
||
1026 | |||
1027 | return html;
|
||
1028 | }; |
||
1029 | defaultTweetTimestampDecorator = function(tweet, options) |
||
1030 | { |
||
1031 | // the default tweet timestamp decorator does a little bit of Twitter like formatting.
|
||
1032 | |||
1033 | // if tweet is a native retweet, use the retweet's timestamp
|
||
1034 | var tw = tweet.retweeted_status || tweet;
|
||
1035 | |||
1036 | // reformat timestamp from Twitter, so IE is happy
|
||
1037 | var createdAt = formatDate(tw.created_at);
|
||
1038 | |||
1039 | // format the timestamp by the tweetTimestampFormatter
|
||
1040 | var tweetTimestamp = options.tweetTimestampFormatter(createdAt, options);
|
||
1041 | var tweetTimestampTooltip = options.tweetTimestampTooltipFormatter(createdAt);
|
||
1042 | |||
1043 | var html =
|
||
1044 | '<span class="jta-tweet-timestamp">' +
|
||
1045 | '<a class="jta-tweet-timestamp-link" data-timestamp="' + createdAt +
|
||
1046 | '" href="http://twitter.com/' + getScreenName(tweet) + '/status/' + tw.id + '" target="_blank" title="' + |
||
1047 | tweetTimestampTooltip + '">' +
|
||
1048 | tweetTimestamp + |
||
1049 | '</a>' +
|
||
1050 | '</span>';
|
||
1051 | |||
1052 | return html;
|
||
1053 | }; |
||
1054 | defaultTweetTwitterBirdDecorator = function(tweet, options) |
||
1055 | { |
||
1056 | var screenName = getScreenName(tweet);
|
||
1057 | var intentUrl = 'https://twitter.com/intent/user?screen_name=' + screenName; |
||
1058 | var linkTitle = screenName + ' ' + options._resourceBundle._('on Twitter'); |
||
1059 | |||
1060 | var html =
|
||
1061 | '<span class="jta-tweet-twitter-bird">' +
|
||
1062 | '<a href="' + intentUrl + '" target="_blank" title="' + linkTitle + '">' + |
||
1063 | '<span class="jta-tweet-twitter-bird-icon"> </span>' +
|
||
1064 | '</a>' +
|
||
1065 | '</span>';
|
||
1066 | |||
1067 | return html;
|
||
1068 | }; |
||
1069 | defaultTweetTimestampTooltipFormatter = function(timeStamp) |
||
1070 | { |
||
1071 | var d = new Date(timeStamp); |
||
1072 | |||
1073 | return d.toLocaleString();
|
||
1074 | }; |
||
1075 | defaultTweetTimestampFormatter = function(timeStamp, options) |
||
1076 | { |
||
1077 | var now = new Date(); |
||
1078 | |||
1079 | var diff = parseInt((now.getTime() - Date.parse(timeStamp)) / 1000); |
||
1080 | |||
1081 | var tweetTimestamp = ''; |
||
1082 | if (diff < 60) |
||
1083 | { |
||
1084 | tweetTimestamp += options._resourceBundle.__('%secs% second ago', '%secs% seconds ago', diff, { '%secs%': diff }); |
||
1085 | } |
||
1086 | else if (diff < 3600) |
||
1087 | { |
||
1088 | var t = parseInt((diff + 30) / 60); |
||
1089 | tweetTimestamp += options._resourceBundle.__('%mins% minute ago', '%mins% minutes ago', t, { '%mins%': t }); |
||
1090 | } |
||
1091 | else if (diff < 86400) |
||
1092 | { |
||
1093 | var t = parseInt((diff + 1800) / 3600); |
||
1094 | tweetTimestamp += options._resourceBundle.__('%hours% hour ago', '%hours% hours ago', t, { '%hours%': t }); |
||
1095 | } |
||
1096 | else
|
||
1097 | { |
||
1098 | var d = new Date(timeStamp); |
||
1099 | |||
1100 | var monthName = options._resourceBundle._('$$monthNames'); |
||
1101 | tweetTimestamp += monthName[d.getMonth()] + ' ' + d.getDate();
|
||
1102 | |||
1103 | if (d.getFullYear() < now.getFullYear())
|
||
1104 | { |
||
1105 | tweetTimestamp += ', ' + d.getFullYear();
|
||
1106 | } |
||
1107 | |||
1108 | var t = parseInt((diff + 43200) / 86400); |
||
1109 | tweetTimestamp += ' (' + options._resourceBundle.__('%days% day ago', '%days% days ago', t, { '%days%': t }) + ')'; |
||
1110 | } |
||
1111 | |||
1112 | return tweetTimestamp;
|
||
1113 | }; |
||
1114 | defaultTweetSourceDecorator = function(tweet, options) |
||
1115 | { |
||
1116 | // if tweet is a native retweet, use the retweet's source
|
||
1117 | var tw = tweet.retweeted_status || tweet;
|
||
1118 | |||
1119 | var source = tw.source.replace(/\<\;/gi,'<').replace(/\>\;/gi,'>').replace(/\"\;/gi,'"'); |
||
1120 | var html =
|
||
1121 | '<span class="jta-tweet-source">' +
|
||
1122 | ' ' + options._resourceBundle._('via') + ' ' + |
||
1123 | '<span class="jta-tweet-source-link">' +
|
||
1124 | source + |
||
1125 | '</span>' +
|
||
1126 | '</span>';
|
||
1127 | |||
1128 | return html;
|
||
1129 | }; |
||
1130 | defaultTweetGeoLocationDecorator = function(tweet, options) |
||
1131 | { |
||
1132 | var html = ''; |
||
1133 | |||
1134 | // if tweet is a native retweet, use the retweet's source
|
||
1135 | var tw = tweet.retweeted_status || tweet;
|
||
1136 | |||
1137 | var q = null; |
||
1138 | if (tw.geo && tw.geo.coordinates)
|
||
1139 | { |
||
1140 | q = tw.geo.coordinates.join(); |
||
1141 | } |
||
1142 | else if (tw.place && tw.place.full_name) |
||
1143 | { |
||
1144 | q = tw.place.full_name; |
||
1145 | } |
||
1146 | |||
1147 | if (q)
|
||
1148 | { |
||
1149 | var location = options._resourceBundle._('here'); |
||
1150 | if (tw.place && tw.place.full_name)
|
||
1151 | { |
||
1152 | location = tw.place.full_name; |
||
1153 | } |
||
1154 | |||
1155 | var link = 'http://maps.google.com/maps?q=' + q; |
||
1156 | |||
1157 | html = |
||
1158 | '<span class="jta-tweet-location">' +
|
||
1159 | ' ' + options._resourceBundle._('from') + ' ' + |
||
1160 | '<a class="jta-tweet-location-link" href="' + link + '" target="_blank">' + |
||
1161 | location + |
||
1162 | '</a>' +
|
||
1163 | '</span>';
|
||
1164 | } |
||
1165 | |||
1166 | return html;
|
||
1167 | }; |
||
1168 | defaultTweetInReplyToDecorator = function(tweet, options) |
||
1169 | { |
||
1170 | // if tweet is a native retweet, use the retweet's source
|
||
1171 | var tw = tweet.retweeted_status || tweet;
|
||
1172 | |||
1173 | var html = ''; |
||
1174 | |||
1175 | if (tw.in_reply_to_status_id && tw.in_reply_to_screen_name)
|
||
1176 | { |
||
1177 | var linkHref = 'http://twitter.com/' + tw.in_reply_to_screen_name + '/status/' + tw.in_reply_to_status_id; |
||
1178 | var linkText = options._resourceBundle._('in reply to') + ' ' + tw.in_reply_to_screen_name; |
||
1179 | |||
1180 | html = |
||
1181 | '<span class="jta-tweet-inreplyto">' +
|
||
1182 | ' ' +
|
||
1183 | '<a class="jta-tweet-inreplyto-link" href="' + linkHref + '" target="_blank">' + |
||
1184 | linkText + |
||
1185 | '</a>' +
|
||
1186 | '</span>';
|
||
1187 | } |
||
1188 | |||
1189 | return html;
|
||
1190 | }; |
||
1191 | defaultTweetRetweeterDecorator = function(tweet, options) |
||
1192 | { |
||
1193 | var html = ''; |
||
1194 | |||
1195 | if (tweet.retweeted_status)
|
||
1196 | { |
||
1197 | var screenName = getUserScreenName(tweet);
|
||
1198 | |||
1199 | var rtc = (tweet.retweeted_status.retweet_count || 0) - 1; |
||
1200 | |||
1201 | var link =
|
||
1202 | '<a class="jta-tweet-retweeter-link" href="http://twitter.com/' + screenName + '" target="_blank">' + |
||
1203 | screenName + |
||
1204 | '</a>';
|
||
1205 | |||
1206 | var rtcount = options._resourceBundle.__(' and %rtc% other', ' and %rtc% others', rtc, { '%rtc%': rtc }); |
||
1207 | |||
1208 | html = |
||
1209 | '<br/>' +
|
||
1210 | '<span class="jta-tweet-retweeter">' +
|
||
1211 | options._resourceBundle._('Retweeted by') + ' ' + link + |
||
1212 | (rtc > 0 ? rtcount : '') + |
||
1213 | '</span>';
|
||
1214 | } |
||
1215 | |||
1216 | return html;
|
||
1217 | }; |
||
1218 | defaultTweetActionsDecorator = function(tweet, options) |
||
1219 | { |
||
1220 | var html = ''; |
||
1221 | |||
1222 | if (options.tweetActionReplyDecorator ||
|
||
1223 | options.tweetActionRetweetDecorator || |
||
1224 | options.tweetActionFavoriteDecorator |
||
1225 | ) |
||
1226 | { |
||
1227 | html += '<span class="jta-tweet-actions">';
|
||
1228 | |||
1229 | if (options.tweetActionReplyDecorator)
|
||
1230 | { |
||
1231 | html += options.tweetActionReplyDecorator(tweet, options); |
||
1232 | } |
||
1233 | |||
1234 | if (options.tweetActionRetweetDecorator)
|
||
1235 | { |
||
1236 | html += options.tweetActionRetweetDecorator(tweet, options); |
||
1237 | } |
||
1238 | |||
1239 | if (options.tweetActionFavoriteDecorator)
|
||
1240 | { |
||
1241 | html += options.tweetActionFavoriteDecorator(tweet, options); |
||
1242 | } |
||
1243 | |||
1244 | html += '</span>';
|
||
1245 | } |
||
1246 | |||
1247 | return html;
|
||
1248 | }; |
||
1249 | defaultTweetActionReplyDecorator = function(tweet, options) |
||
1250 | { |
||
1251 | var intentUrl = 'https://twitter.com/intent/tweet?in_reply_to=' + tweet.id; |
||
1252 | var actionLabel = options._resourceBundle._('Reply'); |
||
1253 | |||
1254 | var html =
|
||
1255 | '<span class="jta-tweet-action-reply">' +
|
||
1256 | '<a href="' + intentUrl + '">' + actionLabel + '</a>' + |
||
1257 | '</span>';
|
||
1258 | |||
1259 | return html;
|
||
1260 | }; |
||
1261 | defaultTweetActionRetweetDecorator = function(tweet, options) |
||
1262 | { |
||
1263 | var intentUrl = 'https://twitter.com/intent/retweet?tweet_id=' + tweet.id; |
||
1264 | var actionLabel = options._resourceBundle._('Retweet'); |
||
1265 | |||
1266 | var html =
|
||
1267 | '<span class="jta-tweet-action-retweet">' +
|
||
1268 | '<a href="' + intentUrl + '">' + actionLabel + '</a>' + |
||
1269 | '</span>';
|
||
1270 | |||
1271 | return html;
|
||
1272 | }; |
||
1273 | defaultTweetActionFavoriteDecorator = function(tweet, options) |
||
1274 | { |
||
1275 | var intentUrl = 'https://twitter.com/intent/favorite?tweet_id=' + tweet.id; |
||
1276 | var actionLabel = options._resourceBundle._('Favorite'); |
||
1277 | |||
1278 | var html =
|
||
1279 | '<span class="jta-tweet-action-favorite">' +
|
||
1280 | '<a href="' + intentUrl + '">' + actionLabel + '</a>' + |
||
1281 | '</span>';
|
||
1282 | |||
1283 | return html;
|
||
1284 | }; |
||
1285 | defaultConnectButtonDecorator = function(options) |
||
1286 | { |
||
1287 | // the default placeholder for the @Anywhere ConnectButton
|
||
1288 | return '<div class="jta-connect-button"></div>'; |
||
1289 | }; |
||
1290 | defaultLoginInfoDecorator = function(options) |
||
1291 | { |
||
1292 | // the default placeholder for the LoginInfo
|
||
1293 | return '<div class="jta-login-info"></div>'; |
||
1294 | }; |
||
1295 | defaultLoginInfoContentDecorator = function(options, T) |
||
1296 | { |
||
1297 | // the default markup of the LoginInfo content: the user's profile image, the
|
||
1298 | // user's screen_name and a "button" to sign out
|
||
1299 | var html = ''; |
||
1300 | |||
1301 | if (T.isConnected())
|
||
1302 | { |
||
1303 | var screenName = T.currentUser.data('screen_name'); |
||
1304 | var imageUrl = T.currentUser.data('profile_image_url'); |
||
1305 | |||
1306 | html = |
||
1307 | '<div class="jta-login-info-profile-image">' +
|
||
1308 | '<a href="http://twitter.com/' + screenName + '" target="_blank">' + |
||
1309 | '<img src="' + imageUrl + '" alt="' + screenName + '" title="' + screenName + '"/>' + |
||
1310 | '</a>' +
|
||
1311 | '</div>' +
|
||
1312 | '<div class="jta-login-info-block">' +
|
||
1313 | '<div class="jta-login-info-screen-name">' +
|
||
1314 | '<a href="http://twitter.com/' + screenName + '" target="_blank">' + screenName + '</a>' + |
||
1315 | '</div>' +
|
||
1316 | '<div class="jta-login-info-sign-out">' +
|
||
1317 | options._resourceBundle._('Sign out') +
|
||
1318 | '</div>' +
|
||
1319 | '</div>' +
|
||
1320 | '<div class="jta-clear"> </div>'
|
||
1321 | ; |
||
1322 | } |
||
1323 | |||
1324 | return html;
|
||
1325 | }; |
||
1326 | defaultFollowButtonDecorator = function(options) |
||
1327 | { |
||
1328 | // the default placeholder for the @Anywhere FollowButton
|
||
1329 | return '<div class="jta-follow-button"></div>'; |
||
1330 | }; |
||
1331 | defaultTweetBoxDecorator = function(options) |
||
1332 | { |
||
1333 | // the default placeholder for the @Anywhere TweetBox
|
||
1334 | return '<div class="jta-tweet-box"></div>'; |
||
1335 | }; |
||
1336 | defaultLinkDecorator = function(text, options) |
||
1337 | { |
||
1338 | // the regex to markup links
|
||
1339 | return text.replace(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi,'<a href="$1" class="jta-tweet-a jta-tweet-link" target="_blank" rel="nofollow">$1<\/a>'); |
||
1340 | }; |
||
1341 | defaultUsernameDecorator = function(text, options) |
||
1342 | { |
||
1343 | // the regex to markup @usernames. if @Anywhere is present the task is left to
|
||
1344 | // them
|
||
1345 | return isAnywherePresent() ? text : text.replace(/\B@(\w+)/gi,'@<a href="http://twitter.com/$1" class="jta-tweet-a twitter-anywhere-user" target="_blank" rel="nofollow">$1<\/a>'); |
||
1346 | }; |
||
1347 | defaultHashtagDecorator = function(text, options) |
||
1348 | { |
||
1349 | // the regex to markup #hashtags
|
||
1350 | return text.replace(/#([a-zA-Z0-9_]+)/gi,'<a href="http://search.twitter.com/search?q=%23$1" class="jta-tweet-a jta-tweet-hashtag" title="#$1" target="_blank" rel="nofollow">#$1<\/a>'); |
||
1351 | }; |
||
1352 | defaultLoadingDecorator = function(options) |
||
1353 | { |
||
1354 | // the default loading decorator simply says: loading ...
|
||
1355 | return '<li class="jta-loading">' + options._resourceBundle._('loading') + ' ...</li>'; |
||
1356 | }; |
||
1357 | defaultErrorDecorator = function(errorText, options) |
||
1358 | { |
||
1359 | // the default error decorator shows the error message
|
||
1360 | return '<li class="jta-error">' + options._resourceBundle._('ERROR') + ': ' + errorText + '</li>'; |
||
1361 | }; |
||
1362 | defaultNoDataDecorator = function(options) |
||
1363 | { |
||
1364 | // the default no-data decorator simply says: No more data
|
||
1365 | return '<li class="jta-nodata">' + options._resourceBundle._('No more data') + '</li>'; |
||
1366 | }; |
||
1367 | |||
1368 | defaultTweetFilter = function(tweet, options) |
||
1369 | { |
||
1370 | return true; |
||
1371 | }; |
||
1372 | |||
1373 | defaultTweetVisualizer = function(tweetFeedElement, tweetElement, inserter, options) |
||
1374 | { |
||
1375 | // insert (append/prepend) the tweetElement to the tweetFeedElement
|
||
1376 | tweetFeedElement[inserter](tweetElement); |
||
1377 | }; |
||
1378 | defaultLoadingIndicatorVisualizer = function(tweetFeedElement, loadingIndicatorElement, options, callback) |
||
1379 | { |
||
1380 | defaultVisualizer(tweetFeedElement, loadingIndicatorElement, 'append', 'fadeIn', 600, 'fadeOut', 200, callback); |
||
1381 | }; |
||
1382 | defaultAutorefreshTriggerVisualizer = function(tweetFeedElement, triggerElement, options, callback) |
||
1383 | { |
||
1384 | defaultVisualizer(tweetFeedElement, triggerElement, 'prepend', 'slideDown', 600, 'fadeOut', 200, callback); |
||
1385 | }; |
||
1386 | defaultVisualizer = function(container, element, inserter, effectIn, durationIn, effectOut, durationOut, callback) |
||
1387 | { |
||
1388 | // if param container is null element has to be removed from
|
||
1389 | // the DOM, else element has to be inserted in container
|
||
1390 | |||
1391 | // if param callback is not null, the callback function must be called
|
||
1392 | // in any case, if the visualizer is done
|
||
1393 | |||
1394 | var cb = function() |
||
1395 | { |
||
1396 | if (callback)
|
||
1397 | { |
||
1398 | callback(); |
||
1399 | } |
||
1400 | }; |
||
1401 | |||
1402 | if (container)
|
||
1403 | { |
||
1404 | element.hide(); |
||
1405 | container[inserter](element); |
||
1406 | element[effectIn](durationIn, cb); |
||
1407 | } |
||
1408 | else
|
||
1409 | { |
||
1410 | element[effectOut](durationOut, function()
|
||
1411 | { |
||
1412 | element.remove(); |
||
1413 | cb(); |
||
1414 | }); |
||
1415 | } |
||
1416 | }; |
||
1417 | defaultOnDataRequestHandler = function(stats, options) |
||
1418 | { |
||
1419 | return true; |
||
1420 | }; |
||
1421 | defaultOnRateLimitDataHandler = function(stats, options) |
||
1422 | { |
||
1423 | }; |
||
1424 | defaultOnOptionsInitializingHandler = function(options) |
||
1425 | { |
||
1426 | }; |
||
1427 | updateLoginInfoElement = function(options, T) |
||
1428 | { |
||
1429 | // update the content of the LoginInfo element
|
||
1430 | if (options._loginInfoElement && options.loginInfoContentDecorator)
|
||
1431 | { |
||
1432 | options._loginInfoElement.children().remove(); |
||
1433 | options._loginInfoElement.append(options.loginInfoContentDecorator(options, T)); |
||
1434 | $(options._baseSelector + ' .jta-login-info-sign-out').bind('click', function() |
||
1435 | { |
||
1436 | twttr.anywhere.signOut(); |
||
1437 | }); |
||
1438 | } |
||
1439 | }; |
||
1440 | getFeedUrl = function(options, flPaging) |
||
1441 | { |
||
1442 | // create the Twitter API URL based on the configuration options
|
||
1443 | var url = ('https:' == document.location.protocol ? 'https:' : 'http:'); |
||
1444 | |||
1445 | if (options.searchParams)
|
||
1446 | { |
||
1447 | url += '//search.twitter.com/search.json?' +
|
||
1448 | ((options.searchParams instanceof Array) ? options.searchParams.join('&') : options.searchParams) + |
||
1449 | '&rpp=100';
|
||
1450 | } |
||
1451 | else if (options.list) |
||
1452 | { |
||
1453 | if ('favorites' == options.list) |
||
1454 | { |
||
1455 | url += '//api.twitter.com/1/favorites/' + options.username + '.json?count=20'; |
||
1456 | } |
||
1457 | else
|
||
1458 | { |
||
1459 | url += '//api.twitter.com/1/' + options.username + '/lists/' + options.list + '/statuses.json?per_page=20'; |
||
1460 | } |
||
1461 | } |
||
1462 | else
|
||
1463 | { |
||
1464 | url += '//api.twitter.com/1/statuses/user_timeline.json?screen_name=' + options.username + '&count=20'; |
||
1465 | if (options._tweetFeedConfig.includeRetweets)
|
||
1466 | url += '&include_rts=true';
|
||
1467 | } |
||
1468 | |||
1469 | if (flPaging)
|
||
1470 | { |
||
1471 | url += |
||
1472 | (options._tweetFeedConfig._maxId ? '&max_id=' + options._tweetFeedConfig._maxId : '') + |
||
1473 | '&page=' + options._tweetFeedConfig._pageParam;
|
||
1474 | } |
||
1475 | |||
1476 | url += '&callback=?';
|
||
1477 | |||
1478 | return url;
|
||
1479 | }; |
||
1480 | isAnywherePresent = function() |
||
1481 | { |
||
1482 | // check, if @Anywhere is present
|
||
1483 | return (typeof(twttr) != 'undefined' && typeof(twttr.anywhere) != 'undefined'); |
||
1484 | }; |
||
1485 | clearTweetFeed = function(options) |
||
1486 | { |
||
1487 | if (options._tweetFeedElement)
|
||
1488 | { |
||
1489 | options._tweetFeedElement.empty(); |
||
1490 | } |
||
1491 | }; |
||
1492 | setupOptions = function(options) |
||
1493 | { |
||
1494 | options._resourceBundle = JTA_I18N.getResourceBundle('jTweetsAnywhere', options.locale);
|
||
1495 | |||
1496 | options._tweetBoxConfig.label = options._resourceBundle._("What's happening?");
|
||
1497 | |||
1498 | // if username is an array, create the search query and flatten username
|
||
1499 | if (typeof(options.username) != 'string') |
||
1500 | { |
||
1501 | if (!options.searchParams)
|
||
1502 | { |
||
1503 | options.searchParams = ['q=from:' + options.username.join(" OR from:")]; |
||
1504 | } |
||
1505 | |||
1506 | options.username = options.username[0];
|
||
1507 | } |
||
1508 | |||
1509 | // if showTweetFeed is not set to a boolean value, we expect the configuration of
|
||
1510 | // the tweet feed
|
||
1511 | if (typeof(options.showTweetFeed) == 'object') |
||
1512 | { |
||
1513 | $.extend(true, options._tweetFeedConfig, options.showTweetFeed); |
||
1514 | } |
||
1515 | |||
1516 | // if showTweetBox is not set to a boolean value, we expect the configuration of
|
||
1517 | // the TweetBox
|
||
1518 | if (typeof(options.showTweetBox) == 'object') |
||
1519 | { |
||
1520 | $.extend(true, options._tweetBoxConfig, options.showTweetBox); |
||
1521 | options.showTweetBox = true;
|
||
1522 | } |
||
1523 | |||
1524 | // if showConnectButton is not set to a boolean value, we expect the
|
||
1525 | // configuration of the Connect Button
|
||
1526 | if (typeof(options.showConnectButton) == 'object') |
||
1527 | { |
||
1528 | options._connectButtonConfig = options.showConnectButton; |
||
1529 | options.showConnectButton = true;
|
||
1530 | } |
||
1531 | |||
1532 | // to be compatible, check the deprecated option 'tweetProfileImagePresent'
|
||
1533 | if (options._tweetFeedConfig.showProfileImages == null) |
||
1534 | { |
||
1535 | options._tweetFeedConfig.showProfileImages = options.tweetProfileImagePresent; |
||
1536 | } |
||
1537 | |||
1538 | // if _tweetFeedConfig.showProfileImages is not set to a boolean value,
|
||
1539 | // we decide to show a profile image if the feed represents a user's
|
||
1540 | // list or the results of a Twitter search
|
||
1541 | if (options._tweetFeedConfig.showProfileImages == null) |
||
1542 | { |
||
1543 | options._tweetFeedConfig.showProfileImages = (options.list || options.searchParams) && options.tweetProfileImageDecorator; |
||
1544 | } |
||
1545 | |||
1546 | // handle the autoConformToTwitterStyleguide
|
||
1547 | if (options._tweetFeedConfig.autoConformToTwitterStyleguide)
|
||
1548 | { |
||
1549 | options._tweetFeedConfig.showUserFullNames = null;
|
||
1550 | options._tweetFeedConfig.showTwitterBird = true;
|
||
1551 | options._tweetFeedConfig.showActionReply = true;
|
||
1552 | options._tweetFeedConfig.showActionRetweet = true;
|
||
1553 | options._tweetFeedConfig.showActionFavorite = true;
|
||
1554 | } |
||
1555 | |||
1556 | // if _tweetFeedConfig.showUserScreenNames is not set to a boolean value,
|
||
1557 | // we decide to show a username if the feed represents a user's
|
||
1558 | // list or the results of a Twitter search or a tweet is a native retweet
|
||
1559 | if (options._tweetFeedConfig.showUserScreenNames == null) |
||
1560 | { |
||
1561 | if (options.list || options.searchParams)
|
||
1562 | { |
||
1563 | options._tweetFeedConfig.showUserScreenNames = true;
|
||
1564 | } |
||
1565 | |||
1566 | if (!options.tweetUsernameDecorator)
|
||
1567 | { |
||
1568 | options._tweetFeedConfig.showUserScreenNames = false;
|
||
1569 | } |
||
1570 | } |
||
1571 | |||
1572 | // if _tweetFeedConfig.showUserFullNames is not set to a boolean value,
|
||
1573 | // we decide to show a user's full name if the feed represents a user's
|
||
1574 | // list or the results of a Twitter search or a tweet is a native retweet
|
||
1575 | if (options._tweetFeedConfig.showUserFullNames == null) |
||
1576 | { |
||
1577 | if (options.list || options.searchParams)
|
||
1578 | { |
||
1579 | options._tweetFeedConfig.showUserFullNames = true;
|
||
1580 | } |
||
1581 | |||
1582 | if (!options.tweetUsernameDecorator)
|
||
1583 | { |
||
1584 | options._tweetFeedConfig.showUserFullNames = false;
|
||
1585 | } |
||
1586 | } |
||
1587 | |||
1588 | |||
1589 | options.count = validateRange(options.count, 0, options.searchParams ? 100 : 20); |
||
1590 | |||
1591 | options._tweetFeedConfig.autorefresh.interval = Math.max(30, options._tweetFeedConfig.autorefresh.interval);
|
||
1592 | if (options._tweetFeedConfig.autorefresh.max <= 0) |
||
1593 | { |
||
1594 | options._tweetFeedConfig.autorefresh.max = -1;
|
||
1595 | } |
||
1596 | options._tweetFeedConfig.paging._offset = 0;
|
||
1597 | options._tweetFeedConfig.paging._limit = options.count; |
||
1598 | |||
1599 | // internally, the decision of what parts of a widget are to be
|
||
1600 | // displayed is based on the existence of the decorators
|
||
1601 | if (options.count == 0 || !options.showTweetFeed) |
||
1602 | { |
||
1603 | options.tweetFeedDecorator = null;
|
||
1604 | options.tweetFeedControlsDecorator = null;
|
||
1605 | } |
||
1606 | |||
1607 | if (options._tweetFeedConfig.paging.mode == 'none') |
||
1608 | { |
||
1609 | options.tweetFeedControlsDecorator = null;
|
||
1610 | } |
||
1611 | |||
1612 | if (!options.showFollowButton)
|
||
1613 | { |
||
1614 | options.followButtonDecorator = null;
|
||
1615 | } |
||
1616 | |||
1617 | if (!options.showTweetBox)
|
||
1618 | { |
||
1619 | options.tweetBoxDecorator = null;
|
||
1620 | } |
||
1621 | |||
1622 | if (!options.showConnectButton)
|
||
1623 | { |
||
1624 | options.connectButtonDecorator = null;
|
||
1625 | } |
||
1626 | |||
1627 | if (!options.showLoginInfo)
|
||
1628 | { |
||
1629 | options.loginInfoDecorator = null;
|
||
1630 | } |
||
1631 | |||
1632 | if (!options._tweetFeedConfig.showTwitterBird)
|
||
1633 | { |
||
1634 | options.tweetTwitterBirdDecorator = null;
|
||
1635 | } |
||
1636 | |||
1637 | if (!options._tweetFeedConfig.showTimestamp)
|
||
1638 | { |
||
1639 | options.tweetTimestampDecorator = null;
|
||
1640 | } |
||
1641 | |||
1642 | if (!options._tweetFeedConfig.showSource)
|
||
1643 | { |
||
1644 | options.tweetSourceDecorator = null;
|
||
1645 | } |
||
1646 | |||
1647 | if (!options._tweetFeedConfig.showGeoLocation)
|
||
1648 | { |
||
1649 | options.tweetGeoLocationDecorator = null;
|
||
1650 | } |
||
1651 | |||
1652 | if (!options._tweetFeedConfig.showInReplyTo)
|
||
1653 | { |
||
1654 | options.tweetInReplyToDecorator = null;
|
||
1655 | } |
||
1656 | |||
1657 | if (!options._tweetFeedConfig.showActionReply)
|
||
1658 | { |
||
1659 | options.tweetActionReplyDecorator = null;
|
||
1660 | } |
||
1661 | |||
1662 | if (!options._tweetFeedConfig.showActionRetweet)
|
||
1663 | { |
||
1664 | options.tweetActionRetweetDecorator = null;
|
||
1665 | } |
||
1666 | |||
1667 | if (!options._tweetFeedConfig.showActionFavorite)
|
||
1668 | { |
||
1669 | options.tweetActionFavoriteDecorator = null;
|
||
1670 | } |
||
1671 | }; |
||
1672 | setupAutorefresh = function(options) |
||
1673 | { |
||
1674 | options._tweetFeedConfig.autorefresh._startTime = new Date().getTime();
|
||
1675 | |||
1676 | startAutorefresh(options); |
||
1677 | startTimestampRefresh(options); |
||
1678 | }; |
||
1679 | populateTweetFeed = function(options) |
||
1680 | { |
||
1681 | // if a tweet feed is to be displayed, get the tweets and show them
|
||
1682 | if (options.tweetDecorator && options._tweetFeedElement)
|
||
1683 | { |
||
1684 | getPagedTweets(options, function(tweets, options)
|
||
1685 | { |
||
1686 | if (options._tweetFeedConfig._clearBeforePopulate)
|
||
1687 | { |
||
1688 | clearTweetFeed(options); |
||
1689 | } |
||
1690 | |||
1691 | hideLoadingIndicator(options, function()
|
||
1692 | { |
||
1693 | // process the tweets
|
||
1694 | $.each(tweets, function(idx, tweet) |
||
1695 | { |
||
1696 | // decorate the tweet and give it to the tweet visualizer
|
||
1697 | options.tweetVisualizer( |
||
1698 | options._tweetFeedElement, |
||
1699 | $(options.tweetDecorator(tweet, options)),
|
||
1700 | 'append',
|
||
1701 | options |
||
1702 | ); |
||
1703 | }); |
||
1704 | |||
1705 | if (options._tweetFeedConfig._noData && options.noDataDecorator && !options._tweetFeedConfig._noDataElement)
|
||
1706 | { |
||
1707 | options._tweetFeedConfig._noDataElement = $(options.noDataDecorator(options));
|
||
1708 | options._tweetFeedElement.append(options._tweetFeedConfig._noDataElement); |
||
1709 | } |
||
1710 | |||
1711 | if (options._tweetFeedConfig._clearBeforePopulate)
|
||
1712 | { |
||
1713 | options._tweetFeedElement.scrollTop(0);
|
||
1714 | } |
||
1715 | |||
1716 | addHovercards(options); |
||
1717 | }); |
||
1718 | }); |
||
1719 | } |
||
1720 | }; |
||
1721 | populateTweetFeed2 = function(options) |
||
1722 | { |
||
1723 | if (options._tweetFeedElement && options._autorefreshTweetsCache.length > 0) |
||
1724 | { |
||
1725 | if (options._tweetFeedConfig.autorefresh.mode == 'trigger-insert') |
||
1726 | { |
||
1727 | if (options._tweetFeedConfig.autorefresh._triggerElement)
|
||
1728 | { |
||
1729 | if (options.tweetFeedAutorefreshTriggerContentDecorator)
|
||
1730 | { |
||
1731 | options._tweetFeedConfig.autorefresh._triggerElement.html( |
||
1732 | options.tweetFeedAutorefreshTriggerContentDecorator(options._autorefreshTweetsCache.length, options) |
||
1733 | ); |
||
1734 | } |
||
1735 | } |
||
1736 | else
|
||
1737 | { |
||
1738 | if (options.tweetFeedAutorefreshTriggerDecorator)
|
||
1739 | { |
||
1740 | options._tweetFeedConfig.autorefresh._triggerElement = |
||
1741 | $(options.tweetFeedAutorefreshTriggerDecorator(options._autorefreshTweetsCache.length, options));
|
||
1742 | options._tweetFeedConfig.autorefresh._triggerElement.bind('click', function() |
||
1743 | { |
||
1744 | options.autorefreshTriggerVisualizer( |
||
1745 | null,
|
||
1746 | options._tweetFeedConfig.autorefresh._triggerElement, |
||
1747 | options, |
||
1748 | function()
|
||
1749 | { |
||
1750 | insertTriggerTweets(options); |
||
1751 | } |
||
1752 | ); |
||
1753 | options._tweetFeedConfig.autorefresh._triggerElement = null;
|
||
1754 | }); |
||
1755 | |||
1756 | options.autorefreshTriggerVisualizer(options._tweetFeedElement, options._tweetFeedConfig.autorefresh._triggerElement, options); |
||
1757 | } |
||
1758 | } |
||
1759 | } |
||
1760 | else
|
||
1761 | { |
||
1762 | insertTriggerTweets(options); |
||
1763 | } |
||
1764 | } |
||
1765 | }; |
||
1766 | insertTriggerTweets = function(options) |
||
1767 | { |
||
1768 | // populate the tweet feed with tweets from the autorefresh cache
|
||
1769 | if (options.tweetDecorator && options._autorefreshTweetsCache.length > 0) |
||
1770 | { |
||
1771 | // process the autorefresh cache
|
||
1772 | while (options._autorefreshTweetsCache.length > 0) |
||
1773 | { |
||
1774 | // get the last tweet and remove it from the autorefresh cache
|
||
1775 | var tweet = options._autorefreshTweetsCache.pop();
|
||
1776 | |||
1777 | // put that tweet on top of the tweets cache
|
||
1778 | options._tweetsCache.unshift(tweet); |
||
1779 | |||
1780 | // adjust paging offset
|
||
1781 | options._tweetFeedConfig.paging._offset++; |
||
1782 | |||
1783 | // decorate the tweet and give it to the tweet visualizer
|
||
1784 | options.tweetVisualizer( |
||
1785 | options._tweetFeedElement, |
||
1786 | $(options.tweetDecorator(tweet, options)),
|
||
1787 | 'prepend',
|
||
1788 | options |
||
1789 | ); |
||
1790 | } |
||
1791 | |||
1792 | addHovercards(options); |
||
1793 | } |
||
1794 | }; |
||
1795 | addHovercards = function(options) |
||
1796 | { |
||
1797 | if (isAnywherePresent())
|
||
1798 | { |
||
1799 | // if @Anywhere is present, append Hovercards to @username and
|
||
1800 | // profile images
|
||
1801 | twttr.anywhere(function(T)
|
||
1802 | { |
||
1803 | T(options._baseSelector + ' .jta-tweet-list').hovercards({expanded: options._tweetFeedConfig.expandHovercards}); |
||
1804 | T(options._baseSelector + ' .jta-tweet-profile-image img').hovercards(
|
||
1805 | { |
||
1806 | expanded: options._tweetFeedConfig.expandHovercards,
|
||
1807 | username: function(node) { return node.alt; } |
||
1808 | }); |
||
1809 | T(options._baseSelector + ' .jta-tweet-retweeter-link').hovercards(
|
||
1810 | { |
||
1811 | expanded: options._tweetFeedConfig.expandHovercards,
|
||
1812 | username: function(node) { return node.text; } |
||
1813 | }); |
||
1814 | T(options._baseSelector + ' .jta-tweet-user-screen-name-link').hovercards(
|
||
1815 | { |
||
1816 | expanded: options._tweetFeedConfig.expandHovercards,
|
||
1817 | username: function(node) { return node.text; } |
||
1818 | }); |
||
1819 | T(options._baseSelector + ' .jta-tweet-user-full-name-link').hovercards(
|
||
1820 | { |
||
1821 | expanded: options._tweetFeedConfig.expandHovercards,
|
||
1822 | username: function(node) { return node.name; } |
||
1823 | }); |
||
1824 | }); |
||
1825 | } |
||
1826 | }; |
||
1827 | populateAnywhereControls = function(options) |
||
1828 | { |
||
1829 | if (isAnywherePresent())
|
||
1830 | { |
||
1831 | twttr.anywhere(function(T)
|
||
1832 | { |
||
1833 | // optionally add an @Anywhere TweetBox
|
||
1834 | if (options.tweetBoxDecorator)
|
||
1835 | { |
||
1836 | T(options._baseSelector + ' .jta-tweet-box').tweetBox(options._tweetBoxConfig);
|
||
1837 | } |
||
1838 | |||
1839 | // optionally add an @Anywhere FollowButton
|
||
1840 | if (options.followButtonDecorator)
|
||
1841 | { |
||
1842 | T(options._baseSelector + ' .jta-follow-button').followButton(options.username);
|
||
1843 | } |
||
1844 | |||
1845 | // optionally add an @Anywhere ConnectButton
|
||
1846 | if (options.connectButtonDecorator)
|
||
1847 | { |
||
1848 | var o = $.extend( |
||
1849 | { |
||
1850 | authComplete: function(user) |
||
1851 | { |
||
1852 | // display/update login infos on connect/signin event
|
||
1853 | updateLoginInfoElement(options, T); |
||
1854 | }, |
||
1855 | signOut: function() |
||
1856 | { |
||
1857 | // display/update login infos on signout event
|
||
1858 | updateLoginInfoElement(options, T); |
||
1859 | } |
||
1860 | }, options._connectButtonConfig); |
||
1861 | |||
1862 | T(options._baseSelector + ' .jta-connect-button').connectButton(o);
|
||
1863 | |||
1864 | // display/update login infos
|
||
1865 | updateLoginInfoElement(options, T); |
||
1866 | } |
||
1867 | }); |
||
1868 | } |
||
1869 | }; |
||
1870 | bindEventHandlers = function(options) |
||
1871 | { |
||
1872 | if (options.tweetFeedControlsDecorator)
|
||
1873 | { |
||
1874 | if (options._tweetFeedConfig.paging.mode == 'prev-next') |
||
1875 | { |
||
1876 | $(options._baseSelector + ' .jta-tweet-list-controls-button-prev').bind('click', function() |
||
1877 | { |
||
1878 | if (!isLoading(options) && options._tweetFeedConfig.paging._offset > 0) |
||
1879 | { |
||
1880 | prevPage(options, true);
|
||
1881 | } |
||
1882 | }); |
||
1883 | $(options._baseSelector + ' .jta-tweet-list-controls-button-next').bind('click', function() |
||
1884 | { |
||
1885 | if (!isLoading(options))
|
||
1886 | { |
||
1887 | nextPage(options, true);
|
||
1888 | } |
||
1889 | }); |
||
1890 | } |
||
1891 | else if (options._tweetFeedConfig.paging.mode == 'endless-scroll') |
||
1892 | { |
||
1893 | options._tweetFeedElement.bind("scroll", function() |
||
1894 | { |
||
1895 | if (!isLoading(options) && ($(this)[0].scrollHeight - $(this).scrollTop() == $(this).outerHeight())) |
||
1896 | { |
||
1897 | nextPage(options, false);
|
||
1898 | } |
||
1899 | }); |
||
1900 | } |
||
1901 | else
|
||
1902 | { |
||
1903 | $(options._baseSelector + ' .jta-tweet-list-controls-button-more').bind('click', function() |
||
1904 | { |
||
1905 | if (!isLoading(options))
|
||
1906 | { |
||
1907 | nextPage(options, false);
|
||
1908 | } |
||
1909 | }); |
||
1910 | } |
||
1911 | } |
||
1912 | }; |
||
1913 | nextPage = function(options, flClear) |
||
1914 | { |
||
1915 | doPage(options, flClear, Math.min(options._tweetFeedConfig.paging._offset + options._tweetFeedConfig.paging._limit, options._tweetsCache.length)); |
||
1916 | }; |
||
1917 | prevPage = function(options, flClear) |
||
1918 | { |
||
1919 | doPage(options, flClear, Math.max(0, options._tweetFeedConfig.paging._offset - options._tweetFeedConfig.paging._limit));
|
||
1920 | }; |
||
1921 | doPage = function(options, flClear, newOffset) |
||
1922 | { |
||
1923 | options._tweetFeedConfig.paging._offset = newOffset; |
||
1924 | options._tweetFeedConfig._clearBeforePopulate = flClear; |
||
1925 | |||
1926 | populateTweetFeed(options); |
||
1927 | }; |
||
1928 | startAutorefresh = function(options) |
||
1929 | { |
||
1930 | if (options._tweetFeedConfig.autorefresh.mode != 'none' && |
||
1931 | options._tweetFeedConfig.paging.mode != 'prev-next' &&
|
||
1932 | options._tweetFeedConfig.autorefresh.duration != 0 &&
|
||
1933 | ( |
||
1934 | options._tweetFeedConfig.autorefresh.duration < 0 ||
|
||
1935 | (new Date().getTime() - options._tweetFeedConfig.autorefresh._startTime) <= options._tweetFeedConfig.autorefresh.duration * 1000 |
||
1936 | ) |
||
1937 | ) |
||
1938 | { |
||
1939 | window.setTimeout(function() { processAutorefresh(options); }, options._tweetFeedConfig.autorefresh.interval * 1000); |
||
1940 | } |
||
1941 | }; |
||
1942 | stopAutorefresh = function(options) |
||
1943 | { |
||
1944 | options._tweetFeedConfig.autorefresh.duration = 0;
|
||
1945 | }; |
||
1946 | processAutorefresh = function(options) |
||
1947 | { |
||
1948 | if (options._tweetFeedConfig.autorefresh.duration != 0) |
||
1949 | { |
||
1950 | // load the data ...
|
||
1951 | getRateLimitedData(options, true, getFeedUrl(options, false), function(data, options) |
||
1952 | { |
||
1953 | // reverse the sequence of the autorefresh tweets ...
|
||
1954 | var tweets = (data.results || data).slice(0); |
||
1955 | tweets.reverse(); |
||
1956 | |||
1957 | // ...then process them
|
||
1958 | $.each(tweets, function(idx, tweet) |
||
1959 | { |
||
1960 | // Snowflake support: just update ids that are currently used
|
||
1961 | if (tweet.id_str)
|
||
1962 | { |
||
1963 | tweet.id = tweet.id_str; |
||
1964 | } |
||
1965 | |||
1966 | if (tweet.in_reply_to_status_id_str)
|
||
1967 | { |
||
1968 | tweet.in_reply_to_status_id = tweet.in_reply_to_status_id_str; |
||
1969 | } |
||
1970 | |||
1971 | // if this tweet is already in one of the tweet caches, ignore it
|
||
1972 | if (!isTweetInAutorefreshCache(tweet, options) && !isTweetInCache(tweet, options))
|
||
1973 | { |
||
1974 | // optionally filter tweet ...
|
||
1975 | if (options.tweetFilter(tweet, options))
|
||
1976 | { |
||
1977 | // ... then put it to the top of the autorefresh cache
|
||
1978 | options._autorefreshTweetsCache.unshift(tweet); |
||
1979 | |||
1980 | // if a maximum autorefresh cache size is configured, remove elder tweets
|
||
1981 | if (options._tweetFeedConfig.autorefresh.max > 0) |
||
1982 | { |
||
1983 | while (options._autorefreshTweetsCache.length > options._tweetFeedConfig.autorefresh.max)
|
||
1984 | { |
||
1985 | options._autorefreshTweetsCache.pop(); |
||
1986 | } |
||
1987 | } |
||
1988 | } |
||
1989 | } |
||
1990 | }); |
||
1991 | |||
1992 | populateTweetFeed2(options); |
||
1993 | }); |
||
1994 | |||
1995 | // restart autorefresh
|
||
1996 | startAutorefresh(options); |
||
1997 | } |
||
1998 | }; |
||
1999 | startTimestampRefresh = function(options) |
||
2000 | { |
||
2001 | if (
|
||
2002 | options.tweetTimestampDecorator && |
||
2003 | typeof(options._tweetFeedConfig.showTimestamp) == 'object' && |
||
2004 | options._tweetFeedConfig.showTimestamp.refreshInterval > 0
|
||
2005 | ) |
||
2006 | { |
||
2007 | window.setTimeout(function() { processTimestampRefresh(options); }, options._tweetFeedConfig.showTimestamp.refreshInterval * 1000); |
||
2008 | } |
||
2009 | }; |
||
2010 | processTimestampRefresh = function(options) |
||
2011 | { |
||
2012 | $.each(options._tweetFeedElement.find('.jta-tweet-timestamp-link'), function(idx, element) |
||
2013 | { |
||
2014 | var dataTimestamp = $(element).attr('data-timestamp'); |
||
2015 | |||
2016 | $(element).html(options.tweetTimestampFormatter(dataTimestamp, options));
|
||
2017 | }); |
||
2018 | |||
2019 | startTimestampRefresh(options); |
||
2020 | }; |
||
2021 | isTweetInCache = function(tweet, options) |
||
2022 | { |
||
2023 | var l = options._tweetsCache.length;
|
||
2024 | |||
2025 | for (var i = 0; i < l; i++) |
||
2026 | { |
||
2027 | if (tweet.id == options._tweetsCache[i].id)
|
||
2028 | { |
||
2029 | return true; |
||
2030 | } |
||
2031 | } |
||
2032 | |||
2033 | return false; |
||
2034 | }; |
||
2035 | isTweetInAutorefreshCache = function(tweet, options) |
||
2036 | { |
||
2037 | var l = options._autorefreshTweetsCache.length;
|
||
2038 | |||
2039 | for (var i = 0; i < l; i++) |
||
2040 | { |
||
2041 | if (tweet.id == options._autorefreshTweetsCache[i].id)
|
||
2042 | { |
||
2043 | return true; |
||
2044 | } |
||
2045 | } |
||
2046 | |||
2047 | return false; |
||
2048 | }; |
||
2049 | showLoadingIndicator = function(options) |
||
2050 | { |
||
2051 | if (options._tweetFeedElement && options.loadingDecorator && !options._loadingIndicatorElement)
|
||
2052 | { |
||
2053 | options._loadingIndicatorElement = $(options.loadingDecorator(options));
|
||
2054 | options.loadingIndicatorVisualizer(options._tweetFeedElement, options._loadingIndicatorElement, options, null);
|
||
2055 | options._tweetFeedElement.scrollTop(1000000);
|
||
2056 | } |
||
2057 | }; |
||
2058 | hideLoadingIndicator = function(options, callback) |
||
2059 | { |
||
2060 | if (options._loadingIndicatorElement)
|
||
2061 | { |
||
2062 | options.loadingIndicatorVisualizer(null, options._loadingIndicatorElement, options, callback);
|
||
2063 | options._loadingIndicatorElement = null;
|
||
2064 | } |
||
2065 | else
|
||
2066 | { |
||
2067 | if (callback)
|
||
2068 | { |
||
2069 | callback(); |
||
2070 | } |
||
2071 | } |
||
2072 | }; |
||
2073 | isLoading = function(options) |
||
2074 | { |
||
2075 | return options._loadingIndicatorElement != null; |
||
2076 | }; |
||
2077 | formatDate = function(dateStr) |
||
2078 | { |
||
2079 | return dateStr.replace(/^([a-z]{3})( [a-z]{3} \d\d?)(.*)( \d{4})$/i, '$1,$2$4$3'); |
||
2080 | }; |
||
2081 | getUserScreenName = function(tweet) |
||
2082 | { |
||
2083 | var screenName = tweet.user ? tweet.user.screen_name : false || tweet.from_user; |
||
2084 | |||
2085 | return screenName;
|
||
2086 | }; |
||
2087 | getScreenName = function(tweet) |
||
2088 | { |
||
2089 | var t = tweet.retweeted_status || tweet;
|
||
2090 | var screenName = t.user ? t.user.screen_name : false || t.from_user; |
||
2091 | |||
2092 | return screenName;
|
||
2093 | }; |
||
2094 | getFullName = function(tweet) |
||
2095 | { |
||
2096 | var t = tweet.retweeted_status || tweet;
|
||
2097 | var fullName = t.user ? t.user.name : undefined; |
||
2098 | |||
2099 | return fullName;
|
||
2100 | }; |
||
2101 | validateRange = function(num, lo, hi) |
||
2102 | { |
||
2103 | if (num < lo)
|
||
2104 | num = lo; |
||
2105 | |||
2106 | if (num > hi)
|
||
2107 | num = hi; |
||
2108 | |||
2109 | return num;
|
||
2110 | }; |
||
2111 | showError = function(options, errorText) |
||
2112 | { |
||
2113 | if (options.errorDecorator && options._tweetFeedElement)
|
||
2114 | { |
||
2115 | options._tweetFeedElement.append(options.errorDecorator(errorText, options)); |
||
2116 | } |
||
2117 | }; |
||
2118 | getPagedTweets = function(options, callback) |
||
2119 | { |
||
2120 | options._tweetFeedConfig._recLevel = 0;
|
||
2121 | |||
2122 | getRecPagedTweets(options, options._tweetFeedConfig.paging._offset, options._tweetFeedConfig.paging._limit, callback); |
||
2123 | }; |
||
2124 | getRecPagedTweets = function(options, offset, limit, callback) |
||
2125 | { |
||
2126 | ++options._tweetFeedConfig._recLevel; |
||
2127 | |||
2128 | if (offset + limit <= options._tweetsCache.length ||
|
||
2129 | options._tweetFeedConfig._recLevel > 3 ||
|
||
2130 | options._tweetFeedConfig._noData |
||
2131 | ) |
||
2132 | { |
||
2133 | // if the requested data is already cached or the max. no. of
|
||
2134 | // consecutive API calls is reached, use the records
|
||
2135 | |||
2136 | if (offset + limit > options._tweetsCache.length)
|
||
2137 | { |
||
2138 | limit = Math.max(0, options._tweetsCache.length - offset);
|
||
2139 | } |
||
2140 | |||
2141 | var tweets = [];
|
||
2142 | |||
2143 | for (var i = 0; i < limit; i++) |
||
2144 | { |
||
2145 | tweets[i] = options._tweetsCache[offset + i]; |
||
2146 | } |
||
2147 | |||
2148 | callback(tweets, options); |
||
2149 | } |
||
2150 | else
|
||
2151 | { |
||
2152 | // ... if not, load the data, fill the cache and try again
|
||
2153 | ++options._tweetFeedConfig._pageParam; |
||
2154 | |||
2155 | getRateLimitedData(options, false, getFeedUrl(options, true), function(data, options) |
||
2156 | { |
||
2157 | var tweets = data.results || data;
|
||
2158 | |||
2159 | if (tweets.length == 0) |
||
2160 | { |
||
2161 | options._tweetFeedConfig._noData = true;
|
||
2162 | } |
||
2163 | else
|
||
2164 | { |
||
2165 | $.each(tweets, function(idx, tweet) |
||
2166 | { |
||
2167 | // Snowflake support: just update ids that are currently used
|
||
2168 | if (tweet.id_str)
|
||
2169 | { |
||
2170 | tweet.id = tweet.id_str; |
||
2171 | } |
||
2172 | |||
2173 | if (tweet.in_reply_to_status_id_str)
|
||
2174 | { |
||
2175 | tweet.in_reply_to_status_id = tweet.in_reply_to_status_id_str; |
||
2176 | } |
||
2177 | |||
2178 | // save the first tweet id for subsequent paging requests
|
||
2179 | if (!options._tweetFeedConfig._maxId)
|
||
2180 | { |
||
2181 | options._tweetFeedConfig._maxId = tweet.id; |
||
2182 | } |
||
2183 | |||
2184 | // optionally filter tweet ...
|
||
2185 | if (options.tweetFilter(tweet, options))
|
||
2186 | { |
||
2187 | // then put it into the cache
|
||
2188 | options._tweetsCache.push(tweet); |
||
2189 | } |
||
2190 | }); |
||
2191 | } |
||
2192 | |||
2193 | getRecPagedTweets(options, offset, limit, callback); |
||
2194 | }); |
||
2195 | } |
||
2196 | }; |
||
2197 | getRateLimitedData = function(options, flAutorefresh, url, callback) |
||
2198 | { |
||
2199 | getRateLimit(options, function(rateLimit)
|
||
2200 | { |
||
2201 | if (rateLimit && rateLimit.remaining_hits <= 0) |
||
2202 | { |
||
2203 | options._stats.rateLimitPreventionCount++; |
||
2204 | hideLoadingIndicator(options, null);
|
||
2205 | return;
|
||
2206 | } |
||
2207 | |||
2208 | getData(options, flAutorefresh, url, callback); |
||
2209 | }); |
||
2210 | }; |
||
2211 | getData = function(options, flAutorefresh, url, callback) |
||
2212 | { |
||
2213 | options._stats.dataRequestCount++; |
||
2214 | |||
2215 | if (!options.onDataRequestHandler(options._stats, options))
|
||
2216 | { |
||
2217 | hideLoadingIndicator(options, null);
|
||
2218 | return;
|
||
2219 | } |
||
2220 | |||
2221 | if (!flAutorefresh)
|
||
2222 | { |
||
2223 | showLoadingIndicator(options); |
||
2224 | } |
||
2225 | |||
2226 | options.tweetDataProvider(url, function(data)
|
||
2227 | { |
||
2228 | if (data.error)
|
||
2229 | { |
||
2230 | // in case of an error, display the error message
|
||
2231 | showError(options, data.error); |
||
2232 | } |
||
2233 | else
|
||
2234 | { |
||
2235 | callback(data, options); |
||
2236 | } |
||
2237 | }); |
||
2238 | }; |
||
2239 | getRateLimit = function(options, callback) |
||
2240 | { |
||
2241 | options.rateLimitDataProvider(function(rateLimit)
|
||
2242 | { |
||
2243 | options._stats.rateLimit = rateLimit; |
||
2244 | |||
2245 | options.onRateLimitDataHandler(options._stats, options); |
||
2246 | |||
2247 | callback(rateLimit); |
||
2248 | }); |
||
2249 | }; |
||
2250 | defaultTweetDataProvider = function(url, callback) |
||
2251 | { |
||
2252 | $.getJSON(url, callback);
|
||
2253 | }; |
||
2254 | defaultRateLimitDataProvider = function(callback) |
||
2255 | { |
||
2256 | $.getJSON('http://api.twitter.com/1/account/rate_limit_status.json?callback=?', callback); |
||
2257 | }; |
||
2258 | })(jQuery); |