thredded 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -5
  3. data/app/assets/javascripts/thredded/components/post_form.es6 +4 -4
  4. data/app/assets/javascripts/thredded/components/quote_post.es6 +45 -0
  5. data/app/assets/javascripts/thredded/components/topic_form.es6 +4 -4
  6. data/app/assets/javascripts/thredded/core/on_page_load.es6 +8 -0
  7. data/app/assets/javascripts/thredded/dependencies.js +1 -1
  8. data/app/assets/stylesheets/thredded/_email.scss +2 -3
  9. data/app/assets/stylesheets/thredded/components/_preferences.scss +17 -4
  10. data/app/controllers/concerns/thredded/new_post_params.rb +20 -0
  11. data/app/controllers/concerns/thredded/new_private_post_params.rb +20 -0
  12. data/app/controllers/thredded/posts_controller.rb +22 -13
  13. data/app/controllers/thredded/preferences_controller.rb +1 -0
  14. data/app/controllers/thredded/private_posts_controller.rb +24 -12
  15. data/app/controllers/thredded/private_topics_controller.rb +4 -1
  16. data/app/controllers/thredded/theme_previews_controller.rb +4 -2
  17. data/app/controllers/thredded/topics_controller.rb +13 -2
  18. data/app/forms/thredded/post_form.rb +52 -0
  19. data/app/forms/thredded/private_post_form.rb +48 -0
  20. data/app/forms/thredded/private_topic_form.rb +8 -0
  21. data/app/forms/thredded/topic_form.rb +8 -0
  22. data/app/forms/thredded/user_preferences_form.rb +7 -1
  23. data/app/helpers/thredded/urls_helper.rb +18 -0
  24. data/app/models/thredded/topic.rb +3 -3
  25. data/app/policies/thredded/private_topic_policy.rb +1 -1
  26. data/app/view_models/thredded/messageboard_group_view.rb +1 -1
  27. data/app/view_models/thredded/post_view.rb +19 -3
  28. data/app/view_models/thredded/private_topic_view.rb +0 -4
  29. data/app/view_models/thredded/topic_view.rb +0 -4
  30. data/app/views/thredded/posts/_form.html.erb +0 -2
  31. data/app/views/thredded/posts/edit.html.erb +2 -5
  32. data/app/views/thredded/posts/new.html.erb +15 -0
  33. data/app/views/thredded/posts_common/_actions.html.erb +3 -0
  34. data/app/views/thredded/posts_common/_form.html.erb +5 -3
  35. data/app/views/thredded/posts_common/_header.html.erb +3 -1
  36. data/app/views/thredded/posts_common/actions/_quote.html.erb +4 -0
  37. data/app/views/thredded/preferences/_form.html.erb +3 -5
  38. data/app/views/thredded/preferences/_messageboards_nav.html.erb +8 -0
  39. data/app/views/thredded/preferences/_messageboards_nav_item.html.erb +2 -0
  40. data/app/views/thredded/preferences/edit.html.erb +13 -3
  41. data/app/views/thredded/private_posts/_form.html.erb +0 -2
  42. data/app/views/thredded/private_posts/edit.html.erb +2 -4
  43. data/app/views/thredded/private_posts/new.html.erb +11 -0
  44. data/app/views/thredded/private_topics/_form.html.erb +2 -2
  45. data/app/views/thredded/private_topics/index.html.erb +1 -2
  46. data/app/views/thredded/private_topics/new.html.erb +0 -1
  47. data/app/views/thredded/private_topics/show.html.erb +5 -3
  48. data/app/views/thredded/shared/_nav.html.erb +1 -7
  49. data/app/views/thredded/shared/nav/_standalone.html.erb +3 -3
  50. data/app/views/thredded/shared/nav/_standalone_profile.html.erb +3 -0
  51. data/app/views/thredded/theme_previews/show.html.erb +3 -17
  52. data/app/views/thredded/topics/_form.html.erb +3 -2
  53. data/app/views/thredded/topics/index.html.erb +0 -2
  54. data/app/views/thredded/topics/new.html.erb +0 -2
  55. data/app/views/thredded/topics/show.html.erb +1 -3
  56. data/config/locales/en.yml +4 -3
  57. data/config/locales/es.yml +4 -3
  58. data/config/locales/pl.yml +4 -3
  59. data/config/locales/pt-BR.yml +4 -3
  60. data/config/locales/ru.yml +12 -7
  61. data/config/routes.rb +2 -0
  62. data/db/migrate/20160329231848_create_thredded.rb +1 -1
  63. data/db/upgrade_migrations/20170420163138_upgrade_thredded_v0_11_to_v0_12.rb +25 -0
  64. data/lib/thredded.rb +0 -1
  65. data/lib/thredded/content_formatter.rb +11 -0
  66. data/lib/thredded/version.rb +1 -1
  67. data/vendor/assets/javascripts/autosize.js +290 -0
  68. metadata +15 -17
  69. data/app/views/thredded/preferences/_header.html.erb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 267a7718fa00308d076699e3970f2e3d74946f28
