murlsh 0.11.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.htaccess +2 -0
  2. data/README.textile +3 -33
  3. data/Rakefile +12 -5
  4. data/VERSION +1 -1
  5. data/config.ru +10 -4
  6. data/config.yaml +6 -12
  7. data/lib/murlsh/dispatch.rb +0 -6
  8. data/lib/murlsh/img_store.rb +36 -0
  9. data/lib/murlsh/markup.rb +0 -1
  10. data/lib/murlsh/plugin.rb +2 -6
  11. data/lib/murlsh/uri_ask.rb +66 -22
  12. data/lib/murlsh/url.rb +0 -18
  13. data/lib/murlsh/url_body.rb +15 -23
  14. data/lib/murlsh/url_server.rb +5 -5
  15. data/murlsh.gemspec +44 -19
  16. data/plugins/add_post_50_update_feed.rb +17 -3
  17. data/plugins/add_post_50_update_podcast.rb +46 -0
  18. data/plugins/add_post_50_update_rss.rb +18 -2
  19. data/plugins/add_post_60_notify_hubs.rb +3 -1
  20. data/plugins/add_pre_40_convert_mobile.rb +30 -0
  21. data/plugins/add_pre_50_lookup_content_type_title.rb +11 -4
  22. data/plugins/add_pre_60_flickr.rb +38 -0
  23. data/plugins/add_pre_60_github_title.rb +5 -1
  24. data/plugins/add_pre_60_google_code_title.rb +5 -2
  25. data/plugins/add_pre_60_imageshack.rb +31 -0
  26. data/plugins/add_pre_60_imgur.rb +32 -0
  27. data/plugins/add_pre_60_s3_image.rb +34 -0
  28. data/plugins/add_pre_60_twitter.rb +35 -0
  29. data/plugins/add_pre_60_vimeo.rb +35 -0
  30. data/plugins/add_pre_60_youtube.rb +31 -0
  31. data/plugins/html_parse_50_hpricot.rb +2 -0
  32. data/plugins/url_display_add_45_mp3.rb +30 -0
  33. data/plugins/url_display_add_50_hostrec.rb +38 -0
  34. data/plugins/url_display_add_55_content_type.rb +27 -0
  35. data/plugins/url_display_add_60_via.rb +52 -0
  36. data/plugins/url_display_add_65_time.rb +22 -0
  37. data/public/css/jquery.jgrowl.css +0 -3
  38. data/public/css/screen.css +0 -18
  39. data/public/img/thumb/README +0 -0
  40. data/public/js/jquery-1.4.3.min.js +166 -0
  41. data/public/js/js.js +62 -234
  42. data/public/js/twitter-text-1.0.3.js +538 -0
  43. data/spec/img_store_spec.rb +53 -0
  44. data/spec/uri_ask_spec.rb +14 -4
  45. metadata +139 -37
  46. data/lib/murlsh/flickr_server.rb +0 -55
  47. data/lib/murlsh/twitter_server.rb +0 -45
  48. data/lib/murlsh/unwrap_jsonp.rb +0 -15
  49. data/lib/murlsh/xhtml_response.rb +0 -20
  50. data/plugins/hostrec_50_redundant.rb +0 -14
  51. data/plugins/hostrec_60_skip.rb +0 -24
  52. data/plugins/time_50_ago.rb +0 -16
  53. data/plugins/via_50_domain.rb +0 -36
  54. data/public/js/jquery-1.4.2.min.js +0 -154
  55. data/spec/unwrap_json_spec.rb +0 -21
  56. data/spec/xhtml_response_spec.rb +0 -112
data/public/js/js.js CHANGED
@@ -3,35 +3,28 @@
3
3
  "use strict";
4
4
 
