actiontext5 5.2.0
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 +7 -0
- data/.gitattributes +2 -0
- data/.gitignore +13 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +140 -0
- data/LICENSE +21 -0
- data/README.md +1 -0
- data/Rakefile +27 -0
- data/actiontext.gemspec +29 -0
- data/app/helpers/action_text/content_helper.rb +30 -0
- data/app/helpers/action_text/tag_helper.rb +75 -0
- data/app/javascript/actiontext/attachment_upload.js +45 -0
- data/app/javascript/actiontext/index.js +11 -0
- data/app/models/action_text/rich_text.rb +25 -0
- data/app/views/action_text/attachables/_missing_attachable.html.erb +1 -0
- data/app/views/action_text/attachables/_remote_image.html.erb +8 -0
- data/app/views/action_text/attachment_galleries/_attachment_gallery.html.erb +3 -0
- data/app/views/action_text/content/_layout.html.erb +3 -0
- data/app/views/active_storage/blobs/_blob.html.erb +14 -0
- data/bin/test +6 -0
- data/bin/webpack +29 -0
- data/bin/webpack-dev-server +29 -0
- data/db/migrate/201805281641_create_action_text_tables.rb +14 -0
- data/lib/action_text/attachable.rb +82 -0
- data/lib/action_text/attachables/content_attachment.rb +38 -0
- data/lib/action_text/attachables/missing_attachable.rb +11 -0
- data/lib/action_text/attachables/remote_image.rb +46 -0
- data/lib/action_text/attachment.rb +103 -0
- data/lib/action_text/attachment_gallery.rb +65 -0
- data/lib/action_text/attachments/caching.rb +16 -0
- data/lib/action_text/attachments/minification.rb +17 -0
- data/lib/action_text/attachments/trix_conversion.rb +34 -0
- data/lib/action_text/attribute.rb +48 -0
- data/lib/action_text/content.rb +126 -0
- data/lib/action_text/engine.rb +45 -0
- data/lib/action_text/fragment.rb +57 -0
- data/lib/action_text/html_conversion.rb +24 -0
- data/lib/action_text/plain_text_conversion.rb +81 -0
- data/lib/action_text/serialization.rb +34 -0
- data/lib/action_text/trix_attachment.rb +92 -0
- data/lib/action_text/version.rb +5 -0
- data/lib/action_text.rb +38 -0
- data/lib/actiontext5.rb +1 -0
- data/lib/tasks/actiontext.rake +20 -0
- data/lib/templates/actiontext.scss +36 -0
- data/lib/templates/fixtures.yml +4 -0
- data/lib/templates/installer.rb +22 -0
- data/package.json +21 -0
- data/test/dummy/.babelrc +18 -0
- data/test/dummy/.postcssrc.yml +3 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +3 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +16 -0
- data/test/dummy/app/assets/stylesheets/messages.css +4 -0
- data/test/dummy/app/assets/stylesheets/scaffold.css +80 -0
- data/test/dummy/app/channels/application_cable/channel.rb +4 -0
- data/test/dummy/app/channels/application_cable/connection.rb +4 -0
- data/test/dummy/app/controllers/application_controller.rb +2 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/messages_controller.rb +58 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/messages_helper.rb +2 -0
- data/test/dummy/app/javascript/packs/application.js +1 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/application_record.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/message.rb +4 -0
- data/test/dummy/app/models/person.rb +7 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/app/views/messages/_form.html.erb +27 -0
- data/test/dummy/app/views/messages/edit.html.erb +6 -0
- data/test/dummy/app/views/messages/index.html.erb +29 -0
- data/test/dummy/app/views/messages/new.html.erb +5 -0
- data/test/dummy/app/views/messages/show.html.erb +13 -0
- data/test/dummy/app/views/people/_trix_content_attachment.html.erb +3 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +36 -0
- data/test/dummy/bin/update +31 -0
- data/test/dummy/bin/yarn +11 -0
- data/test/dummy/config/application.rb +19 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +63 -0
- data/test/dummy/config/environments/production.rb +96 -0
- data/test/dummy/config/environments/test.rb +46 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/test/dummy/config/initializers/assets.rb +14 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/content_security_policy.rb +22 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +33 -0
- data/test/dummy/config/puma.rb +34 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config/storage.yml +35 -0
- data/test/dummy/config/webpack/development.js +3 -0
- data/test/dummy/config/webpack/environment.js +3 -0
- data/test/dummy/config/webpack/production.js +3 -0
- data/test/dummy/config/webpack/test.js +3 -0
- data/test/dummy/config/webpacker.yml +65 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/db/migrate/20180208205311_create_messages.rb +8 -0
- data/test/dummy/db/migrate/20180212164506_create_active_storage_tables.active_storage.rb +26 -0
- data/test/dummy/db/migrate/2018052816_create_action_text_tables.rb +14 -0
- data/test/dummy/db/migrate/20181003185713_create_people.rb +9 -0
- data/test/dummy/db/schema.rb +58 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/package.json +11 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/storage/.keep +0 -0
- data/test/dummy/tmp/.keep +0 -0
- data/test/dummy/tmp/storage/.keep +0 -0
- data/test/dummy/yarn.lock +6071 -0
- data/test/fixtures/files/racecar.jpg +0 -0
- data/test/template/form_helper_test.rb +71 -0
- data/test/test_helper.rb +30 -0
- data/test/unit/attachment_test.rb +60 -0
- data/test/unit/content_test.rb +116 -0
- data/test/unit/model_test.rb +47 -0
- data/test/unit/plain_text_conversion_test.rb +94 -0
- data/test/unit/trix_attachment_test.rb +83 -0
- data/yarn.lock +11 -0
- metadata +372 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8160e6be3d5b37488107aa744e5a8a2b74347ba2a36227c149d9e79dbd0630e5
|
|
4
|
+
data.tar.gz: a0674e2c6bbdd9a4fd9301870768fc560701e3cc1b86f8a68c4db7dd0d73aa40
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 9cc4c4939ae0f7d160faa09aefc48a13f6ee55659ca11b4511304b155982876cff63d4f1c0c5e58df2cebc982a598a2ac3c45fef7c09ef8c7196272415447952
|
|
7
|
+
data.tar.gz: 71bb739f6919d271cef629b64f39c3eb2c0fa9dfa743d4408954956221b6f1e9adb790b101a562f8d561ce5904fd154565750e94083f3e16ba05556891976094
|
data/.gitattributes
ADDED
data/.gitignore
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
.bundle/
|
|
2
|
+
.byebug_history
|
|
3
|
+
log/*.log
|
|
4
|
+
node_modules/
|
|
5
|
+
pkg/
|
|
6
|
+
test/dummy/db/*.sqlite3
|
|
7
|
+
test/dummy/db/*.sqlite3-journal
|
|
8
|
+
test/dummy/log/*.log
|
|
9
|
+
test/dummy/node_modules/
|
|
10
|
+
test/dummy/public/
|
|
11
|
+
test/dummy/yarn-error.log
|
|
12
|
+
test/dummy/storage/
|
|
13
|
+
test/dummy/tmp/
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
actiontext5 (5.2.0)
|
|
5
|
+
nokogiri
|
|
6
|
+
rails (~> 5.2.0)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
actioncable (5.2.8)
|
|
12
|
+
actionpack (= 5.2.8)
|
|
13
|
+
nio4r (~> 2.0)
|
|
14
|
+
websocket-driver (>= 0.6.1)
|
|
15
|
+
actionmailer (5.2.8)
|
|
16
|
+
actionpack (= 5.2.8)
|
|
17
|
+
actionview (= 5.2.8)
|
|
18
|
+
activejob (= 5.2.8)
|
|
19
|
+
mail (~> 2.5, >= 2.5.4)
|
|
20
|
+
rails-dom-testing (~> 2.0)
|
|
21
|
+
actionpack (5.2.8)
|
|
22
|
+
actionview (= 5.2.8)
|
|
23
|
+
activesupport (= 5.2.8)
|
|
24
|
+
rack (~> 2.0, >= 2.0.8)
|
|
25
|
+
rack-test (>= 0.6.3)
|
|
26
|
+
rails-dom-testing (~> 2.0)
|
|
27
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
28
|
+
actionview (5.2.8)
|
|
29
|
+
activesupport (= 5.2.8)
|
|
30
|
+
builder (~> 3.1)
|
|
31
|
+
erubi (~> 1.4)
|
|
32
|
+
rails-dom-testing (~> 2.0)
|
|
33
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
34
|
+
activejob (5.2.8)
|
|
35
|
+
activesupport (= 5.2.8)
|
|
36
|
+
globalid (>= 0.3.6)
|
|
37
|
+
activemodel (5.2.8)
|
|
38
|
+
activesupport (= 5.2.8)
|
|
39
|
+
activerecord (5.2.8)
|
|
40
|
+
activemodel (= 5.2.8)
|
|
41
|
+
activesupport (= 5.2.8)
|
|
42
|
+
arel (>= 9.0)
|
|
43
|
+
activestorage (5.2.8)
|
|
44
|
+
actionpack (= 5.2.8)
|
|
45
|
+
activerecord (= 5.2.8)
|
|
46
|
+
marcel (~> 1.0.0)
|
|
47
|
+
activesupport (5.2.8)
|
|
48
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
49
|
+
i18n (>= 0.7, < 2)
|
|
50
|
+
minitest (~> 5.1)
|
|
51
|
+
tzinfo (~> 1.1)
|
|
52
|
+
arel (9.0.0)
|
|
53
|
+
builder (3.2.4)
|
|
54
|
+
byebug (11.1.3)
|
|
55
|
+
concurrent-ruby (1.1.10)
|
|
56
|
+
crass (1.0.6)
|
|
57
|
+
erubi (1.10.0)
|
|
58
|
+
globalid (1.0.0)
|
|
59
|
+
activesupport (>= 5.0)
|
|
60
|
+
i18n (1.10.0)
|
|
61
|
+
concurrent-ruby (~> 1.0)
|
|
62
|
+
loofah (2.18.0)
|
|
63
|
+
crass (~> 1.0.2)
|
|
64
|
+
nokogiri (>= 1.5.9)
|
|
65
|
+
mail (2.7.1)
|
|
66
|
+
mini_mime (>= 0.1.1)
|
|
67
|
+
marcel (1.0.2)
|
|
68
|
+
method_source (1.0.0)
|
|
69
|
+
mini_magick (4.11.0)
|
|
70
|
+
mini_mime (1.1.2)
|
|
71
|
+
mini_portile2 (2.8.0)
|
|
72
|
+
minitest (5.15.0)
|
|
73
|
+
nio4r (2.5.8)
|
|
74
|
+
nokogiri (1.13.6)
|
|
75
|
+
mini_portile2 (~> 2.8.0)
|
|
76
|
+
racc (~> 1.4)
|
|
77
|
+
racc (1.6.0)
|
|
78
|
+
rack (2.2.3.1)
|
|
79
|
+
rack-proxy (0.7.2)
|
|
80
|
+
rack
|
|
81
|
+
rack-test (1.1.0)
|
|
82
|
+
rack (>= 1.0, < 3)
|
|
83
|
+
rails (5.2.8)
|
|
84
|
+
actioncable (= 5.2.8)
|
|
85
|
+
actionmailer (= 5.2.8)
|
|
86
|
+
actionpack (= 5.2.8)
|
|
87
|
+
actionview (= 5.2.8)
|
|
88
|
+
activejob (= 5.2.8)
|
|
89
|
+
activemodel (= 5.2.8)
|
|
90
|
+
activerecord (= 5.2.8)
|
|
91
|
+
activestorage (= 5.2.8)
|
|
92
|
+
activesupport (= 5.2.8)
|
|
93
|
+
bundler (>= 1.3.0)
|
|
94
|
+
railties (= 5.2.8)
|
|
95
|
+
sprockets-rails (>= 2.0.0)
|
|
96
|
+
rails-dom-testing (2.0.3)
|
|
97
|
+
activesupport (>= 4.2.0)
|
|
98
|
+
nokogiri (>= 1.6)
|
|
99
|
+
rails-html-sanitizer (1.4.2)
|
|
100
|
+
loofah (~> 2.3)
|
|
101
|
+
railties (5.2.8)
|
|
102
|
+
actionpack (= 5.2.8)
|
|
103
|
+
activesupport (= 5.2.8)
|
|
104
|
+
method_source
|
|
105
|
+
rake (>= 0.8.7)
|
|
106
|
+
thor (>= 0.19.0, < 2.0)
|
|
107
|
+
rake (13.0.6)
|
|
108
|
+
sprockets (4.0.3)
|
|
109
|
+
concurrent-ruby (~> 1.0)
|
|
110
|
+
rack (> 1, < 3)
|
|
111
|
+
sprockets-rails (3.4.2)
|
|
112
|
+
actionpack (>= 5.2)
|
|
113
|
+
activesupport (>= 5.2)
|
|
114
|
+
sprockets (>= 3.0.0)
|
|
115
|
+
sqlite3 (1.4.2)
|
|
116
|
+
thor (1.2.1)
|
|
117
|
+
thread_safe (0.3.6)
|
|
118
|
+
tzinfo (1.2.9)
|
|
119
|
+
thread_safe (~> 0.1)
|
|
120
|
+
webpacker (3.2.2)
|
|
121
|
+
activesupport (>= 4.2)
|
|
122
|
+
rack-proxy (>= 0.6.1)
|
|
123
|
+
railties (>= 4.2)
|
|
124
|
+
websocket-driver (0.7.5)
|
|
125
|
+
websocket-extensions (>= 0.1.0)
|
|
126
|
+
websocket-extensions (0.1.5)
|
|
127
|
+
|
|
128
|
+
PLATFORMS
|
|
129
|
+
ruby
|
|
130
|
+
|
|
131
|
+
DEPENDENCIES
|
|
132
|
+
actiontext5!
|
|
133
|
+
bundler (~> 1.15)
|
|
134
|
+
byebug
|
|
135
|
+
mini_magick
|
|
136
|
+
sqlite3
|
|
137
|
+
webpacker (~> 3.2.2)
|
|
138
|
+
|
|
139
|
+
BUNDLED WITH
|
|
140
|
+
1.17.2
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Basecamp, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
This gem is just a fork from https://github.com/rails/actiontext builded to work with Rails 5.2.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
rescue LoadError
|
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'rdoc/task'
|
|
8
|
+
|
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
11
|
+
rdoc.title = 'Action Text'
|
|
12
|
+
rdoc.options << '--line-numbers'
|
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
require 'bundler/gem_tasks'
|
|
18
|
+
|
|
19
|
+
require 'rake/testtask'
|
|
20
|
+
|
|
21
|
+
Rake::TestTask.new(:test) do |t|
|
|
22
|
+
t.libs << 'test'
|
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
|
24
|
+
t.verbose = false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
task default: :test
|
data/actiontext.gemspec
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
$:.push File.expand_path("lib", __dir__)
|
|
2
|
+
|
|
3
|
+
# Maintain your gem's version:
|
|
4
|
+
require "action_text/version"
|
|
5
|
+
|
|
6
|
+
# Describe your gem and declare its dependencies:
|
|
7
|
+
Gem::Specification.new do |s|
|
|
8
|
+
s.name = "actiontext5"
|
|
9
|
+
s.version = ActionText::VERSION
|
|
10
|
+
s.authors = ["Benoit MARTIN-CHAVE"]
|
|
11
|
+
s.email = ["benoit@martin-chave.com"]
|
|
12
|
+
s.summary = "ActionText for Rails 5"
|
|
13
|
+
s.homepage = "https://github.com/BenoitMC/actiontext5"
|
|
14
|
+
s.license = "MIT"
|
|
15
|
+
|
|
16
|
+
s.required_ruby_version = ">= 2.5.0"
|
|
17
|
+
|
|
18
|
+
s.add_dependency "rails", "~> 5.2.0"
|
|
19
|
+
s.add_dependency "nokogiri"
|
|
20
|
+
|
|
21
|
+
s.add_development_dependency "bundler", "~> 1.15"
|
|
22
|
+
s.add_development_dependency "mini_magick"
|
|
23
|
+
s.add_development_dependency "sqlite3"
|
|
24
|
+
s.add_development_dependency "webpacker", "~> 3.2.2"
|
|
25
|
+
s.add_development_dependency "byebug"
|
|
26
|
+
|
|
27
|
+
s.files = `git ls-files`.split("\n")
|
|
28
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
|
29
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionText
|
|
4
|
+
module ContentHelper
|
|
5
|
+
SANITIZER = Rails::Html::Sanitizer.white_list_sanitizer
|
|
6
|
+
ALLOWED_TAGS = SANITIZER.allowed_tags + [ ActionText::Attachment::TAG_NAME, "figure", "figcaption" ]
|
|
7
|
+
ALLOWED_ATTRIBUTES = SANITIZER.allowed_attributes + ActionText::Attachment::ATTRIBUTES
|
|
8
|
+
|
|
9
|
+
def render_action_text_content(content)
|
|
10
|
+
content = content.render_attachments do |attachment|
|
|
11
|
+
unless attachment.in?(content.gallery_attachments)
|
|
12
|
+
attachment.node.tap do |node|
|
|
13
|
+
node.inner_html = render(attachment, in_gallery: false).chomp
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
content = content.render_attachment_galleries do |attachment_gallery|
|
|
19
|
+
render(layout: attachment_gallery, object: attachment_gallery) do
|
|
20
|
+
attachment_gallery.attachments.map do |attachment|
|
|
21
|
+
attachment.node.inner_html = render(attachment, in_gallery: true).chomp
|
|
22
|
+
attachment.to_html
|
|
23
|
+
end.join("").html_safe
|
|
24
|
+
end.chomp
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
sanitize content.to_html, tags: ALLOWED_TAGS, attributes: ALLOWED_ATTRIBUTES
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionText
|
|
4
|
+
module TagHelper
|
|
5
|
+
cattr_accessor(:id, instance_accessor: false) { 0 }
|
|
6
|
+
|
|
7
|
+
# Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as well as a hidden field
|
|
8
|
+
# that Trix will write to on changes, so the content will be sent on form submissions.
|
|
9
|
+
#
|
|
10
|
+
# ==== Options
|
|
11
|
+
# * <tt>:class</tt> - Defaults to "trix-content" which ensures default styling is applied.
|
|
12
|
+
#
|
|
13
|
+
# ==== Example
|
|
14
|
+
#
|
|
15
|
+
# rich_text_area_tag "content", message.content
|
|
16
|
+
# # <input type="hidden" name="content" id="trix_input_post_1">
|
|
17
|
+
# # <trix-editor id="content" input="trix_input_post_1" class="trix-content" ...></trix-editor>
|
|
18
|
+
def rich_text_area_tag(name, value = nil, options = {})
|
|
19
|
+
options = options.symbolize_keys
|
|
20
|
+
|
|
21
|
+
options[:input] ||= "trix_input_#{ActionText::TagHelper.id += 1}"
|
|
22
|
+
options[:class] ||= "trix-content"
|
|
23
|
+
|
|
24
|
+
options[:data] ||= {}
|
|
25
|
+
options[:data][:direct_upload_url] = main_app.rails_direct_uploads_url
|
|
26
|
+
options[:data][:blob_url_template] = main_app.rails_service_blob_url(":signed_id", ":filename")
|
|
27
|
+
|
|
28
|
+
editor_tag = content_tag("trix-editor", "", options)
|
|
29
|
+
input_tag = hidden_field_tag(name, value, id: options[:input])
|
|
30
|
+
|
|
31
|
+
input_tag + editor_tag
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module ActionView::Helpers
|
|
37
|
+
class Tags::ActionText < Tags::Base
|
|
38
|
+
delegate :dom_id, to: ActionView::RecordIdentifier
|
|
39
|
+
|
|
40
|
+
def render
|
|
41
|
+
options = @options.stringify_keys
|
|
42
|
+
add_default_name_and_id(options)
|
|
43
|
+
options["input"] ||= dom_id(object, [options["id"], :trix_input].compact.join("_")) if object
|
|
44
|
+
@template_object.rich_text_area_tag(options.delete("name"), editable_value, options)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def editable_value
|
|
48
|
+
value&.body.try(:to_trix_html)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
module FormHelper
|
|
53
|
+
# Returns a `trix-editor` tag that instantiates the Trix JavaScript editor as well as a hidden field
|
|
54
|
+
# that Trix will write to on changes, so the content will be sent on form submissions.
|
|
55
|
+
#
|
|
56
|
+
# ==== Options
|
|
57
|
+
# * <tt>:class</tt> - Defaults to "trix-content" which ensures default styling is applied.
|
|
58
|
+
#
|
|
59
|
+
# ==== Example
|
|
60
|
+
# form_with(model: @message) do |form|
|
|
61
|
+
# form.rich_text_area :content
|
|
62
|
+
# end
|
|
63
|
+
# # <input type="hidden" name="message[content]" id="message_content_trix_input_message_1">
|
|
64
|
+
# # <trix-editor id="content" input="message_content_trix_input_message_1" class="trix-content" ...></trix-editor>
|
|
65
|
+
def rich_text_area(object_name, method, options = {})
|
|
66
|
+
Tags::ActionText.new(object_name, method, self, options).render
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class FormBuilder
|
|
71
|
+
def rich_text_area(method, options = {})
|
|
72
|
+
@template.rich_text_area(@object_name, method, objectify_options(options))
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DirectUpload } from "activestorage"
|
|
2
|
+
|
|
3
|
+
export class AttachmentUpload {
|
|
4
|
+
constructor(attachment, element) {
|
|
5
|
+
this.attachment = attachment
|
|
6
|
+
this.element = element
|
|
7
|
+
this.directUpload = new DirectUpload(attachment.file, this.directUploadUrl, this)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
start() {
|
|
11
|
+
this.directUpload.create(this.directUploadDidComplete.bind(this))
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
directUploadWillStoreFileWithXHR(xhr) {
|
|
15
|
+
xhr.upload.addEventListener("progress", event => {
|
|
16
|
+
const progress = event.loaded / event.total * 100
|
|
17
|
+
this.attachment.setUploadProgress(progress)
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
directUploadDidComplete(error, attributes) {
|
|
22
|
+
if (error) {
|
|
23
|
+
throw new Error(`Direct upload failed: ${error}`)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.attachment.setAttributes({
|
|
27
|
+
sgid: attributes.attachable_sgid,
|
|
28
|
+
url: this.createBlobUrl(attributes.signed_id, attributes.filename)
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
createBlobUrl(signedId, filename) {
|
|
33
|
+
return this.blobUrlTemplate
|
|
34
|
+
.replace(":signed_id", signedId)
|
|
35
|
+
.replace(":filename", encodeURIComponent(filename))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get directUploadUrl() {
|
|
39
|
+
return this.element.dataset.directUploadUrl
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get blobUrlTemplate() {
|
|
43
|
+
return this.element.dataset.blobUrlTemplate
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as Trix from "trix"
|
|
2
|
+
import { AttachmentUpload } from "./attachment_upload"
|
|
3
|
+
|
|
4
|
+
addEventListener("trix-attachment-add", event => {
|
|
5
|
+
const { attachment, target } = event
|
|
6
|
+
|
|
7
|
+
if (attachment.file) {
|
|
8
|
+
const upload = new AttachmentUpload(attachment, target)
|
|
9
|
+
upload.start()
|
|
10
|
+
}
|
|
11
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The RichText record holds the content produced by the Trix editor in a serialized `body` attribute.
|
|
4
|
+
# It also holds all the references to the embedded files, which are stored using Active Storage.
|
|
5
|
+
# This record is then associated with the Active Record model the application desires to have
|
|
6
|
+
# rich text content using the `has_rich_text` class method.
|
|
7
|
+
class ActionText::RichText < ActiveRecord::Base
|
|
8
|
+
self.table_name = "action_text_rich_texts"
|
|
9
|
+
|
|
10
|
+
serialize :body, ActionText::Content
|
|
11
|
+
delegate :to_s, :nil?, to: :body
|
|
12
|
+
|
|
13
|
+
belongs_to :record, polymorphic: true, touch: true
|
|
14
|
+
has_many_attached :embeds
|
|
15
|
+
|
|
16
|
+
before_save do
|
|
17
|
+
self.embeds = body.attachments.map(&:attachable) if body.present?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_plain_text
|
|
21
|
+
body&.to_plain_text.to_s
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
delegate :blank?, :empty?, :present?, to: :to_plain_text
|
|
25
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= "☒" -%>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<figure class="attachment attachment--preview">
|
|
2
|
+
<%= image_tag(remote_image.url, width: remote_image.width, height: remote_image.height) %>
|
|
3
|
+
<% if caption = remote_image.try(:caption) %>
|
|
4
|
+
<figcaption class="attachment__caption">
|
|
5
|
+
<%= caption %>
|
|
6
|
+
</figcaption>
|
|
7
|
+
<% end %>
|
|
8
|
+
</figure>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>">
|
|
2
|
+
<% if blob.representable? %>
|
|
3
|
+
<%= image_tag blob.representation(resize_to_fit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>
|
|
4
|
+
<% end %>
|
|
5
|
+
|
|
6
|
+
<figcaption class="attachment__caption">
|
|
7
|
+
<% if caption = blob.try(:caption) %>
|
|
8
|
+
<%= caption %>
|
|
9
|
+
<% else %>
|
|
10
|
+
<span class="attachment__name"><%= blob.filename %></span>
|
|
11
|
+
<span class="attachment__size"><%= number_to_human_size blob.byte_size %></span>
|
|
12
|
+
<% end %>
|
|
13
|
+
</figcaption>
|
|
14
|
+
</figure>
|
data/bin/test
ADDED
data/bin/webpack
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'webpack' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require "pathname"
|
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
|
13
|
+
Pathname.new(__FILE__).realpath)
|
|
14
|
+
|
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
|
16
|
+
|
|
17
|
+
if File.file?(bundle_binstub)
|
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
|
19
|
+
load(bundle_binstub)
|
|
20
|
+
else
|
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
require "rubygems"
|
|
27
|
+
require "bundler/setup"
|
|
28
|
+
|
|
29
|
+
load Gem.bin_path("webpacker", "webpack")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'webpack-dev-server' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require "pathname"
|
|
12
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
|
13
|
+
Pathname.new(__FILE__).realpath)
|
|
14
|
+
|
|
15
|
+
bundle_binstub = File.expand_path("../bundle", __FILE__)
|
|
16
|
+
|
|
17
|
+
if File.file?(bundle_binstub)
|
|
18
|
+
if File.read(bundle_binstub, 150) =~ /This file was generated by Bundler/
|
|
19
|
+
load(bundle_binstub)
|
|
20
|
+
else
|
|
21
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
22
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
require "rubygems"
|
|
27
|
+
require "bundler/setup"
|
|
28
|
+
|
|
29
|
+
load Gem.bin_path("webpacker", "webpack-dev-server")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class CreateActionTextTables < ActiveRecord::Migration[5.2]
|
|
2
|
+
def change
|
|
3
|
+
create_table :action_text_rich_texts do |t|
|
|
4
|
+
t.string :name, null: false
|
|
5
|
+
t.text :body, limit: 16777215
|
|
6
|
+
t.references :record, null: false, polymorphic: true, index: false
|
|
7
|
+
|
|
8
|
+
t.datetime :created_at, null: false
|
|
9
|
+
t.datetime :updated_at, null: false
|
|
10
|
+
|
|
11
|
+
t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionText
|
|
4
|
+
module Attachable
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
LOCATOR_NAME = "attachable"
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def from_node(node)
|
|
11
|
+
if attachable = attachable_from_sgid(node["sgid"])
|
|
12
|
+
attachable
|
|
13
|
+
elsif attachable = ActionText::Attachables::ContentAttachment.from_node(node)
|
|
14
|
+
attachable
|
|
15
|
+
elsif attachable = ActionText::Attachables::RemoteImage.from_node(node)
|
|
16
|
+
attachable
|
|
17
|
+
else
|
|
18
|
+
ActionText::Attachables::MissingAttachable
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def from_attachable_sgid(sgid, options = {})
|
|
23
|
+
method = sgid.is_a?(Array) ? :locate_many_signed : :locate_signed
|
|
24
|
+
record = GlobalID::Locator.public_send(method, sgid, options.merge(for: LOCATOR_NAME))
|
|
25
|
+
record or raise ActiveRecord::RecordNotFound
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
def attachable_from_sgid(sgid)
|
|
30
|
+
from_attachable_sgid(sgid)
|
|
31
|
+
rescue ActiveRecord::RecordNotFound
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class_methods do
|
|
37
|
+
def from_attachable_sgid(sgid)
|
|
38
|
+
ActionText::Attachable.from_attachable_sgid(sgid, only: self)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def attachable_sgid
|
|
43
|
+
to_sgid(expires_in: nil, for: LOCATOR_NAME).to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def attachable_content_type
|
|
47
|
+
try(:content_type) || "application/octet-stream"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def attachable_filename
|
|
51
|
+
filename.to_s if respond_to?(:filename)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def attachable_filesize
|
|
55
|
+
try(:byte_size) || try(:filesize)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def attachable_metadata
|
|
59
|
+
try(:metadata) || {}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def previewable_attachable?
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def as_json(*)
|
|
67
|
+
super.merge(attachable_sgid: attachable_sgid)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_rich_text_attributes(attributes = {})
|
|
71
|
+
attributes.dup.tap do |attrs|
|
|
72
|
+
attrs[:sgid] = attachable_sgid
|
|
73
|
+
attrs[:content_type] = attachable_content_type
|
|
74
|
+
attrs[:previewable] = true if previewable_attachable?
|
|
75
|
+
attrs[:filename] = attachable_filename
|
|
76
|
+
attrs[:filesize] = attachable_filesize
|
|
77
|
+
attrs[:width] = attachable_metadata[:width]
|
|
78
|
+
attrs[:height] = attachable_metadata[:height]
|
|
79
|
+
end.compact
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|