4
- data.tar.gz: 40e40286c2af13e04f3af5b72b376d5a3e3a8209
3
+ metadata.gz: 9da3f257731b6397128563a35788225046e8a589
4
+ data.tar.gz: fc0b9d0117acd6de8c6d21fa1d3ff629e3e463e3
5
5
  SHA512:
6
- metadata.gz: 0b2074d057c58a048c9cb3bba55de02e95099f604a95fc75b843cd0c48fb71a81d04b8c2d18a89e0e0a71e193039cacec83aa27eb0d9ea9f09b75e85efe6fb5d
7
- data.tar.gz: 2ebee2bec698ce19036b4845ff4ca1ec04ecf0c5848d71ad5f67593fac08e979997cae369739cfdbc04fcbf6a71295372eee7da8df881f6085ce0eb62bb3e043
6
+ metadata.gz: d811130638a892c28e07b2065f05b0c8e6edd8d2aabea59691dd0f5653424818978fd4bb2d0676875aa85110e9b58bacda911efc60c26ce4dd5bb53fefa306c6
7
+ data.tar.gz: b78b12a3e681153c4b82363b6334a5c09648e86910f17f8d997e4f53dac0cd84555a3141c83d7da20f885b4b532a385913703ad6ff8a36982cc7c4ecc91636d1
data/README.md CHANGED
@@ -99,7 +99,7 @@ Then, see the rest of this Readme for more information about using and customizi
99
99
  Add the gem to your Gemfile:
100
100
 
101
101
  ```ruby
102
- gem 'thredded', '~> 0.11.1'
102
+ gem 'thredded', '~> 0.12.0'
103
103
  ```
104
104
 
105
105
  Add the Thredded [initializer] to your parent app by running the install generator.
@@ -151,7 +151,7 @@ But then compare this with the previous version to decide what to keep.
151
151
  2) To upgrade the database (in this example from v0.10 to v0.11):
152
152
 
153
153
  ```console
154
- # Note that for guaranteed best results you will want to run this with the gem checked out with v0.10.0
154
+ # Note that for guaranteed best results you will want to run this with the gem checked out with v0.11
155
155
  cp `bundle show thredded`/db/upgrade_migrations/20170312131417_upgrade_thredded_v0_10_to_v0_11.rb db/migrate
156
156
  rake db:migrate
157
157
  ```
