thredded 0.14.4 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -2
- data/app/assets/javascripts/thredded/components/preview_area.es6 +3 -0
- data/app/assets/javascripts/thredded/components/spoilers.es6 +37 -0
- data/app/assets/stylesheets/thredded/_email.scss +25 -0
- data/app/assets/stylesheets/thredded/_thredded.scss +1 -0
- data/app/assets/stylesheets/thredded/base/_typography.scss +1 -1
- data/app/assets/stylesheets/thredded/base/_variables.scss +2 -3
- data/app/assets/stylesheets/thredded/components/_post.scss +0 -11
- data/app/assets/stylesheets/thredded/components/_spoiler.scss +41 -0
- data/app/commands/thredded/mark_all_read.rb +1 -7
- data/app/controllers/concerns/thredded/new_post_params.rb +1 -1
- data/app/controllers/concerns/thredded/new_private_post_params.rb +1 -1
- data/app/controllers/concerns/thredded/new_private_topic_params.rb +1 -2
- data/app/controllers/concerns/thredded/new_topic_params.rb +0 -1
- data/app/controllers/thredded/application_controller.rb +10 -0
- data/app/controllers/thredded/posts_controller.rb +1 -2
- data/app/controllers/thredded/private_posts_controller.rb +1 -2
- data/app/controllers/thredded/private_topics_controller.rb +10 -12
- data/app/controllers/thredded/topics_controller.rb +14 -17
- data/app/forms/thredded/edit_topic_form.rb +2 -1
- data/app/forms/thredded/post_form.rb +3 -1
- data/app/forms/thredded/private_post_form.rb +3 -1
- data/app/forms/thredded/private_topic_form.rb +1 -0
- data/app/jobs/thredded/activity_updater_job.rb +18 -8
- data/app/jobs/thredded/auto_follow_and_notify_job.rb +2 -1
- data/app/models/concerns/thredded/post_common.rb +3 -4
- data/app/models/concerns/thredded/topic_common.rb +7 -0
- data/app/models/concerns/thredded/user_topic_read_state_common.rb +62 -5
- data/app/models/thredded/null_user_topic_read_state.rb +8 -0
- data/app/policies/thredded/private_post_policy.rb +16 -0
- data/app/view_hooks/thredded/all_view_hooks.rb +3 -0
- data/app/view_models/thredded/base_topic_view.rb +5 -1
- data/app/view_models/thredded/post_view.rb +13 -1
- data/app/view_models/thredded/posts_page_view.rb +1 -1
- data/app/view_models/thredded/topic_posts_page_view.rb +13 -1
- data/app/views/thredded/posts/_post.html.erb +1 -0
- data/app/views/thredded/posts/edit.html.erb +1 -0
- data/app/views/thredded/posts_common/_before_first_unread_post.html.erb +7 -0
- data/app/views/thredded/posts_common/form/_after_content.html.erb +8 -0
- data/app/views/thredded/posts_common/form/_before_content.html.erb +8 -0
- data/app/views/thredded/private_posts/_private_post.html.erb +2 -1
- data/app/views/thredded/private_posts/edit.html.erb +1 -0
- data/app/views/thredded/private_topics/_form.html.erb +1 -0
- data/app/views/thredded/private_topics/edit.html.erb +2 -1
- data/app/views/thredded/shared/_field_errors.html.erb +3 -0
- data/app/views/thredded/shared/_nav.html.erb +1 -1
- data/app/views/thredded/shared/_page.html.erb +1 -1
- data/app/views/thredded/topics/_form.html.erb +1 -0
- data/app/views/thredded/topics/edit.html.erb +2 -1
- data/config/locales/de.yml +2 -0
- data/config/locales/en.yml +2 -0
- data/config/locales/es.yml +2 -0
- data/config/locales/fr.yml +2 -0
- data/config/locales/it.yml +2 -0
- data/config/locales/pl.yml +2 -0
- data/config/locales/pt-BR.yml +2 -0
- data/config/locales/ru.yml +2 -0
- data/config/locales/zh-CN.yml +2 -0
- data/db/migrate/20160329231848_create_thredded.rb +37 -23
- data/db/upgrade_migrations/{20170811090735_upgrade_thredded_v0_13_to_v_014.rb → 20170811090735_upgrade_thredded_v0_13_to_v0_14.rb} +0 -0
- data/db/upgrade_migrations/20180110200009_upgrade_thredded_v0_14_to_v0_15.rb +91 -0
- data/lib/generators/thredded/install/templates/initializer.rb +16 -7
- data/lib/thredded.rb +143 -125
- data/lib/thredded/arel_compat.rb +57 -0
- data/lib/thredded/base_migration.rb +10 -0
- data/lib/thredded/collection_to_strings_with_cache_renderer.rb +35 -9
- data/lib/thredded/content_formatter.rb +27 -18
- data/lib/thredded/database_seeder.rb +218 -64
- data/lib/thredded/email_transformer.rb +5 -2
- data/lib/thredded/email_transformer/spoiler.rb +25 -0
- data/lib/thredded/formatting_demo_content.rb +12 -0
- data/lib/thredded/html_pipeline/onebox_filter.rb +3 -38
- data/lib/thredded/html_pipeline/spoiler_tag_filter.rb +128 -0
- data/lib/thredded/html_pipeline/utils.rb +47 -0
- data/lib/thredded/rails_lt_5_2_arel_case_node.rb +119 -0
- data/lib/thredded/version.rb +1 -1
- metadata +17 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8f7ee3eae771c92edf97664c74ebbcb42e403521cc09b9c05e7379dc98956f1
|
4
|
+
data.tar.gz: 66ac525459c09f1efd65c947a8df0d41dde083166d857664f7163d0ed0b131b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0516e987e201972234778107cff4be78997dd15580ec0b721f21654510049598216d946966dd6a87d11553a47f7d55f7cf78f41e9fc7d07d1e0ecafd57470370
|
7
|
+
data.tar.gz: 70d7f20e62b6187f1017ceced464e4e0cba2ca2988dd4adc9d1f8e5776f9c0b9b5d75d29ed3d12e7125361e203b549ea44fcfe3fb884a1c9ef25496c03223a5b
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ _Thredded_ is a Rails 4.2+ forum/messageboard engine. Its goal is to be as simpl
|
|
4
4
|
|
5
5
|
Some of the features currently in Thredded:
|
6
6
|
|
7
|
-
* Markdown (default) or BBCode post formatting.
|
7
|
+
* Markdown (default) and / or BBCode post formatting, with [onebox] and `<spoiler>` / `[spoiler]` tag support.
|
8
8
|
* (Un)read posts tracking.
|
9
9
|
* Email notifications, topic subscriptions, @-mentions, per-messageboard notification settings.
|
10
10
|
* Private group messaging.
|
@@ -28,6 +28,7 @@ If you're looking for variations on a theme - see [Discourse]. However, It is a
|
|
28
28
|
application and not an engine like Thredded.
|
29
29
|
|
30
30
|
[Discourse]: http://www.discourse.org/
|
31
|
+
[onebox]: https://github.com/discourse/onebox
|
31
32
|
|
32
33
|
Table of Contents
|
33
34
|
=================
|
@@ -94,7 +95,7 @@ Then, see the rest of this Readme for more information about using and customizi
|
|
94
95
|
Add the gem to your Gemfile:
|
95
96
|
|
96
97
|
```ruby
|
97
|
-
gem 'thredded', '~> 0.
|
98
|
+
gem 'thredded', '~> 0.15.1'
|
98
99
|
```
|
99
100
|
|
100
101
|
Add the Thredded [initializer] to your parent app by running the install generator.
|
@@ -1,6 +1,8 @@
|
|
1
1
|
//= require thredded/core/serialize_form
|
2
|
+
//= require thredded/components/spoilers
|
2
3
|
|
3
4
|
(() => {
|
5
|
+
const Thredded = window.Thredded;
|
4
6
|
const PREVIEW_AREA_SELECTOR = '[data-thredded-preview-area]';
|
5
7
|
const PREVIEW_AREA_POST_SELECTOR = '[data-thredded-preview-area-post]';
|
6
8
|
|
@@ -49,6 +51,7 @@
|
|
49
51
|
onPreviewResponse(data) {
|
50
52
|
this.preview.style.display = 'block';
|
51
53
|
this.previewPost.innerHTML = data;
|
54
|
+
Thredded.spoilers.init(this.previewPost);
|
52
55
|
}
|
53
56
|
}
|
54
57
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
//= require thredded/core/on_page_load
|
2
|
+
|
3
|
+
(() => {
|
4
|
+
const Thredded = window.Thredded;
|
5
|
+
const COMPONENT_SELECTOR = '.thredded--post--content--spoiler';
|
6
|
+
const OPEN_CLASS = 'thredded--post--content--spoiler--is-open';
|
7
|
+
|
8
|
+
Thredded.spoilers = {
|
9
|
+
init(root) {
|
10
|
+
Array.prototype.forEach.call(root.querySelectorAll(COMPONENT_SELECTOR), (node) => {
|
11
|
+
node.addEventListener('mousedown', (evt) => {
|
12
|
+
evt.stopPropagation();
|
13
|
+
this.toggle(evt.currentTarget);
|
14
|
+
});
|
15
|
+
node.addEventListener('keypress', (evt) => {
|
16
|
+
if (event.key === ' ' || event.key === 'Enter') {
|
17
|
+
evt.preventDefault();
|
18
|
+
evt.stopPropagation();
|
19
|
+
this.toggle(evt.currentTarget);
|
20
|
+
}
|
21
|
+
});
|
22
|
+
});
|
23
|
+
},
|
24
|
+
|
25
|
+
toggle(node) {
|
26
|
+
const isOpen = node.classList.contains(OPEN_CLASS);
|
27
|
+
node.classList.toggle(OPEN_CLASS);
|
28
|
+
node.setAttribute('aria-expanded', isOpen ? 'false' : 'true');
|
29
|
+
node.firstElementChild.setAttribute('aria-hidden', isOpen ? 'false' : 'true');
|
30
|
+
node.lastElementChild.setAttribute('aria-hidden', isOpen ? 'true' : 'false');
|
31
|
+
}
|
32
|
+
};
|
33
|
+
|
34
|
+
Thredded.onPageLoad(() => {
|
35
|
+
Thredded.spoilers.init(document);
|
36
|
+
});
|
37
|
+
})();
|
@@ -49,3 +49,28 @@
|
|
49
49
|
}
|
50
50
|
}
|
51
51
|
}
|
52
|
+
|
53
|
+
.thredded--post--content--spoiler {
|
54
|
+
background-color: $thredded-spoiler-background-color;
|
55
|
+
padding: 16px;
|
56
|
+
|
57
|
+
&--summary {
|
58
|
+
border-bottom: 1px solid $thredded-dark-gray;
|
59
|
+
}
|
60
|
+
|
61
|
+
&--contents {
|
62
|
+
color: transparent !important;
|
63
|
+
|
64
|
+
* {
|
65
|
+
color: transparent !important;
|
66
|
+
}
|
67
|
+
|
68
|
+
a {
|
69
|
+
text-decoration: underline;
|
70
|
+
}
|
71
|
+
|
72
|
+
> *:last-child {
|
73
|
+
margin-bottom: 0;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
@@ -22,7 +22,7 @@ $thredded-inline-spacing: 0.4375em !default;
|
|
22
22
|
|
23
23
|
// Named colors
|
24
24
|
$thredded-brand: #4a90e2 !default;
|
25
|
-
$thredded-dark-gray: #
|
25
|
+
$thredded-dark-gray: rgba(#424242, 0.25) !default;
|
26
26
|
$thredded-light-gray: #eee !default;
|
27
27
|
|
28
28
|
// Colors of text, background, actions (links), and navigation
|
@@ -38,8 +38,7 @@ $thredded-nav-current-color: $thredded-action-color !default;
|
|
38
38
|
$thredded-overlay-background-color: opacify($thredded-background-color, 1) !default;
|
39
39
|
$thredded-overlay-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12) !default;
|
40
40
|
$thredded-secondary-nav-color: $thredded-secondary-text-color !default;
|
41
|
-
$thredded-spoiler-
|
42
|
-
$thredded-spoiler-shown-color: black !default;
|
41
|
+
$thredded-spoiler-background-color: rgba(0, 0, 0, .06) !default;
|
43
42
|
$thredded-code-selected-line-background: #f8eec7 !default;
|
44
43
|
|
45
44
|
|
@@ -124,15 +124,4 @@
|
|
124
124
|
pre {
|
125
125
|
overflow-x: auto;
|
126
126
|
}
|
127
|
-
|
128
|
-
&--spoiler {
|
129
|
-
color: $thredded-spoiler-hidden-color;
|
130
|
-
background-color: $thredded-spoiler-hidden-color;
|
131
|
-
cursor: pointer;
|
132
|
-
|
133
|
-
&:hover,
|
134
|
-
&:focus {
|
135
|
-
color: $thredded-spoiler-shown-color;
|
136
|
-
}
|
137
|
-
}
|
138
127
|
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
.thredded--post--content--spoiler {
|
2
|
+
background-color: $thredded-spoiler-background-color;
|
3
|
+
cursor: pointer;
|
4
|
+
margin: 0 0 $thredded-small-spacing;
|
5
|
+
padding: $thredded-small-spacing;
|
6
|
+
position: relative;
|
7
|
+
|
8
|
+
&--contents {
|
9
|
+
visibility: hidden;
|
10
|
+
|
11
|
+
> *:last-child {
|
12
|
+
margin-bottom: 0;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
&--summary {
|
17
|
+
@extend %thredded--link;
|
18
|
+
position: absolute;
|
19
|
+
visibility: visible;
|
20
|
+
}
|
21
|
+
|
22
|
+
.thredded--post--content--spoiler {
|
23
|
+
visibility: visible;
|
24
|
+
}
|
25
|
+
|
26
|
+
table {
|
27
|
+
td, th {
|
28
|
+
border-color: $thredded-dark-gray;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
&.thredded--post--content--spoiler--is-open {
|
33
|
+
> .thredded--post--content--spoiler--contents {
|
34
|
+
visibility: visible;
|
35
|
+
}
|
36
|
+
|
37
|
+
> .thredded--post--content--spoiler--summary {
|
38
|
+
display: none;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
@@ -8,14 +8,8 @@ module Thredded
|
|
8
8
|
|
9
9
|
unread_topics.each do |topic|
|
10
10
|
last_post = topic.posts.order_oldest_first.last
|
11
|
-
total_pages = topic.posts.page(1).total_pages
|
12
11
|
|
13
|
-
Thredded::UserPrivateTopicReadState.touch!(
|
14
|
-
user.id,
|
15
|
-
topic.id,
|
16
|
-
last_post,
|
17
|
-
total_pages
|
18
|
-
)
|
12
|
+
Thredded::UserPrivateTopicReadState.touch!(user.id, topic.id, last_post)
|
19
13
|
end
|
20
14
|
end
|
21
15
|
end
|
@@ -8,7 +8,7 @@ module Thredded
|
|
8
8
|
def new_private_post_params
|
9
9
|
params.fetch(:post, {})
|
10
10
|
.permit(:content, :quote_private_post_id)
|
11
|
-
.
|
11
|
+
.tap do |p|
|
12
12
|
quote_id = p.delete(:quote_private_post_id)
|
13
13
|
if quote_id
|
14
14
|
post = Thredded::PrivatePost.find(quote_id)
|
@@ -7,11 +7,10 @@ module Thredded
|
|
7
7
|
|
8
8
|
def new_private_topic_params
|
9
9
|
params
|
10
|
-
.
|
10
|
+
.fetch(:private_topic, {})
|
11
11
|
.permit(:title, :content, :user_names, user_ids: [])
|
12
12
|
.merge(
|
13
13
|
user: thredded_current_user,
|
14
|
-
ip: request.remote_ip
|
15
14
|
).tap { |p| adapt_user_ids! p }
|
16
15
|
end
|
17
16
|
|
@@ -67,6 +67,16 @@ module Thredded
|
|
67
67
|
given.all? { |k, v| v == params[k] }
|
68
68
|
end
|
69
69
|
|
70
|
+
# Returns true if the current page is beyond the end of the collection
|
71
|
+
def page_beyond_last?(page_scope)
|
72
|
+
page_scope.to_a.empty? && page_scope.current_page != 1
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns URL parameters for the last page of the given page scope.
|
76
|
+
def last_page_params(page_scope)
|
77
|
+
{ page: page_scope.total_pages }
|
78
|
+
end
|
79
|
+
|
70
80
|
private
|
71
81
|
|
72
82
|
def thredded_layout
|
@@ -55,8 +55,7 @@ module Thredded
|
|
55
55
|
|
56
56
|
def mark_as_unread
|
57
57
|
authorize post, :read?
|
58
|
-
|
59
|
-
post.mark_as_unread(thredded_current_user, page)
|
58
|
+
post.mark_as_unread(thredded_current_user)
|
60
59
|
after_mark_as_unread # customization hook
|
61
60
|
end
|
62
61
|
|
@@ -8,14 +8,13 @@ module Thredded
|
|
8
8
|
before_action :thredded_require_login!
|
9
9
|
|
10
10
|
def index
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
)
|
11
|
+
page_scope = Thredded::PrivateTopic
|
12
|
+
.distinct
|
13
|
+
.for_user(thredded_current_user)
|
14
|
+
.order_recently_posted_first
|
15
|
+
.page(params[:page])
|
16
|
+
return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
|
17
|
+
@private_topics = Thredded::PrivateTopicsPageView.new(thredded_current_user, page_scope)
|
19
18
|
|
20
19
|
Thredded::PrivateTopicForm.new(user: thredded_current_user).tap do |form|
|
21
20
|
@new_private_topic = form if policy(form.private_topic).create?
|
@@ -31,12 +30,11 @@ module Thredded
|
|
31
30
|
.includes(:user)
|
32
31
|
.order_oldest_first
|
33
32
|
.page(current_page)
|
33
|
+
return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
|
34
34
|
@posts = Thredded::TopicPostsPageView.new(thredded_current_user, private_topic, page_scope)
|
35
35
|
|
36
36
|
if thredded_signed_in?
|
37
|
-
Thredded::UserPrivateTopicReadState.touch!(
|
38
|
-
thredded_current_user.id, private_topic.id, page_scope.last, current_page
|
39
|
-
)
|
37
|
+
Thredded::UserPrivateTopicReadState.touch!(thredded_current_user.id, private_topic.id, page_scope.last)
|
40
38
|
end
|
41
39
|
|
42
40
|
@new_post = Thredded::PrivatePostForm.new(
|
@@ -45,7 +43,7 @@ module Thredded
|
|
45
43
|
end
|
46
44
|
|
47
45
|
def new
|
48
|
-
@private_topic = Thredded::PrivateTopicForm.new(
|
46
|
+
@private_topic = Thredded::PrivateTopicForm.new(new_private_topic_params)
|
49
47
|
authorize_creating @private_topic.private_topic
|
50
48
|
end
|
51
49
|
|
@@ -23,12 +23,11 @@ module Thredded
|
|
23
23
|
return redirect_to(canonical_messageboard_params)
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
)
|
26
|
+
page_scope = policy_scope(messageboard.topics)
|
27
|
+
.order_sticky_first.order_recently_posted_first
|
28
|
+
.page(current_page)
|
29
|
+
return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
|
30
|
+
@topics = Thredded::TopicsPageView.new(thredded_current_user, page_scope)
|
32
31
|
Thredded::TopicForm.new(messageboard: messageboard, user: thredded_current_user).tap do |form|
|
33
32
|
@new_topic = form if policy(form.topic).create?
|
34
33
|
end
|
@@ -41,12 +40,11 @@ module Thredded
|
|
41
40
|
.order_oldest_first
|
42
41
|
.includes(:user, :messageboard, :postable)
|
43
42
|
.page(current_page)
|
43
|
+
return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
|
44
44
|
@posts = Thredded::TopicPostsPageView.new(thredded_current_user, topic, page_scope)
|
45
45
|
|
46
46
|
if thredded_signed_in?
|
47
|
-
Thredded::UserTopicReadState.touch!(
|
48
|
-
thredded_current_user.id, topic.id, page_scope.last, current_page
|
49
|
-
)
|
47
|
+
Thredded::UserTopicReadState.touch!(thredded_current_user.id, topic.id, page_scope.last)
|
50
48
|
end
|
51
49
|
|
52
50
|
@new_post = Thredded::PostForm.new(user: thredded_current_user, topic: topic, post_params: new_post_params)
|
@@ -69,14 +67,13 @@ module Thredded
|
|
69
67
|
Thredded::Topic.where(messageboard_id: policy_scope(Thredded::Messageboard.all).pluck(:id))
|
70
68
|
end
|
71
69
|
)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
)
|
70
|
+
page_scope = topics_scope
|
71
|
+
.search_query(@query)
|
72
|
+
.order_recently_posted_first
|
73
|
+
.includes(:categories, :last_user, :user)
|
74
|
+
.page(current_page)
|
75
|
+
return redirect_to(last_page_params(page_scope)) if page_beyond_last?(page_scope)
|
76
|
+
@topics = Thredded::TopicsPageView.new(thredded_current_user, page_scope)
|
80
77
|
end
|
81
78
|
|
82
79
|
def new
|
@@ -4,7 +4,8 @@ module Thredded
|
|
4
4
|
class EditTopicForm
|
5
5
|
include ActiveModel::Model
|
6
6
|
|
7
|
-
delegate :id, :title, :category_ids, :locked, :sticky, :messageboard, :messageboard_id, :valid?,
|
7
|
+
delegate :id, :title, :title_was, :category_ids, :locked, :sticky, :messageboard, :messageboard_id, :valid?,
|
8
|
+
:errors,
|
8
9
|
to: :@topic
|
9
10
|
|
10
11
|
# @param user [Thredded.user_class]
|
@@ -11,7 +11,7 @@ module Thredded
|
|
11
11
|
|
12
12
|
# @param user [Thredded.user_class]
|
13
13
|
# @param topic [Topic]
|
14
|
-
# @param post [
|
14
|
+
# @param post [Post]
|
15
15
|
# @param post_params [Hash]
|
16
16
|
def initialize(user:, topic:, post: nil, post_params: {})
|
17
17
|
@messageboard = topic.messageboard
|
@@ -47,7 +47,9 @@ module Thredded
|
|
47
47
|
|
48
48
|
def save
|
49
49
|
return false unless @post.valid?
|
50
|
+
was_persisted = @post.persisted?
|
50
51
|
@post.save!
|
52
|
+
Thredded::UserTopicReadState.touch!(@post.user.id, @topic.id, @post) unless was_persisted
|
51
53
|
true
|
52
54
|
end
|
53
55
|
end
|