radiant-forum-extension 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +155 -0
- data/Rakefile +139 -0
- data/VERSION +1 -0
- data/app/controllers/admin/forums_controller.rb +11 -0
- data/app/controllers/forums_controller.rb +34 -0
- data/app/controllers/posts_controller.rb +238 -0
- data/app/controllers/topics_controller.rb +78 -0
- data/app/models/forum.rb +52 -0
- data/app/models/moderatorship.rb +5 -0
- data/app/models/post.rb +122 -0
- data/app/models/post_attachment.rb +73 -0
- data/app/models/topic.rb +162 -0
- data/app/views/admin/forums/_form.html.haml +25 -0
- data/app/views/admin/forums/edit.html.haml +5 -0
- data/app/views/admin/forums/index.html.haml +76 -0
- data/app/views/admin/forums/moderate.html.haml +2 -0
- data/app/views/admin/forums/new.html.haml +5 -0
- data/app/views/admin/forums/remove.html.haml +22 -0
- data/app/views/admin/pages/_edit_commentability.html.haml +9 -0
- data/app/views/admin/reader_settings/_forum.html.haml +4 -0
- data/app/views/admin/sites/_choose_forum_layout.html.haml +7 -0
- data/app/views/forums/_forum.html.haml +22 -0
- data/app/views/forums/index.html.haml +44 -0
- data/app/views/forums/show.html.haml +38 -0
- data/app/views/forums/show.rss.builder +13 -0
- data/app/views/layouts/feed.rss.builder +5 -0
- data/app/views/monitorships/create.rjs.erb +1 -0
- data/app/views/monitorships/destroy.rjs.erb +1 -0
- data/app/views/monitorships/index.html.erb +35 -0
- data/app/views/pages/_comment.html.haml +10 -0
- data/app/views/pages/_comments.html.haml +15 -0
- data/app/views/posts/_attachment.html.haml +2 -0
- data/app/views/posts/_form.html.haml +6 -0
- data/app/views/posts/_latest.html.haml +17 -0
- data/app/views/posts/_post.html.haml +67 -0
- data/app/views/posts/_post.rss.builder +13 -0
- data/app/views/posts/_reply.html.haml +36 -0
- data/app/views/posts/_search.html.haml +28 -0
- data/app/views/posts/_uploader.html.haml +16 -0
- data/app/views/posts/edit.html.haml +20 -0
- data/app/views/posts/index.html.haml +33 -0
- data/app/views/posts/index.rss.builder +14 -0
- data/app/views/posts/new.html.haml +14 -0
- data/app/views/posts/preview.html.haml +32 -0
- data/app/views/posts/search.html.haml +54 -0
- data/app/views/posts/search.rss.builder +14 -0
- data/app/views/posts/show.html.haml +10 -0
- data/app/views/reader_notifier/post.rhtml +14 -0
- data/app/views/readers/_extra_controls.html.haml +5 -0
- data/app/views/readers/show_with_posts.html.haml +47 -0
- data/app/views/topics/_form.html.haml +26 -0
- data/app/views/topics/_help.html.haml +8 -0
- data/app/views/topics/_locked.html.haml +2 -0
- data/app/views/topics/_topic.html.haml +35 -0
- data/app/views/topics/_topic.rss.builder +9 -0
- data/app/views/topics/comments.html.haml +5 -0
- data/app/views/topics/edit.html.haml +26 -0
- data/app/views/topics/index.html.haml +41 -0
- data/app/views/topics/index.rss.builder +14 -0
- data/app/views/topics/new.html.haml +40 -0
- data/app/views/topics/show.html.haml +45 -0
- data/app/views/topics/show.rss.builder +14 -0
- data/config/routes.rb +16 -0
- data/db/migrate/001_create_forum_tables.rb +64 -0
- data/db/migrate/002_pages_commentable.rb +16 -0
- data/db/migrate/003_extend_sites.rb +13 -0
- data/db/migrate/004_sample_layout.rb +41 -0
- data/db/migrate/005_post_attachments.rb +19 -0
- data/db/migrate/006_user_relations.rb +20 -0
- data/db/migrate/007_reader_ownership.rb +35 -0
- data/db/migrate/008_first_posts.rb +13 -0
- data/db/migrate/20090824111005_import_helpers.rb +15 -0
- data/forum_extension.rb +44 -0
- data/lib/forum_admin_ui.rb +37 -0
- data/lib/forum_helper.rb +109 -0
- data/lib/forum_page.rb +45 -0
- data/lib/forum_reader.rb +9 -0
- data/lib/forum_reader_notifier.rb +9 -0
- data/lib/forum_readers_controller.rb +15 -0
- data/lib/forum_red_cloth3.rb +10 -0
- data/lib/forum_red_cloth4.rb +21 -0
- data/lib/forum_site.rb +12 -0
- data/lib/forum_tags.rb +285 -0
- data/lib/tasks/radiant_forum_extension_tasks.rake +137 -0
- data/pkg/radiant-forum-extension-0.5.0.gem +0 -0
- data/public/images/admin/forum.png +0 -0
- data/public/images/admin/new-forum.png +0 -0
- data/public/images/admin/nominus.png +0 -0
- data/public/images/admin/noremove.png +0 -0
- data/public/images/emoticons/angry.gif +0 -0
- data/public/images/emoticons/bigsmile.gif +0 -0
- data/public/images/emoticons/confused.gif +0 -0
- data/public/images/emoticons/cool.gif +0 -0
- data/public/images/emoticons/cry.gif +0 -0
- data/public/images/emoticons/devil.gif +0 -0
- data/public/images/emoticons/neutral.gif +0 -0
- data/public/images/emoticons/sad.gif +0 -0
- data/public/images/emoticons/shamed.gif +0 -0
- data/public/images/emoticons/shocked.gif +0 -0
- data/public/images/emoticons/smile.gif +0 -0
- data/public/images/emoticons/surprised.gif +0 -0
- data/public/images/emoticons/tongue.gif +0 -0
- data/public/images/emoticons/wink.gif +0 -0
- data/public/images/forum/attachment.png +0 -0
- data/public/images/forum/attachment_link.png +0 -0
- data/public/images/forum/attachment_over.png +0 -0
- data/public/images/forum/chk_off.png +0 -0
- data/public/images/forum/chk_on.png +0 -0
- data/public/images/forum/feed_14.png +0 -0
- data/public/images/forum/feed_28.png +0 -0
- data/public/images/forum/post_14.png +0 -0
- data/public/images/forum/post_14_over.png +0 -0
- data/public/images/forum/rdo_off.png +0 -0
- data/public/images/forum/rdo_on.png +0 -0
- data/public/images/forum/wait_16_grey.gif +0 -0
- data/public/javascripts/platform/forum.js +175 -0
- data/public/javascripts/platform/remotecontent.js +89 -0
- data/public/stylesheets/admin/forum.css +87 -0
- data/public/stylesheets/platform/forum.css +70 -0
- data/radiant-forum-extension.gemspec +215 -0
- data/spec/controllers/admin/forums_controller_spec.rb +54 -0
- data/spec/controllers/forums_controller_spec.rb +42 -0
- data/spec/controllers/posts_controller_spec.rb +310 -0
- data/spec/controllers/topics_controller_spec.rb +133 -0
- data/spec/datasets/forum_layouts_dataset.rb +15 -0
- data/spec/datasets/forum_pages_dataset.rb +11 -0
- data/spec/datasets/forum_readers_dataset.rb +55 -0
- data/spec/datasets/forum_sites_dataset.rb +10 -0
- data/spec/datasets/forums_dataset.rb +28 -0
- data/spec/datasets/posts_dataset.rb +31 -0
- data/spec/datasets/topics_dataset.rb +37 -0
- data/spec/lib/forum_admin_ui_spec.rb +35 -0
- data/spec/lib/forum_page_spec.rb +63 -0
- data/spec/lib/forum_reader_notification_spec.rb +9 -0
- data/spec/lib/forum_reader_spec.rb +13 -0
- data/spec/lib/forum_site_spec.rb +39 -0
- data/spec/models/forum_spec.rb +48 -0
- data/spec/models/post_spec.rb +91 -0
- data/spec/models/topic_spec.rb +105 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +44 -0
- data/vendor/plugins/acts_as_list/README +23 -0
- data/vendor/plugins/acts_as_list/init.rb +3 -0
- data/vendor/plugins/acts_as_list/lib/active_record/acts/list.rb +256 -0
- data/vendor/plugins/acts_as_list/test/list_test.rb +332 -0
- metadata +287 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
class ImportHelpers < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :readers, :old_id, :integer
|
4
|
+
add_column :forums, :old_id, :integer
|
5
|
+
add_column :topics, :old_id, :integer
|
6
|
+
add_column :posts, :old_id, :integer
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
remove_column :readers, :old_id
|
11
|
+
remove_column :forums, :old_id
|
12
|
+
remove_column :topics, :old_id
|
13
|
+
remove_column :posts, :old_id
|
14
|
+
end
|
15
|
+
end
|
data/forum_extension.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require_dependency 'application_controller'
|
2
|
+
|
3
|
+
class ForumExtension < Radiant::Extension
|
4
|
+
version "0.4"
|
5
|
+
description "Nice clean forums and page comments for inclusion in your radiant site. Derived long ago from beast. Requires the reader extension and share_layouts."
|
6
|
+
url "http://spanner.org/radiant/forum"
|
7
|
+
|
8
|
+
def activate
|
9
|
+
Reader.send :include, ForumReader
|
10
|
+
ReaderNotifier.send :include, ForumReaderNotifier
|
11
|
+
ReadersController.send :include, ForumReadersController
|
12
|
+
Page.send :include, ForumPage
|
13
|
+
UserActionObserver.instance.send :add_observer!, Forum
|
14
|
+
UserActionObserver.instance.send :add_observer!, Topic
|
15
|
+
UserActionObserver.instance.send :add_observer!, Post
|
16
|
+
Page.send :include, ForumTags
|
17
|
+
Admin::ReaderSettingsController.make_settable 'forum.editable_period' => 15, 'forum.public?' => true, 'forum.layout' => '', 'forum.allow_page_comments?' => true
|
18
|
+
|
19
|
+
unless defined? admin.forum # UI is a singleton
|
20
|
+
Radiant::AdminUI.send :include, ForumAdminUI
|
21
|
+
admin.forum = Radiant::AdminUI.load_default_forum_regions
|
22
|
+
admin.pages.edit.add :parts_bottom, "edit_commentability", :after => "edit_layout_and_type"
|
23
|
+
admin.reader_settings.index.add :settings, "forum", :after => "sender"
|
24
|
+
if defined? Site && admin.sites
|
25
|
+
Site.send :include, ForumSite
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
if defined? RedCloth::DEFAULT_RULES # identifies redcloth 3
|
30
|
+
RedCloth.send :include, ForumRedCloth3
|
31
|
+
RedCloth::DEFAULT_RULES.push(:smilies)
|
32
|
+
else
|
33
|
+
RedCloth::TextileDoc.send :include, ForumRedCloth4
|
34
|
+
end
|
35
|
+
|
36
|
+
ApplicationHelper.send :include, ForumHelper
|
37
|
+
|
38
|
+
tab("Readers") do
|
39
|
+
add_item 'Forum', '/admin/readers/forums', :before => 'Settings'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module ForumAdminUI
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
|
6
|
+
attr_accessor :forum
|
7
|
+
alias_method :forums, :forum
|
8
|
+
|
9
|
+
def load_default_regions_with_forum
|
10
|
+
load_default_regions_without_forum
|
11
|
+
@forum = load_default_forum_regions
|
12
|
+
end
|
13
|
+
alias_method_chain :load_default_regions, :forum
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def load_default_forum_regions
|
18
|
+
returning OpenStruct.new do |forum|
|
19
|
+
forum.edit = Radiant::AdminUI::RegionSet.new do |edit|
|
20
|
+
edit.main.concat %w{edit_header edit_form}
|
21
|
+
edit.form.concat %w{edit_name edit_description}
|
22
|
+
edit.form_bottom.concat %w{edit_timestamp edit_buttons}
|
23
|
+
end
|
24
|
+
forum.index = Radiant::AdminUI::RegionSet.new do |index|
|
25
|
+
index.thead.concat %w{title_header latest_header modify_header}
|
26
|
+
index.tbody.concat %w{title_cell latest_cell modify_cell}
|
27
|
+
index.bottom.concat %w{new_button}
|
28
|
+
end
|
29
|
+
forum.remove = forum.index
|
30
|
+
forum.new = forum.edit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
data/lib/forum_helper.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'sanitize'
|
2
|
+
module ForumHelper
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.module_eval {
|
6
|
+
|
7
|
+
def home_page_link(options={})
|
8
|
+
home_page = (defined? Site && Site.current) ? Site.current.home_page : Page.find_by_parent_id(nil)
|
9
|
+
link_to home_page.title, home_page.url, options
|
10
|
+
end
|
11
|
+
|
12
|
+
def feed_tag(text, url, options={})
|
13
|
+
link_to text, url, options.merge(:class => 'floating feedlink')
|
14
|
+
end
|
15
|
+
|
16
|
+
def feed_link(url)
|
17
|
+
link_to image_tag('/images/forum/feed_14.png', :class => 'feedicon', :alt => 'rss feed', :size => '14x20'), url
|
18
|
+
end
|
19
|
+
|
20
|
+
def clean_textilize(text) # adding smilies to the default reader method
|
21
|
+
if text.blank?
|
22
|
+
""
|
23
|
+
else
|
24
|
+
textilized = RedCloth.new(text, [ :hard_breaks ])
|
25
|
+
textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
|
26
|
+
Sanitize.clean(textilized.to_html(:textile, :smilies), Sanitize::Config::RELAXED)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def watch_tag(topic, label='watching', formclass=nil)
|
31
|
+
if current_user
|
32
|
+
monitoring = current_user.monitoring?(topic)
|
33
|
+
%{
|
34
|
+
<form action="#{monitorship_path(topic.forum, topic)}" method="post" class="#{formclass}"><div>
|
35
|
+
<input id="monitor_checkbox_#{topic.id}" name="monitor_checkbox" class="monitor_checkbox" type="checkbox"#{ ' checked="checked"' if monitoring } />
|
36
|
+
<label class="monitor_label" for="monitor_checkbox_#{topic.id}">#{label}</label>
|
37
|
+
#{hidden_field_tag '_method', monitoring ? 'delete' : ''}
|
38
|
+
#{submit_tag :set, :class => 'monitor_submit'}
|
39
|
+
</div></form>
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def paged_post_url(post)
|
45
|
+
if post.first?
|
46
|
+
topic_post_url(post.topic, post, :page => post.topic_page, :anchor => post.dom_id)
|
47
|
+
else
|
48
|
+
topic_post_url(post.topic, post, :page => post.topic_page, :anchor => post.dom_id)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def edit_link(post)
|
53
|
+
link_to 'e', edit_topic_post_url(post.topic, post), :class => 'edit_post', :id => "edit_post_#{post.id}", :title => "edit post"
|
54
|
+
end
|
55
|
+
|
56
|
+
def remove_link(post)
|
57
|
+
link_to 'x', topic_post_url(post.topic, post), :method => 'delete', :class => 'delete_post', :id => "delete_post_#{post.id}", :title => "remove post", :confirm => "Are you sure you want to delete this message?"
|
58
|
+
end
|
59
|
+
|
60
|
+
def friendly_date(datetime)
|
61
|
+
if datetime
|
62
|
+
date = datetime.to_date
|
63
|
+
if (date == Date.today)
|
64
|
+
format = "today at %l:%M%p"
|
65
|
+
elsif (date == Date.yesterday)
|
66
|
+
format = "yesterday at %l:%M%p"
|
67
|
+
elsif (date.year == Date.today.year)
|
68
|
+
format = "on %B %e"
|
69
|
+
else
|
70
|
+
format = "on %B %e, %Y"
|
71
|
+
end
|
72
|
+
datetime.strftime(format)
|
73
|
+
else
|
74
|
+
"unknown date"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def paginate_and_summarise(list, plural='')
|
79
|
+
pagination = will_paginate list, :separator => %{<span class="separator">|</span>}, :container => false
|
80
|
+
%{<div class="pagination">
|
81
|
+
#{pagination}
|
82
|
+
<span class="pagination_summary">
|
83
|
+
showing #{pagination_summary(list, plural)}
|
84
|
+
</span>
|
85
|
+
</div>
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def pagination_summary(list, plural='')
|
90
|
+
total = list.total_entries
|
91
|
+
if total == 1
|
92
|
+
if plural.blank?
|
93
|
+
"one"
|
94
|
+
else
|
95
|
+
%{one #{plural.singularize}}
|
96
|
+
end
|
97
|
+
elsif list.current_page == 1 && total < list.per_page
|
98
|
+
%{all #{total} #{plural}}
|
99
|
+
else
|
100
|
+
start = list.offset + 1
|
101
|
+
finish = ((list.offset + list.per_page) < list.total_entries) ? list.offset + list.per_page : list.total_entries
|
102
|
+
%{#{start} to #{finish} of #{total} #{plural}}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
}
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
data/lib/forum_page.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module ForumPage
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval {
|
5
|
+
has_one :topic
|
6
|
+
include InstanceMethods
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
module InstanceMethods
|
11
|
+
|
12
|
+
def find_or_build_topic
|
13
|
+
if self.topic
|
14
|
+
self.topic
|
15
|
+
elsif self.still_commentable?
|
16
|
+
self.build_topic(:name => title, :forum => Forum.find_or_create_comments_forum, :reader => Reader.find_or_create_for_user(created_by)) # posts_controller will do the right thing with a new topic
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def posts
|
21
|
+
self.topic ? self.topic.posts : []
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_posts?
|
25
|
+
self.topic && self.topic.has_posts?
|
26
|
+
end
|
27
|
+
|
28
|
+
# def cache?
|
29
|
+
# !has_posts?
|
30
|
+
# end
|
31
|
+
|
32
|
+
def still_commentable?
|
33
|
+
commentable? && !comments_closed? && (!commentable_period || Time.now - self.created_at < commentable_period)
|
34
|
+
end
|
35
|
+
|
36
|
+
def commentable_period
|
37
|
+
Radiant::Config['forum.commentable_period'].to_i.days if Radiant::Config['forum.commentable_period']
|
38
|
+
end
|
39
|
+
|
40
|
+
def locked?
|
41
|
+
!still_commentable?
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/lib/forum_reader.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module ForumReadersController
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
alias_method_chain :show, :forum
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def show_with_forum
|
10
|
+
@reader = Reader.find(params[:id])
|
11
|
+
@posts = Post.paginate_by_reader_id(@reader.id, :page => params[:page], :include => :topic, :order => 'posts.created_at desc') if @reader
|
12
|
+
render :template => 'readers/show_with_posts'
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module ForumRedCloth3
|
2
|
+
|
3
|
+
def smilies(text)
|
4
|
+
%w{angry smile bigsmile confused cool cry devil neutral sad shamed shocked surprised tongue wink }.each do |icon|
|
5
|
+
imgtag =
|
6
|
+
text.gsub!(/:#{icon}:/, %{<img src="/images/emoticons/#{icon}.gif" alt="(#{icon})" class="smiley" />})
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ForumRedCloth4
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
# base.extend ClassMethods
|
5
|
+
base.class_eval do
|
6
|
+
def to_html_with_smilies(*rules)
|
7
|
+
rules.push(:smilies) unless rules.include?(:smilies)
|
8
|
+
to_html_without_smilies(*rules)
|
9
|
+
end
|
10
|
+
alias_method_chain :to_html, :smilies unless self.instance_methods.include?("to_html_without_smilies")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def smilies(text)
|
15
|
+
%w{angry smile bigsmile confused cool cry devil neutral sad shamed shocked surprised tongue wink }.each do |icon|
|
16
|
+
imgtag =
|
17
|
+
text.gsub!(/:#{icon}:/, %{<img src="/images/emoticons/#{icon}.gif" alt="(#{icon})" title="#{icon}" class="smiley" />})
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/forum_site.rb
ADDED
data/lib/forum_tags.rb
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
module ForumTags
|
2
|
+
include Radiant::Taggable
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
include ActionView::Helpers::FormTagHelper
|
5
|
+
include ActionView::Helpers::FormOptionsHelper
|
6
|
+
|
7
|
+
class TagError < StandardError; end
|
8
|
+
|
9
|
+
tag 'comments' do |tag|
|
10
|
+
raise TagError, "can't have comments without a page" unless page = tag.locals.page
|
11
|
+
if page.commentable?
|
12
|
+
tag.locals.comments = page.posts
|
13
|
+
tag.expand
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc %{
|
18
|
+
Returns a string in the form "x comments" or "no comments yet".
|
19
|
+
|
20
|
+
*Usage:*
|
21
|
+
<pre><code><r:comments:summary /></code></pre>
|
22
|
+
}
|
23
|
+
|
24
|
+
tag 'comments:summary' do |tag|
|
25
|
+
if tag.locals.comments.empty?
|
26
|
+
"no comments yet"
|
27
|
+
elsif tag.locals.comments.size == 1
|
28
|
+
"one comment"
|
29
|
+
else
|
30
|
+
"#{tag.locals.comments.size} comments"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc %{
|
35
|
+
Anything between if_comments tags is displayed only - dramatic pause - if there are comments.
|
36
|
+
|
37
|
+
*Usage:*
|
38
|
+
<pre><code><r:if_comments>...</r:if_comments></code></pre>
|
39
|
+
}
|
40
|
+
tag 'if_comments' do |tag|
|
41
|
+
raise TagError, "can't have if_comments without a page" unless page = tag.locals.page
|
42
|
+
tag.expand if page.posts.any?
|
43
|
+
end
|
44
|
+
|
45
|
+
desc %{
|
46
|
+
Anything between unless_comments tags is displayed only if there are no comments.
|
47
|
+
|
48
|
+
*Usage:*
|
49
|
+
<pre><code><r:unless_comments>...</r:unless_comments></code></pre>
|
50
|
+
}
|
51
|
+
tag 'unless_comments' do |tag|
|
52
|
+
raise TagError, "can't have unless_comments without a page" unless page = tag.locals.page
|
53
|
+
tag.expand if page.posts.any?
|
54
|
+
end
|
55
|
+
|
56
|
+
desc %{
|
57
|
+
If you want more control over the display of page comments, you can spell them out:
|
58
|
+
|
59
|
+
*Usage:*
|
60
|
+
<pre><code><r:comments:each>
|
61
|
+
<h2><r:comment:reader:name /></h2>
|
62
|
+
<p class="date"><r:comment:date /></p>
|
63
|
+
<r:comment:body_html />
|
64
|
+
</r:comments:each>
|
65
|
+
<r:comment_link />
|
66
|
+
</code></pre>
|
67
|
+
}
|
68
|
+
tag 'comments:each' do |tag|
|
69
|
+
results = []
|
70
|
+
tag.locals.comments.each do |post|
|
71
|
+
tag.locals.comment = post
|
72
|
+
results << tag.expand
|
73
|
+
end
|
74
|
+
results
|
75
|
+
end
|
76
|
+
|
77
|
+
desc %{
|
78
|
+
To enable page commenting, all you have to do is put this in your layout:
|
79
|
+
|
80
|
+
*Usage:*
|
81
|
+
<pre><code><r:comments:all /></code></pre>
|
82
|
+
}
|
83
|
+
tag 'comments:all' do |tag|
|
84
|
+
posts = tag.locals.comments
|
85
|
+
results = ""
|
86
|
+
results << %{<div class="page_comments">}
|
87
|
+
results << "<h2>Comments</h2>"
|
88
|
+
results << %{<div id="forum">
|
89
|
+
}
|
90
|
+
if posts.empty?
|
91
|
+
results << "<p>None yet.</p>"
|
92
|
+
else
|
93
|
+
posts.each do |post|
|
94
|
+
tag.locals.comment = post
|
95
|
+
results << tag.render('comment')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
results << %{#{tag.render('comment_link', 'class' => 'inline inviting')}}
|
99
|
+
results << "</div></div>"
|
100
|
+
results
|
101
|
+
end
|
102
|
+
|
103
|
+
tag 'comment' do |tag|
|
104
|
+
raise TagError, "can't have r:comment without a post" unless post = tag.locals.comment
|
105
|
+
if tag.double?
|
106
|
+
tag.locals.reader = post.reader
|
107
|
+
tag.expand
|
108
|
+
else
|
109
|
+
%{<div class="post" id="#{post.dom_id}">
|
110
|
+
<div class="post_header">
|
111
|
+
<h2><img src="#{post.reader.gravatar_url(:size => 40)}" width="40" height ="40" class="gravatar" /> #{post.reader.name}</h2>
|
112
|
+
<p class="context">#{friendly_date(post.created_at)}</p>
|
113
|
+
</div>
|
114
|
+
<div class="post_body">#{post.body_html}</div>
|
115
|
+
</div>}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
tag 'comment:reader' do |tag|
|
120
|
+
raise TagError, "can't have comment:reader without a comment" unless reader = tag.locals.reader
|
121
|
+
tag.expand
|
122
|
+
end
|
123
|
+
|
124
|
+
desc %{
|
125
|
+
The name of the commenter
|
126
|
+
}
|
127
|
+
tag 'comment:reader:name' do |tag|
|
128
|
+
tag.locals.reader.name
|
129
|
+
end
|
130
|
+
|
131
|
+
desc %{
|
132
|
+
A gravatar for the commenter
|
133
|
+
}
|
134
|
+
tag 'comment:reader:gravatar' do |tag|
|
135
|
+
tag.locals.reader.gravatar
|
136
|
+
end
|
137
|
+
|
138
|
+
desc %{
|
139
|
+
The date of the comment
|
140
|
+
}
|
141
|
+
tag 'comment:date' do |tag|
|
142
|
+
tag.locals.comment.created_at.to_s(:html_date)
|
143
|
+
end
|
144
|
+
|
145
|
+
desc %{
|
146
|
+
The time_ago of the comment
|
147
|
+
}
|
148
|
+
tag 'comment:ago' do |tag|
|
149
|
+
time_ago_in_words(tag.locals.comment.created_at)
|
150
|
+
end
|
151
|
+
|
152
|
+
desc %{
|
153
|
+
The body of the comment as it was entered (but html-escaped)
|
154
|
+
}
|
155
|
+
tag 'comment:body' do |tag|
|
156
|
+
h(tag.locals.comment.body)
|
157
|
+
end
|
158
|
+
|
159
|
+
desc %{
|
160
|
+
The body of the comment rendered into html (and whitelisted, so this ought to be safe)
|
161
|
+
}
|
162
|
+
tag 'comment:body_html' do |tag|
|
163
|
+
tag.locals.comment.body_html
|
164
|
+
end
|
165
|
+
|
166
|
+
desc %{
|
167
|
+
A link to the post-a-comment form. Typically you'll use a bit of remote scripting to replace this with
|
168
|
+
a comment or login form depending on whether a reader is detected, but you can just leave the link too.
|
169
|
+
|
170
|
+
If text is given, the link will be wrapped around it. The default is just "Add a comment". Any supplied
|
171
|
+
attributes are passed through, so you can specify class, id and anything else you like.
|
172
|
+
|
173
|
+
*Usage:*
|
174
|
+
<pre><code>
|
175
|
+
<r:if_comments>
|
176
|
+
<r:comment_link />
|
177
|
+
</r:if_comments>
|
178
|
+
<r:unless_comments>
|
179
|
+
<r:comment_link class="how_exciting">Be the first to add a comment!</r:comment_link>
|
180
|
+
</r:unless_comments>
|
181
|
+
</code></pre>
|
182
|
+
}
|
183
|
+
tag 'comment_link' do |tag|
|
184
|
+
raise TagError, "can't have `r:comment_link' without a page." unless tag.locals.page
|
185
|
+
options = tag.attr.dup
|
186
|
+
options['class'] ||= 'newmessage'
|
187
|
+
attributes = options.inject('') { |s, (k, v)| s << %{#{k.to_s.downcase}="#{v}" } }.strip
|
188
|
+
attributes = " #{attributes}" unless attributes.empty?
|
189
|
+
text = tag.double? ? tag.expand : "Add a comment"
|
190
|
+
%{<a href="#{tag.render('comment_url')}"#{attributes}>#{text}</a>}
|
191
|
+
end
|
192
|
+
|
193
|
+
desc %{
|
194
|
+
The address for add-a-comment links
|
195
|
+
}
|
196
|
+
tag 'comment_url' do |tag|
|
197
|
+
raise TagError, "can't have `r:comment_url' without a page." unless tag.locals.page
|
198
|
+
new_page_post_url(tag.locals.page)
|
199
|
+
end
|
200
|
+
|
201
|
+
desc %{
|
202
|
+
Shows the standard block of recent discussion activity.
|
203
|
+
}
|
204
|
+
tag 'forum_latest' do |tag|
|
205
|
+
results = []
|
206
|
+
results << %{<ul class="clean">}
|
207
|
+
Topic.visible.latest(6).each do |topic|
|
208
|
+
tag.locals.topic = topic
|
209
|
+
results << %{<li>#{tag.render('topic:summary')}</li>}
|
210
|
+
end
|
211
|
+
results << %{</ul>}
|
212
|
+
results
|
213
|
+
end
|
214
|
+
|
215
|
+
desc %{
|
216
|
+
Shows the standard forum search form in a reasonably compact and stylable way.
|
217
|
+
|
218
|
+
Takes options with_title (set to false to omit the usual heading), by_forum (set to true to show a discussion category dropdown) and by_reader (set to true to show a message-from dropdown) and label (set to the title you would like to display over the main search field).
|
219
|
+
}
|
220
|
+
tag 'forum_search' do |tag|
|
221
|
+
results = []
|
222
|
+
compact = true unless tag.attr['by_forum'] == 'true' || tag.attr['by_reader'] == 'true'
|
223
|
+
q_label = tag.attr['label']
|
224
|
+
q_label = "Look for this text" if q_label.blank? && !compact
|
225
|
+
results << %{<form class="friendly" action="#{search_posts_url}">}
|
226
|
+
results << %{<h2>Forum Search</h2>} unless tag.attr['with_title'] == 'false'
|
227
|
+
results << %{<p>}
|
228
|
+
results << %{<label for="q">#{q_label}</label><br />} unless q_label.blank?
|
229
|
+
results << %{#{text_field_tag("q", params[:q], :class => 'standard')}}
|
230
|
+
results << %{#{submit_tag "search", :class => 'button'}} if compact
|
231
|
+
results << %{</p>}
|
232
|
+
unless compact
|
233
|
+
results << %{<p><label for="reader_id">From this person</label><br /><select name="reader_id"><option value="">anyone</option>#{options_from_collection_for_select(Reader.all, "id", "name")}</select></p>} if tag.attr['by_reader'] == 'true'
|
234
|
+
results << %{<p><label for="forum_id">In this discussion category</label><br /><select name="forum_id"><option value="">anywhere</option>#{options_from_collection_for_select(Forum.visible, "id", "name")}</select></p>} if tag.attr['by_forum'] == 'true'
|
235
|
+
results << %{<p class="buttons">#{submit_tag "search", :class => 'button'}</p>}
|
236
|
+
end
|
237
|
+
results << %{</form>}
|
238
|
+
results
|
239
|
+
end
|
240
|
+
|
241
|
+
tag 'topic' do |tag|
|
242
|
+
tag.expand if tag.locals.topic
|
243
|
+
end
|
244
|
+
tag 'topic:summary' do |tag|
|
245
|
+
results = []
|
246
|
+
topic = tag.locals.topic
|
247
|
+
post = topic.last_post
|
248
|
+
results << %{<img src="#{post.reader.gravatar_url(:size => 42)}" width="42" height="42" class="gravatar"> } if tag.attr['gravatar'] == 'true'
|
249
|
+
results << %{<a href="#{forum_topic_path(topic.forum, topic)}">#{topic.name}</a> }
|
250
|
+
results << %{<span class="credit">}
|
251
|
+
if topic.page
|
252
|
+
results << " commented upon by "
|
253
|
+
elsif post.first?
|
254
|
+
results << " started by "
|
255
|
+
else
|
256
|
+
results << " replied to by "
|
257
|
+
end
|
258
|
+
results << "#{post.reader.name} #{friendly_date(post.created_at)}"
|
259
|
+
results << %{</span>}
|
260
|
+
results
|
261
|
+
end
|
262
|
+
|
263
|
+
|
264
|
+
|
265
|
+
private
|
266
|
+
|
267
|
+
# copied from forum_helper
|
268
|
+
|
269
|
+
def friendly_date(datetime)
|
270
|
+
if datetime
|
271
|
+
date = datetime.to_date
|
272
|
+
if (date == Date.today)
|
273
|
+
format = "today at %l:%M%p"
|
274
|
+
elsif (date == Date.yesterday)
|
275
|
+
format = "yesterday at %l:%M%p"
|
276
|
+
elsif (date.year == Date.today.year)
|
277
|
+
format = "on %B %e"
|
278
|
+
else
|
279
|
+
format = "on %B %e, %Y"
|
280
|
+
end
|
281
|
+
datetime.strftime(format)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|