radiant-forum-extension 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,10 @@
1
1
  - include_stylesheet 'admin/forum'
2
2
 
3
3
  - fields_for :page do |f|
4
- .commentability
4
+ %p.commentability
5
5
  %label
6
6
  = t('forum_extension.comments').titlecase
7
- %br
8
7
  = f.check_box :commentable, {:onclick => "if (this.checked) { $('page_comments_closed').enable(); $('comments_closed_label').removeClassName('disabled'); } else { $('page_comments_closed').disable(); $('comments_closed_label').addClassName('disabled'); }"}
9
- = f.label :commentable
10
- %br
8
+ = f.label :commentable, nil, :class => 'checkbox'
11
9
  = f.check_box :comments_closed, :disabled => !@page.commentable?
12
- = f.label :comments_closed, nil, :id => 'comments_closed_label', :class => !@page.commentable? ? 'disabled' : ''
10
+ = f.label :comments_closed, nil, :id => 'comments_closed_label', :class => !@page.commentable? ? 'checkbox disabled' : 'checkbox'
@@ -7,7 +7,6 @@
7
7
  .post_header
8
8
  %h2
9
9
  = link_to_topic(topic)
10
- = feed_link(topic_path(topic, :format => :rss))
11
10
 
12
11
  = render :partial => "topics/context", :locals => {:topic => topic}
13
12
 
@@ -124,6 +124,7 @@ en:
124
124
  topics: "Latest"
125
125
  new_comment: "Add a comment"
126
126
  new_forum: "New forum"
127
+ new_reply: "Add a reply"
127
128
  new_reply_to: "New reply to"
128
129
  new_reply_from: "New reply from"
129
130
  new_topic: "Start discussion"
@@ -1,5 +1,5 @@
1
1
  module RadiantForumExtension
2
- VERSION = '3.0.0'
2
+ VERSION = '3.0.1'
3
3
  SUMMARY = %q{Forum and Comment Extension for Radiant CMS}
4
4
  DESCRIPTION = %q{Nice clean forums and page comments for inclusion in your radiant site.}
5
5
  URL = "http://radiant.spanner.org/forum"
@@ -9,8 +9,278 @@
9
9
  */
10
10
 
