whisperblog 0.6
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/Changelog +23 -0
- data/LICENSE +661 -0
- data/README +59 -0
- data/bin/whisper +91 -0
- data/bin/whisper-init +40 -0
- data/bin/whisper-post +88 -0
- data/bin/whisper-process-email +54 -0
- data/lib/whisper.rb +52 -0
- data/lib/whisper/author_tracker.rb +46 -0
- data/lib/whisper/blog.rb +156 -0
- data/lib/whisper/cached_file.rb +65 -0
- data/lib/whisper/comment.rb +35 -0
- data/lib/whisper/comment_set.rb +41 -0
- data/lib/whisper/common.rb +276 -0
- data/lib/whisper/config.rb +49 -0
- data/lib/whisper/dir_scanner.rb +76 -0
- data/lib/whisper/dir_set.rb +50 -0
- data/lib/whisper/email_receiver.rb +212 -0
- data/lib/whisper/email_sender.rb +114 -0
- data/lib/whisper/entry.rb +44 -0
- data/lib/whisper/entry_set.rb +41 -0
- data/lib/whisper/handler.rb +99 -0
- data/lib/whisper/mbox.rb +141 -0
- data/lib/whisper/page.rb +118 -0
- data/lib/whisper/rfc2047.rb +79 -0
- data/lib/whisper/router.rb +50 -0
- data/lib/whisper/server.rb +88 -0
- data/lib/whisper/text.rb +252 -0
- data/lib/whisper/timed_map.rb +43 -0
- data/lib/whisper/version.rb +3 -0
- data/share/whisper/comment-email.rtxt +36 -0
- data/share/whisper/config.yaml +53 -0
- data/share/whisper/entry-email.rtxt +35 -0
- data/share/whisper/entry.rhtml +88 -0
- data/share/whisper/entry.rtxt +19 -0
- data/share/whisper/formatter.rb +52 -0
- data/share/whisper/helper.rb +147 -0
- data/share/whisper/list.rhtml +51 -0
- data/share/whisper/list.rrss +9 -0
- data/share/whisper/list.rtxt +25 -0
- data/share/whisper/master.rhtml +81 -0
- data/share/whisper/master.rrss +21 -0
- data/share/whisper/master.rtxt +5 -0
- data/share/whisper/mootools.js +282 -0
- data/share/whisper/rss-badge.png +0 -0
- data/share/whisper/spinner.gif +0 -0
- data/share/whisper/style.css +314 -0
- metadata +239 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
## Whisper configuration file.
|
2
|
+
##
|
3
|
+
## This is a YAML-ified hash with symbol keys. If you don't understand what
|
4
|
+
## that means, just know that lines starting with a '#' are comments, and lines
|
5
|
+
## starting with : are settings.
|
6
|
+
|
7
|
+
## blog title
|
8
|
+
:title: my fancy new whisper blog
|
9
|
+
|
10
|
+
## blog tagline
|
11
|
+
:tagline: the internet is my internet
|
12
|
+
|
13
|
+
## page size, for pagination purposes. max number of entries per page.
|
14
|
+
:page_size: 10
|
15
|
+
|
16
|
+
## the underlying web server you'd like to use. I suggest "Thin". Other values
|
17
|
+
## might work but are untested!
|
18
|
+
:rack_handler: Thin
|
19
|
+
|
20
|
+
## the base path for the site. used for making relative links.
|
21
|
+
:root: "/"
|
22
|
+
|
23
|
+
## the public, full URL for the site.
|
24
|
+
:public_url_root: "http://YOUR-SITE.HERE"
|
25
|
+
|
26
|
+
## the email address that comments should be sent from
|
27
|
+
:from_email_address: comments@YOUR-SITE.HERE
|
28
|
+
|
29
|
+
## the location of the mbox file that holds email sent to the address in
|
30
|
+
## :from_email_address:.
|
31
|
+
:comment_mbox: /var/mail/comments
|
32
|
+
|
33
|
+
## the sendmail command
|
34
|
+
#:sendmail: /usr/sbin/sendmail -oem -ti
|
35
|
+
|
36
|
+
## the development port to listen on, if not set with --port
|
37
|
+
#:development_port: 9292
|
38
|
+
|
39
|
+
## the production port to listen on, if not set with --port
|
40
|
+
#:port: 80
|
41
|
+
|
42
|
+
## the path to use with X-Accel-Redirect headers, if using nginx. Only active
|
43
|
+
## in production mode. Should be coupled with an nginx configuration block like
|
44
|
+
## this:
|
45
|
+
##
|
46
|
+
## location /static-internal/ {
|
47
|
+
## internal;
|
48
|
+
## root /var/www/YOUR-SITE.HERE/static;
|
49
|
+
## }
|
50
|
+
## which gives the actual location of those static files.
|
51
|
+
#:x_accel_redirect: "/static-internal/"
|
52
|
+
|
53
|
+
## and that's it!
|
@@ -0,0 +1,35 @@
|
|
1
|
+
From: <%= author.email_name %> (on <%= blog_title %>) <<%= from_address %>>
|
2
|
+
To: <%= to_address %>
|
3
|
+
Subject: [<%= blog_title %>] <%= entry.title(:email) %>
|
4
|
+
Date: <%= Time.now %>
|
5
|
+
Message-Id: <<%= message_id %>>
|
6
|
+
|
7
|
+
<% if web_request -%>
|
8
|
+
; Hi there! This is an email containing the original post or a reply from
|
9
|
+
; <%= full_url_for :route => :entry, :id => entry.id %>. Someone (hopefully you!)
|
10
|
+
; requested this email.
|
11
|
+
;
|
12
|
+
; To reply, simply reply to this message, quoting as normal.
|
13
|
+
; You can use Textile markup: http://hobix.com/textile/
|
14
|
+
; DO NOT top-post: http://en.wikipedia.org/wiki/Top-posting#Top-posting
|
15
|
+
;
|
16
|
+
; Future replies may also be sent to you via email, depending on
|
17
|
+
; the setting below.
|
18
|
+
;
|
19
|
+
; SETTINGS:
|
20
|
+
;
|
21
|
+
; Lines starting with a ;, like these, will be stripped out, even if quoted.
|
22
|
+
; Lines starting with a !, like those below, allow you to configure settings.
|
23
|
+
; Just edit them in place and leave them in your reply (quoted is fine).
|
24
|
+
;
|
25
|
+
! <%= Comment::RESEND_SETTING %>: <%= settings["send future comments to me"] || "all" %>
|
26
|
+
; (one of "all", "replies-only", or "none")
|
27
|
+
! <%= Comment::URL_SETTING %>: <%= settings["my url"] || "" %>
|
28
|
+
; (a url to link your name to)
|
29
|
+
;
|
30
|
+
<% else -%>
|
31
|
+
; A reply to this message will be posted at <%= full_url_for :route => :entry, :id => entry.id %>
|
32
|
+
; and emailed to any subscribers to this thread.
|
33
|
+
<% end -%>
|
34
|
+
|
35
|
+
<%= entry.body :email %>
|
@@ -0,0 +1,88 @@
|
|
1
|
+
<h2><%= link_to_current entry.title(:html) %></h2>
|
2
|
+
|
3
|
+
<% unless entry.labels.empty? %>
|
4
|
+
<div class="labels">
|
5
|
+
Topics:
|
6
|
+
<ul class="label-list">
|
7
|
+
<% entry.labels.each do |x| %>
|
8
|
+
<li class='label'><%= link_to x, :route => :label, :label => x %></li>
|
9
|
+
<% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<div class="byline">
|
15
|
+
<div style="float: left">
|
16
|
+
<span class="author-name">
|
17
|
+
<%= link_to entry.author.email_name, :route => :author, :author => entry.author.obfuscated_name, :html_opts => { :class => "author-name" } %>
|
18
|
+
</span>
|
19
|
+
</div>
|
20
|
+
<div style="float: right">
|
21
|
+
<span class="date" title="<%= pretty_time_diff entry.published %>"><%= entry.published.strftime "%B %e, %Y %l:%M%P" %></span>
|
22
|
+
</div>
|
23
|
+
<div style="clear: both;"></div>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
<div class="entry">
|
27
|
+
<%= entry.body :html %>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<a name="comments"></a>
|
31
|
+
|
32
|
+
<ul class="comment-tree">
|
33
|
+
<% thread_to_html_nested_list(comments) do |prefix, c| %>
|
34
|
+
<%= prefix %>
|
35
|
+
<% next unless c %>
|
36
|
+
<a name="<%= c.id.escape %>"></a>
|
37
|
+
<div class="comment-body">
|
38
|
+
<div class="byline">
|
39
|
+
<div style="float: left">
|
40
|
+
<span class="author-name"><%= author_link c.author, author_info %></span>
|
41
|
+
</div>
|
42
|
+
<div style="float: right">
|
43
|
+
<span class="date" title="<%= pretty_time_diff c.published %>">
|
44
|
+
<a href="#<%= c.id.escape %>"><%= c.published.strftime "%B %e, %Y %l:%M%P" %></a>
|
45
|
+
</span>
|
46
|
+
</div>
|
47
|
+
<div style="clear: both"></div>
|
48
|
+
</div>
|
49
|
+
<%= c.body :html %>
|
50
|
+
<div class="reply-to-outer">
|
51
|
+
<div class="reply-to-header"><a href="#" class="reply-to-link">reply</a></div>
|
52
|
+
<div class="reply-to-box" id="reply-to-<%= entry.id %>-<%= c.id %>" >
|
53
|
+
<span class="comment-instructions">To reply, enter your email address. A copy of the comment will be sent to you via email.</span>
|
54
|
+
<%= start_comment_form entry, c %>
|
55
|
+
<%= textfield "email" %>
|
56
|
+
<%= submit_button "email me" %>
|
57
|
+
<%= end_comment_form entry, c %>
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
<% end %>
|
62
|
+
</ul>
|
63
|
+
|
64
|
+
<p class="comment-instructions">To reply to the article, enter your email
|
65
|
+
address. A copy of the article will be sent to you via email.</p>
|
66
|
+
<%= start_comment_form entry %>
|
67
|
+
<%= textfield "email" %>
|
68
|
+
<%= submit_button "email me" %>
|
69
|
+
<%= end_comment_form entry %>
|
70
|
+
|
71
|
+
<%= comment_form_script %>
|
72
|
+
|
73
|
+
<script type="text/javascript">
|
74
|
+
/* <![CDATA[ */
|
75
|
+
$$('.reply-to-link').each(function(link, i) {
|
76
|
+
var box = link.getParent().getParent().getElement('.reply-to-box');
|
77
|
+
var oldHeight = box.getStyle("height");
|
78
|
+
box.setStyle("height", 0);
|
79
|
+
box.setStyle("opacity", 0);
|
80
|
+
link.addEvent('click', function(e) {
|
81
|
+
e.stop();
|
82
|
+
box.setStyle("opacity", 1);
|
83
|
+
box.setStyle("height", oldHeight);
|
84
|
+
box.getElement("input").focus();
|
85
|
+
});
|
86
|
+
});
|
87
|
+
/* ]]> */
|
88
|
+
</script>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<%= entry.title(:txt) %>
|
2
|
+
<%= "-" * entry.title(:txt).size %>
|
3
|
+
Date: <%= entry.published.strftime "%B %e, %Y %l:%M%P" %>
|
4
|
+
Author: <%= entry.author.email_name %>
|
5
|
+
<% unless entry.labels.empty? -%>
|
6
|
+
Labels: <%= entry.labels.join(", ") %>
|
7
|
+
<% end -%>
|
8
|
+
URL: <%= full_url_for_current %>
|
9
|
+
|
10
|
+
<%= entry.body :txt %>
|
11
|
+
<% unless comments.empty? -%>
|
12
|
+
|
13
|
+
Replies
|
14
|
+
--------
|
15
|
+
<% thread_to_text_nested_list(comments) do |c, prefix|%>
|
16
|
+
<%= prefix %><%= c.author.email_name %>, on <%= c.published.strftime "%B %e, %Y %l:%M%P" %>:
|
17
|
+
<%= c.body :email, :prefix => prefix + "| "%>
|
18
|
+
<% end -%>
|
19
|
+
<% end -%>
|
@@ -0,0 +1,52 @@
|
|
1
|
+
### here is the default set of formatting plugins provided by whisper. feel free
|
2
|
+
### to add your own!
|
3
|
+
###
|
4
|
+
### these allow you to pull out regions of the post and do arbitrary stuff to
|
5
|
+
### them, based on the format.
|
6
|
+
|
7
|
+
## format quoted regions (typically in comments, but can be in posts too)
|
8
|
+
## Note that format_quote is special and different from all the other handlers.
|
9
|
+
## (In particular, it is the only nested formatter.)
|
10
|
+
Whisper::Text.format_quote do |format, body, attribution|
|
11
|
+
case format
|
12
|
+
when :html
|
13
|
+
[ attribution ? "<div class='comment-quote' title=\"#{attribution.escape}\">" : "<div class='comment-quote'>",
|
14
|
+
body,
|
15
|
+
"</div>"
|
16
|
+
].join
|
17
|
+
when :txt
|
18
|
+
(attribution ? "#{attribution}\n" : "") + body.lines.map { |l| "> " + l }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
### the rest of these are generic user-defined handlers
|
23
|
+
|
24
|
+
## format pre blocks as html pre blocks (very exciting)
|
25
|
+
Whisper::Text.format "<pre>", "</pre>" do |format, body, smatch, ematch|
|
26
|
+
case format
|
27
|
+
when :html; "<pre>#{body}</pre>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
## format poem blocks with some fancy html
|
32
|
+
Whisper::Text.format /<poem(\s+title\s*=\s*"(.*?)"\s*)?>/, "</poem>" do |format, body, smatch, ematch|
|
33
|
+
title = smatch[2]
|
34
|
+
case format
|
35
|
+
when :html, :rss
|
36
|
+
(title ? "<div class='poem-title'>#{title.escape}</div>" : "") +
|
37
|
+
"<pre class='poem'>#{body}</pre>"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
## format <ruby> blocks with some nice markup
|
42
|
+
require 'syntax/convertors/html'
|
43
|
+
Whisper::Text.format "<ruby>", "</ruby>" do |format, body, smatch, ematch|
|
44
|
+
case format
|
45
|
+
when :html
|
46
|
+
x = Syntax::Convertors::HTML.for_syntax("ruby").convert body
|
47
|
+
x.sub!(/\A<pre>\n+/, "<pre class=\"ruby\">")
|
48
|
+
"<code>#{x}</code>"
|
49
|
+
when :rss
|
50
|
+
"<pre>" + body + "</pre>"
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
def labels_and_counts
|
2
|
+
entryset.entries_by_label.sort_by { |k, v| -v.flatten.size }.map do |k, v|
|
3
|
+
[k, v.flatten.size]
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
def authors_and_counts
|
8
|
+
entryset.entries_by_author.sort_by { |k, v| -v.flatten.size }.map do |k, v|
|
9
|
+
[k, v.flatten.size]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def author_link author, author_info
|
14
|
+
link = author_info[author.email_address]["my url"]
|
15
|
+
if link.nil? || link.empty?
|
16
|
+
author.email_name
|
17
|
+
else
|
18
|
+
"<a href=\"#{link.escape.gsub('"', "")}\">#{author.email_name}</a>"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def pretty_time_diff t, from=Time.now
|
23
|
+
d = (from - t).to_i
|
24
|
+
ad = d.abs
|
25
|
+
num, word = if ad < 60; [ad, "second"]
|
26
|
+
elsif ad < 60*60; [ad/60, "minute"]
|
27
|
+
elsif ad < 60*60*24; [ad/60/60, "hour"]
|
28
|
+
elsif ad < 60*60*24*7; [ad/60/60/24, "day"]
|
29
|
+
elsif ad < 60*60*24*7*10; [ad/60/60/24/7, "week"]
|
30
|
+
else [ad/60/60/24/30, "month"]
|
31
|
+
end
|
32
|
+
|
33
|
+
s = [num.nicenice, " ", word, (num == 1 ? "" : "s")].join
|
34
|
+
d > 0 ? s + " ago" : "in " + s
|
35
|
+
end
|
36
|
+
|
37
|
+
def textfield name; "<input type='text' name='#{name}' id='textfield-#{name}'/>" end
|
38
|
+
def submit_button label; "<input type='submit' value='#{label}' id='submit-#{label}'/>" end
|
39
|
+
def radio_button label, name, value, selected=false
|
40
|
+
id = [name, value].join "-"
|
41
|
+
"<input type='radio' id='#{id}' name='#{name}' value='#{value}' #{selected ? "checked='checked'" : ""}/><label for='#{id}'>#{label}</label>"
|
42
|
+
end
|
43
|
+
|
44
|
+
def start_comment_form entry, comment=nil
|
45
|
+
id = entry.id
|
46
|
+
id += "-#{comment.id}" if comment
|
47
|
+
url = url_for :route => :comment, :id => entry.id
|
48
|
+
"<form id='comment-form-#{id}' action='#{url}' method='post' class='comment-form'>"
|
49
|
+
end
|
50
|
+
|
51
|
+
def end_comment_form entry, comment=nil
|
52
|
+
id, stuff = if comment
|
53
|
+
["#{entry.id}-#{comment.id.escape}",
|
54
|
+
"<input type='hidden' name='comment-id' value='#{comment.id.escape}'/>\n"]
|
55
|
+
else
|
56
|
+
[entry.id, ""]
|
57
|
+
end
|
58
|
+
stuff + <<EOS
|
59
|
+
<span class="form-result" id="form-result-#{id}"><!-- spanna --></span>
|
60
|
+
</form>
|
61
|
+
EOS
|
62
|
+
end
|
63
|
+
|
64
|
+
def thread_to_nested_list t # t the output of a Enumerable#thread
|
65
|
+
return if t.empty?
|
66
|
+
|
67
|
+
s = ""
|
68
|
+
stack = [:root]
|
69
|
+
level = 0
|
70
|
+
|
71
|
+
until stack.empty?
|
72
|
+
case(el = stack.pop)
|
73
|
+
when :end_item
|
74
|
+
yield :end_item, level
|
75
|
+
next
|
76
|
+
when :end_nest
|
77
|
+
level -= 1
|
78
|
+
yield :end_nest, level
|
79
|
+
next
|
80
|
+
when :root
|
81
|
+
# nothin
|
82
|
+
else
|
83
|
+
yield :start_item, level
|
84
|
+
yield :item, level, el
|
85
|
+
end
|
86
|
+
|
87
|
+
children = t[el]
|
88
|
+
if children.nil? || children.empty?
|
89
|
+
yield :end_item, level
|
90
|
+
else
|
91
|
+
unless el == :root
|
92
|
+
level += 1
|
93
|
+
yield :start_nest, level
|
94
|
+
stack << :end_item
|
95
|
+
stack << :end_nest
|
96
|
+
end
|
97
|
+
stack += children
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def thread_to_html_nested_list t
|
103
|
+
prefix = ""
|
104
|
+
thread_to_nested_list(t) do |what, level, obj|
|
105
|
+
case what
|
106
|
+
when :start_item; prefix << "<li>"
|
107
|
+
when :start_nest; prefix << "<ul>"
|
108
|
+
when :end_item; prefix << "</li>"
|
109
|
+
when :end_nest; prefix << "</ul>"
|
110
|
+
when :item
|
111
|
+
yield prefix, obj
|
112
|
+
prefix = ""
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
yield prefix, nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def thread_to_text_nested_list t, spaces=2
|
120
|
+
thread_to_nested_list(t) do |what, level, obj|
|
121
|
+
next unless what == :item
|
122
|
+
prefix = " " * spaces * level
|
123
|
+
yield obj, prefix
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def comment_form_script
|
128
|
+
<<EOS
|
129
|
+
<script type="text/javascript">
|
130
|
+
/* <![CDATA[ */
|
131
|
+
$$('.comment-form').addEvent('submit', function(e) {
|
132
|
+
e.stop();
|
133
|
+
var el = this.getElement('.form-result');
|
134
|
+
var result = el.empty().addClass('ajax-loading');
|
135
|
+
this.set('send', {
|
136
|
+
method: 'post',
|
137
|
+
onComplete: function(response) {
|
138
|
+
result.removeClass('ajax-loading');
|
139
|
+
result.set('html', response);
|
140
|
+
},
|
141
|
+
});
|
142
|
+
this.send();
|
143
|
+
});
|
144
|
+
/* ]]> */
|
145
|
+
</script>
|
146
|
+
EOS
|
147
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<% entries.each do |e, comments| %>
|
2
|
+
<h2><%= link_to e.title(:html), :route => :entry, :id => e.id %></h2>
|
3
|
+
|
4
|
+
<% unless e.labels.empty? %>
|
5
|
+
<div class="labels">
|
6
|
+
<ul class="label-list">
|
7
|
+
Topics:
|
8
|
+
<% e.labels.each do |x| %>
|
9
|
+
<li class='label'><%= link_to x, :route => :label, :label => x %></li>
|
10
|
+
<% end %>
|
11
|
+
</ul>
|
12
|
+
</div>
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<div class="byline">
|
16
|
+
<div style="float: left">
|
17
|
+
<span class="author-name">
|
18
|
+
<%= link_to e.author.email_name, :route => :author, :author => e.author.obfuscated_name, :html_opts => { :class => "author-name" } %>
|
19
|
+
</span>
|
20
|
+
</div>
|
21
|
+
<div style="float: right">
|
22
|
+
<span class="date" title="<%= pretty_time_diff e.published %>"><%= e.published.strftime "%B %e, %Y %l:%M%P" %></span>
|
23
|
+
</div>
|
24
|
+
<div style="clear: both;"></div>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div class="entry">
|
28
|
+
<%= e.body :html %>
|
29
|
+
</div>
|
30
|
+
<div class="comment-link">
|
31
|
+
<% authors = comments.map { |c| c.author.email_name.escape }.uniq.sort_by { rand }
|
32
|
+
title = comments.size.pluralize("reply").capitalize + case authors.size
|
33
|
+
when 0; ""
|
34
|
+
when 1; " by <b>#{authors[0]}</b>"
|
35
|
+
when 2; " by <b>#{authors[0]}</b> and <b>#{authors[1]}</b>"
|
36
|
+
else " by <b>#{authors[0]}</b> and #{(authors.size - 1).pluralize 'other'}"
|
37
|
+
end
|
38
|
+
%>
|
39
|
+
<%= link_to title, :route => :entry, :id => e.id, :anchor => "comments" %>.
|
40
|
+
</div>
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<% if pages > 1 %>
|
44
|
+
<div class="pageblock">
|
45
|
+
<% if page > 0 %> <%= link_to_current "prev", :page => (page - 1), :html_opts => { :class => "pageword" } %> <% end %>
|
46
|
+
<% for i in 0...pages %>
|
47
|
+
<% if i == page %><span class="currentpagelink"><%= sprintf "%2d", i %></span><% else %><%= link_to_current sprintf("%2d", i), :page => i, :html_opts => { :class => "pagelink" } %><% end %>
|
48
|
+
<% end %>
|
49
|
+
<% if page < pages - 1 %> <%= link_to_current "next", :page => (page + 1), :html_opts => { :class => "pageword" } %><% end %>
|
50
|
+
</div>
|
51
|
+
<% end %>
|