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.
Files changed (52) hide show
  1. data/Rakefile +1 -3
  2. data/VERSION +1 -1
  3. data/app/controllers/forums_controller.rb +13 -5
  4. data/app/controllers/posts_controller.rb +9 -3
  5. data/app/controllers/topics_controller.rb +10 -3
  6. data/app/helpers/forum_helper.rb +105 -0
  7. data/app/models/post_attachment.rb +20 -12
  8. data/app/models/topic.rb +1 -1
  9. data/app/views/admin/forums/index.html.haml +63 -65
  10. data/app/views/admin/reader_configuration/_edit_forum.html.haml +6 -0
  11. data/app/views/admin/reader_configuration/_forum.html.haml +6 -0
  12. data/app/views/forums/_forum.html.haml +1 -2
  13. data/app/views/forums/index.html.haml +27 -25
  14. data/app/views/forums/show.html.haml +31 -19
  15. data/app/views/posts/_attachment.html.haml +5 -2
  16. data/app/views/posts/_form.html.haml +3 -5
  17. data/app/views/posts/_post.html.haml +32 -29
  18. data/app/views/posts/_uploader.html.haml +2 -3
  19. data/app/views/posts/index.html.haml +27 -11
  20. data/app/views/topics/_form.html.haml +3 -3
  21. data/app/views/topics/_topic.html.haml +10 -11
  22. data/app/views/topics/index.html.haml +28 -22
  23. data/app/views/topics/new.html.haml +32 -27
  24. data/app/views/topics/show.html.haml +25 -10
  25. data/config/locales/en.yml +58 -0
  26. data/config/routes.rb +5 -5
  27. data/forum_extension.rb +18 -11
  28. data/lib/forum_readers_controller.rb +1 -0
  29. data/lib/tasks/radiant_forum_extension_tasks.rake +54 -31
  30. data/public/images/{forum → furniture}/attachment.png +0 -0
  31. data/public/images/{forum → furniture}/attachment_link.png +0 -0
  32. data/public/images/{forum → furniture}/attachment_over.png +0 -0
  33. data/public/images/{forum → furniture}/chk_off.png +0 -0
  34. data/public/images/{forum → furniture}/chk_on.png +0 -0
  35. data/public/images/{forum → furniture}/feed_14.png +0 -0
  36. data/public/images/{forum → furniture}/feed_28.png +0 -0
  37. data/public/images/furniture/post.png +0 -0
  38. data/public/images/furniture/post_over.png +0 -0
  39. data/public/images/{forum → furniture}/rdo_off.png +0 -0
  40. data/public/images/{forum → furniture}/rdo_on.png +0 -0
  41. data/public/images/{forum → furniture}/wait_16_grey.gif +0 -0
  42. data/public/javascripts/forum.js +198 -0
  43. data/public/stylesheets/sass/forum.sass +247 -0
  44. data/radiant-forum-extension.gemspec +21 -28
  45. metadata +26 -53
  46. data/lib/forum_helper.rb +0 -109
  47. data/public/images/forum/post_14.png +0 -0
  48. data/public/images/forum/post_14_over.png +0 -0
  49. data/public/javascripts/platform/forum.js +0 -175
  50. data/public/javascripts/platform/remotecontent.js +0 -89
  51. data/public/stylesheets/admin/forum.css +0 -87
  52. 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
- }