murlsh 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -16,8 +16,8 @@ Phusion Passenger Setup:
16
16
 
17
17
  <pre>
18
18
  <code>
19
- rake gemspec build
20
- gem install pkg/murlsh-x.x.x.gem
19
+ gem sources -a http://gemcutter.org/
20
+ gem install murlsh
21
21
  </code>
22
22
  </pre>
23
23
 
data/Rakefile CHANGED
@@ -175,6 +175,7 @@ begin
175
175
  gemspec.email = 'matthewm@boedicker.org'
176
176
  gemspec.homepage = 'http://github.com/mmb/murlsh'
177
177
  gemspec.authors = ['Matthew M. Boedicker']
178
+ gemspec.executables = %w{murlsh}
178
179
 
179
180
  %w{
180
181
  activerecord 2.3.4
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.4
1
+ 0.3.0
data/bin/murlsh CHANGED
@@ -6,7 +6,7 @@ FileUtils.cp_r(
6
6
  %w{.htaccess config.ru config.yaml plugins/ public/ Rakefile}.collect { |x|
7
7
  File.join(File.dirname(__FILE__), '..', x) }, '.', :verbose => true)
8
8
 
9
- FileUtils.mkdir('tmp')
9
+ FileUtils.mkdir_p('tmp', :verbose => true)
10
10
 
11
11
  puts <<eos
12
12
  Next steps:
data/config.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- auth_file: /home/mm6/murlsh_users
2
+ auth_file: murlsh_users
3
3
  description: URLs found interesting by Matthew M. Boedicker
4
4
  db_file: murlsh.db
5
5
  feed_file: atom.xml
@@ -5,8 +5,14 @@ require 'uri'
5
5
 
6
6
  module Murlsh
7
7
 
8
+ # ATOM feed builder.
8
9
  class AtomFeed
9
10
 
11
+ # root_url is the base url for the feed items.
12
+ #
13
+ # Options:
14
+ # * :filename - the file name of the feed (atom.xml)
15
+ # * :title - the feed title
10
16
  def initialize(root_url, options={})
11
17
  options = {
12
18
  :filename => 'atom.xml',
@@ -18,6 +24,7 @@ module Murlsh
18
24
  setup_id_fields
19
25
  end
20
26
 
27
+ # Set up fields to use for building item ids.
21
28
  def setup_id_fields
22
29
  uri_parsed = URI(@root_url)
23
30
 
@@ -28,6 +35,7 @@ module Murlsh
28
35
  @path = uri_parsed.path
29
36
  end
30
37
 
38
+ # Generate the feed and write it to the filesystem with locking.
31
39
  def write(entries, path)
32
40
  open(path, 'w') do |f|
33
41
  f.flock(File::LOCK_EX)
@@ -38,6 +46,8 @@ module Murlsh
38
46
  end
39
47
  end
40
48
 
49
+ # Build the feed using XML builder. Options are passed to
50
+ # Builder::XmlMarkup.new.
41
51
  def make(entries, options={})
42
52
  xm = Builder::XmlMarkup.new(options)
43
53
  xm.instruct! :xml
@@ -62,10 +72,12 @@ module Murlsh
62
72
  xm
63
73
  end
64
74
 
75
+ # Build the entry's id.
65
76
  def entry_id(url)
66
77
  "tag:#{@domain},#{url.time.strftime('%Y-%m-%d')}:#{@host}#{@path}#{url.id}"
67
78
  end
68
79
 
80
+ # Add an ATOM enclosure if the url is an image.
69
81
  def enclosure(xm, mu)
70
82
  xm.link(:rel => 'enclosure', :type => mu.content_type, :href => mu.url,
71
83
  :title => 'Full-size') if mu.is_image?
data/lib/murlsh/auth.rb CHANGED
@@ -6,12 +6,21 @@ require 'digest/md5'
6
6
 
7
7
  module Murlsh
8
8
 
9
+ # Interface to authentication file. Format of authentication file:
10
+ #
11
+ # username,MD5 hash of email address,bcrypted password
12
+ #
13
+ # Authentication is done using password only to make adding easier and
14
+ # because there will be a small number of trusted users.
15
+ #
16
+ # See Rakefile for user maintenance tasks.
9
17
  class Auth
10
18
 
11
19
  def initialize(file)
12
20
  @file = file
13
21
  end
14
22
 
23
+ # Authenticate a user by password. Return their name and email if correct.
15
24
  def auth(password)
16
25
  CSV::Reader.parse(open(@file)) do |row|
17
26
  return { :name => row[0], :email => row[1] } if
@@ -19,6 +28,7 @@ module Murlsh
19
28
  end
20
29
  end
21
30
 
31
+ # Add a user to the authentication file.
22
32
  def add_user(username, email, password)
23
33
  open(@file, 'a') do |f|
24
34
  f.flock(File::LOCK_EX)
@@ -11,8 +11,10 @@ yaml
11
11
 
12
12
  module Murlsh
13
13
 
14
+ # Dispatch requests.
14
15
  class Dispatch
15
16
 
17
+ # Set up config hash and database connection.
16
18
  def initialize
17
19
  @config = YAML.load_file('config.yaml')
18
20
  @url_root = URI(@config.fetch('root_url')).path
@@ -25,6 +27,7 @@ module Murlsh
25
27
  @url_server = Murlsh::UrlServer.new(@config, @db)
26
28
  end
27
29
 
30
+ # Rack call.
28
31
  def call(env)
29
32
  dispatch = {
30
33
  ['GET', @url_root] => [@url_server, :get],
@@ -41,6 +44,7 @@ module Murlsh
41
44
  obj.send(meth, req).finish
42
45
  end
43
46
 
47
+ # Called if the request is not found.
44
48
  def not_found(req)
45
49
  Rack::Response.new("<p>#{req.url} not found</p>
46
50
 
@@ -4,6 +4,7 @@ require 'uri'
4
4
 
5
5
  class URI::Generic
6
6
 
7
+ # Return the path and query string.
7
8
  def path_query
8
9
  path + (query ? "?#{query}" : '')
9
10
  end
@@ -14,6 +15,11 @@ module Murlsh
14
15
 
15
16
  module_function
16
17
 
18
+ # Try to get the content type of a url.
19
+ #
20
+ # Options:
21
+ # * :failproof - if true hide all exceptions and return empty string on failure
22
+ # * :headers - hash of headers to send in request
17
23
  def get_content_type(url, options={})
18
24
  options[:headers] = default_headers(url).merge(
19
25
  options.fetch(:headers, {}))
@@ -48,6 +54,10 @@ module Murlsh
48
54
  uri.is_a?(URI::HTTP) ? uri : URI(uri)
49
55
  end
50
56
 
57
+ # Create a Net::HTTP to a host and port.
58
+ #
59
+ # Options:
60
+ # * :debug - stream to write debug output to
51
61
  def make_net_http(url, options={})
52
62
  net_http = Net::HTTP.new(url.host, url.port)
53
63
  net_http.use_ssl = (url.scheme == 'https')
@@ -55,16 +65,14 @@ module Murlsh
55
65
  net_http
56
66
  end
57
67
 
58
- # Get the response to HTTP HEAD. If HEAD not allowed do GET.
68
+ # Get the response to HTTP HEAD. If HEAD returns anything other than success
69
+ # try GET.
59
70
  def get_resp(http, url, headers={})
60
- resp = http.request_head(url.path_query, headers)
61
- if Net::HTTPMethodNotAllowed === resp
62
- http.request_get(url.path_query, headers)
63
- else
64
- resp
65
- end
71
+ resp = http.request_head(url.path_query, headers) === Net::HTTPSuccess ?
72
+ resp : http.request_get(url.path_query, headers)
66
73
  end
67
74
 
75
+ # Get default headers sent with the request. Can be based on url.
68
76
  def default_headers(url)
69
77
  result = {
70
78
  'User-Agent' =>
@@ -10,6 +10,11 @@ module Murlsh
10
10
 
11
11
  module_function
12
12
 
13
+ # Try to get the title of a url.
14
+ #
15
+ # Options:
16
+ # * :failproof - if true hide all exceptions and return empty string on failure
17
+ # * :headers - hash of headers to send in request
13
18
  def get_title(url, options={})
14
19
  options[:headers] = default_headers(url).merge(
15
20
  options.fetch(:headers, {}))
@@ -35,6 +40,8 @@ module Murlsh
35
40
  (result and !result.empty?) ? result : url
36
41
  end
37
42
 
43
+ # Return true if the content type is likely to have a title that can be
44
+ # parsed.
38
45
  def might_have_title(content_type)
39
46
  content_type[/^text\/html/]
40
47
  end
data/lib/murlsh/markup.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  module Murlsh
2
2
 
3
+ # Helper mixin for XML builder.
3
4
  module Markup
4
5
 
6
+ # Javascript link builder. Takes list of script urls.
7
+ #
8
+ # Options:
9
+ # * :prefix - prefix to append to all script urls
5
10
  def javascript(sources, options={})
6
11
  sources.to_a.each do |src|
7
12
  script('', :type => 'text/javascript',
@@ -9,6 +14,15 @@ module Murlsh
9
14
  end
10
15
  end
11
16
 
17
+ # Image tag builder.
18
+ #
19
+ # Options:
20
+ # * :href - make the image a link to this url
21
+ # * :prefix - prefix to append to all image urls
22
+ # * :size - image size if square or [w, h]
23
+ # * :text - text for alt and title tag
24
+ #
25
+ # Any other options in hash will be added as attributes.
12
26
  def murlsh_img(options={})
13
27
  img_convert_prefix(options)
14
28
  img_convert_size(options)
@@ -24,10 +38,16 @@ module Murlsh
24
38
  end
25
39
  end
26
40
 
41
+ # ATOM feed link builder.
27
42
  def atom(href)
28
43
  link(:rel => 'alternate', :type => 'application/atom+xml', :href => href)
29
44
  end
30
45
 
46
+ # CSS link builder.
47
+ #
48
+ # Options:
49
+ # * :media - optional media attribute
50
+ # * :prefix - prepended to all CSS urls
31
51
  def css(hrefs, options={})
32
52
  hrefs.to_a.each do |href|
33
53
  attrs = {
@@ -40,10 +60,16 @@ module Murlsh
40
60
  end
41
61
  end
42
62
 
63
+ # Meta tag builder. Takes a hash of name => content.
43
64
  def metas(tags)
44
65
  tags.each { |k,v| meta(:name => k, :content => v) }
45
66
  end
46
67
 
68
+ # Gravatar builder. Takes MD5 hash of email address.
69
+ # Options:
70
+ # * 'd' - default Gravatar (identicon, monsterid, or wavatar)
71
+ # * 's' - size (0 - 512)
72
+ # * 'r' - rating (g, pg, r or x)
47
73
  def gravatar(email_hash, options={})
48
74
  query = options.reject do |k,v|
49
75
  not ((k == 'd' and %w{identicon monsterid wavatar}.include?(v)) or
@@ -60,6 +86,7 @@ module Murlsh
60
86
  murlsh_img(options)
61
87
  end
62
88
 
89
+ # Query string builder. Takes hash of query string variables.
63
90
  def build_query(h)
64
91
  h.empty? ? '' :
65
92
  '?' + h.collect { |k,v| URI.escape("#{k}=#{v}") }.join('&')
data/lib/murlsh/plugin.rb CHANGED
@@ -1,13 +1,26 @@
1
1
  module Murlsh
2
2
 
3
+ # Superclass for plugins. How plugins are registered.
4
+ #
5
+ # Hooks:
6
+ # * add_pre - called before a new url is saved
7
+ # run arguments (url, config hash)
8
+ # * add_post - called after a new url is saved
9
+ # run arguments (config hash)
10
+ # * hostrec - called to post process the domain that shows after links
11
+ # run arguments (domain, url, title)
3
12
  class Plugin
4
13
 
14
+ # Called when a plugin class inherits from this class (the way plugins
15
+ # are registered).
5
16
  def self.inherited(child)
6
17
  registered << child
7
18
  end
8
19
 
20
+ # Get registered plugins by hook (add_pre, add_post, etc.)
9
21
  def self.hooks(name)
10
- matches = registered.select { |p| p::Hook == name }
22
+ matches = registered.select { |p| p::Hook == name }.
23
+ sort { |a,b| a.to_s <=> b.to_s }
11
24
 
12
25
  if block_given?
13
26
  matches.each { |p| yield p }
@@ -3,6 +3,7 @@ require 'uri'
3
3
 
4
4
  module Murlsh
5
5
 
6
+ # For parsing query strings from referring search engines.
6
7
  class Referrer
7
8
 
8
9
  def initialize(url)
@@ -19,6 +20,7 @@ module Murlsh
19
20
  end
20
21
  end
21
22
 
23
+ # Get the searched for string from a search engine query string.
22
24
  def search_query(qmap=Qmap)
23
25
  if hostpath and query_string
24
26
  qmap.each_pair do |r,v|
@@ -34,6 +36,7 @@ module Murlsh
34
36
  nil
35
37
  end
36
38
 
39
+ # Regex host match to name of query string parameter.
37
40
  Qmap = {
38
41
  /^www\.google\.(bs|ca|com|cz|dk|es|fi|nl)(\/m)?\/search$/ => 'q',
39
42
  /^www\.bing\.com\/search$/ => 'q',
@@ -2,6 +2,7 @@ require 'active_record/connection_adapters/sqlite3_adapter'
2
2
 
3
3
  class ActiveRecord::ConnectionAdapters::SQLite3Adapter
4
4
 
5
+ # Add MATCH function for regex matching.
5
6
  def initialize(connection, logger, config)
6
7
  super
7
8
  @connection.create_function('MATCH', 2) do |func,search_in,search_for|
data/lib/murlsh/time.rb CHANGED
@@ -2,6 +2,8 @@ require 'time'
2
2
 
3
3
  class Time
4
4
 
5
+ # Return a string of the approximate amount of time that has passed since
6
+ # this time.
5
7
  def fuzzy
6
8
  days_ago = (Time.now.to_i - to_i) / 86400
7
9
 
data/lib/murlsh/url.rb CHANGED
@@ -5,36 +5,35 @@ require 'uri'
5
5
 
6
6
  module Murlsh
7
7
 
8
+ # URL ActiveRecord.
8
9
  class Url < ActiveRecord::Base
9
10
 
11
+ # Get the title of this url.
10
12
  def title
11
13
  read_attribute(:title) || read_attribute(:url) || 'title missing'
12
14
  end
13
15
 
16
+ # Return true if this url has the same author as another url.
14
17
  def same_author?(other)
15
18
  other and other.email and other.name and
16
19
  email and name and email == other.email and name == other.name
17
20
  end
18
21
 
19
- Widely_known = %w{
20
- wikipedia.org
21
- flickr.com
22
- github.com
23
- twitter.com
24
- vimeo.com
25
- youtube.com
26
- }
27
-
22
+ # Return text showing what domain a link goes to.
28
23
  def hostrec
29
24
  begin
30
25
  domain = URI(url).host[/[a-z\d-]+\.[a-z]{2,}(\.[a-z]{2})?$/].downcase
31
26
  rescue Exception => e
32
27
  domain = nil
33
28
  end
34
- yield domain unless !domain or title.downcase.index(domain) or
35
- Widely_known.include?(domain)
29
+
30
+ domain = Murlsh::Plugin.hooks('hostrec').inject(domain) {
31
+ |result,plugin| plugin.run(result, url, title) }
32
+
33
+ yield domain if domain
36
34
  end
37
35
 
36
+ # Return true if this url is an image.
38
37
  def is_image?
39
38
  %w{image/gif image/jpeg image/png}.include?(content_type)
40
39
  end
@@ -1,5 +1,6 @@
1
1
  module Murlsh
2
2
 
3
+ # Url list page builder.
3
4
  class UrlBody < Builder::XmlMarkup
4
5
  include Murlsh::Markup
5
6
 
@@ -8,12 +9,14 @@ module Murlsh
8
9
  super(:indent => 2)
9
10
  end
10
11
 
12
+ # Fetch urls base on query string parameters.
11
13
  def urls
12
14
  Murlsh::Url.all(:conditions => search_conditions, :order => 'id DESC',
13
15
  :limit => @req.params['n'] ? @req.params['n'].to_i :
14
16
  @config.fetch('num_posts_page', 100))
15
17
  end
16
18
 
19
+ # Search conditions builder for ActiveRecord conditions.
17
20
  def search_conditions
18
21
  if @q
19
22
  search_cols = %w{name title url}
@@ -24,6 +27,7 @@ module Murlsh
24
27
  end
25
28
  end
26
29
 
30
+ # Url list page body builder.
27
31
  def each
28
32
  instruct! :xml
29
33
  declare! :DOCTYPE, :html, :PUBLIC, '-//W3C//DTD XHTML 1.1//EN',
@@ -65,10 +69,12 @@ module Murlsh
65
69
  clear
66
70
  powered_by
67
71
  js
72
+ div('', :id => 'bottom')
68
73
  }
69
74
  }
70
75
  end
71
76
 
77
+ # Head builder.
72
78
  def headd
73
79
  head {
74
80
  titlee
@@ -84,20 +90,24 @@ module Murlsh
84
90
  }
85
91
  end
86
92
 
93
+ # Title builder.
87
94
  def titlee
88
95
  title(@config.fetch('page_title', '') + (@q ? " /#{@q}" : ''))
89
96
  end
90
97
 
98
+ # Google verification link builder.
91
99
  def google_verify
92
100
  (gv = @config.fetch('google_verify')) and metas('verify-v1' => gv)
93
101
  end
94
102
 
103
+ # Feed icon builder.
95
104
  def feed_icon
96
105
  div(:class => 'icon') {
97
106
  a('feed', :href => @config.fetch('feed_file'), :class => 'feed')
98
107
  }
99
108
  end
100
109
 
110
+ # Search form builder.
101
111
  def search_form
102
112
  form(:action => '', :method => 'get') {
103
113
  value = @q
@@ -113,6 +123,7 @@ module Murlsh
113
123
  }
114
124
  end
115
125
 
126
+ # Url add form builder.
116
127
  def add_form
117
128
  form(:action => '', :method => 'post') {
118
129
  fieldset(:id => 'add') {
@@ -125,15 +136,18 @@ module Murlsh
125
136
  }
126
137
  end
127
138
 
139
+ # Url add form input builder.
128
140
  def add_form_input(label, id, size, tipe='text')
129
141
  label(label, :for => id)
130
142
  input(:type => tipe, :id => id, :name => id, :size => size)
131
143
  end
132
144
 
145
+ # Clear div builder.
133
146
  def clear
134
147
  div(:style => 'clear : both')
135
148
  end
136
149
 
150
+ # Powered by builder.
137
151
  def powered_by
138
152
  self.p {
139
153
  text! 'powered by '
@@ -141,6 +155,7 @@ module Murlsh
141
155
  }
142
156
  end
143
157
 
158
+ # Required javascript builder.
144
159
  def js
145
160
  javascript(%w{
146
161
  jquery-1.3.2.min.js
@@ -6,6 +6,7 @@ rack
6
6
 
7
7
  module Murlsh
8
8
 
9
+ # Build responses for HTTP requests.
9
10
  class UrlServer
10
11
 
11
12
  def initialize(config, db)
@@ -16,6 +17,8 @@ module Murlsh
16
17
  Dir['plugins/*.rb'].each { |p| load p }
17
18
  end
18
19
 
20
+ # Respond to a GET request. Return a page of urls based on the query
21
+ # string parameters.
19
22
  def get(req)
20
23
  resp = Murlsh::XhtmlResponse.new
21
24
 
@@ -30,6 +33,7 @@ module Murlsh
30
33
  resp
31
34
  end
32
35
 
36
+ # Respond to a POST request. Add the new url and return json.
33
37
  def post(req)
34
38
  resp = Rack::Response.new
35
39
 
@@ -42,16 +46,15 @@ module Murlsh
42
46
  ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
43
47
  :database => @config.fetch('db_file'))
44
48
 
45
- content_type = Murlsh.get_content_type(url)
46
49
  mu = Murlsh::Url.new do |u|
47
50
  u.time = Time.now.gmtime
48
51
  u.url = url
49
52
  u.email = user[:email]
50
53
  u.name = user[:name]
51
- u.title = Murlsh.get_title(url, :content_type => content_type)
52
- u.content_type = content_type
53
54
  end
54
55
 
56
+ Murlsh::Plugin.hooks('add_pre') { |p| p.run(mu, @config) }
57
+
55
58
  mu.save
56
59
 
57
60
  Murlsh::Plugin.hooks('add_post') { |p| p.run(@config) }
@@ -1,9 +1,10 @@
1
1
  module Murlsh
2
2
 
3
+ # Set the content type correctly based on accept header and user agent.
3
4
  class XhtmlResponse < Rack::Response
4
5
 
5
- # set the content type to application/xhtml+xml for anything that
6
- # claims to accept it, for anything else or IE use text/html
6
+ # Set the content type to application/xhtml+xml for anything that
7
+ # claims to accept it, for anything else or IE use text/html.
7
8
  def set_content_type(http_accept, http_user_agent)
8
9
  self['Content-Type'] = if http_accept and
9
10
  http_accept[/((\*|application)\/\*|application\/xhtml\+xml)/i] and
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.2.4"
8
+ s.version = "0.3.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{2009-10-23}
12
+ s.date = %q{2009-11-05}
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}
@@ -43,6 +43,9 @@ Gem::Specification.new do |s|
43
43
  "lib/murlsh/url_server.rb",
44
44
  "lib/murlsh/xhtml_response.rb",
45
45
  "murlsh.gemspec",
46
+ "plugins/hostrec_redundant.rb",
47
+ "plugins/hostrec_skip.rb",
48
+ "plugins/lookup_content_type_title.rb",
46
49
  "plugins/update_feed.rb",
47
50
  "public/css/jquery.jgrowl.css",
48
51
  "public/css/phone.css",
@@ -0,0 +1,14 @@
1
+ module Murlsh
2
+
3
+ # skip showing host record if domain is contained in title
4
+ class HostrecRedundant < Plugin
5
+
6
+ Hook = 'hostrec'
7
+
8
+ def self.run(domain, url, title)
9
+ domain unless (title and domain and title.downcase.index(domain))
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,23 @@
1
+ module Murlsh
2
+
3
+ # skip showing host record for some domains
4
+ class HostrecSkip < Plugin
5
+
6
+ Hook = 'hostrec'
7
+
8
+ def self.run(domain, url, title)
9
+ domain unless Skips.include?(domain)
10
+ end
11
+
12
+ Skips = %w{
13
+ wikipedia.org
14
+ flickr.com
15
+ github.com
16
+ twitter.com
17
+ vimeo.com
18
+ youtube.com
19
+ }
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,17 @@
1
+ require 'murlsh'
2
+
3
+ module Murlsh
4
+
5
+ # try to fetch the content type and title of a url
6
+ class LookupContentTypeTitle < Plugin
7
+
8
+ Hook = 'add_pre'
9
+
10
+ def self.run(url, config)
11
+ url.content_type = Murlsh.get_content_type(url.url)
12
+ url.title = Murlsh.get_title(url.url, :content_type => url.content_type)
13
+ end
14
+
15
+ end
16
+
17
+ end
data/public/css/phone.css CHANGED
@@ -1,3 +1,7 @@
1
+ a.feed {
2
+ display : none;
3
+ }
4
+
1
5
  body {
2
6
  margin : 0;
3
7
  padding : 0;
@@ -9,6 +13,14 @@ body {
9
13
  width : 290px;
10
14
  }
11
15
 
16
+ #urls li {
17
+ overflow : hidden;
18
+ }
19
+
12
20
  input#q {
13
21
  width : 130px;
14
22
  }
23
+
24
+ input#url {
25
+ width : 160px;
26
+ }
data/public/js/js.js CHANGED
@@ -205,7 +205,12 @@ Murlsh.orientation_changed = function() {
205
205
  window.onorientationchange = Murlsh.orientation_changed;
206
206
 
207
207
  $(document).ready(function() {
208
- Murlsh.orientation_changed();
208
+ if (Murlsh.is_iphone()) {
209
+ Murlsh.orientation_changed();
210
+ $('#urls li:first').prepend($('<a />').attr('href', '#bottom').text(
211
+ 'bottom'));
212
+ $('#urls li:last').append($('<a />').attr('href', '#urls').text('top'));
213
+ }
209
214
  $('a').map(Murlsh.add_extra);
210
215
  $('#urls li:even').addClass('even');
211
216
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: murlsh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew M. Boedicker
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-23 00:00:00 -04:00
12
+ date: 2009-11-05 00:00:00 -05:00
13
13
  default_executable: murlsh
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -116,6 +116,9 @@ files:
116
116
  - lib/murlsh/url_server.rb
117
117
  - lib/murlsh/xhtml_response.rb
118
118
  - murlsh.gemspec
119
+ - plugins/hostrec_redundant.rb
120
+ - plugins/hostrec_skip.rb
121
+ - plugins/lookup_content_type_title.rb
119
122
  - plugins/update_feed.rb
120
123
  - public/css/jquery.jgrowl.css
121
124
  - public/css/phone.css