thredded 0.11.0 → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +68 -19
  3. data/app/assets/stylesheets/thredded/_base.scss +1 -0
  4. data/app/assets/stylesheets/thredded/base/_dropdown-menu.scss +83 -0
  5. data/app/assets/stylesheets/thredded/components/_post.scss +5 -60
  6. data/app/assets/stylesheets/thredded/layout/_main-navigation.scss +4 -1
  7. data/app/assets/stylesheets/thredded/layout/_search-navigation.scss +31 -6
  8. data/app/assets/stylesheets/thredded/layout/_user-navigation.scss +1 -0
  9. data/app/controllers/thredded/application_controller.rb +6 -0
  10. data/app/controllers/thredded/posts_controller.rb +6 -0
  11. data/app/controllers/thredded/private_posts_controller.rb +6 -0
  12. data/app/controllers/thredded/private_topics_controller.rb +7 -0
  13. data/app/controllers/thredded/topics_controller.rb +23 -1
  14. data/app/policies/thredded/post_policy.rb +1 -1
  15. data/app/view_hooks/thredded/all_view_hooks.rb +3 -0
  16. data/app/views/thredded/moderation/_users_search_form.html.erb +1 -1
  17. data/app/views/thredded/moderation/user.html.erb +13 -11
  18. data/app/views/thredded/moderation/users.html.erb +1 -0
  19. data/app/views/thredded/shared/nav/_notification_preferences.html.erb +1 -1
  20. data/app/views/thredded/shared/nav/_standalone.html.erb +1 -1
  21. data/app/views/thredded/topics/search.html.erb +20 -2
  22. data/config/locales/en.yml +5 -2
  23. data/config/locales/es.yml +6 -3
  24. data/config/locales/pl.yml +5 -2
  25. data/config/locales/pt-BR.yml +5 -2
  26. data/config/locales/ru.yml +6 -3
  27. data/lib/generators/thredded/install/templates/initializer.rb +4 -4
  28. data/lib/thredded.rb +13 -9
  29. data/lib/thredded/content_formatter.rb +6 -3
  30. data/lib/thredded/html_pipeline/kramdown_filter.rb +1 -1
  31. data/lib/thredded/version.rb +1 -1
  32. metadata +18 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2ce9beaa49ff6dabd99f962836ab829e691de0bf
4
- data.tar.gz: a2760f759370094628101ac41ab618a16f358393
3
+ metadata.gz: 267a7718fa00308d076699e3970f2e3d74946f28
4
+ data.tar.gz: 40e40286c2af13e04f3af5b72b376d5a3e3a8209
5
5
  SHA512:
6
- metadata.gz: fa1e55d7ef10e1bfc8404746b7773bd3652c9f78b73ddb6300d698c32dd8f58f5ac09bf4eea6d0a4b84295e4d7d8efb50cbe0f5c6be0dbb28a8de80e89358c1b
7
- data.tar.gz: be8da3f5f1ac118215a12b5122069b2c801c5e6941e8d8ec014cef9acdbb31f5ef09afb8185430e8287877983cf9e01bf6ec2daf9f0c26a3baeec06e3f2eca2a
6
+ metadata.gz: 0b2074d057c58a048c9cb3bba55de02e95099f604a95fc75b843cd0c48fb71a81d04b8c2d18a89e0e0a71e193039cacec83aa27eb0d9ea9f09b75e85efe6fb5d
7
+ data.tar.gz: 2ebee2bec698ce19036b4845ff4ca1ec04ecf0c5848d71ad5f67593fac08e979997cae369739cfdbc04fcbf6a71295372eee7da8df881f6085ce0eb62bb3e043
data/README.md CHANGED
@@ -33,6 +33,49 @@ application and not an engine like Thredded.
33
33
 
34
34
  [Discourse]: http://www.discourse.org/
35
35
 
