frontend-helpers 0.0.1.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. data/Gemfile +18 -0
  2. data/Gemfile.lock +108 -0
  3. data/LICENSE.txt +20 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +97 -0
  6. data/Rakefile +53 -0
  7. data/config/services.yml +95 -0
  8. data/config/settings.yml +24 -0
  9. data/frontend-helpers.gemspec +117 -0
  10. data/lib/.DS_Store +0 -0
  11. data/lib/asset-helpers/rails.rb +4 -0
  12. data/lib/frontend-helpers/html5_helper.rb +19 -0
  13. data/lib/frontend-helpers/metatag_helper.rb +58 -0
  14. data/lib/frontend-helpers/services_helper.rb +89 -0
  15. data/lib/frontend-helpers.rb +16 -0
  16. data/lib/generators/frontend/install/install_generator.rb +27 -0
  17. data/lib/tasks/frontend-helpers_tasks.rake +4 -0
  18. data/script/rails +6 -0
  19. data/test/dummy/Rakefile +7 -0
  20. data/test/dummy/app/assets/javascripts/application.js +9 -0
  21. data/test/dummy/app/assets/stylesheets/application.css +7 -0
  22. data/test/dummy/app/controllers/application_controller.rb +3 -0
  23. data/test/dummy/app/helpers/application_helper.rb +2 -0
  24. data/test/dummy/app/mailers/.gitkeep +0 -0
  25. data/test/dummy/app/models/.gitkeep +0 -0
  26. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  27. data/test/dummy/config/application.rb +42 -0
  28. data/test/dummy/config/boot.rb +10 -0
  29. data/test/dummy/config/database.yml +25 -0
  30. data/test/dummy/config/environment.rb +5 -0
  31. data/test/dummy/config/environments/development.rb +27 -0
  32. data/test/dummy/config/environments/production.rb +54 -0
  33. data/test/dummy/config/environments/test.rb +39 -0
  34. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/test/dummy/config/initializers/inflections.rb +10 -0
  36. data/test/dummy/config/initializers/mime_types.rb +5 -0
  37. data/test/dummy/config/initializers/secret_token.rb +7 -0
  38. data/test/dummy/config/initializers/session_store.rb +8 -0
  39. data/test/dummy/config/initializers/wrap_parameters.rb +12 -0
  40. data/test/dummy/config/locales/en.yml +5 -0
  41. data/test/dummy/config/routes.rb +58 -0
  42. data/test/dummy/config.ru +4 -0
  43. data/test/dummy/log/.gitkeep +0 -0
  44. data/test/dummy/public/404.html +26 -0
  45. data/test/dummy/public/422.html +26 -0
  46. data/test/dummy/public/500.html +26 -0
  47. data/test/dummy/public/favicon.ico +0 -0
  48. data/test/dummy/script/rails +6 -0
  49. data/test/frontend-helpers_test.rb +11 -0
  50. data/test/test_helper.rb +10 -0
  51. data/vendor/assets/javascripts/backbone/backbone.js +1149 -0
  52. data/vendor/assets/javascripts/backbone/index.js +2 -0
  53. data/vendor/assets/javascripts/backbone/underscore.js +807 -0
  54. data/vendor/assets/javascripts/ie/dd_belatedpng.js +13 -0
  55. data/vendor/assets/javascripts/ie/index.js +2 -0
  56. data/vendor/assets/javascripts/ie/reverse_zindex.js +1 -0
  57. data/vendor/assets/javascripts/jquery.async.js +77 -0
  58. data/vendor/assets/javascripts/jquery.cookie.js +89 -0
  59. data/vendor/assets/javascripts/jquery.lifestream.js +1516 -0
  60. data/vendor/assets/javascripts/jquery.validate.js +1166 -0
  61. data/vendor/assets/javascripts/log.js +8 -0
  62. data/vendor/assets/javascripts/modernizr.js +1116 -0
  63. data/vendor/assets/javascripts/shortcut.js +223 -0
  64. data/vendor/assets/javascripts/swfobject.js +4 -0
  65. data/vendor/assets/stylesheets/reset.css.sass +183 -0
  66. data/vendor/assets/stylesheets/variables.css.sass +21 -0
  67. metadata +175 -0
