actiontext5 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|