5
5
  var Murlsh = function (config, $, navigator, window) {
6
- function compileRegexMap(regexMap) {
7
- var result = {};
8
- $.each(regexMap, function (reStr) {
9
- result[reStr] = new RegExp('^' + reStr + '$', 'i');
10
- });
11
-
12
- return result;
13
- }
14
6
 
15
7
  var my = {},
16
8
  hrefRes = {
17
- flickr :
18
- /^http:\/\/(?:www\.)?flickr\.com\/photos\/[@\w\-]+?\/([\d]+)/i,
19
9
  imageshack :
20
- /^(http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.)(jpe?g|gif|png)$/i,
10
+ /^http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.jpe?g|gif|png$/i,
21
11
  imgur :
22
- /^(http:\/\/(?:i\.)?imgur\.com\/)([a-z\d]+)(\.(?:jpe?g|gif|png))$/i,
23
- mp3 :
24
- /\.mp3$/i,
12
+ /^http:\/\/(?:i\.)?imgur\.com\/[a-z\d]+\.(?:jpe?g|gif|png)$/i,
25
13
  s3 :
26
- /^(http:\/\/static\.mmb\.s3\.amazonaws\.com\/[\w\-]+\.)(jpe?g|gif|pdf|png)$/i,
14
+ /^http:\/\/static\.mmb\.s3\.amazonaws\.com\/[\w\-]+\.(jpe?g|gif|pdf|png)$/i,
27
15
  twitter :
28
- /^https?:\/\/twitter\.com\/\w+\/status(?:es)?\/(\d+)$/i,
16
+ /^https?:\/\/twitter\.com\/\w+\/status(?:es)?\/\d+$/i,
29
17
  vimeo :
30
18
  /^http:\/\/(?:www\.)?vimeo\.com\/(\d+)$/i,
31
19
  youtube :
32
20
  /^http:\/\/(?:(?:www|uk)\.)?youtube\.com\/watch\?v=([\w\-]+)(?:&|$)/i
33
- },
34
- thumbLocatorsCompiled = compileRegexMap(config.thumb_locators);
21
+ };
22
+
23
+ function setupClickHandler(jQueryObject, dataKey, dataValue, handler) {
24
+ if (!my.isIphone()) {
25
+ jQueryObject.data(dataKey, dataValue).click(handler);
26
+ }
27
+ }
35
28
 
36
29
  function autoLink(s) {
37
30
  // turn urls into links
@@ -42,8 +35,13 @@ var Murlsh = function (config, $, navigator, window) {
42
35
  return result;
43
36
  }
44
37
 
45
- function escapeXml(s) {
46
- return s.replace(/&/g, '&');
38
+ function makeIframe(src) {
39
+ return $('<iframe />').attr({
40
+ src: src,
41
+ width: 640,
42
+ height: 385,
43
+ frameborder: 0
44
+ });
47
45
  }
48
46
 
49
47
  function img(src, text) {
@@ -67,23 +65,6 @@ var Murlsh = function (config, $, navigator, window) {
67
65
  }
68
66
  }
69
67
 
70
- function objectTag(data, height, width, params) {
71
- // this does not use jQuery to build tags because building object
72
- // tags is broken in IE
73
- var result = '<object data="' + escapeXml(data) +
74
- '" height="' + height +
75
- '" type="application/x-shockwave-flash" width="' + width + '">';
76
-
77
- $.each(params, function (i, v) {
78
- result += '<param name="' + v.name + '" value="' +
79
- escapeXml(v.value) + '" />';
80
- });
81
-
82
- result += '</object>';
83
-
84
- return result;
85
- }
86
-
87
68
  function closerAdd(x, header) {
88
69
  var html = (typeof x === 'object') ? $('<div />').append(x).html() : x;
89
70
 
@@ -97,116 +78,31 @@ var Murlsh = function (config, $, navigator, window) {
97
78
  makeFit($(this), Math.round($(window).width() / 2),
98
79
  Math.round($(window).height() - 100));
99
80
  });
100
- }
81
+ },
82
+ animateOpen : { width : 'show' },
83
+ animateClose : { width : 'hide' }
101
84
  });
102
85
  }
103
86
 
