murlsh 0.10.0 → 0.11.0

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.
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