@@ -193,9 +193,6 @@ In your layout you will probably have links to other paths in your app (e.g. nav
193
193
  For any url helpers (like `users_path` or `projects_path` or whatever) will need to have `main_app.`
194
194
  prefixed to them so that they can be found from thredded (`main_app.users_path` will work from both thredded and your app).
195
195
 
196
- However if you don't want to update your layouts and partials, you can define methods automatically to delegate to the main_app's routes:
197
- See https://gist.github.com/timdiggins/bf6d09b28828a392198562c93554ad07.
198
-
199
196
  #### Add Thredded styles
200
197
 
201
198
  In this case, you will also need to include Thredded styles and JavaScript into the application styles and JavaScript.
@@ -1,6 +1,6 @@
1
1
  //= require ./preview_area
2
2
 
3
- (($) => {
3
+ (($, autosize) => {
4
4
  const COMPONENT_SELECTOR = '[data-thredded-post-form]';
5
5
 
6
6
  class ThreddedPostForm {
@@ -18,11 +18,11 @@
18
18
  }
19
19
 
20
20
  autosize($textarea) {
21
- $textarea.autosize()
21
+ autosize($textarea)
22
22
  }
23
23
 
24
24
  destroy($nodes) {
25
- $nodes.find(this.textareaSelector).trigger('autosize.destroy');
25
+ autosize.destroy($nodes.find(this.textareaSelector));
26
26
  }
27
27
  }
28
28
 
@@ -39,4 +39,4 @@
39
39
  new ThreddedPostForm().destroy($nodes);
40
40
  }
41
41
  });
42
- })(jQuery);
42
+ })(jQuery, window.autosize);
@@ -0,0 +1,45 @@
1
+ (function() {
2
+ window.Thredded.onPageLoad(() => {
3
+ Array.prototype.forEach.call(document.querySelectorAll('[data-thredded-quote-post]'), (el) => {
4
+ el.addEventListener('click', onClick);
5
+ });
6
+ });
7
+
8
+ function onClick(evt) {
9
+ // Handle only left clicks with no modifier keys
10
+ if (evt.button !== 0 || evt.ctrlKey || evt.altKey || evt.metaKey || evt.shiftKey) return;
11
+ evt.preventDefault();
12
+ const target = document.getElementById('post_content');
13
+ target.scrollIntoView();
14
+ target.value = '...';
15
+ fetchReply(evt.target.getAttribute('data-thredded-quote-post'), (replyText) => {
16
+ if (!target.ownerDocument.body.contains(target)) return;
17
+ target.focus();
18
+ target.value = replyText;
19
+
20
+ const autosizeUpdateEvent = document.createEvent('Event');
21
+ autosizeUpdateEvent.initEvent('autosize:update', true, false);
22
+ target.dispatchEvent(autosizeUpdateEvent);
23
+ // Scroll into view again as the size might have changed.
24
+ target.scrollIntoView();
25
+ }, (errorMessage) => {
26
+ target.value = errorMessage;
27
+ });
28
+ }
29
+
30
+ function fetchReply(url, onSuccess, onError) {
31
+ const request = new XMLHttpRequest();
32
+ request.open('GET', url, /* async */ true);
33
+ request.onload = () => {
34
+ if (request.status >= 200 && request.status < 400) {
35
+ onSuccess(request.responseText);
36
+ } else {
37
+ onError(`Error (${request.status}): ${request.statusText} ${request.responseText}`);
38
+ }
39
+ };
40
+ request.onerror = () => {
41
+ onError('Network Error');
42
+ };
43
+ request.send();
44
+ }
45
+ })();
@@ -1,4 +1,4 @@
1
- (($) => {
1
+ (($, autosize) => {
2
2
  const COMPONENT_SELECTOR = '[data-thredded-topic-form]';
3
3
  class ThreddedTopicForm {
4
4
  constructor() {
@@ -15,7 +15,7 @@
15
15
  }
16
16
 
17
17
  init($nodes) {
18
- $nodes.find(this.textareaSelector).autosize();
18
+ autosize($nodes.find(this.textareaSelector));
19
19
  $nodes.each(function() {
20
20
  new ThreddedPreviewArea($(this));
21
21
  });
@@ -47,7 +47,7 @@
47
47
  }
48
48
 
49
49
  destroy($nodes) {
50
- $nodes.find(this.textareaSelector).trigger('autosize.destroy');
50
+ autosize.destroy($nodes.find(this.textareaSelector));
51
51
  }
52
52
  }
53
53
 
@@ -64,6 +64,6 @@
64
64
  new ThreddedTopicForm().destroy($nodes);
65
65
  }
66
66
  });
67
- })(jQuery);
67
+ })(jQuery, window.autosize);
68
68
 
69
69
 
@@ -26,6 +26,14 @@
26
26
  };
27
27
 