104
- function flickrClick() {
105
- closerAdd(img($(this).data('zoom')));
106
- }
107
-
108
- function flickrThumb(d) {
109
- var base,
110
- owner,
111
- photo = d.photo,
112
- zoom;
113
-
114
- if (d.stat === 'ok') {
115
- base = 'http://farm' + photo.farm + '.static.flickr.com/' +
116
- photo.server + '/' + photo.id + '_';
117
- zoom = base + photo.secret + '_m.jpg';
118
-
119
- if (photo.originalsecret) {
120
- zoom = base + photo.originalsecret + '_o.' +
121
- photo.originalformat;
122
- }
123
-
124
- owner = photo.owner;
125
- return img(base + photo.secret + '_s.jpg', photo.title._content +
126
- (owner && owner.username ? ' by ' + owner.username : '')
127
- ).addClass('thumb flickr').data('zoom', zoom);
128
- }
87
+ function imgClick(event) {
88
+ closerAdd(img($(event.target).data('href')));
129
89
  }
130
90
 
131
- function imgClick() {
132
- closerAdd(img($(this).data('href')));
133
- }
134
-
135
- function imgThumb() {
136
- var i,
137
- lastIndex,
138
- urlParts = [];
139
-
140
- for (i = 0; i < arguments.length; i += 1) {
141
- urlParts.push(arguments[i]);
142
- }
143
-
144
- lastIndex = urlParts.length - 1;
145
-
146
- // if pdf the thumbnail will be .png
147
- if (urlParts[lastIndex].match(/^pdf$/i)) {
148
- urlParts.splice(lastIndex, 1, 'png');
149
- }
91
+ function vimeoClick(event) {
92
+ var iframe = makeIframe(
93
+ 'http://player.vimeo.com/video/' + $(event.target).data('id'));
150
94
 
151
- return img(urlParts.join('')).addClass('thumb');
95
+ closerAdd(iframe);
152
96
  }
153
97
 
154
- function thumbInsert(img, clickFunction, a) {
155
- if (img) {
156
- if (my.isIphone()) {
157
- a.prepend(img);
158
- } else {
159
- if (clickFunction) {
160
- img.click(clickFunction);
161
- }
162
- a.before(img);
163
- }
164
- }
165
- }
166
-
167
- function twitterAddLinks(s) {
168
- // turn urls into links and Twitter usernames into links to Twitter
169
- var result = autoLink(s);
170
-
171
- result = result.replace(
172
- /(^|[\s,(])@([0-9a-z_]+)($|[\s,.)])/gi,
173
- '$1<a href="http://twitter.com/$2">@$2</a>$3');
174
-
175
- return result;
176
- }
177
-
178
- function twitterThumb(d) {
179
- return img(d.user.profile_image_url).addClass('thumb twitter');
180
- }
181
-
182
- function vimeoClick() {
183
- closerAdd($(this).data('embedHtml'));
184
- }
185
-
186
- function vimeoThumb(d) {
187
- return img(d.thumbnail_medium, d.title).addClass('thumb vimeo');
188
- }
189
-
190
- function youtubeClick() {
191
- var movie = 'http://www.youtube.com/v/' + $(this).data('id') + '?' +
192
- $.param({
193
- fs : 1,
194
- hd : 1,
195
- hl : 'en',
196
- iv_load_policy : 3,
197
- showinfo : 0,
198
- showsearch : 0
199
- });
200
-
201
- closerAdd(objectTag(movie, 505, 640, [{
202
- name : 'movie',
203
- value : movie
204
- }]));
205
- }
98
+ function youtubeClick(event) {
99
+ var iframe = makeIframe(
100
+ 'http://www.youtube.com/embed/' + $(event.target).data('id')).attr({
101
+ 'class': 'youtube-player',
102
+ type: 'text/html'
103
+ });
206
104
 
207
- function youtubeThumb(id) {
208
- return img('http://img.youtube.com/vi/' + id + '/default.jpg',
209
- 'click to watch').addClass('thumb youtube').data('id', id);
105
+ closerAdd(iframe);
210
106
  }
211
107
 
212
108
  my.addComments = function (link, comments) {
@@ -240,111 +136,42 @@ var Murlsh = function (config, $, navigator, window) {
240
136
  var thisA = $(this),
241
137
  href = thisA.attr('href'),
242
138
  match = {},
243
- swf = 'swf/player_mp3_mini.swf',
244
- thumb;
139
+ tweetMatch,
140
+ tweetLink,
141
+ formattedTweet;
245
142
 
246
143
  $.each(hrefRes, function (x, re) {
247
144
  return !(match[x] = re.exec(href));
248
145
  });
249
146
 
250
- if (match.flickr) {
251
- $.ajax({
252
- // url : 'http://api.flickr.com/services/rest/',
253
- url : 'flickr',
254
- data : {
255
- format : 'json',
256
- method : 'flickr.photos.getinfo',
257
- photo_id : match.flickr[1]
258
- },
259
- dataType : 'jsonp',
260
- jsonp : 'jsoncallback',
261
- success : function (d) {
262
- thumbInsert(flickrThumb(d), flickrClick, $(this));
263
- },
264
- context : thisA,
265
- jsonpCallback : 'flickrCallback' + match.flickr[1]
266
- });
267
- } else if (match.imageshack) {
268
- thumbInsert(imgThumb(match.imageshack[1], 'th.',
269
- match.imageshack[2]).data('href', match.imageshack[0]),
270
- imgClick, thisA.html('imageshack.us'));
271
- } else if (match.imgur) {
272
- thumbInsert(imgThumb(match.imgur[1], match.imgur[2], 's',
273
- match.imgur[3]).data('href', match.imgur[0]), imgClick,
274
- thisA.html('imgur/' + match.imgur[2] + match.imgur[3]));
275
- } else if (match.mp3) {
276
- thisA.before(objectTag(swf, 20, 200, [
277
- { name : 'bgcolor', value : '#000000' },
278
- { name : 'FlashVars', value : 'mp3=' + href },
279
- { name : 'movie', value : swf }
280
- ]));
147
+ if (match.imageshack || match.imgur) {
148
+ setupClickHandler(thisA.siblings('img'), 'href', href, imgClick);
281
149
  } else if (match.s3) {
282
- thumb = imgThumb(match.s3[1], 'th.', match.s3[2]);
283
-
284
- if (match.s3[2].match(/^pdf$/i)) {
285
- thisA.before(thumb).html('pdf');
286
- } else {
287
- if (my.isIphone()) {
288
- thisA.html(thumb);
289
- } else {
290
- thisA.html('link');
291
- thisA.before(thumb.data('href', match.s3[0]).click(
292
- imgClick));
293
- }
150
+ if (!(match.s3[1].match(/^pdf$/i))) {
151
+ setupClickHandler(thisA.siblings('img'), 'href', href,
152
+ imgClick);
294
153
  }
295
154
  } else if (match.twitter) {
296
- $.ajax({
297
- // url : 'http://api.twitter.com/1/statuses/show/' +
298
- url : '/twitter/1/statuses/show/' +
299
- match.twitter[1] + '.json',
300
- dataType : 'jsonp',
301
- success : function (d) {
302
- var nameLink = $('<a />', {
303
- href: 'http://twitter.com/' + d.user.screen_name +
304
- '/status/' + d.id,
305
- text: '@' + d.user.screen_name
306
- }),
307
- tweet = $('<span />').addClass('tweet').append(
308
- nameLink).append(': ').append(twitterAddLinks(
309
- d.text));
310
-
311
- thumbInsert(twitterThumb(d), null, nameLink);
312
-
313
- $(this).replaceWith(tweet);
314
- },
315
- context : thisA,
316
- jsonpCallback : 'twitterCallback' + match.twitter[1]
317
- });
155
+ thisA.siblings('img').addClass('twitter');
156
+ tweetMatch = /^(@[0-9a-z_]+?): (.+)$/i.exec(thisA.text());
157
+ if (tweetMatch) {
158
+ tweetLink = $('<a />', {
159
+ href : href,
160
+ text : tweetMatch[1]
161
+ });
162
+
163
+ formattedTweet = $('<span />').addClass('tweet').append(
164
+ tweetLink).append(': ').append(
165
+ twttr.txt.autoLink(tweetMatch[2]));
166
+
167
+ thisA.replaceWith(formattedTweet);
168
+ }
318
169
  } else if (match.vimeo) {
319
- $.ajax({
320
- url : 'http://vimeo.com/api/v2/video/' + match.vimeo[1] +
321
- '.json',
322
- dataType : 'jsonp',
323
- success : function (d) {
324
- var video = d[0],
325
- movie = 'http://vimeo.com/moogaloop.swf?clip_id=' +
326
- video.id;
327
-
328
- thumbInsert(vimeoThumb(video).data('embedHtml',
329
- objectTag(movie, video.height, video.width, [
330
- { name : 'movie', value : movie }
331
- ])), vimeoClick, $(this));
332
- },
333
- context : thisA,
334
- jsonpCallback : 'vimeoCallback' + match.vimeo[1]
335
- });
170
+ setupClickHandler(thisA.siblings('img'), 'id', match.vimeo[1],
171
+ vimeoClick);
336
172
  } else if (match.youtube) {
337
- thumbInsert(youtubeThumb(match.youtube[1]), youtubeClick, thisA);
338
- } else {
339
- $.each(config.thumb_locators, function (reStr) {
340
- var re = thumbLocatorsCompiled[reStr];
341
- if (href.match(re)) {
342
- thumbInsert(img(href.replace(re,
343
- config.thumb_locators[reStr])).addClass(
344
- 'thumb locator'), null, thisA);
345
- return false;
346
- }
347
- });
173
+ setupClickHandler(thisA.siblings('img'), 'id', match.youtube[1],
174
+ youtubeClick);
348
175
  }
349
176
  };
350
177
 
@@ -425,7 +252,8 @@ $(document).ready(function () {
425
252
  urls.each(murlsh.addExtra);
426
253
 
427
254
  /*
428
- // experimental comment support, to enable uncomment and edit comments.json
255
+ // experimental comment support, to enable uncomment and edit
256
+ // comments.json
429
257
  $.getJSON('/js/comments.json', function (data) {
430
258
  urls.each(function () {
431
259
  var href = $(this).attr('href');