radiant-forum-extension 0.6.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -3
- data/VERSION +1 -1
- data/app/controllers/forums_controller.rb +13 -5
- data/app/controllers/posts_controller.rb +9 -3
- data/app/controllers/topics_controller.rb +10 -3
- data/app/helpers/forum_helper.rb +105 -0
- data/app/models/post_attachment.rb +20 -12
- data/app/models/topic.rb +1 -1
- data/app/views/admin/forums/index.html.haml +63 -65
- data/app/views/admin/reader_configuration/_edit_forum.html.haml +6 -0
- data/app/views/admin/reader_configuration/_forum.html.haml +6 -0
- data/app/views/forums/_forum.html.haml +1 -2
- data/app/views/forums/index.html.haml +27 -25
- data/app/views/forums/show.html.haml +31 -19
- data/app/views/posts/_attachment.html.haml +5 -2
- data/app/views/posts/_form.html.haml +3 -5
- data/app/views/posts/_post.html.haml +32 -29
- data/app/views/posts/_uploader.html.haml +2 -3
- data/app/views/posts/index.html.haml +27 -11
- data/app/views/topics/_form.html.haml +3 -3
- data/app/views/topics/_topic.html.haml +10 -11
- data/app/views/topics/index.html.haml +28 -22
- data/app/views/topics/new.html.haml +32 -27
- data/app/views/topics/show.html.haml +25 -10
- data/config/locales/en.yml +58 -0
- data/config/routes.rb +5 -5
- data/forum_extension.rb +18 -11
- data/lib/forum_readers_controller.rb +1 -0
- data/lib/tasks/radiant_forum_extension_tasks.rake +54 -31
- data/public/images/{forum → furniture}/attachment.png +0 -0
- data/public/images/{forum → furniture}/attachment_link.png +0 -0
- data/public/images/{forum → furniture}/attachment_over.png +0 -0
- data/public/images/{forum → furniture}/chk_off.png +0 -0
- data/public/images/{forum → furniture}/chk_on.png +0 -0
- data/public/images/{forum → furniture}/feed_14.png +0 -0
- data/public/images/{forum → furniture}/feed_28.png +0 -0
- data/public/images/furniture/post.png +0 -0
- data/public/images/furniture/post_over.png +0 -0
- data/public/images/{forum → furniture}/rdo_off.png +0 -0
- data/public/images/{forum → furniture}/rdo_on.png +0 -0
- data/public/images/{forum → furniture}/wait_16_grey.gif +0 -0
- data/public/javascripts/forum.js +198 -0
- data/public/stylesheets/sass/forum.sass +247 -0
- data/radiant-forum-extension.gemspec +21 -28
- metadata +26 -53
- data/lib/forum_helper.rb +0 -109
- data/public/images/forum/post_14.png +0 -0
- data/public/images/forum/post_14_over.png +0 -0
- data/public/javascripts/platform/forum.js +0 -175
- data/public/javascripts/platform/remotecontent.js +0 -89
- data/public/stylesheets/admin/forum.css +0 -87
- data/public/stylesheets/platform/forum.css +0 -70
data/lib/forum_helper.rb
DELETED
@@ -1,109 +0,0 @@
|
|
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
|
Binary file
|
Binary file
|
@@ -1,175 +0,0 @@
|
|
1
|
-
var Post = new Class({
|
2
|
-
initialize: function (div) {
|
3
|
-
this.container = div;
|
4
|
-
this.header = div.getElement('div.post_header');
|
5
|
-
this.wrapper = div.getElement('div.post_wrapper');
|
6
|
-
this.body_holder = div.getElement('div.post_body');
|
7
|
-
this.h = this.body_holder.getHeight();
|
8
|
-
this.editors = this.container.getElements('a.edit_post');
|
9
|
-
this.editors.each(function (a) {
|
10
|
-
a.addEvent('click', this.edit.bindWithEvent(this));
|
11
|
-
}, this);
|
12
|
-
this.showing = false;
|
13
|
-
this.form_holder = null;
|
14
|
-
this.form = null;
|
15
|
-
},
|
16
|
-
|
17
|
-
edit: function(e){
|
18
|
-
unevent(e);
|
19
|
-
var link = e.target;
|
20
|
-
link.addClass('waiting');
|
21
|
-
if (this.showing) this.cancel();
|
22
|
-
else if (this.form_holder) this.prepForm();
|
23
|
-
else this.getForm(link.get('href'));
|
24
|
-
},
|
25
|
-
|
26
|
-
getForm: function (url) {
|
27
|
-
if (url) this.formHolder().load(url);
|
28
|
-
},
|
29
|
-
|
30
|
-
formHolder: function () {
|
31
|
-
if (this.form_holder) return this.form_holder;
|
32
|
-
this.form_holder = new Element('div', {'class': 'post_form'});
|
33
|
-
this.form_holder.set('load', {onComplete: this.prepForm.bind(this)});
|
34
|
-
return this.form_holder;
|
35
|
-
},
|
36
|
-
|
37
|
-
prepForm: function () {
|
38
|
-
this.form_holder.inject(this.wrapper, 'top');
|
39
|
-
this.body_holder.hide();
|
40
|
-
this.editors.removeClass('waiting');
|
41
|
-
this.form = this.form_holder.getElement('form');
|
42
|
-
this.input = this.form.getElement('textarea');
|
43
|
-
this.input.setStyle('height', this.h);
|
44
|
-
this.form_holder.getElement('a.cancel').addEvent('click', this.cancel.bindWithEvent(this));
|
45
|
-
this.uploader = new UploadHandler(this.form_holder.getElement('div.upload_handler'));
|
46
|
-
this.stumbit = this.form_holder.getElement('div.buttons');
|
47
|
-
this.form.onsubmit = this.sendForm.bind(this);
|
48
|
-
// new Fx.Morph(this.input, {duration: 'short'}).start({'height' : 240, opacity : 1});
|
49
|
-
this.form_holder.show();
|
50
|
-
this.showing = true;
|
51
|
-
},
|
52
|
-
|
53
|
-
sendForm: function (e) {
|
54
|
-
var waiter = new Element('p', {'class' : 'waiting'}).set('text', 'please wait');
|
55
|
-
waiter.replaces(this.stumbit);
|
56
|
-
|
57
|
-
if (this.uploader && this.uploader.hasUploads()) {
|
58
|
-
// can't send uploads over xmlhttp so we allow the form to submit
|
59
|
-
// the update-post action will redirect to a hashed url that should return us to the right post
|
60
|
-
} else {
|
61
|
-
unevent(e);
|
62
|
-
new Request.HTML({
|
63
|
-
url: this.form.get('action'),
|
64
|
-
update: this.container,
|
65
|
-
onComplete: this.finishEdit.bind(this)
|
66
|
-
}).post(this.form);
|
67
|
-
}
|
68
|
-
|
69
|
-
},
|
70
|
-
cancel: function (e) {
|
71
|
-
unevent(e);
|
72
|
-
this.finishCancel();
|
73
|
-
// new Fx.Morph(this.input, {duration: 'short', onComplete : this.finishCancel.bind(this)}).start({'height' : this.h, opacity : 0});
|
74
|
-
},
|
75
|
-
finishCancel: function () {
|
76
|
-
this.form_holder.hide();
|
77
|
-
this.body_holder.show();
|
78
|
-
this.editors.removeClass('waiting');
|
79
|
-
this.showing = false;
|
80
|
-
},
|
81
|
-
finishEdit: function () {
|
82
|
-
this.container.highlight();
|
83
|
-
new Post(this.container);
|
84
|
-
}
|
85
|
-
});
|
86
|
-
|
87
|
-
var uh = null;
|
88
|
-
var UploadHandler = new Class({
|
89
|
-
initialize: function (div) {
|
90
|
-
this.container = div;
|
91
|
-
this.shower = div.getElement('a');
|
92
|
-
this.list = div.getElement('ul.attachments');
|
93
|
-
this.pender = div.getElement('div.uploads');
|
94
|
-
this.selector = div.getElement('div.selector');
|
95
|
-
this.file_field_template = this.selector.getElement('input').clone();
|
96
|
-
this.file_pending_template = new Element('li');
|
97
|
-
|
98
|
-
this.attachments = [];
|
99
|
-
this.list.getElements('li.attachment').each(function (li) { this.attachments.push( new Attachment(li)); }, this);
|
100
|
-
|
101
|
-
this.uploads = [];
|
102
|
-
this.uploader = this.selector.getElement('input');
|
103
|
-
this.uploader.addEvent('change', this.addUpload.bindWithEvent(this));
|
104
|
-
this.fakelink = this.selector.getElement('a');
|
105
|
-
|
106
|
-
// this.reveal.hide();
|
107
|
-
uh = this;
|
108
|
-
},
|
109
|
-
addUpload: function (e) {
|
110
|
-
unevent(e);
|
111
|
-
this.uploads.push(new Upload(this));
|
112
|
-
this.fakelink.set('text', 'attach another file');
|
113
|
-
},
|
114
|
-
pendUpload: function (argument) {
|
115
|
-
var ul = this.uploader.inject(this.pender);
|
116
|
-
this.uploader = ul.clone().inject(this.selector);
|
117
|
-
this.uploader.set('value', null);
|
118
|
-
this.uploader.addEvent('change', this.addUpload.bindWithEvent(this));
|
119
|
-
return ul;
|
120
|
-
},
|
121
|
-
hasAttachments: function () {
|
122
|
-
return this.attachments.length > 0;
|
123
|
-
},
|
124
|
-
hasUploads: function () {
|
125
|
-
return this.uploads.length > 0;
|
126
|
-
}
|
127
|
-
});
|
128
|
-
|
129
|
-
var Upload = new Class({
|
130
|
-
initialize: function (handler) {
|
131
|
-
this.handler = handler;
|
132
|
-
this.uploader = this.handler.pendUpload();
|
133
|
-
this.container = new Element('li', {'class': 'attachment'}).set('text', ' ' + this.uploader.value + ' ');
|
134
|
-
this.icon = new Element('img').set('src', this.icon_for(this.uploader.value)).inject(this.container, 'top');
|
135
|
-
this.remover = new Element('a', {'class': 'remove', 'href': '#'}).set('text', 'remove').inject(this.container, 'bottom');
|
136
|
-
this.remover.addEvent('click', this.remove.bindWithEvent(this));
|
137
|
-
this.container.inject(this.handler.list, 'bottom');
|
138
|
-
this.container.set('morph', {duration : 'long'});
|
139
|
-
this.container.reveal();
|
140
|
-
},
|
141
|
-
icon_for: function (filename) {
|
142
|
-
return '/images/forum/attachment.png';
|
143
|
-
},
|
144
|
-
remove: function (e) {
|
145
|
-
unevent(e);
|
146
|
-
this.uploader.destroy();
|
147
|
-
this.container.nix();
|
148
|
-
}
|
149
|
-
});
|
150
|
-
|
151
|
-
var Attachment = new Class({
|
152
|
-
initialize: function (li) {
|
153
|
-
this.container = li;
|
154
|
-
this.checkbox = li.getElement('input.choose_attachment');
|
155
|
-
this.remover = li.getElement('a.remove');
|
156
|
-
this.remover.addEvent('click', this.remove.bindWithEvent(this));
|
157
|
-
},
|
158
|
-
remove: function (e) {
|
159
|
-
unevent(e);
|
160
|
-
if (this.checkbox) this.checkbox.set('checked', false);
|
161
|
-
this.container.nix();
|
162
|
-
},
|
163
|
-
hide: function () {
|
164
|
-
this.container.hide();
|
165
|
-
}
|
166
|
-
});
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
activations.push(function (scope) {
|
173
|
-
scope.getElements('div.post').each(function (div) { new Post(div); });
|
174
|
-
scope.getElements('div.upload_handler').each(function (div) { new UploadHandler(div); });
|
175
|
-
});
|
@@ -1,89 +0,0 @@
|
|
1
|
-
// self-replacing links
|
2
|
-
// puts the get results in place of the link.
|
3
|
-
|
4
|
-
var InlineLink = new Class({
|
5
|
-
initialize: function (a) {
|
6
|
-
this.link = a;
|
7
|
-
this.link.onclick = this.sendLink.bindWithEvent(this);
|
8
|
-
this.catcher = new Element('div', {'class' : 'remote_content'}).wraps(this.link);
|
9
|
-
this.catcher.set('load', {
|
10
|
-
onRequest: this.waiting.bind(this),
|
11
|
-
onSuccess: this.finish.bind(this),
|
12
|
-
onFailure: this.fail.bind(this)
|
13
|
-
});
|
14
|
-
},
|
15
|
-
sendLink: function (e) {
|
16
|
-
unevent(e);
|
17
|
-
this.link.blur();
|
18
|
-
this.catcher.load(this.link.get('href'));
|
19
|
-
},
|
20
|
-
finish: function (response) {
|
21
|
-
activate(this.catcher);
|
22
|
-
this.catcher.highlight('#f27877');
|
23
|
-
activate(this.catcher);
|
24
|
-
},
|
25
|
-
fail: function (response) {
|
26
|
-
this.notWaiting();
|
27
|
-
this.catcher.addClass('failed');
|
28
|
-
},
|
29
|
-
waiting: function () {
|
30
|
-
this.link.addClass('waiting');
|
31
|
-
},
|
32
|
-
notWaiting: function () {
|
33
|
-
this.link.removeClass('waiting');
|
34
|
-
}
|
35
|
-
});
|
36
|
-
|
37
|
-
// self-replacing forms
|
38
|
-
// puts the post results in place of the form.
|
39
|
-
|
40
|
-
var InlineForm = new Class ({
|
41
|
-
initialize: function (form) {
|
42
|
-
this.form = form;
|
43
|
-
var catchers = this.form.getParents().filter(function (parent) { return parent.hasClass('remote_content'); });
|
44
|
-
this.catcher = catchers[0] || new Element('div', {'class' : 'remote_content'}).wraps(this.form);
|
45
|
-
this.catcher.set('load', {
|
46
|
-
url: this.form.get('action'),
|
47
|
-
onRequest: this.waiting.bind(this),
|
48
|
-
onSuccess: this.finish.bind(this),
|
49
|
-
onFailure: this.fail.bind(this)
|
50
|
-
});
|
51
|
-
this.form.onsubmit = this.sendForm.bindWithEvent(this);
|
52
|
-
},
|
53
|
-
|
54
|
-
sendForm: function (e) {
|
55
|
-
unevent(e);
|
56
|
-
this.catcher.get('load').post(this.form);
|
57
|
-
},
|
58
|
-
|
59
|
-
finish: function (response) {
|
60
|
-
activate(this.catcher);
|
61
|
-
this.catcher.highlight('#f27877');
|
62
|
-
activate(this.catcher);
|
63
|
-
},
|
64
|
-
|
65
|
-
fail: function (argument) {
|
66
|
-
this.notWaiting();
|
67
|
-
this.catcher.addClass('failed');
|
68
|
-
},
|
69
|
-
|
70
|
-
waiting: function () {
|
71
|
-
this.form.getElements('input').each(function (input) { input.disabled = true; });
|
72
|
-
this.form.getElement('p.buttons').addClass('waiting');
|
73
|
-
},
|
74
|
-
|
75
|
-
notWaiting: function () {
|
76
|
-
this.form.getElements('input').each(function (input) { input.disabled = false; });
|
77
|
-
this.form.getElement('p.buttons').removeClass('waiting');
|
78
|
-
}
|
79
|
-
});
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
activations.push(function (scope) {
|
86
|
-
scope.getElements('a.inline').each(function (a) { new InlineLink(a); });
|
87
|
-
scope.getElements('a.remote_content').each(function (a) { new InlineLink(a).sendLink(); });
|
88
|
-
scope.getElements('form.inline').each(function (form) { new InlineForm(form); });
|
89
|
-
});
|
@@ -1,87 +0,0 @@
|
|
1
|
-
#content table.index tr.node td {
|
2
|
-
vertical-align: top;
|
3
|
-
padding: 1em;
|
4
|
-
}
|
5
|
-
|
6
|
-
#content table.index tr.node td {
|
7
|
-
vertical-align: top;
|
8
|
-
padding: 1em;
|
9
|
-
}
|
10
|
-
|
11
|
-
#content table.index tr.node td.forum {
|
12
|
-
width: 40%;
|
13
|
-
}
|
14
|
-
|
15
|
-
#content table.index tr.node td.forum_latest {
|
16
|
-
width: 50%;
|
17
|
-
}
|
18
|
-
|
19
|
-
#content table.index .node .forum small {
|
20
|
-
color: #666;
|
21
|
-
font-size: 90%;
|
22
|
-
font-style: italic;
|
23
|
-
font-weight: normal;
|
24
|
-
margin-left: .5em;
|
25
|
-
}
|
26
|
-
|
27
|
-
#content table.index .node .forum a, #content table.index .node .forum a:visited {
|
28
|
-
font-size: 115%;
|
29
|
-
font-weight: bold;
|
30
|
-
color: black;
|
31
|
-
text-decoration: none;
|
32
|
-
}
|
33
|
-
|
34
|
-
#content table.index .node .forum a.untrusted, #content table.index .node .forum a.untrusted:visited {
|
35
|
-
color: #c00;
|
36
|
-
}
|
37
|
-
|
38
|
-
#content table.index .node .forum a:hover, #content table.index .node .forum a:visited:hover {
|
39
|
-
color: blue;
|
40
|
-
text-decoration: underline;
|
41
|
-
}
|
42
|
-
|
43
|
-
#content table.index tr.node td.forum p {
|
44
|
-
color: #666;
|
45
|
-
}
|
46
|
-
|
47
|
-
#content table.index p.admin_notes {
|
48
|
-
color: #c00;
|
49
|
-
margin: 0 0 0 40px;
|
50
|
-
}
|
51
|
-
|
52
|
-
#content table.index p.admin_notes {
|
53
|
-
color: #c00;
|
54
|
-
margin: 0 0 0 40px;
|
55
|
-
}
|
56
|
-
|
57
|
-
#content table.index tr.node td h3 {
|
58
|
-
margin: 0;
|
59
|
-
}
|
60
|
-
|
61
|
-
#content table.index tr.node td .context {
|
62
|
-
margin: 0;
|
63
|
-
font-size: 85%;
|
64
|
-
color: #999;
|
65
|
-
}
|
66
|
-
|
67
|
-
#content table.index tr.node td .context a {
|
68
|
-
color: #666;
|
69
|
-
}
|
70
|
-
|
71
|
-
#content table.index tr.node td.forum_latest ul {
|
72
|
-
list-style: square;
|
73
|
-
}
|
74
|
-
|
75
|
-
#content table.index tr.node td.forum_latest li {
|
76
|
-
margin: 4px 0;
|
77
|
-
color: #999;
|
78
|
-
}
|
79
|
-
|
80
|
-
#content table.index tr.node td.forum_latest a.topic {
|
81
|
-
color: #666;
|
82
|
-
font-weight: bold;
|
83
|
-
}
|
84
|
-
|
85
|
-
#content table.index tr.node td.forum_latest a.reader {
|
86
|
-
color: #666;
|
87
|
-
}
|