36
+ Table of Contents
37
+ =================
38
+
39
+ * [Installation](#installation)
40
+ * [Creating a new Rails app with Thredded](#creating-a-new-rails-app-with-thredded)
41
+ * [Adding Thredded to an existing Rails app](#adding-thredded-to-an-existing-rails-app)
42
+ * [Upgrading an existing install](#upgrading-an-existing-install)
43
+ * [Migrating from Forem](#migrating-from-forem)
44
+ * [Views and other assets](#views-and-other-assets)
45
+ * [Standalone layout](#standalone-layout)
46
+ * [Application layout](#application-layout)
47
+ * [Reference your paths so that Thredded can find them](#reference-your-paths-so-that-thredded-can-find-them)
48
+ * [Add Thredded styles](#add-thredded-styles)
49
+ * [Add Thredded JavaScripts](#add-thredded-javascripts)
50
+ * [jQuery version](#jquery-version)
51
+ * [User profile page](#user-profile-page)
52
+ * [Customizing views](#customizing-views)
53
+ * [View hooks](#view-hooks)
54
+ * [Theming](#theming)
55
+ * [Styles](#styles)
56
+ * [Email and other notifications](#email-and-other-notifications)
57
+ * [Enabling auto-follow](#enabling-auto-follow)
58
+ * [I18n](#i18n)
59
+ * [Permissions](#permissions)
60
+ * [Permission methods](#permission-methods)
61
+ * [Reading messageboards](#reading-messageboards)
62
+ * [Posting to messageboards](#posting-to-messageboards)
63
+ * [Messaging other users (posting to private topics)](#messaging-other-users-posting-to-private-topics)
64
+ * [Moderating messageboards](#moderating-messageboards)
65
+ * [Admin permissions](#admin-permissions)
66
+ * [Default permissions](#default-permissions)
67
+ * [Handling "Permission denied" and "Not found" errors](#handling-permission-denied-and-not-found-errors)
68
+ * [Moderation](#moderation)
69
+ * [Disabling moderation](#disabling-moderation)
70
+ * [Plugins](#plugins)
71
+ * [Development](#development)
72
+ * [Testing](#testing)
73
+ * [Ruby](#ruby)
74
+ * [JavaScript](#javascript)
75
+ * [Testing with all the databases and Rails versions locally.](#testing-with-all-the-databases-and-rails-versions-locally)
76
+ * [Developing and Testing with Docker Compose](#developing-and-testing-with-docker-compose)
77
+
78
+
36
79
  ## Installation
37
80
 
38
81
  ### Creating a new Rails app with Thredded
@@ -56,7 +99,7 @@ Then, see the rest of this Readme for more information about using and customizi
56
99
  Add the gem to your Gemfile:
57
100
 
58
101
  ```ruby
59
- gem 'thredded', '~> 0.11.0'
102
+ gem 'thredded', '~> 0.11.1'
60
103
  ```
61
104
 
62
105
  Add the Thredded [initializer] to your parent app by running the install generator.
@@ -105,11 +148,11 @@ rails g thredded:install
105
148
 
106
149
  But then compare this with the previous version to decide what to keep.
107
150
 
108
- 2) To upgrade the database (in this example from v0.9 to v0.10):
151
+ 2) To upgrade the database (in this example from v0.10 to v0.11):
109
152
 
110
153
  ```console
111
154
  # Note that for guaranteed best results you will want to run this with the gem checked out with v0.10.0
112
- cp `bundle show thredded`/db/upgrade_migrations/20170125033319_upgrade_v0_9_to_v0_10.rb db/migrate
155
+ cp `bundle show thredded`/db/upgrade_migrations/20170312131417_upgrade_thredded_v0_10_to_v0_11.rb db/migrate
113
156
  rake db:migrate
114
157
  ```
115
158
 
@@ -261,13 +304,13 @@ To see the complete list of view hooks and their arguments, run:
261
304
  grep view_hooks -R --include '*.html.erb' "$(bundle show thredded)"
262
305
  ```
263
306
 
264
- ## Theming
307
+ ### Theming
265
308
 
266
309
  The engine comes by default with a light and effective implementation of the
267
310
  views, styles, and javascript. Once you mount the engine you will be presented
268
311
  with a "themed" version of thredded.
269
312
 
270
- ### Styles
313
+ #### Styles
271
314
 
272
315
  Thredded comes with a light Sass theme controlled by a handful of variables that can be found here:
273
316
  https://github.com/thredded/thredded/blob/master/app/assets/stylesheets/thredded/base/_variables.scss.
@@ -307,8 +350,18 @@ If you use [Rails Email Preview], you can include Thredded emails into the list
307
350
 
308
351
  [Rails Email Preview]: https://github.com/glebm/rails_email_preview
309
352
 
310
- You can also turn off the email notifier totally, or add other notifiers (e.g. Pushover, possibly Slack) by adjusting the
311
- `Thredded.notifiers` configuration in your initializer. See the default initializer for examples.
353
+ You can also turn off the email notifier totally, or add other notifiers (e.g. Pushover, possibly Slack) by adjusting
354
+ the `Thredded.notifiers` configuration in your initializer. See the default initializer for examples.
355
+
356
+ ### Enabling auto-follow
357
+
358
+ In some cases, you'll want all users to auto-follow new messageboard topics by default. This might be useful
359
+ for a team messageboard or a company announcements board, for example. To enable user auto-follow of new topics,
360
+ run the following migration(s):
361
+
362
+ ```ruby
363
+ change_column_default :thredded_user_preferences, :auto_follow_topics, 1
364
+ ```
312
365
 
313
366
  ## I18n
314
367
 
@@ -318,7 +371,7 @@ We welcome PRs adding support for new languages.
318
371
 
319
372
  Here are the steps to ensure the best support for your language if it isn't English:
320
373
 
321
- 1. Add `rails-i18n` to your Gemfile.
374
+ 1. Add `rails-i18n` and `kaminari-i18n` to your Gemfile.
322
375
 
323
376
  2. Require the translations for rails-timeago in your JavaScript before `thredded` but after `jquery.timeago`
324
377
  (included in `thredded/dependencies`). E.g. for Brazilian Portuguese:
@@ -504,16 +557,6 @@ To disable moderation, e.g. if you run internal forums that do not need moderati
504
557
  change_column_default :thredded_user_details, :moderation_state, 1 # approved
505
558
  ```
506
559
 
507
- ### Enabling auto-follow
508
-
509
- In some cases, you'll want all users to auto-follow new messageboard topics by default. This might be useful
510
- for a team messageboard or a company announcements board, for example. To enable user auto-follow of new topics,
511
- run the following migration(s):
512
-
513
- ```ruby
514
- change_column_default :thredded_user_preferences, :auto_follow_topics, 1
515
- ```
516
-
517
560
  ## Plugins
518
561
 
519
562
  The following official plugins are available for Thredded:
@@ -544,12 +587,18 @@ Then, start the dummy app server:
544
587
  rake dev:server
545
588
  ```
546
589
 
590
+ ### Testing
591
+
547
592
  To run the tests, just run `rspec`. The test suite will re-create the test database on every run, so there is no need to
548
593
  run tasks that maintain the test database.
549
594
 
550
595
  By default, SQLite is used in development and test. On Travis, the tests will run using SQLite, PostgreSQL, MySQL,
551
596
  and all the supported Rails versions.
552
597
 
598
+ The test suite requires [PhantomJS](http://phantomjs.org) to be present in the path.
599
+ To install it, run `sudo apt-get install phantomjs` on Ubuntu or Debian, or `brew install phantomjs` on Mac.
600
+ For other operating systems, refer to the [PhantomJS documentation](http://phantomjs.org/download.html).
601
+
553
602
  ### Ruby
554
603
 
555
604
  Thredded Ruby code formatting is ensured by [Rubocop](https://github.com/bbatsov/rubocop). Run `rubocop -a` to ensure a
@@ -635,7 +684,7 @@ To test all combinations of supported databases and Rails versions, run:
635
684
  rake test_all
636
685
  ```
637
686
 
638
- ## Developing and Testing with [Docker Compose](http://docs.docker.com/compose/)
687
+ ### Developing and Testing with [Docker Compose](http://docs.docker.com/compose/)
639
688
 
640
689
  To quickly try out _Thredded_ with the included dummy app, clone the source and
641
690
  start the included docker-compose.yml file with:
@@ -5,6 +5,7 @@
5
5
 
6
6
  @import "base/alerts";
7
7
  @import "base/buttons";
8
+ @import "base/dropdown-menu";
8
9
  @import "base/forms";
9
10
  @import "base/lists";
10
11
  @import "base/nav";
@@ -0,0 +1,83 @@
1
+ %thredded--dropdown-menu--container {
2
+ position: relative;
3
+ display: inline-block;
4
+ cursor: pointer;
5
+
6
+ &:hover {
7
+ %thredded--dropdown-menu--toggle {
8
+ color: $thredded-action-hover-color;
9
+ }
10
+
11
+ %thredded--dropdown-menu--actions {
12
+ transform: scale(1);
13
+ opacity: 1;
14
+ }
15
+ }
16
+ }
17
+
18
+ %thredded--dropdown-menu--toggle {
19
+ color: $thredded-action-color;
20
+ }
21
+
22
+ %thredded--dropdown-menu--actions {
23
+ position: absolute;
24
+ background-color: $thredded-overlay-background-color;
25
+ border-radius: 2px;
26
+ overflow: hidden;
27
+ min-width: 8.5rem;
28
+ z-index: 3;
29
+ cursor: pointer;
30
+ box-shadow: $thredded-overlay-box-shadow;
31
+ transform: scale(0);
32
+ opacity: 0;
33
+ transition: transform .3s cubic-bezier(.4, 0, .2, 1), opacity .2s cubic-bezier(.4, 0, .2, 1);
34
+ will-change: transform;
35
+ }
36
+
37
+ %thredded--dropdown-menu--actions-bottom-left {
38
+ @extend %thredded--dropdown-menu--actions;
39
+ right: 0;
40
+ transform-origin: 100% 0;
41
+ }
42
+
43
+ %thredded--dropdown-menu--actions-bottom-right {
44
+ @extend %thredded--dropdown-menu--actions;
45
+ left: 0;
46
+ transform-origin: 0 0;
47
+ }
48
+
49
+ %thredded--dropdown-menu--actions--item,
50
+ // This specific selector protects from global button rules
51
+ form.button_to > %thredded--dropdown-menu--actions--item {
52
+ // Override potential global rules
53
+ background: none;
54
+ border-radius: 0;
55
+ border: 0;
56
+ box-sizing: border-box;
57
+ font: inherit;
58
+ margin: 0;
59
+ text-align: left;
60
+ transition: none;
61
+ width: 100%;
62
+
63
+ font-size: $thredded-font-size-small;
64
+ color: $thredded-text-color;
65
+ text-decoration: none;
66
+ padding: 1rem 0.75rem;
67
+ display: block;
68
+ white-space: nowrap;
69
+
70
+ &:active,
71
+ &:focus,
72
+ &:hover {
73
+ background-color: $thredded-button-background;
74
+ color: $thredded-button-color;
75
+ text-decoration: none;
76
+ cursor: pointer;
77
+ }
78
+
79
+ &:active,
80
+ &:focus {
81
+ outline: none;
82
+ }
83
+ }
@@ -7,6 +7,7 @@
7
7
  }
8
8
 
9
9
  .thredded--post--dropdown--toggle {
10
+ @extend %thredded--dropdown-menu--toggle;
10
11
  fill: currentColor;
11
12
  box-sizing: content-box;
12
13
  color: $thredded-action-color;
@@ -22,76 +23,20 @@
22
23
  }
23
24
 
24
25
  .thredded--post--dropdown {
25
- position: relative;
26
- display: inline-block;
26
+ @extend %thredded--dropdown-menu--container;
27
27
  float: right;
28
- cursor: pointer;
29
28
  @media print {
30
29
  display: none;
31
30
  }
32
31
  }
33
32
 
34
33
  .thredded--post--dropdown--actions {
35
- position: absolute;
34
+ @extend %thredded--dropdown-menu--actions-bottom-left;
36
35
  margin-top: -0.875rem;
37
- right: 0;
38
- background-color: $thredded-overlay-background-color;
39
- border-radius: 2px;
40
- overflow: hidden;
41
- min-width: 10rem;
42
- z-index: 1;
43
- cursor: pointer;
44
- box-shadow: $thredded-overlay-box-shadow;
45
- transform: scale(0);
46
- opacity: 0;
47
- transform-origin: 100% 0;
48
- transition: transform .3s cubic-bezier(.4, 0, .2, 1), opacity .2s cubic-bezier(.4, 0, .2, 1);
49
- will-change: transform;
50
- }
51
-
52
- .thredded--post--dropdown--actions--item,
53
- // This specific selector protects from global button rules
54
- form.button_to > .thredded--post--dropdown--actions--item {
55
- // Override potential global rules
56
- background: none;
57
- border-radius: 0;
58
- border: 0;
59
- box-sizing: border-box;
60
- font: inherit;
61
- margin: 0;
62
- text-align: left;
63
- transition: none;
64
- width: 100%;
65
-
66
- font-size: $thredded-font-size-small;
67
- color: $thredded-text-color;
68
- text-decoration: none;
69
- padding: 1rem 0.75rem;
70
- display: block;
71
- white-space: nowrap;
72
-
73
- &:active,
74
- &:focus,
75
- &:hover {
76
- background-color: $thredded-button-background;
77
- color: $thredded-button-color;
78
- text-decoration: none;
79
- cursor: pointer;
80
- }
81
-
82
- &:active,
83
- &:focus {
84
- outline: none;
85
- }
86
- }
87
-
88
- .thredded--post--dropdown:hover .thredded--post--dropdown--actions {
89
- transform: scale(1);
90
- opacity: 1;
91
36
  }
92
37
 
93
- .thredded--post--dropdown:hover .thredded--post--dropdown--toggle {
94
- color: $thredded-action-hover-color;
38
+ .thredded--post--dropdown--actions--item {
39
+ @extend %thredded--dropdown-menu--actions--item;
95
40
  }
96
41
 
97
42
  .thredded--post--avatar {
@@ -18,12 +18,15 @@
18
18
 
19
19
  li {
20
20
  display: block;
21
- font-weight: bold;
22
21
 
23
22
  a {
24
23
  display: block;
25
24
  }
26
25
 
26
+ @include thredded-media-tablet-and-down {
27
+ font-weight: bold;
28
+ }
29
+
27
30
  @include thredded-media-mobile {
28
31
  a {
29
32
  position: relative;
@@ -1,9 +1,10 @@
1
1
  .thredded--navigation--search {
2
- margin-right: 0;
2
+ $input-padding-x: 0.75rem;
3
+
4
+ margin: 0;
3
5
  padding: 0;
4
6
  position: absolute;
5
7
  top: 0;
6
- right: 0;
7
8
 
8
9
  @include thredded-media-tablet-and-down {
9
10
  position: initial;
@@ -20,16 +21,15 @@
20
21
 
21
22
  @include thredded-media-desktop-and-up {
22
23
  $line-height: 1rem;
23
- $padding-x: 0.75rem;
24
24
  background: transparent;
25
25
  border-color: transparent;
26
26
  font-size: $thredded-font-size-small;
27
27
  line-height: $line-height;
28
28
  min-width: 13rem;
29
- text-align: right;
30
29
  width: auto;
31
- padding: 0.9375rem 0.75rem 0.875rem 0.75rem;
32
- margin: -1px (-$padding-x) 0 0;
30
+ padding: 0.9375rem $input-padding-x 0.875rem $input-padding-x;
31
+ margin-top: -1px;
32
+ margin-bottom: 0;
33
33
 
34
34
  &, &:focus {
35
35
  transition: background, border-color, box-shadow, min-width 0.15s ease-out 0s;
@@ -39,6 +39,7 @@
39
39
  background: $thredded-background-color;
40
40
  box-shadow: none;
41
41
  margin-right: 0;
42
+ margin-left: 0;
42
43
  min-width: 16rem;
43
44
  text-align: left;
44
45
  }
@@ -98,4 +99,28 @@
98
99
  @media print {
99
100
  display: none;
100
101
  }
102
+
103
+ // On the left:
104
+ right: auto;
105
+ left: 0;
106
+ @include thredded-media-desktop-and-up {
107
+ input[type="search"] {
108
+ text-align: left;
109
+ margin-right: 0;
110
+ margin-left: -$input-padding-x;
111
+ }
112
+ }
113
+
114
+ // On the right:
115
+ &--right {
116
+ right: 0;
117
+ left: auto;
118
+ @include thredded-media-desktop-and-up {
119
+ input[type="search"] {
120
+ text-align: right;
121
+ margin-right: -$input-padding-x;
122
+ margin-left: 0;
123
+ }
124
+ }
125
+ }
101
126
  }
@@ -1,5 +1,6 @@
1
1
  .thredded--user-navigation {
2
2
  @extend %thredded--nav-tabs;
3
+ text-align: right;
3
4
  @media print {
4
5
  display: none;
5
6
  }
@@ -60,6 +60,12 @@ module Thredded
60
60
  end
61
61
  end
62
62
 
63
+ # @param given [Hash]
64
+ # @return [Boolean] whether the given params are a subset of the controller's {#params}.
65
+ def params_match?(given = {})
66
+ given.all? { |k, v| v == params[k] }
67
+ end
68
+
63
69
  private
64
70
 
65
71
  def thredded_layout
@@ -19,6 +19,8 @@ module Thredded
19
19
 
20
20
  def edit
21
21
  authorize post, :update?
22
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
23
+ render
22
24
  end
23
25
 
24
26
  def update
@@ -45,6 +47,10 @@ module Thredded
45
47
 
46
48
  private
47
49
 
50
+ def canonical_topic_params
51
+ { messageboard_id: messageboard.slug, topic_id: topic.slug }
52
+ end
53
+
48
54
  def after_mark_as_unread
49
55
  redirect_to messageboard_topics_path(messageboard)
50
56
  end
@@ -19,6 +19,8 @@ module Thredded
19
19
 
20
20
  def edit
21
21
  authorize post, :update?
22
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
23
+ render
22
24
  end
23
25
 
24
26
  def update
@@ -45,6 +47,10 @@ module Thredded
45
47
 
46
48
  private
47
49
 
50
+ def canonical_topic_params
51
+ { private_topic_id: topic.slug }
52
+ end
53
+
48
54
  def after_mark_as_unread
49
55
  redirect_to private_topics_path
50
56
  end
@@ -22,6 +22,7 @@ module Thredded
22
22
 
23
23
  def show
24
24
  authorize private_topic, :read?
25
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
25
26
 
26
27
  page_scope = private_topic
27
28
  .posts
@@ -55,6 +56,8 @@ module Thredded
55
56
 
56
57
  def edit
57
58
  authorize private_topic, :update?
59
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
60
+ render
58
61
  end
59
62
 
60
63
  def update
@@ -69,6 +72,10 @@ module Thredded
69
72
 
70
73
  private
71
74
 
75
+ def canonical_topic_params
76
+ { id: private_topic.slug }
77
+ end
78
+
72
79
  def current_page
73
80
  (params[:page] || 1).to_i
74
81
  end
@@ -12,6 +12,10 @@ module Thredded
12
12
 
13
13
  def index
14
14
  authorize_reading messageboard
15
+ unless params_match?(canonical_messageboard_params)
16
+ skip_policy_scope
17
+ return redirect_to(canonical_messageboard_params)
18
+ end
15
19
 
16
20
  @topics = Thredded::TopicsPageView.new(
17
21
  thredded_current_user,
@@ -26,6 +30,7 @@ module Thredded
26
30
 
27
31
  def show
28
32
  authorize topic, :read?
33
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
29
34
  page_scope = policy_scope(topic.posts)
30
35
  .order_oldest_first
31
36
  .includes(:user, :messageboard, :postable)
@@ -43,7 +48,13 @@ module Thredded
43
48
 
44
49
  def search
45
50
  in_messageboard = params.key?(:messageboard_id)
46
- authorize_reading messageboard if in_messageboard
51
+ if in_messageboard
52
+ authorize_reading messageboard
53
+ unless params_match?(canonical_messageboard_params)
54
+ skip_policy_scope
55
+ return redirect_to(canonical_messageboard_params)
56
+ end
57
+ end
47
58
  @query = params[:q].to_s
48
59
  topics_scope = policy_scope(
49
60
  if in_messageboard
@@ -65,6 +76,8 @@ module Thredded
65
76
  def new
66
77
  @new_topic = Thredded::TopicForm.new(new_topic_params)
67
78
  authorize_creating @new_topic.topic
79
+ return redirect_to(canonical_messageboard_params) unless params_match?(canonical_messageboard_params)
80
+ render
68
81
  end
69
82
 
70
83
  def category
@@ -92,6 +105,7 @@ module Thredded
92
105
 
93
106
  def edit
94
107
  authorize topic, :update?
108
+ return redirect_to(canonical_topic_params) unless params_match?(canonical_topic_params)
95
109
  @edit_topic = Thredded::EditTopicForm.new(user: thredded_current_user, topic: topic)
96
110
  end
97
111
 
@@ -136,6 +150,14 @@ module Thredded
136
150
 
137
151
  private
138
152
 
153
+ def canonical_messageboard_params
154
+ { messageboard_id: messageboard.slug }
155
+ end
156
+
157
+ def canonical_topic_params
158
+ { messageboard_id: messageboard.slug, id: topic.slug }
159
+ end
160
+
139
161
  def follow_change_response(following:)
140
162
  notice = following ? t('thredded.topics.followed_notice') : t('thredded.topics.unfollowed_notice')
141
163
  respond_to do |format|
@@ -53,7 +53,7 @@ module Thredded
53
53
  end
54
54
 
55
55
  def own_post?
56
- @user.id == @post.user_id
56
+ !anonymous? && @user.id == @post.user_id
57
57
  end
58
58
  end
59
59
  end
@@ -94,11 +94,14 @@ module Thredded
94
94
  # @return [Thredded::AllViewHooks::ViewHook]
95
95
  attr_reader :user_info
96
96
  # @return [Thredded::AllViewHooks::ViewHook]
97
+ attr_reader :user_info_list_items
98
+ # @return [Thredded::AllViewHooks::ViewHook]
97
99
  attr_reader :user_moderation_actions
98
100
 
99
101
  def initialize
100
102
  @user_title = ViewHook.new
101
103
  @user_info = ViewHook.new
104
+ @user_info_list_items = ViewHook.new
102
105
  @user_moderation_actions = ViewHook.new
103
106
  end
104
107
  end
@@ -1,6 +1,6 @@
1
1
  <%= form_tag users_moderation_path,
2
2
  method: 'get',
3
- class: 'thredded--form thredded--navigation--search',
3
+ class: 'thredded--form thredded--navigation--search thredded--navigation--search--right',
4
4
  'data-thredded-turboform' => true do %>
5
5
  <%= label_tag :q, t('thredded.moderation.search_users.form_label') %>
6
6
  <%= text_field_tag :q, @query,
@@ -14,17 +14,19 @@
14
14
  <% end %>
15
15
  <%= view_hooks.moderation_user_page.user_info.render self, user: user do %>
16
16
  <ul class="thredded--moderation--user--info">
17
- <li><%= t 'thredded.users.user_since_html', time_ago: time_ago(user.created_at) %></li>
18
- <% if user_detail.last_seen_at %>
19
- <li><%= t 'thredded.users.last_active_html', time_ago: time_ago(user_detail.last_seen_at) %></li>
20
- <% end %>
21
- <% if user_detail.topics_count > 0 %>
22
- <li><%= t 'thredded.users.started_topics_count', count: user_detail.topics_count %></li>
23
- <% end %>
24
- <% if user_detail.posts_count > 0 %>
25
- <li><%= t 'thredded.users.posts_count', count: user_detail.posts_count %></li>
26
- <% end %>
27
- <li><%= render 'user_moderation_state', user: @user %></li>
17
+ <%= view_hooks.moderation_user_page.user_info_list_items.render self, user: user do %>
18
+ <li><%= t 'thredded.users.user_since_html', time_ago: time_ago(user.created_at) %></li>
19
+ <% if user_detail.last_seen_at %>
20
+ <li><%= t 'thredded.users.last_active_html', time_ago: time_ago(user_detail.last_seen_at) %></li>
21
+ <% end %>
22
+ <% if user_detail.topics_count > 0 %>
23
+ <li><%= t 'thredded.users.started_topics_count', count: user_detail.topics_count %></li>
24
+ <% end %>
25
+ <% if user_detail.posts_count > 0 %>
26
+ <li><%= t 'thredded.users.posts_count', count: user_detail.posts_count %></li>
27
+ <% end %>
28
+ <li><%= render 'user_moderation_state', user: @user %></li>
29
+ <% end %>
28
30
  </ul>
29
31
  <% end %>
30
32
  <%= view_hooks.moderation_user_page.user_moderation_actions.render self, user: user do %>
@@ -11,6 +11,7 @@
11
11
  </p>
12
12
  <% end %>
13
13
  <table class="thredded--moderation--users-table thredded--table">
14
+ <caption><%= page_entries_info @users %></caption>
14
15
  <thead>
15
16
  <tr>
16
17
  <th>User</th>
@@ -1,7 +1,7 @@
1
1
  <% current = current_page_preferences? %>
2
2
  <li class="thredded--user-navigation--settings thredded--user-navigation--item<%= ' thredded--is-current' if current %>">
3
3
  <%= link_to current ? (messageboard ? messageboard_topics_path(messageboard) : messageboards_path)
4
- : edit_preferences_path(messageboard) do %>
4
+ : edit_preferences_path(messageboard), rel: 'nofollow' do %>
5
5
  <%= inline_svg 'thredded/settings.svg', class: 'thredded--icon', title: t('thredded.nav.settings') %>
6
6
  <span class="thredded--nav-text"><%= t('thredded.nav.settings') %></span>
7
7
  <% end %>
@@ -1,5 +1,5 @@
1
1
  <li class="thredded--user-navigation--standalone thredded--user-navigation--item">
2
- <% resource_name = Thredded.user_class.name.underscore %>
2
+ <% resource_name = Thredded.user_class_name.underscore %>
3
3
  <% if thredded_signed_in? %>
4
4
  <%= link_to main_app.send(:"destroy_#{resource_name}_session_path"), method: :delete do %>
5
5
  <span>Sign Out</span>
@@ -5,7 +5,16 @@
5
5
  <%= thredded_page do %>
6
6
  <% if @topics.present? %>
7
7
  <p class="thredded--alert thredded--alert-success">
8
- <%= t 'thredded.topics.search.results_message', query: "'#{@query}'" %>
8
+ <% if messageboard_or_nil %>
9
+ <%= t 'thredded.topics.search.results_in_messageboard_message_html',
10
+ query: @query, messageboard: messageboard.name %>
11
+ <br>
12
+ <a href="<%= messageboards_search_path(q: @query) %>">
13
+ <%= t('thredded.topics.search.search_in_all_messageboards_btn') -%>
14
+ </a>
15
+ <% else %>
16
+ <%= t 'thredded.topics.search.results_message_html', query: @query %>
17
+ <% end %>
9
18
  </p>
10
19
  <section class="thredded--main-section thredded--topics">
11
20
  <%= render @topics %>
@@ -15,7 +24,16 @@
15
24
  </footer>
16
25
  <% else %>
17
26
  <p class="thredded--alert thredded--alert-danger">
18
- <%= t 'thredded.topics.search.no_results_message', query: "'#{@query}'" %>
27
+ <% if messageboard_or_nil %>
28
+ <%= t 'thredded.topics.search.no_results_in_messageboard_message_html',
29
+ query: @query, messageboard: messageboard.name -%>
30
+ <br>
31
+ <a href="<%= messageboards_search_path(q: @query) %>">
32
+ <%= t('thredded.topics.search.search_in_all_messageboards_btn') -%>
33
+ </a>
34
+ <% else %>
35
+ <%= t 'thredded.topics.search.no_results_message_html', query: @query %>
36
+ <% end %>
19
37
  </p>
20
38
  <% end %>
21
39
  <% end %>
@@ -172,9 +172,12 @@ en:
172
172
  mark_as_unread: Mark unread from here
173
173
  not_following: You are not following this topic.
174
174
  search:
175
- no_results_message: There are no results for your search - %{query}
175
+ no_results_in_messageboard_message_html: There are no results for your search <q>%{query}</q> in %{messageboard}
176
+ no_results_message_html: There are no results for your search <q>%{query}</q>
176
177
  page_title: Topics Search Results
177
- results_message: Search Results for %{query}
178
+ results_in_messageboard_message_html: Search results for <q>%{query}</q> in %{messageboard}
179
+ results_message_html: Search results for <q>%{query}</q>
180
+ search_in_all_messageboards_btn: Search everywhere
178
181
  started_by_html: Started %{time_ago} by %{user}
179
182
  sticky:
180
183
  label: Sticky
@@ -27,7 +27,7 @@ es:
27
27
  update_btn_submitting: :thredded.form.update_btn_submitting
28
28
  index:
29
29
  page_title: Foros
30
- last_updated_by_html: Actualizado hace %{time_ago} <cite>por %{user}</cite>
30
+ last_updated_by_html: Actualizado %{time_ago} <cite>por %{user}</cite>
31
31
  topics_and_posts_counts: "%{topics_count} temas / %{posts_count} mensajes"
32
32
  update: :thredded.form.update
33
33
  updated_notice: Foro actualizado
@@ -174,9 +174,12 @@ es:
174
174
  mark_as_unread: Marcar sin leer desde aquí
175
175
  not_following: No estás siguiendo este tema.
176
176
  search:
177
- no_results_message: No hay resultados para tu búsqueda - %{query}
177
+ no_results_in_messageboard_message_html: No hay resultados para tu búsqueda <q>%{query}</q> en %{messageboard}
178
+ no_results_message_html: No hay resultados para tu búsqueda - <q>%{query}</q>
178
179
  page_title: Temas encontrados
179
- results_message: Resultados de búsqueda para %{query}
180
+ results_in_messageboard_message_html: Resultados de la búsqueda para <q>%{query}</q> en %{messageboard}
181
+ results_message_html: Resultados de búsqueda para <q>%{query}</q>
182
+ search_in_all_messageboards_btn: Buscar en todas partes
180
183
  started_by_html: Empezado hace %{time_ago} por %{user}
181
184
  sticky:
182
185
  label: Fijado
@@ -172,9 +172,12 @@ pl:
172
172
  mark_as_unread: Oznacz jako nieprzeczytane stąd
173
173
  not_following: Nie obserwujesz tego tematu.
174
174
  search:
175
- no_results_message: 'Nie odnaleziono żadnych wyników dla frazy: %{query}'
175
+ no_results_in_messageboard_message_html: Nie odnaleziono żadnych wyników dla frazy <q>%{query}</q> w %{messageboard}
176
+ no_results_message_html: 'Nie odnaleziono żadnych wyników dla frazy: <q>%{query}</q>'
176
177
  page_title: Wyniki wyszukiwania
177
- results_message: 'Wyniki wyszukiwania dla: %{query}'
178
+ results_in_messageboard_message_html: Wyniki wyszukiwania dla <q>%{query}</q> w %{messageboard}
179
+ results_message_html: 'Wyniki wyszukiwania dla: <q>%{query}</q>'
180
+ search_in_all_messageboards_btn: Szukaj wszędzie
178
181
  started_by_html: Rozpoczęty %{time_ago} przez %{user}
179
182
  sticky:
180
183
  label: Przyklejony
@@ -175,9 +175,12 @@ pt-BR:
175
175
  mark_as_unread: Marca não lida a partir daqui
176
176
  not_following: Você não está seguindo este tema.
177
177
  search:
178
- no_results_message: Nenhum resultado encontrado para sua busca - %{query}
178
+ no_results_in_messageboard_message_html: Não resultados para sua busca <q>%{query}</q> em %{messageboard}
179
+ no_results_message_html: Nenhum resultado encontrado para sua busca <q>%{query}</q>
179
180
  page_title: Tópicos dos Resultados da Busca
180
- results_message: Resultados de Busca para %{query}
181
+ results_in_messageboard_message_html: Resultados da pesquisa para <q>%{query}</q> em %{messageboard}
182
+ results_message_html: Resultados de busca para <q>%{query}</q>
183
+ search_in_all_messageboards_btn: Buscar em todos os lugares
181
184
  started_by_html: Iniciado %{time_ago} por %{user}
182
185
  sticky:
183
186
  label: Pegajoso
@@ -171,9 +171,12 @@ ru:
171
171
  mark_as_unread: Пометить как непрочитанное
172
172
  not_following: не отслеживаю
173
173
  search:
174
- no_results_message: Там нет никаких результатов для этой категории - %{query}
175
- page_title: Темы Результаты поиска
176
- results_message: Результаты поиска для %{query}
174
+ no_results_in_messageboard_message_html: Не найдо результатов по запросу <q>%{query}</q> в %{messageboard}
175
+ no_results_message_html: Не найдо результатов по запросу <q>%{query}</q>
176
+ page_title: Результаты поиска
177
+ results_in_messageboard_message_html: Результаты поиска для <q>%{query}</q> в %{messageboard}
178
+ results_message_html: Результаты поиска для <q>%{query}</q>
179
+ search_in_all_messageboards_btn: Искать везде
177
180
  started_by_html: Начат %{user} %{time_ago}
178
181
  sticky:
179
182
  label: Закрепить
@@ -7,7 +7,7 @@
7
7
  # for your user class - change it here.
8
8
  Thredded.user_class = 'User'
9
9
 
10
- # User name column, used in @mention syntax and should be unique.
10
+ # User name column, used in @mention syntax and *must* be unique.
11
11
  # This is the column used to search for users' names if/when someone is @ mentioned.
12
12
  Thredded.user_name_column = :name
13
13
 
@@ -19,12 +19,12 @@ Thredded.user_name_column = :name
19
19
  # When linking to a user, Thredded will use this lambda to spit out
20
20
  # the path or url to your user. This lambda is evaluated in the view context.
21
21
  Thredded.user_path = lambda do |user|
22
- user_path = :"#{Thredded.user_class.name.underscore}_path"
22
+ user_path = :"#{Thredded.user_class_name.underscore}_path"
23
23
  main_app.respond_to?(user_path) ? main_app.send(user_path, user) : "/users/#{user.to_param}"
24
24
  end
25
25
 
26
26
  # This method is used by Thredded controllers and views to fetch the currently signed-in user
27
- Thredded.current_user_method = :"current_#{Thredded.user_class.name.underscore}"
27
+ Thredded.current_user_method = :"current_#{Thredded.user_class_name.underscore}"
28
28
 
29
29
  # User avatar URL. rb-gravatar gem is used by default:
30
30
  Thredded.avatar_url = ->(user) { Gravatar.src(user.email, 128, 'mm') }
@@ -83,7 +83,7 @@ Thredded.layout = 'thredded/application'
83
83
  # Thredded.slugifier = ->(input) { input.parameterize }
84
84
 
85
85
  # If your forum is in a language other than English, you might want to use the babosa gem instead
86
- # Thredded.slugifier = ->(input) { Babosa::Identifier.new(input).normalize.to_s }
86
+ # Thredded.slugifier = ->(input) { Babosa::Identifier.new(input).normalize.transliterate(:russian).to_s }
87
87
 
88
88
  # ==> Post Content Formatting
89
89
  # Customize the way Thredded handles post formatting.
@@ -52,7 +52,6 @@ module Thredded
52
52
  :layout,
53
53
  :messageboards_order,
54
54
  :routes_id_constraint,
55
- :user_class,
56
55
  :user_display_name_method,
57
56
  :user_name_column,
58
57
  :user_path
@@ -94,6 +93,9 @@ module Thredded
94
93
  mattr_accessor :auto_follow_when_posting_in_topic
95
94
  self.auto_follow_when_posting_in_topic = true
96
95
 
96
+ # @return [String] The name of the user class
97
+ mattr_reader :user_class_name
98
+
97
99
  self.active_user_threshold = 5.minutes
98
100
  self.admin_column = :admin
99
101
  self.avatar_url = ->(user) { Gravatar.src(user.email, 128, 'mm') }
@@ -138,17 +140,19 @@ module Thredded
138
140
  end
139
141
  end
140
142
 
143
+ # @param user_class_name [String]
144
+ def self.user_class=(user_class_name)
145
+ unless user_class_name.is_a?(String)
146
+ fail "Thredded.user_class must be set to a String, got #{user_class_name.inspect}"
147
+ end
148
+ @@user_class_name = user_class_name # rubocop:disable Style/ClassVars
149
+ end
150
+
141
151
  # @return [Class<Thredded::UserExtender>] the user class from the host application.
142
152
  def self.user_class
143
153
  # This is nil before the initializer is installed.
144
- return nil if @@user_class.nil?
145
- fail 'Please use a String instead of a Class' if @@user_class.is_a?(Class)
146
- fail "user_class must be a String, got #{@@user_class.inspect}" unless @@user_class.is_a?(String)
147
- begin
148
- Object.const_get(@@user_class)
149
- rescue NameError
150
- @@user_class.constantize
151
- end
154
+ return nil if @@user_class_name.nil?
155
+ @@user_class_name.constantize
152
156
  end
153
157
 
154
158
  # @param view_context [Object] context to execute the lambda in.
@@ -6,7 +6,7 @@ module Thredded
6
6
  mattr_accessor :whitelist
7
7
 
8
8
  self.whitelist = HTML::Pipeline::SanitizationFilter::WHITELIST.deep_merge(
9
- elements: HTML::Pipeline::SanitizationFilter::WHITELIST[:elements] + %w(iframe span figure figcaption),
9
+ elements: HTML::Pipeline::SanitizationFilter::WHITELIST[:elements] + %w(abbr iframe span figure figcaption),
10
10
  transformers: HTML::Pipeline::SanitizationFilter::WHITELIST[:transformers] + [
11
11
  lambda do |env|
12
12
  next unless env[:node_name] == 'a'
@@ -20,8 +20,11 @@ module Thredded
20
20
  ],
21
21
  attributes: {
22
22
  'a' => %w(href rel),
23
+ 'abbr' => %w(title),
23
24
  'span' => %w(class),
24
- 'div' => %w(class)
25
+ 'div' => %w(class),
26
+ :all => HTML::Pipeline::SanitizationFilter::WHITELIST[:attributes][:all] +
27
+ %w(aria-label aria-labelledby aria-hidden),
25
28
  }
26
29
  )
27
30
 
@@ -89,7 +92,7 @@ module Thredded
89
92
  # @param content [String]
90
93
  # @return [String] formatted and sanitized html-safe content.
91
94
  def format_content(content)
92
- pipeline = HTML::Pipeline.new(content_pipeline_filters, content_pipeline_options.merge(@pipeline_options))
95
+ pipeline = HTML::Pipeline.new(content_pipeline_filters, content_pipeline_options.deep_merge(@pipeline_options))
93
96
  result = pipeline.call(content, view_context: @view_context)
94
97
  # rubocop:disable Rails/OutputSafety
95
98
  result[:output].to_s.html_safe
@@ -29,7 +29,7 @@ module Thredded
29
29
  # Convert Markdown to HTML using the best available implementation
30
30
  # and convert into a DocumentFragment.
31
31
  def call
32
- result = Kramdown::Document.new(@text, self.class.options).to_html
32
+ result = Kramdown::Document.new(@text, self.class.options.deep_merge(context[:kramdown_options] || {})).to_html
33
33
  result.rstrip!
34
34
  result
35
35
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Thredded
3
- VERSION = '0.11.0'
3
+ VERSION = '0.11.1'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thredded
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Oliveira
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-03-26 00:00:00.000000000 Z
12
+ date: 2017-04-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pundit
@@ -493,6 +493,20 @@ dependencies:
493
493
  - - ">="
494
494
  - !ruby/object:Gem::Version
495
495
  version: '0'
496
+ - !ruby/object:Gem::Dependency
497
+ name: kaminari-i18n
498
+ requirement: !ruby/object:Gem::Requirement
499
+ requirements:
500
+ - - ">="
501
+ - !ruby/object:Gem::Version
502
+ version: '0'
503
+ type: :development
504
+ prerelease: false
505
+ version_requirements: !ruby/object:Gem::Requirement
506
+ requirements:
507
+ - - ">="
508
+ - !ruby/object:Gem::Version
509
+ version: '0'
496
510
  - !ruby/object:Gem::Dependency
497
511
  name: http_accept_language
498
512
  requirement: !ruby/object:Gem::Requirement
@@ -732,6 +746,7 @@ files:
732
746
  - app/assets/stylesheets/thredded/_thredded.scss
733
747
  - app/assets/stylesheets/thredded/base/_alerts.scss
734
748
  - app/assets/stylesheets/thredded/base/_buttons.scss
749
+ - app/assets/stylesheets/thredded/base/_dropdown-menu.scss
735
750
  - app/assets/stylesheets/thredded/base/_forms.scss
736
751
  - app/assets/stylesheets/thredded/base/_grid.scss
737
752
  - app/assets/stylesheets/thredded/base/_lists.scss
@@ -1044,7 +1059,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
1044
1059
  version: '0'
1045
1060
  requirements: []
1046
1061
  rubyforge_project:
1047
- rubygems_version: 2.6.10
1062
+ rubygems_version: 2.6.11
1048
1063
  signing_key:
1049
1064
  specification_version: 4
1050
1065
  summary: The best Rails forums engine ever.