murlsh 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -84,4 +84,35 @@ subscribe_url is what gets put in the feed as link rel="hub"
84
84
 
85
85
  This will make updates to your feed show up in Google Reader instantly.
86
86
 
87
+ h1. Thumbnail Locators
88
+
89
+ If the url for a thumbnail image can be generated by regex search and replace
90
+ on a posted url, a rule can be added to the configuration to automatically
91
+ show a thumbnail image for it. The 'thumb_locators' config key is a hash
92
+ of Javascript regex to Javascript replacement string (which can include
93
+ captured groups). The hash key is wrapped in ^ and $ before compilation so
94
+ it must match the entire url. The regex is compiled case-insensitive.
95
+
96
+ For example:
97
+
98
+ * Show the GitHub octocat Apple touch icon
99
+ (http://github.com/apple-touch-icon.png) as a thumbnail for GitHub links
100
+ * Show a friend's Gravatar for the thumbnails of links to his blog
101
+
102
+ <pre>
103
+ <code>
104
+ thumb_locators:
105
+ (http:\/\/github\.com\/).*: $1apple-touch-icon.png
106
+ http:\/\/myfriend\.com\/.*: http://gravatar.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</code>
107
+ </pre>
108
+
109
+ h1. Design Goals
110
+
111
+ * make site fast and very cacheable, caching wrapper around calls to third party JSON APIs
112
+ * low effort required to add a url, get metadata programatically instead of requiring user to specify
113
+ * heavy lifting on the client side
114
+ * allow customization with config and plugins
115
+ * full regex search for finding saved urls
116
+ * simple security (no sessions, no cookies)
117
+
87
118
  Questions and comments: "matthewm@boedicker.org":mailto:matthewm@boedicker.org
data/Rakefile CHANGED
@@ -15,6 +15,11 @@ sqlite3
15
15
  murlsh
16
16
  }.each { |d| require d }
17
17
 
18
+ # optional libraries
19
+ %w{
20
+ metric_fu
21
+ }.each { |d| Murlsh::failproof { require d } }
22
+
18
23
  config = YAML.load_file('config.yaml')
19
24
 
20
25
  desc 'Initialize a new installation.'
@@ -261,6 +266,8 @@ directory 'public/js'
261
266
 
262
267
  namespace :js do
263
268
 
269
+ MURLSH_JS = %w{public/js/js.js}
270
+
264
271
  desc 'Combine and compress javascript.'
265
272
  task :compress => ['public/js'] do
266
273
  combined = cat(config['js_files'].map { |x| "public/#{x}" } )
@@ -293,13 +300,21 @@ namespace :js do
293
300
  end
294
301
 
295
302
  desc 'Run javascript through jslint.'
296
- task :lint do
297
- %{public/js/js.js}.each do |jsf|
303
+ task :jslint do
304
+ MURLSH_JS.each do |jsf|
298
305
  puts jsf
299
306
  puts `rhino http://www.jslint.com/rhino/jslint.js #{jsf}`
300
307
  end
301
308
  end
302
309
 
310
+ desc "Run javascript through Google's Closure Linter."
311
+ task :gjslint do
312
+ MURLSH_JS.each do |jsf|
313
+ puts jsf
314
+ puts `gjslint #{jsf}`
315
+ end
316
+ end
317
+
303
318
  end
304
319
 
305
320
  def ask(prompt, sep=':')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.10.0
1
+ 0.11.0
data/config.yaml CHANGED
@@ -1,11 +1,9 @@
1
1
  ---
2
- apple_icon_hosts: []
3
-
4
2
  auth_file: murlsh_users
5
3
  cache_entitystore: file:tmp/cache/rack/body
6
4
  cache_metastore: file:tmp/cache/rack/meta
7
5
  config_js:
8
- - apple_icon_hosts
6
+ - thumb_locators
9
7
  css_files:
10
8
  - css/jquery.jgrowl.css
11
9
  - css/screen.css
