murlsh 1.2.1 → 1.3.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/.htaccess +4 -2
- data/README.textile +21 -2
- data/Rakefile +15 -11
- data/VERSION +1 -1
- data/bin/murlsh +3 -2
- data/config.ru +1 -1
- data/config.yaml +6 -2
- data/lib/murlsh/build_md5.rb +12 -0
- data/lib/murlsh/dispatch.rb +3 -3
- data/lib/murlsh/far_future_expires.rb +5 -1
- data/lib/murlsh/json_body.rb +41 -0
- data/lib/murlsh/json_server.rb +39 -0
- data/lib/murlsh/jsonp_body.rb +17 -0
- data/lib/murlsh/search_conditions.rb +22 -0
- data/lib/murlsh/url.rb +2 -0
- data/lib/murlsh/url_body.rb +93 -102
- data/lib/murlsh/url_result_set.rb +35 -0
- data/lib/murlsh/url_server.rb +30 -15
- data/lib/murlsh.rb +6 -1
- data/murlsh.gemspec +13 -8
- data/plugins/add_pre_45_supplied_thumbnail.rb +32 -0
- data/plugins/add_pre_50_lookup_content_type_title.rb +4 -1
- data/plugins/add_pre_50_open_graph_image.rb +8 -2
- data/plugins/add_pre_60_flickr.rb +1 -1
- data/plugins/add_pre_60_github_title.rb +1 -1
- data/plugins/add_pre_60_google_code_title.rb +2 -1
- data/plugins/add_pre_60_imgur.rb +1 -1
- data/plugins/add_pre_60_s3_image.rb +1 -1
- data/plugins/add_pre_60_twitter.rb +1 -1
- data/plugins/add_pre_60_vimeo.rb +3 -1
- data/plugins/add_pre_65_html_thumb.rb +1 -1
- data/public/css/screen.css +1 -3
- data/public/js/js.js +46 -46
- data/spec/uri_ask_spec.rb +0 -2
- metadata +18 -12
- data/lib/murlsh/config_server.rb +0 -32
data/.htaccess
CHANGED
@@ -9,11 +9,13 @@ AddOutputFilterByType DEFLATE text/css
|
|
9
9
|
AddOutputFilterByType DEFLATE text/html
|
10
10
|
|
11
11
|
<FilesMatch "\.gen\.(css|js)$">
|
12
|
-
|
12
|
+
ExpiresActive On
|
13
|
+
ExpiresDefault "now plus 1 years"
|
13
14
|
FileETag None
|
14
15
|
</FilesMatch>
|
15
16
|
|
16
17
|
<FilesMatch "[\da-z]{32}\.(gif|jpe?g|png)$">
|
17
|
-
|
18
|
+
ExpiresActive On
|
19
|
+
ExpiresDefault "now plus 1 years"
|
18
20
|
FileETag None
|
19
21
|
</FilesMatch>
|
data/README.textile
CHANGED
@@ -4,14 +4,15 @@ Site for sharing and archiving links.
|
|
4
4
|
* jGrowls embedded versions of Imageshack, Vimeo and YouTube urls
|
5
5
|
* converts Twitter status urls to their full text and adds user thumbnail
|
6
6
|
* generates Atom and RSS feeds
|
7
|
+
* generates json and jsonp feeds for client-side inclusion in other sites
|
7
8
|
* regex search
|
8
|
-
*
|
9
|
+
* uses HTML5 audio for mp3 and ogg urls
|
9
10
|
* looks good on iPhone
|
10
11
|
* PubSubHubbub notification
|
11
12
|
* plugin interface
|
12
13
|
* rack interface
|
13
14
|
* Gravatar support
|
14
|
-
*
|
15
|
+
* generates import scripts from delicious api exports
|
15
16
|
|
16
17
|
See "http://urls.matthewm.boedicker.org/":http://urls.matthewm.boedicker.org/ for example.
|
17
18
|
|
@@ -32,6 +33,14 @@ rake init
|
|
32
33
|
</code>
|
33
34
|
</pre>
|
34
35
|
|
36
|
+
h2. Development
|
37
|
+
|
38
|
+
* Create a fork and check it out
|
39
|
+
* edit config.yaml
|
40
|
+
* rake init
|
41
|
+
* rackup
|
42
|
+
* open http://localhost:9292/
|
43
|
+
|
35
44
|
h1. Updating
|
36
45
|
|
37
46
|
If you are using the gem and it gets updated to a new version you should run
|
@@ -39,6 +48,16 @@ the murlsh command again from your web directory to update plugins, javascript
|
|
39
48
|
and css. It will prompt before overwriting anything in case you have made
|
40
49
|
modifications.
|
41
50
|
|
51
|
+
h1. API
|
52
|
+
|
53
|
+
h2. Recent urls
|
54
|
+
|
55
|
+
* http://your_root/atom.atom
|
56
|
+
* http://your_root/rss.rss
|
57
|
+
* http://your_root/podcast.rss (urls with audio/mpeg content type)
|
58
|
+
* http://your_root/json.json
|
59
|
+
* http://your_root/json.json?callback=x (jsonp)
|
60
|
+
|
42
61
|
h1. Plugins
|
43
62
|
|
44
63
|
Classes in the plugins directory can be used to change behavior at certain
|
data/Rakefile
CHANGED
@@ -3,6 +3,7 @@ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
3
3
|
require 'cgi'
|
4
4
|
require 'digest/md5'
|
5
5
|
require 'net/http'
|
6
|
+
require 'open-uri'
|
6
7
|
require 'pp'
|
7
8
|
require 'set'
|
8
9
|
require 'uri'
|
@@ -131,17 +132,12 @@ end
|
|
131
132
|
|
132
133
|
desc 'Run test suite.'
|
133
134
|
begin
|
134
|
-
require '
|
135
|
+
require 'rspec/core/rake_task'
|
135
136
|
|
136
|
-
|
137
|
-
t.
|
138
|
-
t.
|
137
|
+
RSpec::Core::RakeTask.new('test') do |t|
|
138
|
+
t.pattern = 'spec/**/*_spec.rb'
|
139
|
+
t.rspec_opts = %w{--color}
|
139
140
|
t.verbose = true
|
140
|
-
t.warning = true
|
141
|
-
end
|
142
|
-
rescue LoadError
|
143
|
-
task :test do
|
144
|
-
gem_not_found 'rspec'
|
145
141
|
end
|
146
142
|
end
|
147
143
|
|
@@ -320,9 +316,17 @@ namespace :js do
|
|
320
316
|
|
321
317
|
desc 'Run javascript through jslint.'
|
322
318
|
task :jslint do
|
319
|
+
local_jslint = 'jslint_rhino.js'
|
320
|
+
open(local_jslint, 'w') do |f|
|
321
|
+
f.write(cat(%w{
|
322
|
+
https://github.com/AndyStricker/JSLint/raw/rhinocmdline/fulljslint.js
|
323
|
+
https://github.com/AndyStricker/JSLint/raw/rhinocmdline/rhino.js
|
324
|
+
}))
|
325
|
+
end
|
326
|
+
|
323
327
|
MURLSH_JS.each do |jsf|
|
324
328
|
puts jsf
|
325
|
-
puts `rhino
|
329
|
+
puts `rhino #{local_jslint} #{jsf}`
|
326
330
|
end
|
327
331
|
end
|
328
332
|
|
@@ -455,7 +459,7 @@ begin
|
|
455
459
|
%w{
|
456
460
|
flog >= 2.5.0
|
457
461
|
rack-test ~> 0.5
|
458
|
-
rspec ~>
|
462
|
+
rspec ~> 2.0
|
459
463
|
}.each_slice(3) do |g,o,v|
|
460
464
|
gemspec.add_development_dependency(g, "#{o} #{v}")
|
461
465
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.3.0
|
data/bin/murlsh
CHANGED
@@ -50,10 +50,11 @@ cp_r_safe(
|
|
50
50
|
|
51
51
|
FileUtils.mkdir_p('tmp', :verbose => true)
|
52
52
|
|
53
|
+
cd_command = File.expand_path(dest_dir) == Dir.pwd ? '' : "cd #{dest_dir}\n"
|
54
|
+
|
53
55
|
puts <<eos
|
54
56
|
Next steps:
|
55
57
|
|
56
|
-
|
57
|
-
edit config.yaml
|
58
|
+
#{cd_command}edit config.yaml
|
58
59
|
rake init
|
59
60
|
eos
|
data/config.ru
CHANGED
@@ -31,7 +31,7 @@ use Murlsh::FarFutureExpires, :patterns => [
|
|
31
31
|
feed_url = URI.join(config.fetch('root_url'), config.fetch('feed_file'))
|
32
32
|
use Murlsh::MustRevalidate, :patterns => %r{^#{Regexp.escape(feed_url.path)}$}
|
33
33
|
|
34
|
-
use Rack::Static, :urls => %w{/css /img /js
|
34
|
+
use Rack::Static, :urls => %w{/css/ /img/ /js/}, :root => 'public'
|
35
35
|
use Rack::Static, :urls => %w{/atom.atom /podcast.rss /rss.rss}
|
36
36
|
|
37
37
|
use Rack::Rewrite do
|
data/config.yaml
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
auth_file: murlsh_users
|
3
3
|
cache_entitystore: file:tmp/cache/rack/body
|
4
4
|
cache_metastore: file:tmp/cache/rack/meta
|
5
|
-
config_js: []
|
6
|
-
|
7
5
|
css_files:
|
8
6
|
- css/jquery.jgrowl.css
|
9
7
|
- css/screen.css
|
@@ -28,3 +26,9 @@ root_url: http://urls.matthewm.boedicker.org/
|
|
28
26
|
show_names: true
|
29
27
|
thumbnail_max_side: 90
|
30
28
|
user_agent: murlsh (http://github.com/mmb/murlsh)
|
29
|
+
predefined_searches:
|
30
|
+
audio: \.(mp3|ogg)$
|
31
|
+
code: (code\.google|github)\.com/
|
32
|
+
images: \.(png|gif|jpe?g)$
|
33
|
+
tweets: twitter\.com/
|
34
|
+
video: (youtube|vimeo)\.com/
|
data/lib/murlsh/dispatch.rb
CHANGED
@@ -15,15 +15,15 @@ module Murlsh
|
|
15
15
|
@config = config
|
16
16
|
|
17
17
|
url_server = Murlsh::UrlServer.new(config)
|
18
|
-
|
18
|
+
json_server = Murlsh::JsonServer.new(config)
|
19
19
|
root_path = URI(config.fetch('root_url')).path
|
20
20
|
|
21
21
|
@routes = [
|
22
22
|
[%r{^HEAD #{root_path}(url)?$}, url_server.method(:head)],
|
23
23
|
[%r{^GET #{root_path}(url)?$}, url_server.method(:get)],
|
24
24
|
[%r{^POST #{root_path}(url)?$}, url_server.method(:post)],
|
25
|
-
[%r{^HEAD #{root_path}
|
26
|
-
[%r{^GET #{root_path}
|
25
|
+
[%r{^HEAD #{root_path}json\.json$}, json_server.method(:head)],
|
26
|
+
[%r{^GET #{root_path}json\.json$}, json_server.method(:get)],
|
27
27
|
]
|
28
28
|
|
29
29
|
db_init
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
1
3
|
require 'rack'
|
2
4
|
require 'rack/utils'
|
3
5
|
|
@@ -10,7 +12,9 @@ module Murlsh
|
|
10
12
|
def initialize(app, options={})
|
11
13
|
@app = app
|
12
14
|
@patterns = options[:patterns] ? [*options[:patterns]] : []
|
13
|
-
|
15
|
+
# rfc2616 HTTP/1.1 servers SHOULD NOT send Expires dates more than one
|
16
|
+
# year in the future.
|
17
|
+
@future = options[:future] || (Time.now + 31536000).httpdate
|
14
18
|
end
|
15
19
|
|
16
20
|
def call(env)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Murlsh
|
4
|
+
|
5
|
+
# Recent urls json response builder.
|
6
|
+
class JsonBody
|
7
|
+
include Murlsh::BuildMd5
|
8
|
+
|
9
|
+
def initialize(config, req, result_set)
|
10
|
+
@config, @req, @result_set = config, req, result_set
|
11
|
+
end
|
12
|
+
|
13
|
+
# Yield body for Rack.
|
14
|
+
def each; yield build; end
|
15
|
+
|
16
|
+
# Recent urls json response builder.
|
17
|
+
def build
|
18
|
+
if defined?(@body)
|
19
|
+
@body
|
20
|
+
else
|
21
|
+
urls = @result_set.results.map do |mu|
|
22
|
+
h = mu.attributes
|
23
|
+
|
24
|
+
h['title'] = mu.title_stripped
|
25
|
+
|
26
|
+
# add site root url to relative thumbnail urls
|
27
|
+
if h['thumbnail_url'] and
|
28
|
+
not URI(h['thumbnail_url']).scheme.to_s.downcase[/https?/]
|
29
|
+
h['thumbnail_url'] = URI.join(@config['root_url'],
|
30
|
+
h['thumbnail_url']).to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
h
|
34
|
+
end
|
35
|
+
@body = urls.to_json
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Murlsh
|
4
|
+
|
5
|
+
# Serve most recent urls in json and jsonp.
|
6
|
+
class JsonServer
|
7
|
+
|
8
|
+
include Murlsh::HeadFromGet
|
9
|
+
|
10
|
+
def initialize(config); @config = config; end
|
11
|
+
|
12
|
+
# Respond to a GET request. Return json of recent urls or jsonp if
|
13
|
+
# if callback parameter is sent.
|
14
|
+
def get(req)
|
15
|
+
conditions = Murlsh::SearchConditions.new(req['q']).conditions
|
16
|
+
page = 1
|
17
|
+
per_page = @config.fetch('num_posts_feed', 25)
|
18
|
+
|
19
|
+
result_set = Murlsh::UrlResultSet.new(conditions, page, per_page)
|
20
|
+
|
21
|
+
resp = Rack::Response.new
|
22
|
+
|
23
|
+
if req['callback']
|
24
|
+
resp['Content-Type'] = 'application/javascript'
|
25
|
+
resp.body = Murlsh::JsonpBody.new(@config, req, result_set)
|
26
|
+
else
|
27
|
+
resp['Content-Type'] = 'application/json'
|
28
|
+
resp.body = Murlsh::JsonBody.new(@config, req, result_set)
|
29
|
+
end
|
30
|
+
|
31
|
+
resp['Cache-Control'] = 'must-revalidate, max-age=0'
|
32
|
+
resp['ETag'] = "\"#{resp.body.md5}\""
|
33
|
+
|
34
|
+
resp
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Murlsh
|
2
|
+
|
3
|
+
# Recent urls jsonp response builder.
|
4
|
+
class JsonpBody < Murlsh::JsonBody
|
5
|
+
|
6
|
+
# Recent urls jsonp response builder.
|
7
|
+
def build
|
8
|
+
if defined?(@body)
|
9
|
+
@body
|
10
|
+
else
|
11
|
+
@body = "#{@req['callback']}(#{super})"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Murlsh
|
2
|
+
|
3
|
+
# Search conditions builder for ActiveRecord conditions.
|
4
|
+
class SearchConditions
|
5
|
+
|
6
|
+
def initialize(q); @q = q; end
|
7
|
+
|
8
|
+
# Search conditions builder for ActiveRecord conditions.
|
9
|
+
def conditions
|
10
|
+
if q
|
11
|
+
search_cols = %w{name title url}
|
12
|
+
[search_cols.map { |x| "MURLSHMATCH(#{x}, ?)" }.join(' OR ')].push(
|
13
|
+
*[q] * search_cols.size)
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :q
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/murlsh/url.rb
CHANGED
data/lib/murlsh/url_body.rb
CHANGED
@@ -1,119 +1,98 @@
|
|
1
1
|
require 'builder'
|
2
|
+
require 'uri'
|
2
3
|
|
3
4
|
module Murlsh
|
4
5
|
|
5
6
|
# Url list page builder.
|
6
7
|
class UrlBody < Builder::XmlMarkup
|
8
|
+
include Murlsh::BuildMd5
|
7
9
|
include Murlsh::Markup
|
8
10
|
|
9
|
-
def initialize(config, req, content_type='text/html')
|
10
|
-
@config, @req, @
|
11
|
-
|
12
|
-
@page = [req.params['p'].to_i, 1].max
|
13
|
-
|
14
|
-
@first_href, @prev_href, @next_href = page_href(1), nil, nil
|
15
|
-
|
16
|
-
@total_entries, @total_pages = 0, 0
|
17
|
-
|
18
|
-
@per_page = @req.params['pp'] ? @req.params['pp'].to_i :
|
19
|
-
config.fetch('num_posts_page', 25)
|
20
|
-
|
11
|
+
def initialize(config, req, result_set, content_type='text/html')
|
12
|
+
@config, @req, @result_set, @content_type = config, req, result_set,
|
13
|
+
content_type
|
21
14
|
super(:indent => @config['html_indent'] || 0)
|
22
15
|
end
|
23
16
|
|
24
17
|
# Get the href of a page in the same result set as this page.
|
18
|
+
#
|
19
|
+
# Return nil if page is invalid.
|
25
20
|
def page_href(page)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# Fetch urls based on query string parameters.
|
32
|
-
def urls
|
33
|
-
search = search_conditions
|
34
|
-
|
35
|
-
@total_entries = Murlsh::Url.count(:conditions => search)
|
36
|
-
@total_pages = (@total_entries / @per_page.to_f).ceil
|
37
|
-
|
38
|
-
if @page > 1 and @page <= @total_pages
|
39
|
-
@prev_href = page_href(@page - 1)
|
40
|
-
end
|
41
|
-
|
42
|
-
if @page < @total_pages
|
43
|
-
@next_href = page_href(@page + 1)
|
44
|
-
end
|
45
|
-
|
46
|
-
offset = (@page - 1) * @per_page
|
47
|
-
|
48
|
-
Murlsh::Url.all(:conditions => search_conditions, :order => 'time DESC',
|
49
|
-
:limit => @per_page, :offset => offset)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Search conditions builder for ActiveRecord conditions.
|
53
|
-
def search_conditions
|
54
|
-
if @q
|
55
|
-
search_cols = %w{name title url}
|
56
|
-
[search_cols.map { |x| "MURLSHMATCH(#{x}, ?)" }.join(' OR ')].push(
|
57
|
-
*[@q] * search_cols.size)
|
58
|
-
else
|
59
|
-
[]
|
21
|
+
if page.to_i >= 1
|
22
|
+
query = @req.params.dup
|
23
|
+
query['p'] = page
|
24
|
+
Murlsh.build_query(query)
|
60
25
|
end
|
61
26
|
end
|
62
27
|
|
63
|
-
#
|
64
|
-
def
|
65
|
-
mus = urls
|
28
|
+
# Get the url of the previous page or nil if this is the first.
|
29
|
+
def prev_href; page_href(@result_set.prev_page); end
|
66
30
|
|
67
|
-
|
31
|
+
# Get the url of the next page or nil if this is the last.
|
32
|
+
def next_href; page_href(@result_set.next_page); end
|
68
33
|
|
69
|
-
|
70
|
-
|
71
|
-
body {
|
72
|
-
ul(:id => 'urls') {
|
73
|
-
li { feed_icon ; search_form }
|
34
|
+
# Yield body for Rack.
|
35
|
+
def each; yield build; end
|
74
36
|
|
75
|
-
|
37
|
+
# Url list page body builder.
|
38
|
+
def build
|
39
|
+
if defined?(@body)
|
40
|
+
@body
|
41
|
+
else
|
42
|
+
declare! :DOCTYPE, :html
|
43
|
+
|
44
|
+
@body = html(:lang => 'en') {
|
45
|
+
headd
|
46
|
+
body {
|
47
|
+
search_form
|
48
|
+
self.p {
|
49
|
+
predefined_searches
|
50
|
+
feed_link
|
51
|
+
}
|
52
|
+
ul(:id => 'urls') {
|
53
|
+
last = nil
|
54
|
+
|
55
|
+
@result_set.results.each do |mu|
|
56
|
+
li {
|
57
|
+
unless mu.same_author?(last)
|
58
|
+
avatar_url = Murlsh::Plugin.hooks('avatar').inject(
|
59
|
+
nil) do |url_so_far,plugin|
|
60
|
+
plugin.run(url_so_far, mu, @config)
|
61
|
+
end
|
62
|
+
div(:class => 'icon') {
|
63
|
+
murlsh_img :src => avatar_url, :text => mu.name
|
64
|
+
} if avatar_url
|
65
|
+
div(mu.name, :class => 'name') if
|
66
|
+
@config.fetch('show_names', false) and mu.name
|
67
|
+
end
|
76
68
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
avatar_url = Murlsh::Plugin.hooks('avatar').inject(
|
81
|
-
nil) do |url_so_far,plugin|
|
82
|
-
plugin.run(url_so_far, mu, @config)
|
69
|
+
if mu.thumbnail_url
|
70
|
+
murlsh_img :src => mu.thumbnail_url,
|
71
|
+
:text => mu.title_stripped, :class => 'thumb'
|
83
72
|
end
|
84
|
-
div(:class => 'icon') {
|
85
|
-
murlsh_img :src => avatar_url, :text => mu.name
|
86
|
-
} if avatar_url
|
87
|
-
div(mu.name, :class => 'name') if
|
88
|
-
@config.fetch('show_names', false) and mu.name
|
89
|
-
end
|
90
73
|
|
91
|
-
|
92
|
-
murlsh_img :src => mu.thumbnail_url,
|
93
|
-
:text => mu.title_stripped, :class => 'thumb'
|
94
|
-
end
|
74
|
+
a mu.title_stripped, :href => mu.url, :class => 'm'
|
95
75
|
|
96
|
-
|
76
|
+
Murlsh::Plugin.hooks('url_display_add') do |p|
|
77
|
+
p.run self, mu, @config
|
78
|
+
end
|
97
79
|
|
98
|
-
|
99
|
-
|
100
|
-
|
80
|
+
last = mu
|
81
|
+
}
|
82
|
+
end
|
83
|
+
}
|
101
84
|
|
102
|
-
|
103
|
-
}
|
104
|
-
end
|
85
|
+
clear
|
105
86
|
|
106
|
-
|
87
|
+
paging_nav
|
88
|
+
add_form
|
89
|
+
powered_by
|
107
90
|
|
108
|
-
|
91
|
+
js
|
92
|
+
div '', :id => 'bottom'
|
109
93
|
}
|
110
|
-
|
111
|
-
clear
|
112
|
-
powered_by
|
113
|
-
js
|
114
|
-
div '', :id => 'bottom'
|
115
94
|
}
|
116
|
-
|
95
|
+
end
|
117
96
|
end
|
118
97
|
|
119
98
|
# Head builder.
|
@@ -125,29 +104,39 @@ module Murlsh
|
|
125
104
|
map { |k,v| [k.sub('meta_tag_', ''), v] })
|
126
105
|
css(@config['css_compressed'] || @config['css_files'])
|
127
106
|
atom @config.fetch('feed_file')
|
128
|
-
link :rel => 'first', :href =>
|
107
|
+
link :rel => 'first', :href => page_href(1)
|
129
108
|
link :rel => 'prev', :href => @prev_href if @prev_href
|
130
109
|
link :rel => 'next', :href => @next_href if @next_href
|
131
110
|
}
|
132
111
|
end
|
133
112
|
|
113
|
+
# Predefined search list builder.
|
114
|
+
def predefined_searches
|
115
|
+
if @config['predefined_searches']
|
116
|
+
text! 'search: '
|
117
|
+
@config['predefined_searches'].each do |k,v|
|
118
|
+
a "/#{k}", :href => "?q=#{URI.escape(v)}" ; text! ' '
|
119
|
+
end
|
120
|
+
text! '| '
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
134
124
|
# Title builder.
|
135
125
|
def titlee
|
136
|
-
title(@config.fetch('page_title', '') +
|
126
|
+
title(@config.fetch('page_title', '') +
|
127
|
+
(@req['q'] ? " /#{@req['q']}" : ''))
|
137
128
|
end
|
138
129
|
|
139
|
-
# Feed
|
140
|
-
def
|
141
|
-
|
142
|
-
a('feed', :href => @config.fetch('feed_file'), :class => 'feed')
|
143
|
-
}
|
130
|
+
# Feed link builder.
|
131
|
+
def feed_link
|
132
|
+
a('feed', :href => @config.fetch('feed_file'), :class => 'feed')
|
144
133
|
end
|
145
134
|
|
146
135
|
# Search form builder.
|
147
136
|
def search_form
|
148
137
|
form(:action => '', :method => 'get') {
|
149
138
|
fieldset {
|
150
|
-
form_input :id => 'q', :size => 32, :value => @q
|
139
|
+
form_input :id => 'q', :size => 32, :value => @req['q']
|
151
140
|
form_input :type => 'submit', :value => 'Regex Search'
|
152
141
|
}
|
153
142
|
}
|
@@ -155,13 +144,15 @@ module Murlsh
|
|
155
144
|
|
156
145
|
# Paging navigation.
|
157
146
|
def paging_nav
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
147
|
+
self.p {
|
148
|
+
text! "Page #{@result_set.page}/#{@result_set.total_pages}"
|
149
|
+
if p_href = prev_href
|
150
|
+
text! ' | '; a 'previous', :href => p_href
|
151
|
+
end
|
152
|
+
if n_href = next_href
|
153
|
+
text! ' | '; a 'next', :href => n_href
|
154
|
+
end
|
155
|
+
}
|
165
156
|
end
|
166
157
|
|
167
158
|
# Url add form builder.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Murlsh
|
2
|
+
|
3
|
+
class UrlResultSet
|
4
|
+
|
5
|
+
def initialize(conditions, page, per_page)
|
6
|
+
@conditions, @page, @per_page = conditions, page, per_page
|
7
|
+
@order = 'time DESC'
|
8
|
+
end
|
9
|
+
|
10
|
+
def total_entries
|
11
|
+
@total_entries ||= Murlsh::Url.count(:conditions => conditions)
|
12
|
+
end
|
13
|
+
|
14
|
+
def total_pages
|
15
|
+
@total_pages ||= [(total_entries / per_page.to_f).ceil, 1].max
|
16
|
+
end
|
17
|
+
|
18
|
+
def offset; @offset ||= (page - 1) * per_page; end
|
19
|
+
|
20
|
+
def results
|
21
|
+
Murlsh::Url.all(:conditions => conditions, :order => order,
|
22
|
+
:limit => per_page, :offset => offset)
|
23
|
+
end
|
24
|
+
|
25
|
+
def prev_page; @prev_page ||= page - 1 if (2..total_pages) === page; end
|
26
|
+
|
27
|
+
def next_page; @next_page ||= page + 1 if page < total_pages; end
|
28
|
+
|
29
|
+
attr_reader :conditions
|
30
|
+
attr_reader :page
|
31
|
+
attr_reader :per_page
|
32
|
+
attr_reader :order
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|