thredded 0.16.13 → 0.16.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +57 -9
- data/app/assets/config/thredded_manifest.js +4 -0
- data/app/assets/javascripts/thredded/components/currently_online.es6 +1 -0
- data/app/assets/javascripts/thredded/components/post_form.es6 +1 -0
- data/app/assets/javascripts/thredded/components/preview_area.es6 +2 -0
- data/app/assets/javascripts/thredded/components/quote_post.es6 +1 -0
- data/app/assets/javascripts/thredded/components/spoilers.es6 +1 -0
- data/app/assets/javascripts/thredded/components/submit_hotkey.es6 +1 -0
- data/app/assets/javascripts/thredded/components/time_stamps.es6 +1 -0
- data/app/assets/javascripts/thredded/components/topic_form.es6 +1 -0
- data/app/assets/javascripts/thredded/components/topics.es6 +1 -0
- data/app/assets/javascripts/thredded/components/turboforms.es6 +8 -7
- data/app/assets/javascripts/thredded/components/user_preferences_form.es6 +1 -0
- data/app/assets/javascripts/thredded/components/user_textcomplete.es6 +1 -0
- data/app/assets/javascripts/thredded/components/users_select.es6 +1 -0
- data/app/assets/javascripts/thredded/dependencies/autosize.js +1 -1
- data/app/controllers/thredded/messageboard_groups_controller.rb +8 -0
- data/app/models/thredded/messageboard.rb +1 -0
- data/app/view_hooks/thredded/all_view_hooks.rb +21 -0
- data/app/view_models/thredded/messageboard_group_view.rb +1 -1
- data/app/views/thredded/messageboard_groups/show.html.erb +41 -0
- data/app/views/thredded/messageboards/index.html.erb +6 -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/config/routes.rb +1 -0
- data/lib/generators/thredded/install/templates/initializer.rb +3 -0
- data/lib/thredded.rb +6 -0
- data/lib/thredded/engine.rb +1 -3
- data/lib/thredded/version.rb +1 -1
- data/lib/thredded/webpack_assets.rb +110 -0
- data/vendor/assets/javascripts/autosize.js +280 -0
- metadata +9 -6
- data/vendor/assets/javascripts/autosize.min.js +0 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b96a82c0482d773cd074fdd77a4e67a408ba43e2e079bbbd2a4eefeb55085f37
|
4
|
+
data.tar.gz: 6949b12a03a39430340dbd8870cb6e5cc4dcddc583e093de576e2a3621becdb4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4403418748bbb9b7bdcf5a503908fb526d60ff0f6100d11be98d64f625da8e9479c2be127adb2b88435686371d58cb75c39d1e4c73789e5e8297eabf9d01198d
|
7
|
+
data.tar.gz: 154ddbcd92f7e8f705bf4fe27bbc32f03fff0e3af7fdb81aca82143783dfd389eed1cbd516802356288af0c839cd3ddc61087209037c60bc521bee072939efa6
|
data/README.md
CHANGED
@@ -43,7 +43,8 @@ Table of Contents
|
|
43
43
|
* [Application layout](#application-layout)
|
44
44
|
* [Reference your paths so that Thredded can find them](#reference-your-paths-so-that-thredded-can-find-them)
|
45
45
|
* [Add Thredded styles](#add-thredded-styles)
|
46
|
-
* [Add Thredded JavaScripts](#add-thredded-javascripts)
|
46
|
+
* [Add Thredded JavaScripts (Sprockets)](#add-thredded-javascripts-sprockets)
|
47
|
+
* [Add Thredded JavaScripts (Webpack)](#add-thredded-javascripts-webpack)
|
47
48
|
* [User profile page](#user-profile-page)
|
48
49
|
* [Customizing views](#customizing-views)
|
49
50
|
* [View hooks](#view-hooks)
|
@@ -95,7 +96,7 @@ Then, see the rest of this Readme for more information about using and customizi
|
|
95
96
|
Add the gem to your Gemfile:
|
96
97
|
|
97
98
|
```ruby
|
98
|
-
gem 'thredded', '~> 0.16.
|
99
|
+
gem 'thredded', '~> 0.16.14'
|
99
100
|
```
|
100
101
|
|
101
102
|
Add the Thredded [initializer] to your parent app by running the install generator.
|
@@ -210,7 +211,7 @@ from the Thredded one by adding this Sass snippet after `@import "thredded";`:
|
|
210
211
|
|
211
212
|
See [below](#styles) for customizing the styles via Sass variables.
|
212
213
|
|
213
|
-
#### Add Thredded JavaScripts
|
214
|
+
#### Add Thredded JavaScripts (Sprockets)
|
214
215
|
|
215
216
|
Include thredded JavaScripts in your `application.js`:
|
216
217
|
|
@@ -220,6 +221,28 @@ Include thredded JavaScripts in your `application.js`:
|
|
220
221
|
|
221
222
|
Thredded is fully compatible with deferred and async script loading.
|
222
223
|
|
224
|
+
#### Add Thredded JavaScripts (Webpack)
|
225
|
+
|
226
|
+
You can also include Thredded JavaScript into your webpack pack.
|
227
|
+
|
228
|
+
First, run `bundle exec rails webpacker:install:erb`.
|
229
|
+
|
230
|
+
Then, add an `app/javascript/thredded_imports.js.erb` file with the following contents:
|
231
|
+
|
232
|
+
```erb
|
233
|
+
<%= Thredded::WebpackAssets.javascripts %>
|
234
|
+
```
|
235
|
+
|
236
|
+
Finally, add the following to your `app/javascript/packs/application.js`:
|
237
|
+
|
238
|
+
```js
|
239
|
+
require('thredded_imports.js');
|
240
|
+
```
|
241
|
+
|
242
|
+
Note that you must use `require` (not `import`) because Thredded JavaScript must be run after UJS/Turbolink `start()`
|
243
|
+
has been called. This is because Webpack places `import` calls before the code in the same file (unlike `require`,
|
244
|
+
which are placed in the same order as in the source).
|
245
|
+
|
223
246
|
##### Alternative JavaScript dependencies
|
224
247
|
|
225
248
|
<details><summary><b>Rails UJS version</b></summary>
|
@@ -381,15 +404,27 @@ Here are the steps to ensure the best support for your language if it isn't Engl
|
|
381
404
|
|
382
405
|
1. Add `rails-i18n` and `kaminari-i18n` to your Gemfile.
|
383
406
|
|
384
|
-
2. Require the translations for timeago.js in your JavaScript. E.g.
|
407
|
+
2. Require the translations for timeago.js in your JavaScript. E.g. if you want to add German and Brazilian Portuguese:
|
408
|
+
|
409
|
+
Sprockets:
|
385
410
|
|
386
411
|
```js
|
387
412
|
//= require thredded/dependencies/timeago
|
413
|
+
//= require timeago/locales/de
|
388
414
|
//= require timeago/locales/pt_BR
|
389
415
|
//= require thredded
|
390
|
-
```
|
391
|
-
|
392
|
-
|
416
|
+
```
|
417
|
+
|
418
|
+
Webpack:
|
419
|
+
|
420
|
+
```erb
|
421
|
+
<% timeago_root = File.join(Gem.loaded_specs['timeago_js'].full_gem_path, 'assets', 'javascripts') %>
|
422
|
+
import "<%= File.join(timeago_root, 'timeago.js') %>";
|
423
|
+
<%= %w[de pt_BR].map { |locale| %(import "#{File.join(timeago_root, "timeago/locales/#{locale}.js")}";) } * "\n" %>
|
424
|
+
<%= Thredded::WebpackAssets.javascripts %>
|
425
|
+
```
|
426
|
+
|
427
|
+
Note that it is important that timeago and its locales are required *before* Thredded.
|
393
428
|
|
394
429
|
3. To generate URL slugs for messageboards, categories, and topics with support for more language than English,
|
395
430
|
you can use a gem like [babosa](https://github.com/norman/babosa).
|
@@ -601,13 +636,26 @@ First, to get started, migrate and seed the database (SQLite by default):
|
|
601
636
|
```bash
|
602
637
|
bundle
|
603
638
|
# Create, migrate, and seed the development database with fake forum users, topics, and posts:
|
604
|
-
|
639
|
+
bin/rails db:create db:migrate db:seed
|
640
|
+
```
|
641
|
+
|
642
|
+
Install NPM dependencies for the dummy app:
|
643
|
+
|
644
|
+
```bash
|
645
|
+
cd spec/dummy && yarn && cd -
|
605
646
|
```
|
606
647
|
|
607
648
|
Then, start the dummy app server:
|
608
649
|
|
609
650
|
```bash
|
610
|
-
|
651
|
+
bin/rails s
|
652
|
+
```
|
653
|
+
|
654
|
+
By default, the dummy app server uses Webpack for JavaScript.
|
655
|
+
To use Sprockets instead, run:
|
656
|
+
|
657
|
+
```bash
|
658
|
+
THREDDED_TESTAPP_WEBPACK=1 bin/rails s
|
611
659
|
```
|
612
660
|
|
613
661
|
### Testing
|
@@ -1,3 +1,4 @@
|
|
1
|
+
//= require thredded/core/thredded
|
1
2
|
//= require thredded/core/on_page_load
|
2
3
|
//= require thredded/core/serialize_form
|
3
4
|
|
@@ -6,13 +7,6 @@
|
|
6
7
|
const Thredded = window.Thredded;
|
7
8
|
const Turbolinks = window.Turbolinks;
|
8
9
|
|
9
|
-
Thredded.onPageLoad(() => {
|
10
|
-
if (!Turbolinks || !Turbolinks.supported) return;
|
11
|
-
Array.prototype.forEach.call(document.querySelectorAll('[data-thredded-turboform]'), (form) => {
|
12
|
-
form.addEventListener('submit', handleSubmit);
|
13
|
-
});
|
14
|
-
});
|
15
|
-
|
16
10
|
const handleSubmit = (evt) => {
|
17
11
|
evt.preventDefault();
|
18
12
|
const form = evt.currentTarget;
|
@@ -22,4 +16,11 @@
|
|
22
16
|
// Turbolinks. Hide it:
|
23
17
|
Thredded.hideSoftKeyboard();
|
24
18
|
};
|
19
|
+
|
20
|
+
Thredded.onPageLoad(() => {
|
21
|
+
if (!Turbolinks || !Turbolinks.supported) return;
|
22
|
+
Array.prototype.forEach.call(document.querySelectorAll('[data-thredded-turboform]'), (form) => {
|
23
|
+
form.addEventListener('submit', handleSubmit);
|
24
|
+
});
|
25
|
+
});
|
25
26
|
})();
|
@@ -1 +1 @@
|
|
1
|
-
//= require autosize
|
1
|
+
//= require autosize
|
@@ -20,6 +20,14 @@ module Thredded
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
def show
|
24
|
+
@group = Thredded::MessageboardGroup.where(id: params[:id])
|
25
|
+
@groups = Thredded::MessageboardGroupView.grouped(
|
26
|
+
policy_scope(Thredded::Messageboard.where(group: params[:id])),
|
27
|
+
user: thredded_current_user
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
23
31
|
private
|
24
32
|
|
25
33
|
def messageboard_group_params
|
@@ -10,6 +10,8 @@ module Thredded
|
|
10
10
|
attr_reader :post_form
|
11
11
|
# @return [MessageboardsIndex]
|
12
12
|
attr_reader :messageboards_index
|
13
|
+
# @return [MessageboardGroupShow]
|
14
|
+
attr_reader :messageboard_group_show
|
13
15
|
# @return [ModerationUserPage]
|
14
16
|
attr_reader :moderation_user_page
|
15
17
|
# @return [TopicPage]
|
@@ -33,6 +35,7 @@ module Thredded
|
|
33
35
|
@post_form = PostForm.new
|
34
36
|
@moderation_user_page = ModerationUserPage.new
|
35
37
|
@messageboards_index = MessageboardsIndex.new
|
38
|
+
@messageboard_group_show = MessageboardGroupShow.new
|
36
39
|
@topic_page = TopicPage.new
|
37
40
|
end
|
38
41
|
|
@@ -95,6 +98,24 @@ module Thredded
|
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
101
|
+
class MessageboardGroupShow
|
102
|
+
# @return [Thredded::AllViewHooks::ViewHook]
|
103
|
+
attr_reader :container
|
104
|
+
# @return [Thredded::AllViewHooks::ViewHook]
|
105
|
+
attr_reader :list
|
106
|
+
# @return [Thredded::AllViewHooks::ViewHook]
|
107
|
+
attr_reader :group
|
108
|
+
# @return [Thredded::AllViewHooks::ViewHook]
|
109
|
+
attr_reader :messageboard
|
110
|
+
|
111
|
+
def initialize
|
112
|
+
@container = ViewHook.new
|
113
|
+
@list = ViewHook.new
|
114
|
+
@group = ViewHook.new
|
115
|
+
@messageboard = ViewHook.new
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
98
119
|
class ModerationUserPage
|
99
120
|
# @return [Thredded::AllViewHooks::ViewHook]
|
100
121
|
attr_reader :user_title
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Thredded
|
4
4
|
# A view model for a page of MessageboardGroupViews.
|
5
5
|
class MessageboardGroupView
|
6
|
-
delegate :name, to: :@group, allow_nil: true
|
6
|
+
delegate :name, :id, to: :@group, allow_nil: true
|
7
7
|
attr_reader :group, :messageboards
|
8
8
|
|
9
9
|
# @param [ActiveRecord::Relation<Thredded::Messageboard>] messageboards_scope
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<% content_for :thredded_page_title, t('thredded.messageboard_group.show.page_title', name: @group.name) %>
|
2
|
+
<% content_for :thredded_page_id, 'thredded--messageboard-groups--index' %>
|
3
|
+
<% content_for :thredded_breadcrumbs, render('thredded/shared/breadcrumbs') %>
|
4
|
+
<%= thredded_page do %>
|
5
|
+
<%= define_svg_icons('thredded/follow.svg', 'thredded/lock.svg') %>
|
6
|
+
<%= view_hooks.messageboard_group_show.container.render self, groups: @groups do %>
|
7
|
+
<section class="thredded--main-section thredded--messageboards">
|
8
|
+
<%= view_hooks.messageboard_group_show.list.render self, groups: @groups do %>
|
9
|
+
<% @groups.each do |group| %>
|
10
|
+
<% if group.name.present? %>
|
11
|
+
<h3 class="thredded--messageboards-group--title">
|
12
|
+
<%= link_to group.name,
|
13
|
+
show_messageboard_group_path(group.id),
|
14
|
+
class: 'thredded--link' %>
|
15
|
+
</h3>
|
16
|
+
<% end %>
|
17
|
+
<div class="thredded--messageboards-group">
|
18
|
+
<%= view_hooks.messageboard_group_show.group.render self, group: group do %>
|
19
|
+
<%= render partial: 'thredded/messageboards/messageboard',
|
20
|
+
collection: group.messageboards %>
|
21
|
+
<% end %>
|
22
|
+
<%= render partial: 'thredded/messageboards/grid_sizers' %>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
<div class="thredded--messageboards--actions">
|
28
|
+
<% if policy(Thredded::Messageboard.new).create? %>
|
29
|
+
<a class="thredded--button" href="<%= new_messageboard_path %>" rel="nofollow">
|
30
|
+
<%= t('thredded.messageboard.create') %>
|
31
|
+
</a>
|
32
|
+
<% end %>
|
33
|
+
<% if policy(Thredded::MessageboardGroup.new).create? %>
|
34
|
+
<a class="thredded--button" href="<%= new_messageboard_group_path %>" rel="nofollow">
|
35
|
+
<%= t('thredded.messageboard_group.create') %>
|
36
|
+
</a>
|
37
|
+
<% end %>
|
38
|
+
</div>
|
39
|
+
</section>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
@@ -8,7 +8,12 @@
|
|
8
8
|
<%= view_hooks.messageboards_index.list.render self, groups: @groups do %>
|
9
9
|
<% @groups.each do |group| %>
|
10
10
|
<% if group.name.present? %>
|
11
|
-
<h3 class="thredded--messageboards-group--title"
|
11
|
+
<h3 class="thredded--messageboards-group--title">
|
12
|
+
<%= link_to_if Thredded.show_messageboard_group_page,
|
13
|
+
group.name,
|
14
|
+
show_messageboard_group_path(group.id),
|
15
|
+
class: 'thredded--link' %>
|
16
|
+
</h3>
|
12
17
|
<% end %>
|
13
18
|
<div class="thredded--messageboards-group">
|
14
19
|
<%= view_hooks.messageboards_index.group.render self, group: group do %>
|
data/config/locales/de.yml
CHANGED
data/config/locales/en.yml
CHANGED
data/config/locales/es.yml
CHANGED
data/config/locales/fr.yml
CHANGED
data/config/locales/it.yml
CHANGED
data/config/locales/pl.yml
CHANGED
data/config/locales/pt-BR.yml
CHANGED
data/config/locales/ru.yml
CHANGED
data/config/locales/zh-CN.yml
CHANGED
data/config/routes.rb
CHANGED
@@ -59,6 +59,7 @@ Thredded::Engine.routes.draw do # rubocop:disable Metrics/BlockLength
|
|
59
59
|
|
60
60
|
resource :preferences, only: %i[edit update], as: :global_preferences
|
61
61
|
resource :messageboard, path: 'messageboards', only: [:new]
|
62
|
+
get '/messageboard-groups/:id', action: :show, controller: 'messageboard_groups', as: :show_messageboard_group
|
62
63
|
resources :messageboards, only: %i[edit update destroy]
|
63
64
|
resources :messageboards, only: %i[index create], path: '' do
|
64
65
|
resource :preferences, only: %i[edit update]
|
@@ -58,6 +58,9 @@ Thredded.messageboards_order = :position
|
|
58
58
|
# Whether admin users see button to delete entire messageboards on the messageboard edit page.
|
59
59
|
Thredded.show_messageboard_delete_button = false
|
60
60
|
|
61
|
+
# Whether MessageboardGroup show page is enabled.
|
62
|
+
Thredded.show_messageboard_group_page = true
|
63
|
+
|
61
64
|
# Whether users that are following a topic are listed on the topic page.
|
62
65
|
Thredded.show_topic_followers = false
|
63
66
|
|
data/lib/thredded.rb
CHANGED
@@ -46,6 +46,8 @@ require 'thredded/base_notifier'
|
|
46
46
|
require 'thredded/arel_compat'
|
47
47
|
require 'thredded/collection_to_strings_with_cache_renderer'
|
48
48
|
|
49
|
+
require 'thredded/webpack_assets'
|
50
|
+
|
49
51
|
if Rails::VERSION::MAJOR < 5
|
50
52
|
begin
|
51
53
|
require 'where-or'
|
@@ -132,6 +134,9 @@ module Thredded # rubocop:disable Metrics/ModuleLength
|
|
132
134
|
# @return [Number] Minimum length to trigger username auto-completion for @-mentions and private message recipients.
|
133
135
|
attr_accessor :autocomplete_min_length
|
134
136
|
|
137
|
+
# @return [Boolean] Whether MessageboardGroup show page is enabled.
|
138
|
+
attr_accessor :show_messageboard_group_page
|
139
|
+
|
135
140
|
# @return [Thredded::AllViewHooks] View hooks configuration.
|
136
141
|
def view_hooks
|
137
142
|
Thredded::AllViewHooks.instance ||
|
@@ -282,6 +287,7 @@ module Thredded # rubocop:disable Metrics/ModuleLength
|
|
282
287
|
self.messageboards_order = :position
|
283
288
|
self.topics_per_page = 50
|
284
289
|
self.autocomplete_min_length = 2
|
290
|
+
self.show_messageboard_group_page = true
|
285
291
|
|
286
292
|
self.auto_follow_when_creating_topic = true
|
287
293
|
self.auto_follow_when_posting_in_topic = true
|
data/lib/thredded/engine.rb
CHANGED
data/lib/thredded/version.rb
CHANGED
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
module Thredded
|
7
|
+
# Lets you include Thredded JavaScripts into your Webpack "pack".
|
8
|
+
#
|
9
|
+
# To use this, first run `bundle exec rails webpacker:install:erb`.
|
10
|
+
# Then, rename `app/javascript/packs/application.js` to `app/javascript/packs/application.js.erb`
|
11
|
+
# Finally, add this line to `app/javascript/packs/application.js.erb`:
|
12
|
+
#
|
13
|
+
# <%= Thredded::WebpackAssets.javascripts %>
|
14
|
+
#
|
15
|
+
# To include additional timeago locales, add this *before* `Thredded::WebpackAssets.javascripts`:
|
16
|
+
#
|
17
|
+
# <% timeago_root = File.join(Gem.loaded_specs['timeago_js'].full_gem_path, 'assets', 'javascripts') %>
|
18
|
+
# import "<%= File.join(timeago_root, 'timeago.js') %>";
|
19
|
+
# <%= %w[de pt_BR].map { |locale| %(import "#{File.join(timeago_root, "timeago/locales/#{locale}.js")}";) } * "\n" %>
|
20
|
+
module WebpackAssets
|
21
|
+
JAVASCRIPT_EXTS = %w[.es6 .js].freeze
|
22
|
+
|
23
|
+
def self.javascripts
|
24
|
+
@javascripts ||= JavaScriptsResolver.new.resolve('thredded.es6')
|
25
|
+
end
|
26
|
+
|
27
|
+
class JavaScriptsResolver
|
28
|
+
def resolve(entry_point)
|
29
|
+
resolve_full_paths(entry_point).map do |dep|
|
30
|
+
%(import "#{dep}";)
|
31
|
+
end.join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def resolve_full_paths(entry_point)
|
37
|
+
deps = []
|
38
|
+
seen = Set.new
|
39
|
+
queue = [[:start, dep_to_path(entry_point)]]
|
40
|
+
until queue.empty?
|
41
|
+
state, path = queue.pop
|
42
|
+
if state == :visiting
|
43
|
+
deps << path
|
44
|
+
next
|
45
|
+
end
|
46
|
+
next unless seen.add?(path)
|
47
|
+
queue << [:visiting, path]
|
48
|
+
next if path.to_s.start_with?('@')
|
49
|
+
src = File.read(path)
|
50
|
+
src.scan(%r{//= require (\S+)}).each do |m|
|
51
|
+
queue << [:start, dep_to_path(m[0])]
|
52
|
+
end
|
53
|
+
tree_root = Pathname.new(File.dirname(path))
|
54
|
+
src.scan(%r{//= require_tree (\S+)}).each do |m|
|
55
|
+
tree_root.join(m[0]).each_child do |pn|
|
56
|
+
next unless JAVASCRIPT_EXTS.include?(pn.extname)
|
57
|
+
queue << [:start, pn.cleanpath.to_s]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
deps
|
62
|
+
end
|
63
|
+
|
64
|
+
def engine_js_root
|
65
|
+
@engine_js_root ||= Pathname.new(engine_js_prefix)
|
66
|
+
end
|
67
|
+
|
68
|
+
def engine_js_prefix
|
69
|
+
@engine_js_prefix ||=
|
70
|
+
File.expand_path('app/assets/javascripts', File.join(__dir__, '../..'))
|
71
|
+
end
|
72
|
+
|
73
|
+
def engine_vendor_js_prefix
|
74
|
+
@engine_vendor_js_prefix ||=
|
75
|
+
File.expand_path('vendor/assets/javascripts', File.join(__dir__, '../..'))
|
76
|
+
end
|
77
|
+
|
78
|
+
def engine_dep?(dep)
|
79
|
+
dep.start_with?('thredded/')
|
80
|
+
end
|
81
|
+
|
82
|
+
def engine_dep_to_path(dep)
|
83
|
+
find_dep_in_path(engine_js_prefix, dep) ||
|
84
|
+
find_dep_in_path(engine_vendor_js_prefix, dep) ||
|
85
|
+
fail("Failed to find #{dep}")
|
86
|
+
end
|
87
|
+
|
88
|
+
def find_dep_in_path(dir, dep)
|
89
|
+
path = File.join(dir, dep)
|
90
|
+
return path if File.file?(path)
|
91
|
+
JAVASCRIPT_EXTS.each do |ext|
|
92
|
+
path_with_ext = "#{path}#{ext}"
|
93
|
+
return path_with_ext if File.file?(path_with_ext)
|
94
|
+
end
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def dep_to_path(dep)
|
99
|
+
if dep == 'timeago'
|
100
|
+
path = File.join(Gem.loaded_specs['timeago_js'].full_gem_path, 'assets', 'javascripts', "#{dep}.js")
|
101
|
+
fail "Failed to find #{dep}" unless File.file?(path)
|
102
|
+
return path
|
103
|
+
elsif dep == 'rails-ujs'
|
104
|
+
return '@rails/ujs'
|
105
|
+
end
|
106
|
+
engine_dep_to_path(dep)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
/** https://unpkg.com/autosize@4.0.2/dist/autosize.js **/
|
2
|
+
// Modified to always define the autosize global.
|
3
|
+
// This allows Thredded code to be compatible with both Webpack and Sprockets.
|
4
|
+
(function (global, factory) {
|
5
|
+
var mod = {
|
6
|
+
exports: {}
|
7
|
+
};
|
8
|
+
factory(mod, mod.exports);
|
9
|
+
global.autosize = mod.exports;
|
10
|
+
})(window, function (module, exports) {
|
11
|
+
'use strict';
|
12
|
+
|
13
|
+
var map = typeof Map === "function" ? new Map() : function () {
|
14
|
+
var keys = [];
|
15
|
+
var values = [];
|
16
|
+
|
17
|
+
return {
|
18
|
+
has: function has(key) {
|
19
|
+
return keys.indexOf(key) > -1;
|
20
|
+
},
|
21
|
+
get: function get(key) {
|
22
|
+
return values[keys.indexOf(key)];
|
23
|
+
},
|
24
|
+
set: function set(key, value) {
|
25
|
+
if (keys.indexOf(key) === -1) {
|
26
|
+
keys.push(key);
|
27
|
+
values.push(value);
|
28
|
+
}
|
29
|
+
},
|
30
|
+
delete: function _delete(key) {
|
31
|
+
var index = keys.indexOf(key);
|
32
|
+
if (index > -1) {
|
33
|
+
keys.splice(index, 1);
|
34
|
+
values.splice(index, 1);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
};
|
38
|
+
}();
|
39
|
+
|
40
|
+
var createEvent = function createEvent(name) {
|
41
|
+
return new Event(name, { bubbles: true });
|
42
|
+
};
|
43
|
+
try {
|
44
|
+
new Event('test');
|
45
|
+
} catch (e) {
|
46
|
+
// IE does not support `new Event()`
|
47
|
+
createEvent = function createEvent(name) {
|
48
|
+
var evt = document.createEvent('Event');
|
49
|
+
evt.initEvent(name, true, false);
|
50
|
+
return evt;
|
51
|
+
};
|
52
|
+
}
|
53
|
+
|
54
|
+
function assign(ta) {
|
55
|
+
if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || map.has(ta)) return;
|
56
|
+
|
57
|
+
var heightOffset = null;
|
58
|
+
var clientWidth = null;
|
59
|
+
var cachedHeight = null;
|
60
|
+
|
61
|
+
function init() {
|
62
|
+
var style = window.getComputedStyle(ta, null);
|
63
|
+
|
64
|
+
if (style.resize === 'vertical') {
|
65
|
+
ta.style.resize = 'none';
|
66
|
+
} else if (style.resize === 'both') {
|
67
|
+
ta.style.resize = 'horizontal';
|
68
|
+
}
|
69
|
+
|
70
|
+
if (style.boxSizing === 'content-box') {
|
71
|
+
heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
|
72
|
+
} else {
|
73
|
+
heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
|
74
|
+
}
|
75
|
+
// Fix when a textarea is not on document body and heightOffset is Not a Number
|
76
|
+
if (isNaN(heightOffset)) {
|
77
|
+
heightOffset = 0;
|
78
|
+
}
|
79
|
+
|
80
|
+
update();
|
81
|
+
}
|
82
|
+
|
83
|
+
function changeOverflow(value) {
|
84
|
+
{
|
85
|
+
// Chrome/Safari-specific fix:
|
86
|
+
// When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
|
87
|
+
// made available by removing the scrollbar. The following forces the necessary text reflow.
|
88
|
+
var width = ta.style.width;
|
89
|
+
ta.style.width = '0px';
|
90
|
+
// Force reflow:
|
91
|
+
/* jshint ignore:start */
|
92
|
+
ta.offsetWidth;
|
93
|
+
/* jshint ignore:end */
|
94
|
+
ta.style.width = width;
|
95
|
+
}
|
96
|
+
|
97
|
+
ta.style.overflowY = value;
|
98
|
+
}
|
99
|
+
|
100
|
+
function getParentOverflows(el) {
|
101
|
+
var arr = [];
|
102
|
+
|
103
|
+
while (el && el.parentNode && el.parentNode instanceof Element) {
|
104
|
+
if (el.parentNode.scrollTop) {
|
105
|
+
arr.push({
|
106
|
+
node: el.parentNode,
|
107
|
+
scrollTop: el.parentNode.scrollTop
|
108
|
+
});
|
109
|
+
}
|
110
|
+
el = el.parentNode;
|
111
|
+
}
|
112
|
+
|
113
|
+
return arr;
|
114
|
+
}
|
115
|
+
|
116
|
+
function resize() {
|
117
|
+
if (ta.scrollHeight === 0) {
|
118
|
+
// If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
|
122
|
+
var overflows = getParentOverflows(ta);
|
123
|
+
var docTop = document.documentElement && document.documentElement.scrollTop; // Needed for Mobile IE (ticket #240)
|
124
|
+
|
125
|
+
ta.style.height = '';
|
126
|
+
ta.style.height = ta.scrollHeight + heightOffset + 'px';
|
127
|
+
|
128
|
+
// used to check if an update is actually necessary on window.resize
|
129
|
+
clientWidth = ta.clientWidth;
|
130
|
+
|
131
|
+
// prevents scroll-position jumping
|
132
|
+
overflows.forEach(function (el) {
|
133
|
+
el.node.scrollTop = el.scrollTop;
|
134
|
+
});
|
135
|
+
|
136
|
+
if (docTop) {
|
137
|
+
document.documentElement.scrollTop = docTop;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
function update() {
|
142
|
+
resize();
|
143
|
+
|
144
|
+
var styleHeight = Math.round(parseFloat(ta.style.height));
|
145
|
+
var computed = window.getComputedStyle(ta, null);
|
146
|
+
|
147
|
+
// Using offsetHeight as a replacement for computed.height in IE, because IE does not account use of border-box
|
148
|
+
var actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(computed.height)) : ta.offsetHeight;
|
149
|
+
|
150
|
+
// The actual height not matching the style height (set via the resize method) indicates that
|
151
|
+
// the max-height has been exceeded, in which case the overflow should be allowed.
|
152
|
+
if (actualHeight < styleHeight) {
|
153
|
+
if (computed.overflowY === 'hidden') {
|
154
|
+
changeOverflow('scroll');
|
155
|
+
resize();
|
156
|
+
actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
157
|
+
}
|
158
|
+
} else {
|
159
|
+
// Normally keep overflow set to hidden, to avoid flash of scrollbar as the textarea expands.
|
160
|
+
if (computed.overflowY !== 'hidden') {
|
161
|
+
changeOverflow('hidden');
|
162
|
+
resize();
|
163
|
+
actualHeight = computed.boxSizing === 'content-box' ? Math.round(parseFloat(window.getComputedStyle(ta, null).height)) : ta.offsetHeight;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
if (cachedHeight !== actualHeight) {
|
168
|
+
cachedHeight = actualHeight;
|
169
|
+
var evt = createEvent('autosize:resized');
|
170
|
+
try {
|
171
|
+
ta.dispatchEvent(evt);
|
172
|
+
} catch (err) {
|
173
|
+
// Firefox will throw an error on dispatchEvent for a detached element
|
174
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=889376
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
var pageResize = function pageResize() {
|
180
|
+
if (ta.clientWidth !== clientWidth) {
|
181
|
+
update();
|
182
|
+
}
|
183
|
+
};
|
184
|
+
|
185
|
+
var destroy = function (style) {
|
186
|
+
window.removeEventListener('resize', pageResize, false);
|
187
|
+
ta.removeEventListener('input', update, false);
|
188
|
+
ta.removeEventListener('keyup', update, false);
|
189
|
+
ta.removeEventListener('autosize:destroy', destroy, false);
|
190
|
+
ta.removeEventListener('autosize:update', update, false);
|
191
|
+
|
192
|
+
Object.keys(style).forEach(function (key) {
|
193
|
+
ta.style[key] = style[key];
|
194
|
+
});
|
195
|
+
|
196
|
+
map.delete(ta);
|
197
|
+
}.bind(ta, {
|
198
|
+
height: ta.style.height,
|
199
|
+
resize: ta.style.resize,
|
200
|
+
overflowY: ta.style.overflowY,
|
201
|
+
overflowX: ta.style.overflowX,
|
202
|
+
wordWrap: ta.style.wordWrap
|
203
|
+
});
|
204
|
+
|
205
|
+
ta.addEventListener('autosize:destroy', destroy, false);
|
206
|
+
|
207
|
+
// IE9 does not fire onpropertychange or oninput for deletions,
|
208
|
+
// so binding to onkeyup to catch most of those events.
|
209
|
+
// There is no way that I know of to detect something like 'cut' in IE9.
|
210
|
+
if ('onpropertychange' in ta && 'oninput' in ta) {
|
211
|
+
ta.addEventListener('keyup', update, false);
|
212
|
+
}
|
213
|
+
|
214
|
+
window.addEventListener('resize', pageResize, false);
|
215
|
+
ta.addEventListener('input', update, false);
|
216
|
+
ta.addEventListener('autosize:update', update, false);
|
217
|
+
ta.style.overflowX = 'hidden';
|
218
|
+
ta.style.wordWrap = 'break-word';
|
219
|
+
|
220
|
+
map.set(ta, {
|
221
|
+
destroy: destroy,
|
222
|
+
update: update
|
223
|
+
});
|
224
|
+
|
225
|
+
init();
|
226
|
+
}
|
227
|
+
|
228
|
+
function destroy(ta) {
|
229
|
+
var methods = map.get(ta);
|
230
|
+
if (methods) {
|
231
|
+
methods.destroy();
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
function update(ta) {
|
236
|
+
var methods = map.get(ta);
|
237
|
+
if (methods) {
|
238
|
+
methods.update();
|
239
|
+
}
|
240
|
+
}
|
241
|
+
|
242
|
+
var autosize = null;
|
243
|
+
|
244
|
+
// Do nothing in Node.js environment and IE8 (or lower)
|
245
|
+
if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
|
246
|
+
autosize = function autosize(el) {
|
247
|
+
return el;
|
248
|
+
};
|
249
|
+
autosize.destroy = function (el) {
|
250
|
+
return el;
|
251
|
+
};
|
252
|
+
autosize.update = function (el) {
|
253
|
+
return el;
|
254
|
+
};
|
255
|
+
} else {
|
256
|
+
autosize = function autosize(el, options) {
|
257
|
+
if (el) {
|
258
|
+
Array.prototype.forEach.call(el.length ? el : [el], function (x) {
|
259
|
+
return assign(x, options);
|
260
|
+
});
|
261
|
+
}
|
262
|
+
return el;
|
263
|
+
};
|
264
|
+
autosize.destroy = function (el) {
|
265
|
+
if (el) {
|
266
|
+
Array.prototype.forEach.call(el.length ? el : [el], destroy);
|
267
|
+
}
|
268
|
+
return el;
|
269
|
+
};
|
270
|
+
autosize.update = function (el) {
|
271
|
+
if (el) {
|
272
|
+
Array.prototype.forEach.call(el.length ? el : [el], update);
|
273
|
+
}
|
274
|
+
return el;
|
275
|
+
};
|
276
|
+
}
|
277
|
+
|
278
|
+
exports.default = autosize;
|
279
|
+
module.exports = exports['default'];
|
280
|
+
});
|
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.16.
|
4
|
+
version: 0.16.14
|
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: 2019-
|
12
|
+
date: 2019-10-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: active_record_union
|
@@ -295,14 +295,14 @@ dependencies:
|
|
295
295
|
requirements:
|
296
296
|
- - ">="
|
297
297
|
- !ruby/object:Gem::Version
|
298
|
-
version:
|
298
|
+
version: 3.0.2.2
|
299
299
|
type: :runtime
|
300
300
|
prerelease: false
|
301
301
|
version_requirements: !ruby/object:Gem::Requirement
|
302
302
|
requirements:
|
303
303
|
- - ">="
|
304
304
|
- !ruby/object:Gem::Version
|
305
|
-
version:
|
305
|
+
version: 3.0.2.2
|
306
306
|
- !ruby/object:Gem::Dependency
|
307
307
|
name: capybara
|
308
308
|
requirement: !ruby/object:Gem::Requirement
|
@@ -623,6 +623,7 @@ extra_rdoc_files: []
|
|
623
623
|
files:
|
624
624
|
- MIT-LICENSE
|
625
625
|
- README.md
|
626
|
+
- app/assets/config/thredded_manifest.js
|
626
627
|
- app/assets/images/favicons/README.md
|
627
628
|
- app/assets/images/favicons/amazon.png
|
628
629
|
- app/assets/images/favicons/github.png
|
@@ -845,6 +846,7 @@ files:
|
|
845
846
|
- app/views/thredded/kaminari/_paginator.html.erb
|
846
847
|
- app/views/thredded/kaminari/_prev_page.html.erb
|
847
848
|
- app/views/thredded/messageboard_groups/new.html.erb
|
849
|
+
- app/views/thredded/messageboard_groups/show.html.erb
|
848
850
|
- app/views/thredded/messageboards/_form.html.erb
|
849
851
|
- app/views/thredded/messageboards/_grid_sizers.html.erb
|
850
852
|
- app/views/thredded/messageboards/_messageboard.html.erb
|
@@ -1013,7 +1015,8 @@ files:
|
|
1013
1015
|
- lib/thredded/version.rb
|
1014
1016
|
- lib/thredded/view_hooks/config.rb
|
1015
1017
|
- lib/thredded/view_hooks/renderer.rb
|
1016
|
-
-
|
1018
|
+
- lib/thredded/webpack_assets.rb
|
1019
|
+
- vendor/assets/javascripts/autosize.js
|
1017
1020
|
- vendor/assets/javascripts/textcomplete.min.js
|
1018
1021
|
homepage: https://thredded.org
|
1019
1022
|
licenses:
|
@@ -1034,7 +1037,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1034
1037
|
- !ruby/object:Gem::Version
|
1035
1038
|
version: '0'
|
1036
1039
|
requirements: []
|
1037
|
-
rubygems_version: 3.0.
|
1040
|
+
rubygems_version: 3.0.6
|
1038
1041
|
signing_key:
|
1039
1042
|
specification_version: 4
|
1040
1043
|
summary: The best Rails forums engine ever.
|
@@ -1,2 +0,0 @@
|
|
1
|
-
/** https://unpkg.com/autosize@4.0.2/dist/autosize.min.js **/
|
2
|
-
!function(e,t){if("function"==typeof define&&define.amd)define(["module","exports"],t);else if("undefined"!=typeof exports)t(module,exports);else{var n={exports:{}};t(n,n.exports),e.autosize=n.exports}}(this,function(e,t){"use strict";var n,o,p="function"==typeof Map?new Map:(n=[],o=[],{has:function(e){return-1<n.indexOf(e)},get:function(e){return o[n.indexOf(e)]},set:function(e,t){-1===n.indexOf(e)&&(n.push(e),o.push(t))},delete:function(e){var t=n.indexOf(e);-1<t&&(n.splice(t,1),o.splice(t,1))}}),c=function(e){return new Event(e,{bubbles:!0})};try{new Event("test")}catch(e){c=function(e){var t=document.createEvent("Event");return t.initEvent(e,!0,!1),t}}function r(r){if(r&&r.nodeName&&"TEXTAREA"===r.nodeName&&!p.has(r)){var e,n=null,o=null,i=null,d=function(){r.clientWidth!==o&&a()},l=function(t){window.removeEventListener("resize",d,!1),r.removeEventListener("input",a,!1),r.removeEventListener("keyup",a,!1),r.removeEventListener("autosize:destroy",l,!1),r.removeEventListener("autosize:update",a,!1),Object.keys(t).forEach(function(e){r.style[e]=t[e]}),p.delete(r)}.bind(r,{height:r.style.height,resize:r.style.resize,overflowY:r.style.overflowY,overflowX:r.style.overflowX,wordWrap:r.style.wordWrap});r.addEventListener("autosize:destroy",l,!1),"onpropertychange"in r&&"oninput"in r&&r.addEventListener("keyup",a,!1),window.addEventListener("resize",d,!1),r.addEventListener("input",a,!1),r.addEventListener("autosize:update",a,!1),r.style.overflowX="hidden",r.style.wordWrap="break-word",p.set(r,{destroy:l,update:a}),"vertical"===(e=window.getComputedStyle(r,null)).resize?r.style.resize="none":"both"===e.resize&&(r.style.resize="horizontal"),n="content-box"===e.boxSizing?-(parseFloat(e.paddingTop)+parseFloat(e.paddingBottom)):parseFloat(e.borderTopWidth)+parseFloat(e.borderBottomWidth),isNaN(n)&&(n=0),a()}function s(e){var t=r.style.width;r.style.width="0px",r.offsetWidth,r.style.width=t,r.style.overflowY=e}function u(){if(0!==r.scrollHeight){var e=function(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push({node:e.parentNode,scrollTop:e.parentNode.scrollTop}),e=e.parentNode;return t}(r),t=document.documentElement&&document.documentElement.scrollTop;r.style.height="",r.style.height=r.scrollHeight+n+"px",o=r.clientWidth,e.forEach(function(e){e.node.scrollTop=e.scrollTop}),t&&(document.documentElement.scrollTop=t)}}function a(){u();var e=Math.round(parseFloat(r.style.height)),t=window.getComputedStyle(r,null),n="content-box"===t.boxSizing?Math.round(parseFloat(t.height)):r.offsetHeight;if(n<e?"hidden"===t.overflowY&&(s("scroll"),u(),n="content-box"===t.boxSizing?Math.round(parseFloat(window.getComputedStyle(r,null).height)):r.offsetHeight):"hidden"!==t.overflowY&&(s("hidden"),u(),n="content-box"===t.boxSizing?Math.round(parseFloat(window.getComputedStyle(r,null).height)):r.offsetHeight),i!==n){i=n;var o=c("autosize:resized");try{r.dispatchEvent(o)}catch(e){}}}}function i(e){var t=p.get(e);t&&t.destroy()}function d(e){var t=p.get(e);t&&t.update()}var l=null;"undefined"==typeof window||"function"!=typeof window.getComputedStyle?((l=function(e){return e}).destroy=function(e){return e},l.update=function(e){return e}):((l=function(e,t){return e&&Array.prototype.forEach.call(e.length?e:[e],function(e){return r(e)}),e}).destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],i),e},l.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],d),e}),t.default=l,e.exports=t.default});
|