@@ -27,3 +25,11 @@ pubsubhubbub_hubs: []
27
25
 
28
26
  root_url: http://urls.matthewm.boedicker.org/
29
27
  show_names: true
28
+ thumb_locators:
29
+ (http:\/\/(cgi\.)?ebay\.(com|co\.uk)\/).*: $1apple-touch-icon.png
30
+ (http:\/\/blog\.makezine\.com\/).*: $1apple-touch-icon.png
31
+ (http:\/\/en\.wikipedia\.org\/).*: $1apple-touch-icon.png
32
+ (http:\/\/github\.com\/).*: $1apple-touch-icon.png
33
+ (http:\/\/stackoverflow\.com\/).*: $1apple-touch-icon.png
34
+ (http:\/\/www\.nytimes\.com\/).*: $1apple-touch-icon.png
35
+ (http:\/\/www\.wired\.com\/).*: $1apple-touch-icon.png
@@ -12,6 +12,8 @@ module Murlsh
12
12
  # Will include all config keys contained in the config key named config_js.
13
13
  class ConfigServer
14
14
 
15
+ include HeadFromGet
16
+
15
17
  def initialize(config)
16
18
  @config_json =
17
19
  config.reject { |k,v| !config.fetch('config_js', []).
@@ -16,6 +16,7 @@ module Murlsh
16
16
 
17
17
  ActiveRecord::Base.establish_connection(
18
18
  :adapter => 'sqlite3', :database => @config.fetch('db_file'))
19
+ ActiveRecord::Base.include_root_in_json = false
19
20
 
20
21
  db = ActiveRecord::Base.connection.instance_variable_get(:@connection)
21
22
 
@@ -27,10 +28,14 @@ module Murlsh
27
28
  root_path = URI(@config.fetch('root_url')).path
28
29
 
29
30
  @dispatch = [
31
+ [%r{^HEAD #{root_path}(url)?$}, url_server.method(:head)],
30
32
  [%r{^GET #{root_path}(url)?$}, url_server.method(:get)],
31
33
  [%r{^POST #{root_path}(url)?$}, url_server.method(:post)],
34
+ [%r{^HEAD #{root_path}config$}, config_server.method(:head)],
32
35
  [%r{^GET #{root_path}config$}, config_server.method(:get)],
36
+ [%r{^HEAD #{root_path}flickr$}, flickr_server.method(:head)],
33
37
  [%r{^GET #{root_path}flickr$}, flickr_server.method(:get)],
38
+ [%r{^HEAD #{root_path}twitter/.+$}, twitter_server.method(:head)],
34
39
  [%r{^GET #{root_path}twitter/.+$}, twitter_server.method(:get)],
35
40
  ]
36
41
  end
data/lib/murlsh/doc.rb CHANGED
@@ -18,8 +18,8 @@ module Murlsh
18
18
  nil
19
19
  end
20
20
 
21
- # Check a list of xpaths in order and return the inner html of the first
22
- # one that is not nil.
21
+ # Check a list of xpaths in order and yield and return the node matching
22
+ # the first one that is not nil
23
23
  def xpath_search(xpaths)
24
24
  [*xpaths].each do |xpath|
25
25
  selection = (self/xpath).first
@@ -15,6 +15,8 @@ module Murlsh
15
15
  # with cache-control, etag and last-modified headers set.
16
16
  class FlickrServer
17
17
 
18
+ include HeadFromGet
19
+
18
20
  def initialize(config); @config = config; end
19
21
 
20
22
  # Proxy a request to the Flickr API.
@@ -0,0 +1,15 @@
1
+ module Murlsh
2
+
3
+ # mixin for adding head() that calls get() and removed the body
4
+ module HeadFromGet
5
+
6
+ # call get() and remove the body
7
+ def head(req)
8
+ resp = get(req)
9
+ resp.body = ''
10
+ resp
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -7,7 +7,7 @@ class ActiveRecord::ConnectionAdapters::SQLite3Adapter
7
7
  # Add MATCH function for regex matching.
8
8
  def initialize(connection, logger, config)
9
9
  super
10
- @connection.create_function('MATCH', 2) do |func,search_in,search_for|
10
+ @connection.create_function('MURLSHMATCH', 2) do |func,search_in,search_for|
11
11
  func.result = search_in.to_s.match(/#{search_for}/i) ? 1 : nil
12
12
  end
13
13
  end
@@ -15,6 +15,8 @@ module Murlsh
15
15
  # cache-control, etag and last-modified headers set.
16
16
  class TwitterServer
17
17
 
18
+ include HeadFromGet
19
+
18
20
  # Proxy a request to the Twitter API.
19
21
  def get(req)
20
22
  resp = Rack::Response.new
@@ -4,6 +4,7 @@ net/https
4
4
  open-uri
5
5
  uri
6
6
 
7
+ hpricot
7
8
  htmlentities
8
9
  iconv
9
10
  }.each { |m| require m }
@@ -22,19 +23,23 @@ module Murlsh
22
23
  return @content_type if defined?(@content_type)
23
24
  options[:headers] = default_headers.merge(options.fetch(:headers, {}))
24
25
 
25
- @content_type = ''
26
+ content_type = ''
26
27
  Murlsh::failproof(options) do
27
28
  # try head first to save bandwidth
28
29
  http = Net::HTTP.new(host, port)
29
30
  http.use_ssl = (scheme == 'https')
30
31
 
31
32
  resp = http.request_head(path_query, options[:headers])
32
- @content_type = case resp
33
- when Net::HTTPSuccess then resp['content-type']
34
- else self.open(options[:headers]) { |f| f.content_type }
33
+
34
+ if Net::HTTPSuccess === resp
35
+ content_type = resp['content-type']
36
+ end
37
+
38
+ if not content_type or content_type.empty?
39
+ content_type = self.open(options[:headers]) { |f| f.content_type }
35
40
  end
36
41
  end
37
- @content_type
42
+ @content_type = content_type
38
43
  end
39
44
 
40
45
  # Get the HTML title.
@@ -91,8 +96,12 @@ module Murlsh
91
96
  if html?(options)
92
97
  Murlsh::failproof(options) do
93
98
  self.open(options[:headers]) do |f|
94
- @doc = Murlsh::Plugin.hooks('html_parse').first.run(f).extend(
95
- Murlsh::Doc)
99
+ html_parse_plugins = Murlsh::Plugin.hooks('html_parse')
100
+ @doc = if html_parse_plugins.empty?
101
+ Hpricot(f).extend(Murlsh::Doc)
102
+ else
103
+ html_parse_plugins.first.run(f).extend(Murlsh::Doc)
104
+ end
96
105
 
97
106
  @charset = @doc.charset || f.charset
98
107
  end
data/lib/murlsh/url.rb CHANGED
@@ -8,6 +8,7 @@ module Murlsh
8
8
 
9
9
  # URL ActiveRecord.
10
10
  class Url < ActiveRecord::Base
11
+ validates_format_of :url, :with => URI.regexp
11
12
 
12
13
  # Get the title of this url.
13
14
  def title
@@ -1,3 +1,7 @@
1
+ %w{
2
+ builder
3
+ }.each { |m| require m }
4
+
1
5
  module Murlsh
2
6
 
3
7
  # Url list page builder.
@@ -20,7 +24,7 @@ module Murlsh
20
24
  def search_conditions
21
25
  if @q
22
26
  search_cols = %w{name title url}
23
- [search_cols.map { |x| "MATCH(#{x}, ?)" }.join(' OR ')].push(
27
+ [search_cols.map { |x| "MURLSHMATCH(#{x}, ?)" }.join(' OR ')].push(
24
28
  *[@q] * search_cols.size)
25
29
  else
26
30
  []
@@ -8,6 +8,8 @@ module Murlsh
8
8
  # Build responses for HTTP requests.
9
9
  class UrlServer
10
10
 
11
+ include HeadFromGet
12
+
11
13
  def initialize(config, db)
12
14
  @config, @db = config, db
13
15
  ActiveRecord::Base.default_timezone = :utc
@@ -34,38 +36,40 @@ module Murlsh
34
36
 
35
37
  # Respond to a POST request. Add the new url and return json.
36
38
  def post(req)
37
- unless req.params['url'].empty?
38
- auth = req.params['auth']
39
- if user = auth.empty? ? nil : Murlsh::Auth.new(
40
- @config.fetch('auth_file')).auth(auth)
41
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
42
- :database => @config.fetch('db_file'))
43
-
44
- mu = Murlsh::Url.new do |u|
45
- u.time = Time.now.gmtime
46
- u.url = req.params['url']
47
- u.email = user[:email]
48
- u.name = user[:name]
49
- u.via = req.params['via'] unless (req.params['via'] || []).empty?
50
- end
39
+ auth = req.params['auth']
40
+ if user = auth.empty? ? nil : Murlsh::Auth.new(
41
+ @config.fetch('auth_file')).auth(auth)
42
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
43
+ :database => @config.fetch('db_file'))
44
+
45
+ mu = Murlsh::Url.new do |u|
46
+ u.time = Time.now.gmtime
47
+ u.url = req.params['url']
48
+ u.email = user[:email]
49
+ u.name = user[:name]
50
+ u.via = req.params['via'] unless (req.params['via'] || []).empty?
51
+ end
51
52
 
53
+ begin
54
+ # validate before add_pre plugins have run and also after (in save!)
55
+ raise ActiveRecord::RecordInvalid.new(mu) unless mu.valid?
52
56
  Murlsh::Plugin.hooks('add_pre') { |p| p.run(mu, @config) }
53
-
54
- mu.save
55
-
57
+ mu.save!
56
58
  Murlsh::Plugin.hooks('add_post') { |p| p.run(@config) }
57
-
58
- resp = Rack::Response.new([mu].to_json, 200, {
59
- 'Content-Type' => 'application/json' })
60
-
61
- resp
62
- else
63
- Rack::Response.new('Permission denied', 403, {
64
- 'Content-Type' => 'text/plain' })
59
+ response_body, response_code = [mu], 200
60
+ rescue ActiveRecord::RecordInvalid => error
61
+ response_body = {
62
+ 'url' => error.record,
63
+ 'errors' => error.record.errors,
64
+ }
65
+ response_code = 500
65
66
  end
66
67
  else
67
- Rack::Response.new('No url', 500, { 'Content-Type' => 'text/plain' })
68
+ response_body, response_code = '', 403
68
69
  end
70
+
71
+ Rack::Response.new(response_body.to_json, response_code, {
72
+ 'Content-Type' => 'application/json' })
69
73
  end
70
74
 
71
75
  end
data/lib/murlsh.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'murlsh/head_from_get'
2
+
1
3
  Dir.glob(File.join(File.dirname(__FILE__), 'murlsh', '*.rb')).
2
4
  map { |f| File.join('murlsh', File.basename(f, '.rb')) }.
3
5
  sort.
data/murlsh.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{murlsh}
8
- s.version = "0.10.0"
8
+ s.version = "0.11.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Matthew M. Boedicker"]
12
- s.date = %q{2010-08-05}
12
+ s.date = %q{2010-09-21}
13
13
  s.default_executable = %q{murlsh}
14
14
  s.description = %q{url sharing site framework with easy adding, title lookup, atom feed, thumbnails and embedding}
15
15
  s.email = %q{matthewm@boedicker.org}
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
36
36
  "lib/murlsh/failproof.rb",
37
37
  "lib/murlsh/far_future_expires.rb",
38
38
  "lib/murlsh/flickr_server.rb",
39
+ "lib/murlsh/head_from_get.rb",
39
40
  "lib/murlsh/markup.rb",
40
41
  "lib/murlsh/must_revalidate.rb",
41
42
  "lib/murlsh/openlock.rb",
@@ -57,6 +58,7 @@ Gem::Specification.new do |s|
57
58
  "plugins/add_post_60_notify_hubs.rb",
58
59
  "plugins/add_pre_50_lookup_content_type_title.rb",
59
60
  "plugins/add_pre_60_github_title.rb",
61
+ "plugins/add_pre_60_google_code_title.rb",
60
62
  "plugins/hostrec_50_redundant.rb",
61
63
  "plugins/hostrec_60_skip.rb",
62
64
  "plugins/html_parse_50_hpricot.rb",
@@ -11,8 +11,11 @@ module Murlsh
11
11
 
12
12
  def self.run(url, config)
13
13
  ask = URI(url.url).extend(Murlsh::UriAsk)
14
- url.content_type = ask.content_type
15
- url.title = ask.title
14
+ headers = {
15
+ 'User-Agent' => 'murlsh (http://github.com/mmb/murlsh)'
16
+ }
17
+ url.content_type = ask.content_type(:headers => headers)
18
+ url.title = ask.title(:headers => headers)
16
19
  end
17
20
 
18
21
  end
@@ -11,7 +11,7 @@ module Murlsh
11
11
  @hook = 'add_pre'
12
12
 
13
13
  def self.run(url, config)
14
- if url.url[%r{http://github.com/\w+/\w+}]
14
+ if url.url[%r{^http://github\.com/\w+/[\w.-]+$}]
15
15
  ask = URI(url.url).extend(Murlsh::UriAsk)
16
16
  url.title << " - #{ask.description}" unless ask.description.empty?
17
17
  end
@@ -0,0 +1,27 @@
1
+ %w{
2
+ murlsh
3
+ }.each { |m| require m }
4
+
5
+ module Murlsh
6
+
7
+ # Google Code project page titles are not very descriptive so add summary
8
+ # from page
9
+ class AddPre60GoogleCodeTitle < Plugin
10
+
11
+ @hook = 'add_pre'
12
+
13
+ def self.run(url, config)
14
+ if url.url[%r{^http://code\.google\.com/p/[\w-]+/$}]
15
+ puts 'xxx'
16
+ ask = URI(url.url).extend(Murlsh::UriAsk)
17
+ ask.doc.xpath_search("//a[@id='project_summary_link']") do |node|
18
+ summary = node ? node.inner_html : nil
19
+ url.title << " - #{ask.decode(summary)}" unless !summary or
20
+ summary.empty?
21
+ end
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -21,7 +21,7 @@ module Murlsh
21
21
  "#{m[1]}.reddit"
22
22
  when m = search.match(%r{^delicious\.com/(\w+)}i)
23
23
  "delicious/#{m[1]}"
24
- when m = search.match(%r{^twitter\.com/(\w+)/}i)
24
+ when m = search.match(%r{^twitter\.com/(\w+)}i)
25
25
  "twitter/#{m[1]}"
26
26
  when m = search.match(%r{^([a-z\d][a-z\d-]{0,61}[a-z\d])\.tumblr\.com/}i)
27
27
  "#{m[1]}.tumblr"
@@ -60,9 +60,8 @@ img.thumb.twitter {
60
60
  width : 48px;
61
61
  }
62
62
 
63
- img.thumb.apple {
64
- height : 48px;
65
- width : 48px;
63
+ img.thumb.locator {
64
+ max-height : 48px;
66
65
  }
67
66
 
68
67
  span.host {
@@ -1,12 +1 @@
1
- {
2
- "http://url/being/commented/on": [
3
- {
4
- "authorAvatar": "http://url/of/your/avatar/image",
5
- "authorName": "yourname",
6
- "authorUrl": "http://url/of/your/site",
7
- "comment": "your comment",
8
- "createdTime": 1275005075,
9
- "updatedTime": 1275005075
10
- },
11
- ],
12
- }
1
+ {"http://www.youtube.com/watch?v=KrfpnbGXL70":[{"createdTime":1277520298,"updatedTime":1277520298,"authorAvatar":"http://www.gravatar.com/avatar/355af1bc931baca530e66571923286b4?s=16","authorName":"mmb","authorUrl":"http://matthewm.boedicker.org/","comment":"Through SOAP!"},{"createdTime":1277520298,"updatedTime":1277520298,"authorAvatar":"http://www.gravatar.com/avatar/355af1bc931baca530e66571923286b4?s=16","authorName":"mmb","authorUrl":"http://matthewm.boedicker.org/","comment":"dead, can be seen at http://jz10.java.no/java-4-ever-trailer.html"}]}
data/public/js/js.js CHANGED
@@ -3,6 +3,15 @@
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
  var my = {},
7
16
  hrefRes = {
8
17
  flickr :
@@ -10,7 +19,7 @@ var Murlsh = function (config, $, navigator, window) {
10
19
  imageshack :
11
20
  /^(http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.)(jpe?g|gif|png)$/i,
12
21
  imgur :
13
- /^(http:\/\/(?:i\.)?imgur\.com\/[a-z\d]+)(\.(?:jpe?g|gif|png))$/i,
22
+ /^(http:\/\/(?:i\.)?imgur\.com\/)([a-z\d]+)(\.(?:jpe?g|gif|png))$/i,
14
23
  mp3 :
15
24
  /\.mp3$/i,
16
25
  s3 :
@@ -22,7 +31,7 @@ var Murlsh = function (config, $, navigator, window) {
22
31
  youtube :
23
32
  /^http:\/\/(?:(?:www|uk)\.)?youtube\.com\/watch\?v=([\w\-]+)(?:&|$)/i
24
33
  },
25
- hostRe = /^http:\/\/([a-z\d\.\-]+(?::\d+)?)\//i;
34
+ thumbLocatorsCompiled = compileRegexMap(config.thumb_locators);
26
35
 
27
36
  function autoLink(s) {
28
37
  // turn urls into links
@@ -75,11 +84,6 @@ var Murlsh = function (config, $, navigator, window) {
75
84
  return result;
76
85
  }
77
86
 
78
- function appleThumb(host) {
79
- return img('http://' + host + '/apple-touch-icon.png', '').addClass(
80
- 'thumb apple');
81
- }
82
-
83
87
  function closerAdd(x, header) {
84
88
  var html = (typeof x === 'object') ? $('<div />').append(x).html() : x;
85
89
 
@@ -226,16 +230,15 @@ var Murlsh = function (config, $, navigator, window) {
226
230
  .append($('<span />').append(comment.authorName).addClass(
227
231
  'comment-name'))
228
232
  .append(' : ')
229
- .append($('<span />').append(autoLink(comment.comment)).
230
- addClass('comment-comment'))
233
+ .append($('<span />').append(autoLink(comment.comment))
234
+ .addClass('comment-comment'))
231
235
  .appendTo(ul);
232
236
  }
233
237
  };
234
238
 
235
239
  my.addExtra = function () {
236
- var host,
237
- hostMatch,
238
- href = $(this).attr('href'),
240
+ var thisA = $(this),
241
+ href = thisA.attr('href'),
239
242
  match = {},
240
243
  swf = 'swf/player_mp3_mini.swf',
241
244
  thumb;
@@ -258,18 +261,19 @@ var Murlsh = function (config, $, navigator, window) {
258
261
  success : function (d) {
259
262
  thumbInsert(flickrThumb(d), flickrClick, $(this));
260
263
  },
261
- context : $(this),
264
+ context : thisA,
262
265
  jsonpCallback : 'flickrCallback' + match.flickr[1]
263
266
  });
264
267
  } else if (match.imageshack) {
265
268
  thumbInsert(imgThumb(match.imageshack[1], 'th.',
266
269
  match.imageshack[2]).data('href', match.imageshack[0]),
267
- imgClick, $(this).html('imageshack.us'));
270
+ imgClick, thisA.html('imageshack.us'));
268
271
  } else if (match.imgur) {
269
- thumbInsert(imgThumb(match.imgur[1], 's', match.imgur[2]).data(
270
- 'href', match.imgur[0]), imgClick, $(this).html('imgur.com'));
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]));
271
275
  } else if (match.mp3) {
272
- $(this).before(objectTag(swf, 20, 200, [
276
+ thisA.before(objectTag(swf, 20, 200, [
273
277
  { name : 'bgcolor', value : '#000000' },
274
278
  { name : 'FlashVars', value : 'mp3=' + href },
275
279
  { name : 'movie', value : swf }
@@ -278,13 +282,13 @@ var Murlsh = function (config, $, navigator, window) {
278
282
  thumb = imgThumb(match.s3[1], 'th.', match.s3[2]);
279
283
 
280
284
  if (match.s3[2].match(/^pdf$/i)) {
281
- $(this).before(thumb).html('pdf');
285
+ thisA.before(thumb).html('pdf');
282
286
  } else {
283
287
  if (my.isIphone()) {
284
- $(this).html(thumb);
288
+ thisA.html(thumb);
285
289
  } else {
286
- $(this).html('link');
287
- $(this).before(thumb.data('href', match.s3[0]).click(
290
+ thisA.html('link');
291
+ thisA.before(thumb.data('href', match.s3[0]).click(
288
292
  imgClick));
289
293
  }
290
294
  }
@@ -308,7 +312,7 @@ var Murlsh = function (config, $, navigator, window) {
308
312
 
309
313
  $(this).replaceWith(tweet);
310
314
  },
311
- context : $(this),
315
+ context : thisA,
312
316
  jsonpCallback : 'twitterCallback' + match.twitter[1]
313
317
  });
314
318
  } else if (match.vimeo) {
@@ -326,20 +330,21 @@ var Murlsh = function (config, $, navigator, window) {
326
330
  { name : 'movie', value : movie }
327
331
  ])), vimeoClick, $(this));
328
332
  },
329
- context : $(this),
333
+ context : thisA,
330
334
  jsonpCallback : 'vimeoCallback' + match.vimeo[1]
331
335
  });
332
336
  } else if (match.youtube) {
333
- thumbInsert(youtubeThumb(match.youtube[1]), youtubeClick, $(this));
337
+ thumbInsert(youtubeThumb(match.youtube[1]), youtubeClick, thisA);
334
338
  } else {
335
- // Apple touch icon if available
336
- hostMatch = hostRe.exec(href);
337
- if (hostMatch) {
338
- host = hostMatch[1];
339
- if ($.inArray(host, config.apple_icon_hosts) > -1) {
340
- thumbInsert(appleThumb(host), null, $(this));
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;
341
346
  }
342
- }
347
+ });
343
348
  }
344
349
  };
345
350
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: murlsh
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 51
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 10
8
+ - 11
9
9
  - 0
10
- version: 0.10.0
10
+ version: 0.11.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matthew M. Boedicker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-05 00:00:00 -04:00
18
+ date: 2010-09-21 00:00:00 -04:00
19
19
  default_executable: murlsh
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -237,6 +237,7 @@ files:
237
237
  - lib/murlsh/failproof.rb
238
238
  - lib/murlsh/far_future_expires.rb
239
239
  - lib/murlsh/flickr_server.rb
240
+ - lib/murlsh/head_from_get.rb
240
241
  - lib/murlsh/markup.rb
241
242
  - lib/murlsh/must_revalidate.rb
242
243
  - lib/murlsh/openlock.rb
@@ -258,6 +259,7 @@ files:
258
259
  - plugins/add_post_60_notify_hubs.rb
259
260
  - plugins/add_pre_50_lookup_content_type_title.rb
260
261
  - plugins/add_pre_60_github_title.rb
262
+ - plugins/add_pre_60_google_code_title.rb
261
263
  - plugins/hostrec_50_redundant.rb
262
264
  - plugins/hostrec_60_skip.rb
263
265
  - plugins/html_parse_50_hpricot.rb