28
28
  if (isTurbolinks5) {
29
+ // In Turbolinks 5.0.1, turbolinks:load may have already fired (before DOMContentLoaded).
30
+ // If so, add our own DOMContentLoaded listener:
31
+ // See: https://github.com/turbolinks/turbolinks/commit/69d353ea73d10ee6b25c2866fc5706879ba403e3
32
+ if (window.Turbolinks.controller.lastRenderedLocation) {
33
+ document.addEventListener('DOMContentLoaded', () => {
34
+ triggerOnPageLoad();
35
+ });
36
+ }
29
37
  document.addEventListener('turbolinks:load', () => {
30
38
  triggerOnPageLoad();
31
39
  });
@@ -2,7 +2,7 @@
2
2
  // Require jquery.timeago instead of rails-timeago so that we can control the initialization.
3
3
  //= require jquery.timeago
4
4
  //= require jquery_ujs
5
- //= require jquery.autosize
5
+ //= require autosize
6
6
  //= require jquery.textcomplete
7
7
  //= require select2
8
8
 
@@ -21,14 +21,13 @@
21
21
  margin: 0;
22
22
 
23
23
  &--author {
24
- margin-bottom: 1em;
24
+ margin-bottom: 2px;
25
25
  }
26
26
 
27
27
  .thredded--post--content {
28
28
  font-size: inherit;
29
- border-left: solid 5px $thredded-blockquote-border-color;
30
29
  margin: 0 0 0.75rem;
31
- padding: ($thredded-small-spacing / 2) $thredded-small-spacing;
30
+ padding-left: 0;
32
31
 
33
32
  .onebox-wrapper-table {
34
33
  width: 100%;
@@ -1,6 +1,19 @@
1
- .thredded--preferences-header {
2
- &--title {
3
- @extend %thredded--heading;
4
- font-size: 1.5rem; // 24px
1
+ .thredded--preferences--title {
2
+ @extend %thredded--heading;
3
+ font-size: 1.5rem; // 24px
4
+ }
5
+
6
+ .thredded--preferences--form {
7
+ padding-bottom: $thredded-base-spacing;
8
+ }
9
+
10
+ .thredded--preferences--messageboards-nav {
11
+ border-top: $thredded-base-border;
12
+ padding-top: $thredded-base-spacing;
13
+ }
14
+
15
+ .thredded--preferences--messageboards-nav--item {
16
+ &.thredded--messageboard {
17
+ padding: $thredded-small-spacing;
5
18
  }
6
19
  }
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ # @api private
4
+ module NewPostParams
5
+ protected
6
+
7
+ def new_post_params
8
+ params.fetch(:post, {})
9
+ .permit(:content, :quote_post_id)
10
+ .merge(ip: request.remote_ip).tap do |p|
11
+ quote_id = p.delete(:quote_post_id)
12
+ if quote_id
13
+ post = Post.find(quote_id)
14
+ authorize_reading post
15
+ p[:quote_post] = post
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module Thredded
3
+ # @api private
4
+ module NewPrivatePostParams
5
+ protected
6
+
7
+ def new_private_post_params
8
+ params.fetch(:post, {})
9
+ .permit(:content, :quote_private_post_id)
10
+ .merge(ip: request.remote_ip).tap do |p|
11
+ quote_id = p.delete(:quote_private_post_id)
12
+ if quote_id
13
+ post = PrivatePost.find(quote_id)
14
+ authorize_reading post
15
+ p[:quote_post] = post
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -3,29 +3,39 @@ module Thredded
3
3
  # A controller for managing {Post}s.
4
4
  class PostsController < Thredded::ApplicationController
5
5
  include ActionView::RecordIdentifier
6
+ include Thredded::NewPostParams
6
7
 
7
8
  helper_method :topic
8
9
  after_action :update_user_activity
9
10
 
10
11
  after_action :verify_authorized
11
12
 
12
- def create
13
- post = parent_topic.posts.build(post_params)
14
- authorize_creating post
15
- post.save!
13
+ def new
14
+ @post_form = PostForm.new(user: thredded_current_user, topic: parent_topic, post_params: new_post_params)
15
+ authorize_creating @post_form.post
16
+ end
16
17
 
17
- redirect_to post_path(post, user: thredded_current_user)
18
+ def create
19
+ @post_form = PostForm.new(user: thredded_current_user, topic: parent_topic, post_params: new_post_params)
20
+ authorize_creating @post_form.post
21
+
22
+ if @post_form.save
23
+ redirect_to post_path(@post_form.post, user: thredded_current_user)
24
+ else
25
+ render :new
26
+ end
18
27
  end
19
28
 
20
29
  def edit
21
- authorize post, :update?
30
+ @post_form = PostForm.for_persisted(post)
31
+ authorize @post_form.post, :update?
22
32
  return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
23
33
  render
24
34
  end
25
35
 
26
36
  def update
27
37
  authorize post, :update?
28
- post.update_attributes(post_params.except(:user, :ip))
38
+ post.update_attributes(new_post_params)
29
39
 
30
40
  redirect_to post_path(post, user: thredded_current_user)
31
41
  end
@@ -45,6 +55,11 @@ module Thredded
45
55
  after_mark_as_unread # customization hook
46
56
  end
47
57
 
58
+ def quote
59
+ authorize_reading post
60
+ render plain: Thredded::ContentFormatter.quote_content(post.content)
61
+ end
62
+
48
63
  private
49
64
 
50
65
  def canonical_topic_params
@@ -59,12 +74,6 @@ module Thredded
59
74
  post.postable
60
75
  end
61
76
 
62
- def post_params
63
- params.require(:post)
64
- .permit(:content)
65
- .merge(user: thredded_current_user, ip: request.remote_ip, messageboard: messageboard)
66
- end
67
-
68
77
  def parent_topic
69
78
  Topic
70
79
  .where(messageboard: messageboard)
@@ -21,6 +21,7 @@ module Thredded
21
21
  @preferences = UserPreferencesForm.new(
22
22
  user: thredded_current_user,
23
23
  messageboard: messageboard_or_nil,
24
+ messageboards: policy_scope(Messageboard.all),
24
25
  params: preferences_params
25
26
  )
26
27
  end
@@ -3,22 +3,35 @@ module Thredded
3
3
  # A controller for managing {PrivatePost}s.
4
4
  class PrivatePostsController < Thredded::ApplicationController
5
5
  include ActionView::RecordIdentifier
6
+ include NewPrivatePostParams
6
7
 
7
8
  helper_method :topic
8
9
  after_action :update_user_activity
9
10
 
10
11
  after_action :verify_authorized
11
12
 
12
- def create
13
- post = parent_topic.posts.build(post_params)
14
- authorize_creating post
15
- post.save!
13
+ def new
14
+ @post_form = PrivatePostForm.new(
15
+ user: thredded_current_user, topic: parent_topic, post_params: new_private_post_params
16
+ )
17
+ authorize_creating @post_form.post
18
+ end
16
19
 
17
- redirect_to post_path(post, user: thredded_current_user)
20
+ def create
21
+ @post_form = PrivatePostForm.new(
22
+ user: thredded_current_user, topic: parent_topic, post_params: new_private_post_params
23
+ )
24
+ authorize_creating @post_form.post
25
+ if @post_form.save
26
+ redirect_to post_path(@post_form.post, user: thredded_current_user)
27
+ else
28
+ render :new
29
+ end
18
30
  end
19
31
 
20
32
  def edit
21
- authorize post, :update?
33
+ @post_form = PrivatePostForm.for_persisted(post)
34
+ authorize @post_form.post, :update?
22
35
  return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
23
36
  render
24
37
  end
@@ -45,6 +58,11 @@ module Thredded
45
58
  after_mark_as_unread # customization hook
46
59
  end
47
60
 
61
+ def quote
62
+ authorize_reading post
63
+ render plain: Thredded::ContentFormatter.quote_content(post.content)
64
+ end
65
+
48
66
  private
49
67
 
50
68
  def canonical_topic_params
@@ -59,12 +77,6 @@ module Thredded
59
77
  post.postable
60
78
  end
61
79
 
62
- def post_params
63
- params.require(:post)
64
- .permit(:content)
65
- .merge(user: thredded_current_user, ip: request.remote_ip)
66
- end
67
-
68
80
  def parent_topic
69
81
  PrivateTopic
70
82
  .includes(:private_users)
@@ -2,6 +2,7 @@
2
2
  module Thredded
3
3
  class PrivateTopicsController < Thredded::ApplicationController
4
4
  include Thredded::NewPrivateTopicParams
5
+ include Thredded::NewPrivatePostParams
5
6
 
6
7
  before_action :thredded_require_login!
7
8
 
@@ -37,7 +38,9 @@ module Thredded
37
38
  )
38
39
  end
39
40
 
40
- @post = private_topic.posts.build
41
+ @new_post = Thredded::PrivatePostForm.new(
42
+ user: thredded_current_user, topic: private_topic, post_params: new_private_post_params
43
+ )
41
44
  end
42
45
 
43
46
  def new
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module Thredded
3
3
  class ThemePreviewsController < Thredded::ApplicationController
4
- def show
4
+ def show # rubocop:disable Metrics/MethodLength
5
5
  @messageboard = Messageboard.first
6
6
  fail Thredded::Errors::DatabaseEmpty unless @messageboard
7
7
  @user = if thredded_current_user.thredded_anonymous?
@@ -16,7 +16,8 @@ module Thredded
16
16
  @topic = TopicView.from_user(topic, @user)
17
17
  @posts = TopicPostsPageView.new(@user, topic, topic.posts.page(1).limit(3))
18
18
  @post = topic.posts.build(id: 1337, postable: topic, content: 'Hello world', user: @user)
19
- @new_post = @messageboard.posts.build(postable: topic)
19
+ @post_form = PostForm.for_persisted(@post)
20
+ @new_post = PostForm.new(user: @user, topic: topic)
20
21
  @new_topic = TopicForm.new(user: @user, messageboard: @messageboard)
21
22
  @new_private_topic = PrivateTopicForm.new(user: @user)
22
23
  private_topic = PrivateTopic.new(id: 1337, title: 'Hello', user: @user, last_user: @user, users: [@user])
@@ -25,6 +26,7 @@ module Thredded
25
26
  @private_post = private_topic.posts.build(
26
27
  id: 1337, postable: private_topic, content: 'A private hello world', user: @user
27
28
  )
29
+ @private_post_form = PrivatePostForm.for_persisted(@private_post)
28
30
  @preferences = UserPreferencesForm.new(user: @user, messageboard: @messageboard)
29
31
  end
30
32
  end