11
11
  (function($) {
12
+
12
13
  $.ajaxSettings.accepts.html = $.ajaxSettings.accepts.script;
13
14
 
15
+ /*
16
+ * Some easing functions borrowed from the effects library to save loading the whole lot.
17
+ * Glide is really quartic out. Boing is back out.
18
+ */
19
+
20
+ $.easing.glide = function (x, t, b, c, d) {
21
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
22
+ }
23
+
24
+ $.easing.boing = function (x, t, b, c, d, s) {
25
+ if (s == undefined) s = 1.70158;
26
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
27
+ };
28
+
29
+ function Gallery() {
30
+ var self = this;
31
+ var container = $('<div class="gallery"><img class="preview" /><p class="caption" /><div class="controls"><a href="#" class="previous" /><a href="#" class="download" /><a href="#" class="next" /></a></div><div class="closer"><a href="#" /></div></div>').hide().appendTo($('body'));
32
+ $.extend(self, {
33
+ container: container,
34
+ zoomer: new Zoomer(),
35
+ image: container.find('img.preview'),
36
+ caption: container.find('p.caption'),
37
+ controls: container.find('div.controls'),
38
+ closer: container.find('div.closer'),
39
+ stack: [],
40
+ item: null,
41
+ click_outside: null,
42
+ escape_key: null,
43
+ add: function (a) {
44
+ self.stack.push(new GalleryItem(a));
45
+ },
46
+ display: function (item) {
47
+ self.item = item;
48
+ if (self.visible()) self.crossfade();
49
+ else self.zoomUp();
50
+ },
51
+
52
+ mimic: function () {
53
+ self.zoomer.setImage(self.item.src);
54
+ self.image.attr('src', self.item.src);
55
+ self.controls.find('a.download').attr('href', self.item.download_url());
56
+ if (self.item.caption.html()) self.caption.html(self.item.caption.html()).show();
57
+ else self.caption.hide();
58
+ },
59
+ zoomUp: function () {
60
+ self.hide();
61
+ self.mimic();
62
+ self.zoomer.zoomUp(self.item, self.show);
63
+ self.setClosers();
64
+ },
65
+ zoomDown: function () {
66
+ self.zoomer.zoomDown(self.item);
67
+ self.unsetClosers();
68
+ self.hide();
69
+ },
70
+ crossfade: function () {
71
+ self.fadeDown(self.fadeUp);
72
+ },
73
+ fadeDown: function (onFade) {
74
+ self.caption.fadeTo('fast', 0.2);
75
+ self.image.fadeTo('fast', 0.2, onFade);
76
+ },
77
+ fadeUp: function (onFade) {
78
+ self.mimic();
79
+ self.resize();
80
+ self.caption.fadeTo('fast', 1);
81
+ self.image.fadeTo('fast', 1, onFade);
82
+ },
83
+
84
+ current: function () {
85
+ return self.stack.indexOf(self.item);
86
+ },
87
+ next: function (e) {
88
+ if (e) e.preventDefault();
89
+ var at = self.current();
90
+ var next = (at == self.stack.length-1) ? 0 : at + 1;
91
+ self.display(self.stack[next]);
92
+ },
93
+ previous: function (e) {
94
+ if (e) e.preventDefault();
95
+ var at = self.current();
96
+ var previous = (at == 0) ? self.stack.length-1 : at - 1;
97
+ self.display(self.stack[previous]);
98
+ },
99
+ close: function (e) {
100
+ if (e) e.preventDefault();
101
+ if (self.visible) self.zoomDown();
102
+ },
103
+ setClosers: function (argument) {
104
+ self.escape_key = $(document).keyup(function(e) {
105
+ if (e.keyCode == 27) self.close(e);
106
+ if (!e.metaKey) {
107
+ if (e.keyCode == 39) self.next(e);
108
+ if (e.keyCode == 37) self.previous(e);
109
+ }
110
+ return false;
111
+ });
112
+ },
113
+ unsetClosers: function (argument) {
114
+ if (self.escape_key) $(document).unbind('keyup', self.escape_key);
115
+ },
116
+
117
+
118
+ show: function () {
119
+ self.zoomer.hide();
120
+ self.container.show();
121
+ },
122
+ hide: function () {
123
+ self.container.hide();
124
+ },
125
+ visible: function () {
126
+ return self.container.is(':visible');
127
+ },
128
+ showControls: function (e) {
129
+ self.controls.fadeIn("fast");
130
+ self.closer.fadeIn("fast");
131
+ },
132
+ hideControls: function (e) {
133
+ self.controls.fadeOut("fast");
134
+ self.closer.fadeOut("fast");
135
+ },
136
+
137
+ resize: function (item) {
138
+ if (!item) item = self.item;
139
+ var w = $(window);
140
+ var d = item.imageSize();
141
+ var p = self.container.offset();
142
+ var r = {
143
+ left: p.left + (self.image.innerWidth() - d.width)/2,
144
+ top: p.top + (self.image.innerHeight() - d.height)/2
145
+ };
146
+ if (r.top <= 10) r.top = 10;
147
+ self.image.animate(d, 'fast');
148
+ self.container.animate(r, 'fast');
149
+ self.controls.css({left: (d.width - 96)/2});
150
+ },
151
+ reposition: function (item) {
152
+ if (!item) item = self.item;
153
+ var w = $(window);
154
+ var d = item.imageSize();
155
+ var p = {
156
+ top: w.scrollTop() + (w.height() - d.height)/2,
157
+ left: w.scrollLeft() + (w.width() - d.width)/2
158
+ };
159
+ if (p.top <= 10) p.top = 10;
160
+ if (self.visible) {
161
+ self.image.animate(d, 'fast');
162
+ self.container.animate(p, 'fast');
163
+ } else {
164
+ self.image.css(d);
165
+ self.container.css(p);
166
+ }
167
+ self.controls.css({left: (d.width - 96)/2});
168
+ return $.extend(d,p);
169
+ },
170
+ currentPosition: function () {
171
+ var p = self.container.offset();
172
+ return {
173
+ left: p.left,
174
+ top: p.top,
175
+ width: self.image.innerWidth(),
176
+ height: self.image.innerHeight()
177
+ };
178
+ }
179
+ });
180
+
181
+ self.closer.find('a').click(self.close);
182
+ self.controls.find('a.previous').click(self.previous);
183
+ self.controls.find('a.next').click(self.next);
184
+ self.container.hover(self.showControls, self.hideControls);
185
+ };
186
+
187
+ function Zoomer() {
188
+ var self = this;
189
+ var sprite = $('<img class="grower" />').hide().appendTo($('body'));
190
+ $.extend(self, {
191
+ sprite: sprite,
192
+ defaultUpState: {position: 'absolute', opacity: 1, borderLeftWidth: 20, borderRightWidth: 20, borderTopWidth: 20, borderBottomWidth: 20},
193
+ defaultDownState: {position: 'absolute', opacity: 0, borderLeftWidth: 4, borderRightWidth: 4, borderTopWidth: 4, borderBottomWidth: 4},
194
+ zoomDuration: 'slow',
195
+ setImage: function (src) {
196
+ self.sprite.attr('src', src);
197
+ },
198
+ zoomUp: function (item, onZoom) {
199
+ if (!onZoom) onZoom = self.hide;
200
+ self.sprite.css($.extend(self.defaultDownState, item.position()));
201
+ self.show();
202
+ self.sprite.animate($.extend({}, self.defaultUpState, $.gallery.reposition()), self.zoomDuration, onZoom);
203
+ },
204
+ zoomDown: function (item, onZoom) {
205
+ if (!onZoom) onZoom = self.hide;
206
+ self.interrupt();
207
+ self.show();
208
+ self.sprite.css($.extend(self.defaultUpState, $.gallery.currentPosition()));
209
+ self.sprite.animate($.extend({}, self.defaultDownState, item.position()), self.zoomDuration, onZoom);
210
+ },
211
+ interrupt: function () {
212
+ self.sprite.stop(true, false);
213
+ },
214
+ show: function () {
215
+ self.sprite.show();
216
+ },
217
+ hide: function () {
218
+ self.sprite.hide();
219
+ }
220
+ });
221
+ }
222
+
223
+ function GalleryItem(a) {
224
+ var self = this;
225
+ var link = $(a);
226
+ $.extend(self, {
227
+ link: link,
228
+ thumb: link.find('img'),
229
+ image: $('<img class="preloader" />').css({visibility: 'hidden'}).appendTo($('body')),
230
+ caption: link.next('.caption'),
231
+ src: link.attr('href'),
232
+ deactivate: function (event) {
233
+ self.thumb.fadeTo('slow', 0.3);
234
+ self.thumb.css('cursor', 'text');
235
+ self.image.bind("load", self.activate);
236
+ self.image.attr('src', self.src);
237
+ },
238
+ activate: function () {
239
+ self.thumb.fadeTo('slow', 1);
240
+ self.thumb.css('cursor', 'pointer');
241
+ self.link.click(function (e) {
242
+ if (e) {
243
+ e.preventDefault();
244
+ e.stopPropagation();
245
+ }
246
+ $.gallery.display(self);
247
+ });
248
+ },
249
+ position: function () {
250
+ var p = self.thumb.offset();
251
+ return {
252
+ left: p.left,
253
+ top: p.top,
254
+ width: self.thumb.outerWidth(),
255
+ height: self.thumb.outerHeight()
256
+ };
257
+ },
258
+ imageSize: function () {
259
+ return {
260
+ width: self.image.innerWidth(),
261
+ height: self.image.innerHeight()
262
+ };
263
+ },
264
+ download_url: function () {
265
+ return self.link.attr('rel');
266
+ }
267
+ });
268
+ if (!self.image.complete) {
269
+ self.deactivate();
270
+ } else {
271
+ self.activate();
272
+ }
273
+ }
274
+
275
+ $.fn.galleried = function() {
276
+ this.each(function() {
277
+ if (!$.gallery) $.gallery = new Gallery();
278
+ $.gallery.add(this);
279
+ });
280
+ };
281
+
282
+ // Edit in place for forum posts
283
+
14
284
  function RemoteAction (url, holder) {
15
285
  var self = this;
16
286
  $.extend(self, {
@@ -27,6 +297,7 @@
27
297
  $.get(self.url, self.step, 'html');
28
298
  }
29
299
  },
300
+
30
301
  submit: function (e) {
31
302
  var ajaxable = true;
32
303
  // file to upload means not ajaxable at all
@@ -35,7 +306,7 @@
35
306
  if (file && file != "") ajaxable = false;
36
307
  });
37
308
  // presence of title field means not ajaxable because that appears elsewhere on the page
38
- if (self.container.find('input:text').length > 0) ajaxable = false;
309
+ if (self.container.find('input.titular').length > 0) ajaxable = false;
39
310
 
40
311
  if (ajaxable) {
41
312
  e.preventDefault();
@@ -56,10 +327,12 @@
56
327
  self.container.find('.cancel').click(self.cancel);
57
328
  self.form = self.container.find('form');
58
329
  if (self.form.length > 0) {
330
+ // intermediate step: hook up the new form
59
331
  self.form.submit(self.submit);
60
332
  self.form.init_forum();
61
333
  self.show();
62
334
  } else {
335
+ // final step: complete replacement with outcome
63
336
  $(results).init_forum();
64
337
  holder.replaceWith(results);
65
338
  }
@@ -159,6 +432,8 @@
159
432
  return this;
160
433
  };
161
434
 
435
+ // First post on pages after 1 is hidden but can be revealed for reference
436
+
162
437
  function HideablePost(container, conf) {
163
438
  var self = this;
164
439
  $.extend(self, {
@@ -193,6 +468,9 @@
193
468
  return this;
194
469
  };
195
470
 
471
+ // The upload stack is a friendly attacher and uploader.
472
+ // the edit in place functionality will check for uploads and route over normal http if any are found.
473
+
196
474
  function UploadStack(container) {
197
475
  var self = this;
198
476
  $.extend(self, {
@@ -204,15 +482,19 @@
204
482
 
205
483
  addUpload: function(event) {
206
484
  if (event) event.preventDefault();
207
- var upload_field = self.file_field.clone();
485
+ var title = self.file_field.val().replace(/C:\\fakepath\\/, '');
486
+ var empty_field = self.file_field.clone();
487
+ var upload_field = self.file_field;
208
488
  var nest_id = self.attachmentCount() + self.uploadCount(); // nb. starts at zero so this total is +1
209
- var container = $('<li class="attachment">' + upload_field.val() + '</li>');
489
+ var container = $('<li class="attachment unsaved">' + title + '</li>');
210
490
  upload_field.attr("id", upload_field.attr('id').replace(/\d+/, nest_id));
211
491
  upload_field.attr("name", upload_field.attr('name').replace(/\d+/, nest_id));
212
492
  container.append(upload_field);
213
493
  container.add_remover();
214
494
  container.appendTo(self.uploads_list).slideDown('slow');
215
- self.file_field.val(null);
495
+ empty_field.val(null);
496
+ self.file_field = empty_field;
497
+ self.selector.prepend(empty_field);
216
498
  self.selector.find('a').text = 'attach another file';
217
499
  },
218
500
 
@@ -259,23 +541,7 @@
259
541
  return self;
260
542
  };
261
543
 
262
- $.fn.add_editor = function() {
263
- if(window.punymce !== undefined) {
264
- this.each(function() {
265
- var self = $(this);
266
- var editor = new punymce.Editor({
267
- id : self.attr('id'),
268
- plugins : 'Link,Image,Emoticons,EditSource',
269
- toolbar : 'bold,italic,link,unlink,image,emoticons,editsource',
270
- width : 510,
271
- height : 375,
272
- resize : true
273
- });
274
- self.data('editor', editor);
275
- });
276
- }
277
- return this;
278
- };
544
+ // turns the standard search box into a remote form with dropdown results list
279
545
 
280
546
  $.fn.capture_search = function() {
281
547
  this.each(function() {
@@ -298,14 +564,19 @@
298
564
  return this;
299
565
  };
300
566
 
567
+ // adds a cleditor toolbar to a textarea
568
+
301
569
  $.fn.add_rte = function() {
302
570
  this.cleditor({
303
571
  width: 630,
304
572
  height: 400,
305
- controls: "bold italic underline strikethrough size removeformat | bullets numbering outdent indent | icon image link unlink | source"
573
+ controls: "bold italic underline strikethrough size removeformat | bullets numbering outdent indent | icon link unlink | source"
306
574
  });
307
575
  };
308
576
 
577
+ // initializes forum functionality in any block of html
578
+ // including, initially, the document.
579
+
309
580
  $.fn.init_forum = function () {
310
581
  this.each(function() {
311
582
  var self = $(this);
@@ -140,6 +140,9 @@ div.upload_stack, div.post_attachments
140
140
  li
141
141
  clear: none
142
142
  margin: 0
143
+ &.unsaved
144
+ background-image: url(/images/furniture/attachment_over.png)
145
+ padding-left: 18px
143
146
  a.attachment
144
147
  background: url(/images/furniture/attachment_link.png) no-repeat 0 2px
145
148
  padding-left: 18px
@@ -158,7 +161,7 @@ div.upload_stack, div.post_attachments
158
161
  img
159
162
  border: 4px solid white
160
163
  +box-shadow
161
-
164
+
162
165
  div.upload_stack
163
166
  ul.attachments input, ul.uploads input
164
167
  display: none
@@ -273,3 +276,6 @@ img.emoticon
273
276
  &.cool
274
277
  background-position: -176px 0
275
278
 
279
+ span.excerpt
280
+ +small
281
+ line-height: 1.2
@@ -17,11 +17,11 @@ describe "Forum Tags" do
17
17
  it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:author /></r:forum:topic>}).as("Normal") }
18
18
  it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:date /></r:forum:topic>}).as(on_date) }
19
19
  it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:url /></r:forum:topic>}).as("/forum/forums/#{topic.forum.id}/topics/#{topic.id}") }
20
- it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:context /></r:forum:topic>}).as(%{reply from <a href="/readers/#{reader_id(:normal)}">Normal</a>}) }
20
+ it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:context /></r:forum:topic>}).as(%{reply from <a href="#{reader_url(reader_id(:normal))}">Normal</a>}) }
21
21
  it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:body /></r:forum:topic>}).as("<p>original topic message</p>") }