@@ -0,0 +1,1516 @@
1
+ /*!
2
+ * jQuery Lifestream Plug-in
3
+ * @version 0.1.2
4
+ * Show a stream of your online activity
5
+ *
6
+ * Copyright 2011, Christian Vuerings - http://denbuzze.com
7
+ */
8
+ /*globals jQuery, $ */
9
+ ;(function( $ ){
10
+
11
+ /**
12
+ * Create a valid YQL URL by passing in a query
13
+ * @param {String} query The query you want to convert into a valid yql url
14
+ * @return {String} A valid YQL URL
15
+ */
16
+ var createYqlUrl = function( query ) {
17
+ return ( "http://query.yahooapis.com/v1/public/yql?q=__QUERY__&env=" +
18
+ "store://datatables.org/alltableswithkeys&format=json")
19
+ .replace( "__QUERY__" , encodeURIComponent( query ) );
20
+ };
21
+
22
+ /**
23
+ * Initialize the lifestream plug-in
24
+ * @param {Object} config Configuration object
25
+ */
26
+ $.fn.lifestream = function( config ) {
27
+
28
+ // Make the plug-in chainable
29
+ return this.each(function() {
30
+
31
+ // The element where the lifestream is linked to
32
+ var outputElement = $(this),
33
+
34
+ // Extend the default settings with the values passed
35
+ settings = jQuery.extend({
36
+ // The name of the main lifestream class
37
+ // We use this for the main ul class e.g. lifestream
38
+ // and for the specific feeds e.g. lifestream-twitter
39
+ classname: "lifestream",
40
+ // Callback function which will be triggered when a feed is loaded
41
+ feedloaded: null,
42
+ // The amount of feed items you want to show
43
+ limit: 10,
44
+ // An array of feed items which you want to use
45
+ list: []
46
+ }, config),
47
+
48
+ // The data object contains all the feed items
49
+ data = {
50
+ count: settings.list.length,
51
+ items: []
52
+ },
53
+
54
+ // We use the item settings to pass the global settings variable to
55
+ // every feed
56
+ itemsettings = jQuery.extend( true, {}, settings ),
57
+
58
+ /**
59
+ * This method will be called every time a feed is loaded. This means
60
+ * that several DOM changes will occur. We did this because otherwise it
61
+ * takes to look before anything shows up.
62
+ * We allow 1 request per feed - so 1 DOM change per feed
63
+ * @private
64
+ * @param {Array} inputdata an array containing all the feeditems for a
65
+ * specific feed.
66
+ */
67
+ finished = function( inputdata ) {
68
+
69
+ // Merge the feed items we have from other feeds, with the feeditems
70
+ // from the new feed
71
+ $.merge( data.items, inputdata );
72
+
73
+ // Sort the feeditems by date - we want the most recent one first
74
+ data.items.sort( function( a, b ) {
75
+ return ( b.date - a.date );
76
+ });
77
+
78
+ var items = data.items,
79
+
80
+ // We need to check whether the amount of current feed items is
81
+ // smaller than the main limit. This parameter will be used in the
82
+ // for loop
83
+ length = ( items.length < settings.limit ) ?
84
+ items.length :
85
+ settings.limit,
86
+ i = 0, item,
87
+
88
+ // We create an unordered list which will create all the feed
89
+ // items
90
+ ul = $('<ul class="' + settings.classname + '"/>');
91
+
92
+ // Run over all the feed items + add them as list items to the
93
+ // unordered list
94
+ for ( ; i < length; i++ ) {
95
+ item = items[i];
96
+ if ( item.html ) {
97
+ $('<li class="'+ settings.classname + '-'
98
+ + item.config.service + '">').append( item.html )
99
+ .appendTo( ul );
100
+ }
101
+ }
102
+
103
+ // Change the innerHTML with a list of all the feeditems in
104
+ // chronological order
105
+ outputElement.html( ul );
106
+
107
+ // Trigger the feedloaded callback, if it is a function
108
+ if ( $.isFunction( settings.feedloaded ) ) {
109
+ settings.feedloaded();
110
+ }
111
+
112
+ },
113
+
114
+ /**
115
+ * Fire up all the feeds and pass them the right arugments.
116
+ * @private
117
+ */
118
+ load = function() {
119
+
120
+ var i = 0, j = settings.list.length;
121
+
122
+ // We don't pass the list array to each feed because this will create
123
+ // a recursive JavaScript object
124
+ delete itemsettings.list;
125
+
126
+ // Run over all the items in the list
127
+ for( ; i < j; i++ ) {
128
+
129
+ var config = settings.list[i];
130
+
131
+ // Check whether the feed exists, if the feed is a function and if a
132
+ // user has been filled in
133
+ if ( $.fn.lifestream.feeds[config.service] &&
134
+ $.isFunction( $.fn.lifestream.feeds[config.service] )
135
+ && config.user) {
136
+
137
+ // You'll be able to get the global settings by using
138
+ // config._settings in your feed
139
+ config._settings = itemsettings;
140
+
141
+ // Call the feed with a config object and finished callback
142
+ $.fn.lifestream.feeds[config.service]( config, finished );
143
+ }
144
+
145
+ }
146
+
147
+ };
148
+
149
+ // Load the jQuery templates plug-in if it wasn't included in the page.
150
+ // At then end we call the load method.
151
+ if( !jQuery.tmpl ) {
152
+ jQuery.getScript(
153
+ "https://raw.github.com/jquery/jquery-tmpl/master/"
154
+ + "jquery.tmpl.min.js",
155
+ load);
156
+ } else {
157
+ load();
158
+ }
159
+
160
+ });
161
+
162
+ };
163
+
164
+ /**
165
+ * A big container which contains all available feeds
166
+ */
167
+ $.fn.lifestream.feeds = $.fn.lifestream.feeds || {};
168
+
169
+ $.fn.lifestream.feeds.blogger = function( config, callback ) {
170
+
171
+ var template = $.extend({},
172
+ {
173
+ posted: 'posted <a href="${origLink}">${title}</a>'
174
+ },
175
+ config.template),
176
+
177
+ parseBlogger = function ( input ) {
178
+ var output = [], list, i = 0, j, item;
179
+
180
+ if ( input.query && input.query.count && input.query.count > 0
181
+ && input.query.results.feed.entry ) {
182
+ list = input.query.results.feed.entry;
183
+ j = list.length;
184
+ for ( ; i < j; i++) {
185
+ item = list[i];
186
+
187
+ output.push({
188
+ date: new Date( item.published ),
189
+ config: config,
190
+ html: $.tmpl( template.posted, item )
191
+ });
192
+ }
193
+ }
194
+
195
+ return output;
196
+ };
197
+
198
+ $.ajax({
199
+ url: createYqlUrl('select * from xml where url="http://'
200
+ + config.user + '.blogspot.com/feeds/posts/default"'),
201
+ dataType: "jsonp",
202
+ success: function ( data ) {
203
+ callback(parseBlogger(data));
204
+ }
205
+ });
206
+
207
+ // Expose the template.
208
+ // We use this to check which templates are available
209
+ return {
210
+ "template" : template
211
+ };
212
+
213
+ };
214
+
215
+ $.fn.lifestream.feeds.dailymotion = function( config, callback ) {
216
+
217
+ var template = $.extend({},
218
+ {
219
+ uploaded: 'uploaded a video <a href="${link}">${title[0]}</a>'
220
+ },
221
+ config.template),
222
+
223
+ parseDailymotion = function( input ) {
224
+
225
+ var output = [], list, i = 0, j, item;
226
+
227
+ if ( input.query && input.query.count && input.query.count > 0
228
+ && input.query.results.rss.channel.item ) {
229
+ list = input.query.results.rss.channel.item;
230
+ j = list.length;
231
+ for ( ; i < j; i++) {
232
+ item = list[i];
233
+ output.push({
234
+ date: new Date ( item.pubDate ),
235
+ config: config,
236
+ html: $.tmpl( template.uploaded, item )
237
+ });
238
+ }
239
+ }
240
+
241
+ return output;
242
+
243
+ };
244
+
245
+ $.ajax({
246
+ url: createYqlUrl('select * from xml where '
247
+ + 'url="http://www.dailymotion.com/rss/user/' + config.user + '"'),
248
+ dataType: "jsonp",
249
+ success: function( data ) {
250
+ callback(parseDailymotion(data));
251
+ }
252
+ });
253
+
254
+ // Expose the template.
255
+ // We use this to check which templates are available
256
+ return {
257
+ "template" : template
258
+ };
259
+
260
+ };
261
+
262
+ $.fn.lifestream.feeds.delicious = function( config, callback ) {
263
+
264
+ var template = $.extend({},
265
+ {
266
+ bookmarked: 'bookmarked <a href="${u}">${d}</a>'
267
+ },
268
+ config.template);
269
+
270
+ $.ajax({
271
+ url: "http://feeds.delicious.com/v2/json/" + config.user,
272
+ dataType: "jsonp",
273
+ success: function( data ) {
274
+ var output = [], i = 0, j;
275
+ if (data && data.length && data.length > 0) {
276
+ j = data.length;
277
+ for( ; i < j; i++) {
278
+ var item = data[i];
279
+ output.push({
280
+ date: new Date(item.dt),
281
+ config: config,
282
+ html: $.tmpl( template.bookmarked, item )
283
+ });
284
+ }
285
+ }
286
+ callback(output);
287
+ }
288
+ });
289
+
290
+ // Expose the template.
291
+ // We use this to check which templates are available
292
+ return {
293
+ "template" : template
294
+ };
295
+
296
+ };
297
+
298
+ $.fn.lifestream.feeds.deviantart = function( config, callback ) {
299
+
300
+ var template = $.extend({},
301
+ {
302
+ posted: 'posted <a href="${link}">${title}</a>'
303
+ },
304
+ config.template);
305
+
306
+ $.ajax({
307
+ url: createYqlUrl(
308
+ 'select title,link,pubDate from rss where '
309
+ + 'url="http://backend.deviantart.com/rss.xml?q=gallery%3A'
310
+ + encodeURIComponent(config.user)
311
+ + '&type=deviation'
312
+ + '" | unique(field="title")'
313
+ ),
314
+ dataType: 'jsonp',
315
+ success: function( resp ) {
316
+ var output = [],
317
+ items, item,
318
+ i = 0, j;
319
+ if (resp.query && resp.query.count > 0) {
320
+ items = resp.query.results.item;
321
+ j = items.length;
322
+ for ( ; i < j; i++) {
323
+ item = items[i];
324
+ output.push({
325
+ date: new Date(item.pubDate),
326
+ config: config,
327
+ html: $.tmpl( template.posted, item )
328
+ });
329
+ }
330
+ }
331
+ callback(output);
332
+ }
333
+ });
334
+
335
+ // Expose the template.
336
+ // We use this to check which templates are available
337
+ return {
338
+ "template" : template
339
+ };
340
+
341
+ };
342
+
343
+ $.fn.lifestream.feeds.dribbble = function( config, callback ) {
344
+
345
+ var template = $.extend({},
346
+ {
347
+ posted: 'posted a shot <a href="${url}">${title}</a>'
348
+ },
349
+ config.template);
350
+
351
+ $.ajax({
352
+ url: "http://api.dribbble.com/players/" + config.user + "/shots",
353
+ dataType: "jsonp",
354
+ success: function( data ) {
355
+ var output = [], i = 0, j;
356
+
357
+ if(data && data.total) {
358
+ j = data.shots.length;
359
+ for( ; i<j; i++) {
360
+ var item = data.shots[i];
361
+ output.push({
362
+ date: new Date(item.created_at),
363
+ config: config,
364
+ html: $.tmpl( template.posted, item )
365
+ });
366
+ }
367
+ }
368
+
369
+ callback(output);
370
+ }
371
+ });
372
+
373
+ // Expose the template.
374
+ // We use this to check which templates are available
375
+ return {
376
+ "template" : template
377
+ };
378
+
379
+ };
380
+
381
+ $.fn.lifestream.feeds.flickr = function( config, callback ) {
382
+
383
+ var template = $.extend({},
384
+ {
385
+ posted: 'posted a photo <a href="${link}">${title}</a>'
386
+ },
387
+ config.template);
388
+
389
+ $.ajax({
390
+ url: "http://api.flickr.com/services/feeds/photos_public.gne?id="
391
+ + config.user + "&lang=en-us&format=json",
392
+ dataType: "jsonp",
393
+ jsonp: 'jsoncallback',
394
+ success: function( data ) {
395
+ var output = [], i = 0, j;
396
+
397
+ if(data && data.items && data.items.length > 0) {
398
+ j = data.items.length;
399
+ for( ; i<j; i++) {
400
+ var item = data.items[i];
401
+ output.push({
402
+ date: new Date( item.published ),
403
+ config: config,
404
+ html: $.tmpl( template.posted, item )
405
+ });
406
+ }
407
+ }
408
+
409
+ callback(output);
410
+ }
411
+ });
412
+
413
+ // Expose the template.
414
+ // We use this to check which templates are available
415
+ return {
416
+ "template" : template
417
+ };
418
+
419
+ };
420
+
421
+ $.fn.lifestream.feeds.foomark = function( config, callback ) {
422
+
423
+ var template = $.extend({},
424
+
425
+ {
426
+ bookmarked: 'bookmarked <a href="${url}">${url}</a>'
427
+
428
+ },
429
+ config.template);
430
+
431
+ $.ajax({
432
+ url: "http://api.foomark.com/urls/list/",
433
+ data: {
434
+ format: "jsonp",
435
+ username: config.user
436
+ },
437
+ dataType: "jsonp",
438
+ success: function( data ) {
439
+
440
+ var output = [], i=0, j;
441
+ if( data && data.length && data.length > 0 ) {
442
+ j = data.length;
443
+ for( ; i < j; i++ ) {
444
+ var item = data[i];
445
+ output.push({
446
+ date: new Date( item.created_at.replace(' ', 'T') ),
447
+ config: config,
448
+ html: $.tmpl( template.bookmarked, item )
449
+ });
450
+ }
451
+ }
452
+ callback( output );
453
+ }
454
+ });
455
+
456
+ // Expose the template.
457
+ // We use this to check which templates are available
458
+ return {
459
+ "template" : template
460
+ };
461
+
462
+ };
463
+
464
+ $.fn.lifestream.feeds.formspring = function( config, callback ) {
465
+
466
+ var template = $.extend({},
467
+ {
468
+ answered: 'answered a question <a href="${link}">${title}</a>'
469
+ },
470
+ config.template);
471
+
472
+ var parseFormspring = function ( input ) {
473
+ var output = [], list, i = 0, j, item;
474
+
475
+ if ( input.query && input.query.count && input.query.count > 0
476
+ && input.query.results.rss.channel.item ) {
477
+ list = input.query.results.rss.channel.item;
478
+ j = list.length;
479
+ for ( ; i < j; i++) {
480
+ item = list[i];
481
+
482
+ output.push({
483
+ date: new Date( item.pubDate ),
484
+ config: config,
485
+ html: $.tmpl( template.answered, item )
486
+ });
487
+ }
488
+ }
489
+
490
+ return output;
491
+ };
492
+
493
+ $.ajax({
494
+ url: createYqlUrl('select * from xml where '
495
+ + 'url="http://www.formspring.me/profile/' + config.user + '.rss"'),
496
+ dataType: "jsonp",
497
+ success: function ( data ) {
498
+ callback(parseFormspring(data));
499
+ }
500
+ });
501
+
502
+ // Expose the template.
503
+ // We use this to check which templates are available
504
+ return {
505
+ "template" : template
506
+ };
507
+
508
+ };
509
+
510
+ $.fn.lifestream.feeds.forrst = function( config, callback ) {
511
+
512
+ var template = $.extend({},
513
+ {
514
+ posted: 'posted a ${post_type} '
515
+ + '<a href="${post_url}">${title}</a>'
516
+ },
517
+ config.template);
518
+
519
+ $.ajax({
520
+ url: "http://forrst.com/api/v2/users/posts?username=" + config.user,
521
+ dataType: "jsonp",
522
+ success: function( data ) {
523
+ var output = [], i=0, j;
524
+ if( data && data.resp.length && data.resp.length > 0 ) {
525
+ j = data.resp.length;
526
+ for( ; i < j; i++ ) {
527
+ var item = data.resp[i];
528
+ output.push({
529
+ date: new Date( item.created_at.replace(' ', 'T') ),
530
+ config: config,
531
+ html: $.tmpl( template.posted, item )
532
+ });
533
+ }
534
+ }
535
+ callback( output );
536
+ }
537
+ });
538
+
539
+ // Expose the template.
540
+ // We use this to check which templates are available
541
+ return {
542
+ "template" : template
543
+ };
544
+
545
+ };
546
+
547
+ $.fn.lifestream.feeds.foursquare = function( config, callback ) {
548
+
549
+ var template = $.extend({},
550
+ {
551
+ checkedin: 'checked in @ <a href="${link}">${title}</a>'
552
+ },
553
+ config.template),
554
+
555
+ parseFoursquare = function( input ) {
556
+ var output = [], i = 0, j;
557
+
558
+ if(input.query && input.query.count && input.query.count >0) {
559
+ j = input.query.count;
560
+ for( ; i<j; i++) {
561
+ var item = input.query.results.item[i];
562
+ output.push({
563
+ date: new Date(item.pubDate),
564
+ config: config,
565
+ html: $.tmpl( template.checkedin, item )
566
+ });
567
+ }
568
+ }
569
+
570
+ return output;
571
+ };
572
+
573
+ $.ajax({
574
+ url: createYqlUrl('select * from rss where url='
575
+ + '"https://feeds.foursquare.com/history/'
576
+ + config.user + '.rss"'),
577
+ dataType: 'jsonp',
578
+ success: function( data ) {
579
+ callback(parseFoursquare(data));
580
+ }
581
+ });
582
+
583
+ // Expose the template.
584
+ // We use this to check which templates are available
585
+ return {
586
+ "template" : template
587
+ };
588
+
589
+ };
590
+
591
+ $.fn.lifestream.feeds.github = function( config, callback ) {
592
+
593
+ var template = $.extend({},
594
+ {
595
+ pushed: '<a href="${status.url}" title="{{if title}}${title} '
596
+ +'by ${author} {{/if}}">pushed</a> to '
597
+ +'<a href="http://github.com/${repo}">${repo}</a>',
598
+ gist: '<a href="${status.payload.url}" title="'
599
+ +'${status.payload.desc || ""}">${status.payload.name}</a>',
600
+ commented: '<a href="${status.url}">commented</a> on '
601
+ +'<a href="http://github.com/${repo}">${repo}</a>',
602
+ pullrequest: '<a href="${status.url}">${status.payload.action}</a> '
603
+ +'pull request on <a href="http://github.com/${repo}">${repo}</a>',
604
+ created: 'created ${status.payload.ref_type || status.payload.object}'
605
+ +' <a href="${status.url}">${status.payload.ref || '
606
+ +'status.payload.object_name}</a> for '
607
+ +'<a href="http://github.com/${repo}">${repo}</a>',
608
+ createdglobal: 'created ${status.payload.object} '
609
+ +'<a href="${status.url}">${title}</a>',
610
+ deleted: 'deleted ${status.payload.ref_type} '
611
+ +'<a href="http://github.com/${status.repository.owner}/'
612
+ +'${status.repository.name}">status.payload.ref</a>'
613
+ },
614
+ config.template);
615
+
616
+ var returnRepo = function( status ) {
617
+ return status.payload.repo
618
+ || ( status.repository ? status.repository.owner + "/"
619
+ + status.repository.name : null )
620
+ || status.url.split("/")[3] + "/" + status.url.split("/")[4];
621
+ },
622
+ parseGithubStatus = function( status ) {
623
+ var repo, title;
624
+ if(status.type === "PushEvent") {
625
+ title = status.payload && status.payload.shas
626
+ && status.payload.shas.json
627
+ && status.payload.shas.json[2];
628
+ repo = returnRepo(status);
629
+
630
+ return $.tmpl( template.pushed, {
631
+ status: status,
632
+ title: title,
633
+ author: title ? status.payload.shas.json[3] : "",
634
+ repo: returnRepo(status)
635
+ } );
636
+ }
637
+ else if (status.type === "GistEvent") {
638
+ return $.tmpl( template.gist, status );
639
+ }
640
+ else if (status.type === "CommitCommentEvent" ||
641
+ status.type === "IssueCommentEvent") {
642
+ repo = returnRepo(status);
643
+ return $.tmpl( template.commented, {
644
+ repo: repo,
645
+ status: status
646
+ } );
647
+ }
648
+ else if (status.type === "PullRequestEvent") {
649
+ repo = returnRepo(status);
650
+ return $.tmpl( template.pullrequest, {
651
+ repo: repo,
652
+ status: status
653
+ } );
654
+ }
655
+ // Github has several syntaxes for create tag events
656
+ else if (status.type === "CreateEvent" &&
657
+ (status.payload.ref_type === "tag" ||
658
+ status.payload.ref_type === "branch" ||
659
+ status.payload.object === "tag")) {
660
+ repo = returnRepo(status);
661
+ return $.tmpl( template.created, {
662
+ repo: repo,
663
+ status: status
664
+ } );
665
+ }
666
+ else if (status.type === "CreateEvent") {
667
+ title = (status.payload.object_name === "null")
668
+ ? status.payload.name
669
+ : status.payload.object_name;
670
+ return $.tmpl( template.createdglobal, {
671
+ title: title,
672
+ status: status
673
+ } );
674
+ }
675
+ else if (status.type === "DeleteEvent") {
676
+ return $.tmpl( template.deleted, status );
677
+ }
678
+
679
+ },
680
+ parseGithub = function( input ) {
681
+ var output = [], i = 0, j;
682
+
683
+ if(input.query && input.query.count && input.query.count >0) {
684
+ j = input.query.count;
685
+ for( ; i<j; i++) {
686
+ var status = input.query.results.json[i].json;
687
+ output.push({
688
+ date: new Date(status.created_at),
689
+ config: config,
690
+ html: parseGithubStatus(status)
691
+ });
692
+ }
693
+ }
694
+
695
+ return output;
696
+
697
+ };
698
+
699
+ $.ajax({
700
+ url: createYqlUrl('select json.repository.owner,json.repository.name'
701
+ + ',json.payload,json.type'
702
+ + ',json.url, json.created_at from json where url="http://github.com/'
703
+ + config.user + '.json"'),
704
+ dataType: 'jsonp',
705
+ success: function( data ) {
706
+ callback(parseGithub(data));
707
+ }
708
+ });
709
+
710
+ // Expose the template.
711
+ // We use this to check which templates are available
712
+ return {
713
+ "template" : template
714
+ };
715
+
716
+ };
717
+
718
+ $.fn.lifestream.feeds.googlereader = function( config, callback ) {
719
+
720
+ var template = $.extend({},
721
+ {
722
+ starred: 'starred post <a href="${link.href}">${title.content}</a>'
723
+ },
724
+ config.template),
725
+
726
+ /**
727
+ * Parse the input from google reader
728
+ */
729
+ parseReader = function( input ) {
730
+ var output = [], list, i = 0, j;
731
+
732
+ if(input.query && input.query.count && input.query.count >0) {
733
+ list = input.query.results.feed.entry;
734
+ j = list.length;
735
+ for( ; i<j; i++) {
736
+ var item = list[i];
737
+ output.push({
738
+ date: new Date(parseInt(item["crawl-timestamp-msec"], 10)),
739
+ config: config,
740
+ html: $.tmpl( template.starred, item )
741
+ });
742
+ }
743
+ }
744
+ return output;
745
+ };
746
+
747
+ $.ajax({
748
+ url: createYqlUrl('select * from xml where url="'
749
+ + 'www.google.com/reader/public/atom/user%2F'
750
+ + config.user + '%2Fstate%2Fcom.google%2Fstarred"'),
751
+ dataType: 'jsonp',
752
+ success: function( data ) {
753
+ callback(parseReader(data));
754
+ }
755
+ });
756
+
757
+ // Expose the template.
758
+ // We use this to check which templates are available
759
+ return {
760
+ "template" : template
761
+ };
762
+
763
+ };
764
+
765
+ $.fn.lifestream.feeds.iusethis = function( config, callback ) {
766
+
767
+ var template = $.extend({},
768
+ {
769
+ global: '${action} <a href="${link}">${what}</a> on (${os})'
770
+ },
771
+ config.template);
772
+
773
+ var parseIusethis = function( input ) {
774
+ var output = [], list, i, j, k, l, m = 0, n, item, title, actions,
775
+ action, what, os, oss = ["iPhone", "OS X", "Windows"];
776
+
777
+ if (input.query && input.query.count && input.query.count > 0
778
+ && input.query.results.rss) {
779
+ n = input.query.results.rss.length;
780
+ actions = ['started using', 'stopped using', 'stopped loving',
781
+ 'Downloaded', 'commented on', 'updated entry for',
782
+ 'started loving', 'registered'];
783
+ l = actions.length;
784
+
785
+ for( ; m < n; m++) {
786
+
787
+ os = oss[m];
788
+ list = input.query.results.rss[m].channel.item;
789
+ i = 0;
790
+ j = list.length;
791
+
792
+ for ( ; i < j; i++) {
793
+ item = list[i];
794
+ title = item.title.replace(config.user + ' ', '');
795
+ k = 0;
796
+
797
+ for( ; k < l; k++) {
798
+ if(title.indexOf(actions[k]) > -1) {
799
+ action = actions[k];
800
+ break;
801
+ }
802
+ }
803
+
804
+ what = title.split(action);
805
+
806
+ output.push({
807
+ date: new Date(item.pubDate),
808
+ config: config,
809
+ html: $.tmpl( template.global, {
810
+ action: action.toLowerCase(),
811
+ link: item.link,
812
+ what: what[1],
813
+ os: os
814
+ } )
815
+ });
816
+ }
817
+ }
818
+ }
819
+
820
+ return output;
821
+ };
822
+
823
+ $.ajax({
824
+ url: createYqlUrl('select * from xml where '
825
+ + 'url="http://iphone.iusethis.com/user/feed.rss/' + config.user
826
+ + '" or '
827
+ + 'url="http://osx.iusethis.com/user/feed.rss/' + config.user
828
+ + '" or '
829
+ + 'url="http://win.iusethis.com/user/feed.rss/' + config.user + '"'),
830
+ dataType: "jsonp",
831
+ success: function( data ) {
832
+ callback(parseIusethis(data));
833
+ }
834
+ });
835
+
836
+ // Expose the template.
837
+ // We use this to check which templates are available
838
+ return {
839
+ "template" : template
840
+ };
841
+
842
+ };
843
+
844
+ $.fn.lifestream.feeds.lastfm = function( config, callback ) {
845
+
846
+ var template = $.extend({},
847
+ {
848
+ loved: 'loved <a href="${url}">${name}</a> by '
849
+ + '<a href="${artist.url}">${artist.name}</a>'
850
+ },
851
+ config.template),
852
+
853
+ parseLastfm = function( input ) {
854
+ var output = [], list, i = 0, j;
855
+
856
+ if(input.query && input.query.count && input.query.count > 0
857
+ && input.query.results.lovedtracks
858
+ && input.query.results.lovedtracks.track) {
859
+ list = input.query.results.lovedtracks.track;
860
+ j = list.length;
861
+ for( ; i<j; i++) {
862
+ var item = list[i];
863
+ output.push({
864
+ date: new Date(parseInt((item.date.uts * 1000), 10)),
865
+ config: config,
866
+ html: $.tmpl( template.loved, item )
867
+ });
868
+ }
869
+ }
870
+ return output;
871
+ };
872
+
873
+ $.ajax({
874
+ url: createYqlUrl('select * from xml where url='
875
+ + '"http://ws.audioscrobbler.com/2.0/user/'
876
+ + config.user + '/lovedtracks.xml"'),
877
+ dataType: 'jsonp',
878
+ success: function( data ) {
879
+ callback(parseLastfm(data));
880
+ }
881
+ });
882
+
883
+ // Expose the template.
884
+ // We use this to check which templates are available
885
+ return {
886
+ "template" : template
887
+ };
888
+
889
+ };
890
+
891
+ $.fn.lifestream.feeds.picplz = function( config, callback ) {
892
+
893
+ var template = $.extend({},
894
+ {
895
+ uploaded: 'uploaded <a href="${url}">${title}</a>'
896
+ },
897
+ config.template);
898
+
899
+ $.ajax({
900
+ url: "http://picplz.com/api/v2/user.json?username="
901
+ + config.user + "&include_pics=1",
902
+ dataType: "jsonp",
903
+ success: function( data ) {
904
+ var output = [], i=0, j, images;
905
+ images = data.value.users[0].pics;
906
+ if( images && images.length && images.length > 0 ) {
907
+ j = images.length;
908
+ for( ; i < j; i++ ) {
909
+ var item = images[i];
910
+ output.push({
911
+ date: new Date( ( item.date ) * 1000 ),
912
+ config: config,
913
+ html: $.tmpl( template.uploaded, {
914
+ url: item.pic_files["640r"].img_url,
915
+ title: item.caption || item.id
916
+ } )
917
+ });
918
+ }
919
+ }
920
+ callback( output );
921
+ }
922
+ });
923
+
924
+ // Expose the template.
925
+ // We use this to check which templates are available
926
+ return {
927
+ "template" : template
928
+ };
929
+
930
+ };
931
+
932
+ $.fn.lifestream.feeds.pinboard = function( config, callback ) {
933
+
934
+ var template = $.extend({},
935
+ {
936
+ bookmarked: 'bookmarked <a href="${link}">${title}</a>'
937
+ },
938
+ config.template);
939
+
940
+ var parsePinboard = function( input ) {
941
+ var output = [], list, i = 0, j, item;
942
+
943
+ if (input.query && input.query.count && input.query.count > 0) {
944
+ list = input.query.results.RDF.item;
945
+ j = list.length;
946
+ for ( ; i < j; i++) {
947
+ item = list[i];
948
+
949
+ output.push({
950
+ date: new Date(item.date),
951
+ config: config,
952
+ html: $.tmpl( template.bookmarked, item )
953
+ });
954
+
955
+ }
956
+ }
957
+
958
+ return output;
959
+ };
960
+
961
+ $.ajax({
962
+ url: createYqlUrl('select * from xml where '
963
+ + 'url="http://feeds.pinboard.in/rss/u:' + config.user + '"'),
964
+ dataType: "jsonp",
965
+ success: function( data ) {
966
+ callback(parsePinboard(data));
967
+ }
968
+ });
969
+
970
+ // Expose the template.
971
+ // We use this to check which templates are available
972
+ return {
973
+ "template" : template
974
+ };
975
+
976
+ };
977
+
978
+ $.fn.lifestream.feeds.posterous = function( config, callback ) {
979
+
980
+ var template = $.extend({},
981
+ {
982
+ posted: 'posted <a href="${link}">${title}</a>'
983
+ },
984
+ config.template);
985
+
986
+ var parsePosterous = function ( input ) {
987
+ var output = [], list, i = 0, j, item;
988
+
989
+ if ( input.query && input.query.count && input.query.count > 0
990
+ && input.query.results.rss.channel.item ) {
991
+ list = input.query.results.rss.channel.item;
992
+ j = list.length;
993
+ for ( ; i < j; i++) {
994
+ item = list[i];
995
+
996
+ output.push({
997
+ date: new Date( item.pubDate ),
998
+ config: config,
999
+ html: $.tmpl( template.posted, item )
1000
+ });
1001
+ }
1002
+ }
1003
+
1004
+ return output;
1005
+ };
1006
+
1007
+ $.ajax({
1008
+ url: createYqlUrl('select * from xml where '
1009
+ + 'url="http://' + config.user + '.posterous.com/rss.xml"'),
1010
+ dataType: "jsonp",
1011
+ success: function ( data ) {
1012
+ callback(parsePosterous(data));
1013
+ }
1014
+ });
1015
+
1016
+ // Expose the template.
1017
+ // We use this to check which templates are available
1018
+ return {
1019
+ "template" : template
1020
+ };
1021
+
1022
+ };
1023
+
1024
+ $.fn.lifestream.feeds.reddit = function( config, callback ) {
1025
+
1026
+ var template = $.extend({},
1027
+ {
1028
+ commented: '<a href="http://www.reddit.com/r/${item.data.subreddit}'
1029
+ + '/comments/${item.data.link_id.substring(3)}/u/'
1030
+ + '${item.data.name.substring(3)}?context=3">commented '
1031
+ + '(${score})</a> in <a href="http://www.reddit.com/r/'
1032
+ + '${item.data.subreddit}">${item.data.subreddit}</a>',
1033
+ created: '<a href="http://www.reddit.com${item.data.permalink}">'
1034
+ + 'created new thread (${score})</a> in '
1035
+ + '<a href="http://www.reddit.com/r/${item.data.subreddit}">'
1036
+ + '${item.data.subreddit}</a>'
1037
+ },
1038
+ config.template);
1039
+
1040
+ /**
1041
+ * Parsed one item from the Reddit API.
1042
+ * item.kind == t1 is a reply, t2 is a new thread
1043
+ */
1044
+ var parseRedditItem = function( item ) {
1045
+
1046
+ var score = item.data.ups - item.data.downs,
1047
+ pass = {
1048
+ item: item,
1049
+ score: (score > 0) ? "+" + score : score
1050
+ };
1051
+
1052
+ // t1 = reply, t3 = new thread
1053
+ if (item.kind === "t1") {
1054
+ return $.tmpl( template.commented, pass );
1055
+ }
1056
+ else if (item.kind === "t3") {
1057
+ return $.tmpl( template.created, pass );
1058
+ }
1059
+
1060
+ },
1061
+ /**
1062
+ * Reddit date's are simple epochs.
1063
+ * seconds*1000 = milliseconds
1064
+ */
1065
+ convertDate = function( date ) {
1066
+ return new Date(date * 1000);
1067
+ };
1068
+
1069
+ $.ajax({
1070
+ url: "http://www.reddit.com/user/" + config.user + ".json",
1071
+ dataType: "jsonp",
1072
+ jsonp:"jsonp",
1073
+ success: function( data ) {
1074
+ var output = [], i = 0, j;
1075
+
1076
+ if(data && data.data && data.data.children
1077
+ && data.data.children.length > 0) {
1078
+ j = data.data.children.length;
1079
+ for( ; i<j; i++) {
1080
+ var item = data.data.children[i];
1081
+ output.push({
1082
+ date: convertDate(item.data.created),
1083
+ config: config,
1084
+ html: parseRedditItem(item)
1085
+ });
1086
+ }
1087
+ }
1088
+
1089
+ callback(output);
1090
+ }
1091
+ });
1092
+
1093
+ // Expose the template.
1094
+ // We use this to check which templates are available
1095
+ return {
1096
+ "template" : template
1097
+ };
1098
+
1099
+ };
1100
+
1101
+ $.fn.lifestream.feeds.slideshare = function( config, callback ) {
1102
+
1103
+ var template = $.extend({},
1104
+ {
1105
+ uploaded: 'uploaded a presentation <a href="${link}">${title}</a>'
1106
+ },
1107
+ config.template);
1108
+
1109
+ var parseSlideshare = function( input ) {
1110
+ var output = [], list, i = 0, j, item;
1111
+
1112
+ if (input.query && input.query.count && input.query.count > 0) {
1113
+ list = input.query.results.rss.channel.item;
1114
+ j = list.length;
1115
+ for ( ; i < j; i++) {
1116
+ item = list[i];
1117
+
1118
+ output.push({
1119
+ date: new Date(item.pubDate),
1120
+ config: config,
1121
+ html: $.tmpl( template.uploaded, item )
1122
+ });
1123
+
1124
+ }
1125
+ }
1126
+
1127
+ return output;
1128
+ };
1129
+
1130
+ $.ajax({
1131
+ url: createYqlUrl('select * from xml where '
1132
+ + 'url="http://www.slideshare.net/rss/user/' + config.user + '"'),
1133
+ dataType: "jsonp",
1134
+ success: function( data ) {
1135
+ callback(parseSlideshare(data));
1136
+ }
1137
+ });
1138
+
1139
+ // Expose the template.
1140
+ // We use this to check which templates are available
1141
+ return {
1142
+ "template" : template
1143
+ };
1144
+
1145
+ };
1146
+
1147
+ $.fn.lifestream.feeds.stackoverflow = function( config, callback ) {
1148
+
1149
+ var template = $.extend({},
1150
+ {
1151
+ global: '<a href="${link}">${text}</a> - ${title}'
1152
+ },
1153
+ config.template);
1154
+
1155
+ var parseStackoverflowItem = function( item ) {
1156
+ var text="", title="", link="",
1157
+ stackoverflow_link = "http://stackoverflow.com/users/" + config.user,
1158
+ question_link = "http://stackoverflow.com/questions/";
1159
+
1160
+ if(item.timeline_type === "badge") {
1161
+ text = item.timeline_type + " " + item.action + ": "
1162
+ + item.description;
1163
+ title = item.detail;
1164
+ link = stackoverflow_link + "?tab=reputation";
1165
+ }
1166
+ else if (item.timeline_type === "revision"
1167
+ || item.timeline_type === "comment"
1168
+ || item.timeline_type === "accepted"
1169
+ || item.timeline_type === "askoranswered") {
1170
+ text = item.post_type + " " + item.action;
1171
+ title = item.detail || item.description || "";
1172
+ link = question_link + item.post_id;
1173
+ }
1174
+ return {
1175
+ link: link,
1176
+ title: title,
1177
+ text: text
1178
+ };
1179
+ },
1180
+ convertDate = function( date ) {
1181
+ return new Date(date * 1000);
1182
+ };
1183
+
1184
+ $.ajax({
1185
+ url: "http://api.stackoverflow.com/1.1/users/" + config.user
1186
+ + "/timeline?"
1187
+ + "jsonp",
1188
+ dataType: "jsonp",
1189
+ jsonp: 'jsonp',
1190
+ success: function( data ) {
1191
+ var output = [], i = 0, j;
1192
+
1193
+ if(data && data.total && data.total > 0 && data.user_timelines) {
1194
+ j = data.user_timelines.length;
1195
+ for( ; i<j; i++) {
1196
+ var item = data.user_timelines[i];
1197
+ output.push({
1198
+ date: convertDate(item.creation_date),
1199
+ config: config,
1200
+ html: $.tmpl( template.global, parseStackoverflowItem(item) )
1201
+ });
1202
+ }
1203
+ }
1204
+
1205
+ callback(output);
1206
+ }
1207
+ });
1208
+
1209
+ // Expose the template.
1210
+ // We use this to check which templates are available
1211
+ return {
1212
+ "template" : template
1213
+ };
1214
+
1215
+ };
1216
+
1217
+ $.fn.lifestream.feeds.tumblr = function( config, callback ) {
1218
+
1219
+ var template = $.extend({},
1220
+ {
1221
+ posted: 'posted a ${type} <a href="${url}">${title}</a>'
1222
+ },
1223
+ config.template),
1224
+
1225
+ /**
1226
+ * get title text
1227
+ */
1228
+ getTitle = function( post ) {
1229
+ var title = post["regular-title"]
1230
+ || post["quote-text"]
1231
+ || post["conversation-title"]
1232
+ || post["photo-caption"]
1233
+ || post["video-caption"]
1234
+ || post["audio-caption"]
1235
+ || post["regular-body"]
1236
+ || post["link-text"]
1237
+ || post.type
1238
+ || "";
1239
+
1240
+ // remove tags
1241
+ return title.replace( /<.+?>/gi, " ");
1242
+ },
1243
+ createTumblrOutput = function( config, post ) {
1244
+ return {
1245
+ date: new Date(post.date),
1246
+ config: config,
1247
+ html: $.tmpl( template.posted, {
1248
+ type: post.type,
1249
+ url: post.url,
1250
+ title: getTitle(post)
1251
+ } )
1252
+ };
1253
+ },
1254
+ parseTumblr = function( input ) {
1255
+ var output = [], i = 0, j, post;
1256
+ if(input.query && input.query.count && input.query.count > 0) {
1257
+ // If a user only has one post, post is a plain object, otherwise it
1258
+ // is an array
1259
+ if ( $.isArray(input.query.results.posts.post) ) {
1260
+ j = input.query.results.posts.post.length;
1261
+ for( ; i < j; i++) {
1262
+ post = input.query.results.posts.post[i];
1263
+ output.push(createTumblrOutput(config, post));
1264
+ }
1265
+ }
1266
+ else if ( $.isPlainObject(input.query.results.posts.post) ) {
1267
+ output.push(createTumblrOutput(config,input.query.results.posts.post));
1268
+ }
1269
+ }
1270
+ return output;
1271
+ };
1272
+
1273
+ $.ajax({
1274
+ url: createYqlUrl('select *'
1275
+ + ' from tumblr.posts where username="'+ config.user +'"'),
1276
+ dataType: 'jsonp',
1277
+ success: function( data ) {
1278
+ callback(parseTumblr(data));
1279
+ }
1280
+ });
1281
+
1282
+ // Expose the template.
1283
+ // We use this to check which templates are available
1284
+ return {
1285
+ "template" : template
1286
+ };
1287
+
1288
+ };
1289
+
1290
+ $.fn.lifestream.feeds.twitter = function( config, callback ) {
1291
+
1292
+ var template = $.extend({},
1293
+ {
1294
+ posted: '{{html tweet}}'
1295
+ },
1296
+ config.template),
1297
+
1298
+ /**
1299
+ * Add links to the twitter feed.
1300
+ * Hashes, @ and regular links are supported.
1301
+ * @private
1302
+ * @param {String} tweet A string of a tweet
1303
+ * @return {String} A linkified tweet
1304
+ */
1305
+ linkify = function( tweet ) {
1306
+
1307
+ var link = function( t ) {
1308
+ return t.replace(
1309
+ /[a-z]+:\/\/[a-z0-9-_]+\.[a-z0-9-_:~%&\?\/.=]+[^:\.,\)\s*$]/ig,
1310
+ function( m ) {
1311
+ return '<a href="' + m + '">'
1312
+ + ( ( m.length > 25 ) ? m.substr( 0, 24 ) + '...' : m )
1313
+ + '</a>';
1314
+ }
1315
+ );
1316
+ },
1317
+ at = function( t ) {
1318
+ return t.replace(
1319
+ /(^|[^\w]+)\@([a-zA-Z0-9_]{1,15})/g,
1320
+ function( m, m1, m2 ) {
1321
+ return m1 + '<a href="http://twitter.com/' + m2 + '">@'
1322
+ + m2 + '</a>';
1323
+ }
1324
+ );
1325
+ },
1326
+ hash = function( t ) {
1327
+ return t.replace(
1328
+ /(^|[^\w'"]+)\#([a-zA-Z0-9_]+)/g,
1329
+ function( m, m1, m2 ) {
1330
+ return m1 + '<a href="http://search.twitter.com/search?q=%23'
1331
+ + m2 + '">#' + m2 + '</a>';
1332
+ }
1333
+ );
1334
+ };
1335
+
1336
+ return hash(at(link(tweet)));
1337
+
1338
+ },
1339
+ /**
1340
+ * Parse the input from twitter
1341
+ */
1342
+ parseTwitter = function( input ) {
1343
+ var output = [], i = 0, j;
1344
+
1345
+ if(input.query && input.query.count && input.query.count >0) {
1346
+ j = input.query.count;
1347
+ for( ; i<j; i++) {
1348
+ var status = input.query.results.statuses[i].status;
1349
+ output.push({
1350
+ date: new Date(status.created_at),
1351
+ config: config,
1352
+ html: $.tmpl( template.posted, {
1353
+ tweet: linkify(status.text)
1354
+ } )
1355
+ });
1356
+ }
1357
+ }
1358
+ return output;
1359
+ };
1360
+
1361
+ $.ajax({
1362
+ url: createYqlUrl('select status.id, status.created_at, status.text'
1363
+ + ' from twitter.user.timeline where screen_name="'+ config.user +'"'),
1364
+ dataType: 'jsonp',
1365
+ success: function( data ) {
1366
+ callback(parseTwitter(data));
1367
+ }
1368
+ });
1369
+
1370
+ // Expose the template.
1371
+ // We use this to check which templates are available
1372
+ return {
1373
+ "template" : template
1374
+ };
1375
+
1376
+ };
1377
+
1378
+ $.fn.lifestream.feeds.vimeo = function( config, callback ) {
1379
+
1380
+ var template = $.extend({},
1381
+ {
1382
+ posted: 'posted <a href="${url}" title="${description}">${title}</a>'
1383
+ },
1384
+ config.template),
1385
+
1386
+ parseVimeo = function( input ) {
1387
+ var output = [], i = 0, j, item;
1388
+
1389
+ if (input) {
1390
+ j = input.length;
1391
+ for( ; i < j; i++) {
1392
+ item = input[i];
1393
+ output.push({
1394
+ date: new Date( item.upload_date.replace(' ', 'T') ),
1395
+ config: config,
1396
+ html: $.tmpl( template.posted, {
1397
+ url: item.url,
1398
+ description: item.description.replace(/"/g, "'")
1399
+ .replace( /<.+?>/gi, ""),
1400
+ title: item.title
1401
+ } )
1402
+ });
1403
+ }
1404
+ }
1405
+
1406
+ return output;
1407
+ };
1408
+
1409
+ $.ajax({
1410
+ url: "http://vimeo.com/api/v2/" + config.user + "/videos.json",
1411
+ dataType: "jsonp",
1412
+ crossDomain: true,
1413
+ success: function( data ) {
1414
+ callback(parseVimeo(data));
1415
+ }
1416
+ });
1417
+
1418
+ // Expose the template.
1419
+ // We use this to check which templates are available
1420
+ return {
1421
+ "template" : template
1422
+ };
1423
+
1424
+ };
1425
+
1426
+ $.fn.lifestream.feeds.wordpress = function( config, callback ) {
1427
+
1428
+ var template = $.extend({},
1429
+ {
1430
+ posted: 'posted <a href="${link}">${title}</a>'
1431
+ },
1432
+ config.template);
1433
+
1434
+ var parseWordpress = function ( input ) {
1435
+ var output = [], list, i = 0, j, item;
1436
+
1437
+ if ( input.query && input.query.count && input.query.count > 0
1438
+ && input.query.results.rss.channel.item ) {
1439
+ list = input.query.results.rss.channel.item;
1440
+ j = list.length;
1441
+ for ( ; i < j; i++) {
1442
+ item = list[i];
1443
+
1444
+ output.push({
1445
+ date: new Date( item.pubDate ),
1446
+ config: config,
1447
+ html: $.tmpl( template.posted, item )
1448
+ });
1449
+ }
1450
+ }
1451
+
1452
+ return output;
1453
+ };
1454
+
1455
+ $.ajax({
1456
+ url: createYqlUrl('select * from xml where '
1457
+ + 'url="http://' + config.user + '.wordpress.com/feed"'),
1458
+ dataType: "jsonp",
1459
+ success: function ( data ) {
1460
+ callback(parseWordpress(data));
1461
+ }
1462
+ });
1463
+
1464
+ // Expose the template.
1465
+ // We use this to check which templates are available
1466
+ return {
1467
+ "template" : template
1468
+ };
1469
+
1470
+ };
1471
+
1472
+ $.fn.lifestream.feeds.youtube = function( config, callback ) {
1473
+
1474
+ var template = $.extend({},
1475
+ {
1476
+ favorited: 'favorited <a href="${video.player.default}" '
1477
+ + 'title="${video.description}">${video.title}</a>'
1478
+ },
1479
+ config.template),
1480
+
1481
+ parseYoutube = function( input ) {
1482
+ var output = [], i = 0, j, item;
1483
+
1484
+ if(input.data && input.data.items) {
1485
+ j = input.data.items.length;
1486
+ for( ; i<j; i++) {
1487
+ item = input.data.items[i];
1488
+ output.push({
1489
+ date: new Date(item.created),
1490
+ config: config,
1491
+ html: $.tmpl( template.favorited, item )
1492
+ });
1493
+ }
1494
+ }
1495
+
1496
+ return output;
1497
+ };
1498
+
1499
+ $.ajax({
1500
+ url: "http://gdata.youtube.com/feeds/api/users/" + config.user
1501
+ + "/favorites?v=2&alt=jsonc",
1502
+ dataType: 'jsonp',
1503
+ success: function( data ) {
1504
+ callback(parseYoutube(data));
1505
+ }
1506
+ });
1507
+
1508
+ // Expose the template.
1509
+ // We use this to check which templates are available
1510
+ return {
1511
+ "template" : template
1512
+ };
1513
+
1514
+ };
1515
+
1516
+ }( jQuery ));