22
22
  it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:link /></r:forum:topic>}).as(%{<a href="/forum/forums/#{topic.forum.id}/topics/#{topic.id}">#{topic.name}</a>}) }
23
- it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:summary /></r:forum:topic>}).as(%{<li><a href="/forum/forums/#{topic.forum.id}/topics/#{topic.id}">#{topic.name}</a><br />reply from <a href="/readers/#{reader_id(:normal)}">Normal</a></li>}) }
24
- it { should render(%{<r:forum:topic id="#{sticky.id}"><r:forum:topic:summary /></r:forum:topic>}).as(%{<li><a href="/forum/forums/#{sticky.forum.id}/topics/#{sticky.id}">#{sticky.name}</a><br />Started by <a href="/readers/#{reader_id(:normal)}">Normal</a></li>}) }
23
+ it { should render(%{<r:forum:topic id="#{topic.id}"><r:forum:topic:summary /></r:forum:topic>}).as(%{<li><a href="/forum/forums/#{topic.forum.id}/topics/#{topic.id}">#{topic.name}</a><br />reply from <a href=#{reader_url(reader_id(:normal))}">Normal</a></li>}) }
24
+ it { should render(%{<r:forum:topic id="#{sticky.id}"><r:forum:topic:summary /></r:forum:topic>}).as(%{<li><a href="/forum/forums/#{sticky.forum.id}/topics/#{sticky.id}">#{sticky.name}</a><br />Started by <a href="#{reader_url(reader_id(:normal))}">Normal</a></li>}) }
25
25
  end
26
26
 
27
27
  describe "r:forum:post tags" do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: radiant-forum-extension
3
3
  version: !ruby/object:Gem::Version
4
- hash: 7
4
+ hash: 5
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 0
10
- version: 3.0.0
9
+ - 1
10
+ version: 3.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - William Ross
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-06 00:00:00 +01:00
19
- default_executable:
18
+ date: 2011-10-05 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: radiant-reader-extension
@@ -257,11 +256,10 @@ files:
257
256
  - spec/models/topic_spec.rb
258
257
  - spec/spec.opts
259
258
  - spec/spec_helper.rb
260
- has_rdoc: true
261
259
  homepage: http://radiant.spanner.org/forum
262
260
  licenses: []
263
261
 
264
- post_install_message: "\n Add this to the Gemfile in your radiant project:\n\n gem 'radiant-forum-extension', '~> 3.0.0'\n\n "
262
+ post_install_message: "\n Add this to the Gemfile in your radiant project:\n\n gem 'radiant-forum-extension', '~> 3.0.1'\n\n "
265
263
  rdoc_options: []
266
264
 
267
265
  require_paths:
@@ -287,7 +285,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
287
285
  requirements: []
288
286
 
289
287
  rubyforge_project:
290
- rubygems_version: 1.5.3
288
+ rubygems_version: 1.8.10
291
289
  signing_key:
292
290
  specification_version: 3
293
291
  summary: Forum and Comment Extension for Radiant CMS