actiontext 7.1.5.2 → 8.1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -132
- data/app/assets/javascripts/actiontext.esm.js +114 -14
- data/app/assets/javascripts/actiontext.js +120 -17
- data/app/helpers/action_text/content_helper.rb +2 -0
- data/app/helpers/action_text/tag_helper.rb +63 -37
- data/app/javascript/actiontext/attachment_upload.js +78 -12
- data/app/javascript/actiontext/index.js +10 -1
- data/app/models/action_text/encrypted_rich_text.rb +2 -2
- data/app/models/action_text/record.rb +2 -0
- data/app/models/action_text/rich_text.rb +62 -27
- data/db/migrate/20180528164100_create_action_text_tables.rb +1 -1
- data/lib/action_text/attachable.rb +35 -33
- data/lib/action_text/attachables/content_attachment.rb +2 -0
- data/lib/action_text/attachables/missing_attachable.rb +2 -0
- data/lib/action_text/attachables/remote_image.rb +2 -0
- data/lib/action_text/attachment.rb +27 -25
- data/lib/action_text/attachment_gallery.rb +2 -0
- data/lib/action_text/attachments/caching.rb +2 -0
- data/lib/action_text/attachments/minification.rb +2 -0
- data/lib/action_text/attachments/trix_conversion.rb +2 -0
- data/lib/action_text/attribute.rb +61 -27
- data/lib/action_text/content.rb +49 -28
- data/lib/action_text/deprecator.rb +2 -0
- data/lib/action_text/encryption.rb +2 -0
- data/lib/action_text/engine.rb +7 -2
- data/lib/action_text/fixture_set.rb +35 -35
- data/lib/action_text/fragment.rb +4 -0
- data/lib/action_text/gem_version.rb +6 -4
- data/lib/action_text/html_conversion.rb +2 -0
- data/lib/action_text/plain_text_conversion.rb +65 -28
- data/lib/action_text/rendering.rb +2 -1
- data/lib/action_text/serialization.rb +2 -0
- data/lib/action_text/system_test_helper.rb +52 -33
- data/lib/action_text/trix_attachment.rb +2 -0
- data/lib/action_text/version.rb +3 -1
- data/lib/generators/action_text/install/install_generator.rb +4 -21
- data/lib/generators/action_text/install/templates/actiontext.css +414 -5
- data/lib/rails/generators/test_unit/install_generator.rb +2 -0
- data/package.json +3 -2
- metadata +28 -16
- data/app/assets/javascripts/trix.js +0 -13720
- data/app/assets/stylesheets/trix.css +0 -412
|
@@ -1,68 +1,76 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionText
|
|
4
6
|
module PlainTextConversion
|
|
5
7
|
extend self
|
|
6
8
|
|
|
7
9
|
def node_to_plain_text(node)
|
|
8
|
-
|
|
10
|
+
BottomUpReducer.new(node).reduce do |n, child_values|
|
|
11
|
+
plain_text_for_node(n, child_values)
|
|
12
|
+
end.then(&method(:remove_trailing_newlines))
|
|
9
13
|
end
|
|
10
14
|
|
|
11
15
|
private
|
|
12
|
-
def plain_text_for_node(node,
|
|
16
|
+
def plain_text_for_node(node, child_values)
|
|
13
17
|
if respond_to?(plain_text_method_for_node(node), true)
|
|
14
|
-
send(plain_text_method_for_node(node), node,
|
|
18
|
+
send(plain_text_method_for_node(node), node, child_values)
|
|
15
19
|
else
|
|
16
|
-
|
|
20
|
+
plain_text_for_child_values(child_values)
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
def plain_text_for_node_children(node)
|
|
21
|
-
texts = []
|
|
22
|
-
node.children.each_with_index do |child, index|
|
|
23
|
-
texts << plain_text_for_node(child, index)
|
|
24
|
-
end
|
|
25
|
-
texts.join
|
|
26
|
-
end
|
|
27
|
-
|
|
28
24
|
def plain_text_method_for_node(node)
|
|
29
25
|
:"plain_text_for_#{node.name}_node"
|
|
30
26
|
end
|
|
31
27
|
|
|
32
|
-
def
|
|
33
|
-
|
|
28
|
+
def plain_text_for_child_values(child_values)
|
|
29
|
+
child_values.join
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def plain_text_for_unsupported_node(node, _child_values)
|
|
33
|
+
""
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
%i[ script style].each do |element|
|
|
37
|
+
alias_method :"plain_text_for_#{element}_node", :plain_text_for_unsupported_node
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def plain_text_for_block(node, child_values)
|
|
41
|
+
"#{remove_trailing_newlines(plain_text_for_child_values(child_values))}\n\n"
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
%i[ h1 p ].each do |element|
|
|
37
45
|
alias_method :"plain_text_for_#{element}_node", :plain_text_for_block
|
|
38
46
|
end
|
|
39
47
|
|
|
40
|
-
def plain_text_for_list(node,
|
|
41
|
-
"#{break_if_nested_list(node, plain_text_for_block(node))}"
|
|
48
|
+
def plain_text_for_list(node, child_values)
|
|
49
|
+
"#{break_if_nested_list(node, plain_text_for_block(node, child_values))}"
|
|
42
50
|
end
|
|
43
51
|
|
|
44
52
|
%i[ ul ol ].each do |element|
|
|
45
53
|
alias_method :"plain_text_for_#{element}_node", :plain_text_for_list
|
|
46
54
|
end
|
|
47
55
|
|
|
48
|
-
def plain_text_for_br_node(node,
|
|
56
|
+
def plain_text_for_br_node(node, _child_values)
|
|
49
57
|
"\n"
|
|
50
58
|
end
|
|
51
59
|
|
|
52
|
-
def plain_text_for_text_node(node,
|
|
60
|
+
def plain_text_for_text_node(node, _child_values)
|
|
53
61
|
remove_trailing_newlines(node.text)
|
|
54
62
|
end
|
|
55
63
|
|
|
56
|
-
def plain_text_for_div_node(node,
|
|
57
|
-
"#{remove_trailing_newlines(
|
|
64
|
+
def plain_text_for_div_node(node, child_values)
|
|
65
|
+
"#{remove_trailing_newlines(plain_text_for_child_values(child_values))}\n"
|
|
58
66
|
end
|
|
59
67
|
|
|
60
|
-
def plain_text_for_figcaption_node(node,
|
|
61
|
-
"[#{remove_trailing_newlines(
|
|
68
|
+
def plain_text_for_figcaption_node(node, child_values)
|
|
69
|
+
"[#{remove_trailing_newlines(plain_text_for_child_values(child_values))}]"
|
|
62
70
|
end
|
|
63
71
|
|
|
64
|
-
def plain_text_for_blockquote_node(node,
|
|
65
|
-
text = plain_text_for_block(node)
|
|
72
|
+
def plain_text_for_blockquote_node(node, child_values)
|
|
73
|
+
text = plain_text_for_block(node, child_values)
|
|
66
74
|
return "“”" if text.blank?
|
|
67
75
|
|
|
68
76
|
text = text.dup
|
|
@@ -71,9 +79,9 @@ module ActionText
|
|
|
71
79
|
text
|
|
72
80
|
end
|
|
73
81
|
|
|
74
|
-
def plain_text_for_li_node(node,
|
|
75
|
-
bullet = bullet_for_li_node(node
|
|
76
|
-
text = remove_trailing_newlines(
|
|
82
|
+
def plain_text_for_li_node(node, child_values)
|
|
83
|
+
bullet = bullet_for_li_node(node)
|
|
84
|
+
text = remove_trailing_newlines(plain_text_for_child_values(child_values))
|
|
77
85
|
indentation = indentation_for_li_node(node)
|
|
78
86
|
|
|
79
87
|
"#{indentation}#{bullet} #{text}\n"
|
|
@@ -83,8 +91,9 @@ module ActionText
|
|
|
83
91
|
text.chomp("")
|
|
84
92
|
end
|
|
85
93
|
|
|
86
|
-
def bullet_for_li_node(node
|
|
94
|
+
def bullet_for_li_node(node)
|
|
87
95
|
if list_node_name_for_li_node(node) == "ol"
|
|
96
|
+
index = node.parent.elements.index(node)
|
|
88
97
|
"#{index + 1}."
|
|
89
98
|
else
|
|
90
99
|
"•"
|
|
@@ -113,5 +122,33 @@ module ActionText
|
|
|
113
122
|
text
|
|
114
123
|
end
|
|
115
124
|
end
|
|
125
|
+
|
|
126
|
+
class BottomUpReducer # :nodoc:
|
|
127
|
+
def initialize(node)
|
|
128
|
+
@node = node
|
|
129
|
+
@values = {}
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def reduce(&block)
|
|
133
|
+
traverse_bottom_up(@node) do |n|
|
|
134
|
+
child_values = @values.values_at(*n.children)
|
|
135
|
+
@values[n] = block.call(n, child_values)
|
|
136
|
+
end
|
|
137
|
+
@values[@node]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
def traverse_bottom_up(node, &block)
|
|
142
|
+
call_stack, processing_stack = [ node ], []
|
|
143
|
+
|
|
144
|
+
until call_stack.empty?
|
|
145
|
+
node = call_stack.pop
|
|
146
|
+
processing_stack.push(node)
|
|
147
|
+
call_stack.concat node.children
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
processing_stack.reverse_each(&block)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
116
153
|
end
|
|
117
154
|
end
|
|
@@ -1,55 +1,74 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
module ActionText
|
|
4
6
|
module SystemTestHelper
|
|
5
7
|
# Locates a Trix editor and fills it in with the given HTML.
|
|
6
8
|
#
|
|
7
9
|
# The editor can be found by:
|
|
8
|
-
#
|
|
9
|
-
# *
|
|
10
|
-
# *
|
|
11
|
-
# * its
|
|
12
|
-
# *
|
|
10
|
+
#
|
|
11
|
+
# * its `id`
|
|
12
|
+
# * its `placeholder`
|
|
13
|
+
# * the text from its `label` element
|
|
14
|
+
# * its `aria-label`
|
|
15
|
+
# * the `name` of its input
|
|
16
|
+
#
|
|
17
|
+
# Additional options are forwarded to Capybara as filters
|
|
13
18
|
#
|
|
14
19
|
# Examples:
|
|
15
20
|
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
21
|
+
# # <trix-editor id="message_content" ...></trix-editor>
|
|
22
|
+
# fill_in_rich_textarea "message_content", with: "Hello <em>world!</em>"
|
|
18
23
|
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
24
|
+
# # <trix-editor placeholder="Your message here" ...></trix-editor>
|
|
25
|
+
# fill_in_rich_textarea "Your message here", with: "Hello <em>world!</em>"
|
|
21
26
|
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
27
|
+
# # <label for="message_content">Message content</label>
|
|
28
|
+
# # <trix-editor id="message_content" ...></trix-editor>
|
|
29
|
+
# fill_in_rich_textarea "Message content", with: "Hello <em>world!</em>"
|
|
25
30
|
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
31
|
+
# # <trix-editor aria-label="Message content" ...></trix-editor>
|
|
32
|
+
# fill_in_rich_textarea "Message content", with: "Hello <em>world!</em>"
|
|
28
33
|
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
def
|
|
33
|
-
find(:
|
|
34
|
+
# # <input id="trix_input_1" name="message[content]" type="hidden">
|
|
35
|
+
# # <trix-editor input="trix_input_1"></trix-editor>
|
|
36
|
+
# fill_in_rich_textarea "message[content]", with: "Hello <em>world!</em>"
|
|
37
|
+
def fill_in_rich_textarea(locator = nil, with:, **)
|
|
38
|
+
find(:rich_textarea, locator, **).execute_script(<<~JS, with.to_s)
|
|
39
|
+
if ("value" in this) {
|
|
40
|
+
this.value = arguments[0]
|
|
41
|
+
} else {
|
|
42
|
+
this.editor.loadHTML(arguments[0])
|
|
43
|
+
}
|
|
44
|
+
JS
|
|
34
45
|
end
|
|
46
|
+
alias_method :fill_in_rich_text_area, :fill_in_rich_textarea
|
|
35
47
|
end
|
|
36
48
|
end
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
XPath.descendant
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
50
|
+
%i[rich_textarea rich_text_area].each do |rich_textarea|
|
|
51
|
+
Capybara.add_selector rich_textarea do
|
|
52
|
+
label "rich-text area"
|
|
53
|
+
xpath do |locator|
|
|
54
|
+
xpath = XPath.descendant[[
|
|
55
|
+
XPath.attribute(:role) == "textbox",
|
|
56
|
+
(XPath.attribute(:contenteditable) == "") | (XPath.attribute(:contenteditable) == "true")
|
|
57
|
+
].reduce(:&)]
|
|
58
|
+
|
|
59
|
+
if locator.nil?
|
|
60
|
+
xpath
|
|
61
|
+
else
|
|
62
|
+
input_located_by_name = XPath.anywhere(:input).where(XPath.attr(:name) == locator).attr(:id)
|
|
63
|
+
input_located_by_label = XPath.anywhere(:label).where(XPath.string.n.is(locator)).attr(:for)
|
|
46
64
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
xpath.where \
|
|
66
|
+
XPath.attr(:id).equals(locator) |
|
|
67
|
+
XPath.attr(:placeholder).equals(locator) |
|
|
68
|
+
XPath.attr(:"aria-label").equals(locator) |
|
|
69
|
+
XPath.attr(:input).equals(input_located_by_name) |
|
|
70
|
+
XPath.attr(:id).equals(input_located_by_label)
|
|
71
|
+
end
|
|
53
72
|
end
|
|
54
73
|
end
|
|
55
74
|
end
|
data/lib/action_text/version.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require_relative "gem_version"
|
|
4
6
|
|
|
5
7
|
module ActionText
|
|
6
|
-
# Returns the currently loaded version of Action Text as a
|
|
8
|
+
# Returns the currently loaded version of Action Text as a `Gem::Version`.
|
|
7
9
|
def self.version
|
|
8
10
|
gem_version
|
|
9
11
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# :markup: markdown
|
|
4
|
+
|
|
3
5
|
require "pathname"
|
|
4
6
|
require "json"
|
|
5
7
|
|
|
@@ -34,20 +36,8 @@ module ActionText
|
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
def create_actiontext_files
|
|
37
|
-
destination = Pathname(destination_root)
|
|
38
|
-
|
|
39
39
|
template "actiontext.css", "app/assets/stylesheets/actiontext.css"
|
|
40
40
|
|
|
41
|
-
unless destination.join("app/assets/application.css").exist?
|
|
42
|
-
if (stylesheets = Dir.glob "#{destination_root}/app/assets/stylesheets/application.*.{scss,css}").length > 0
|
|
43
|
-
insert_into_file stylesheets.first.to_s, %(@import 'actiontext.css';)
|
|
44
|
-
else
|
|
45
|
-
say <<~INSTRUCTIONS, :green
|
|
46
|
-
To use the Trix editor, you must require 'app/assets/stylesheets/actiontext.css' in your base stylesheet.
|
|
47
|
-
INSTRUCTIONS
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
41
|
gem_root = "#{__dir__}/../../../.."
|
|
52
42
|
|
|
53
43
|
copy_file "#{gem_root}/app/views/active_storage/blobs/_blob.html.erb",
|
|
@@ -57,13 +47,6 @@ module ActionText
|
|
|
57
47
|
"app/views/layouts/action_text/contents/_content.html.erb"
|
|
58
48
|
end
|
|
59
49
|
|
|
60
|
-
def enable_image_processing_gem
|
|
61
|
-
if (gemfile_path = Pathname(destination_root).join("Gemfile")).exist?
|
|
62
|
-
say "Ensure image_processing gem has been enabled so image uploads will work (remember to bundle!)"
|
|
63
|
-
uncomment_lines gemfile_path, /gem "image_processing"/
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
|
|
67
50
|
def create_migrations
|
|
68
51
|
rails_command "railties:install:migrations FROM=active_storage,action_text", inline: true
|
|
69
52
|
end
|
|
@@ -73,8 +56,8 @@ module ActionText
|
|
|
73
56
|
end
|
|
74
57
|
|
|
75
58
|
def using_bun?
|
|
76
|
-
# Cannot assume yarn.lock has been generated yet so we look for
|
|
77
|
-
#
|
|
59
|
+
# Cannot assume yarn.lock has been generated yet so we look for a file known to
|
|
60
|
+
# be generated by the jsbundling-rails gem
|
|
78
61
|
@using_bun ||= using_js_runtime? && Pathname(destination_root).join("bun.config.js").exist?
|
|
79
62
|
end
|
|
80
63
|
|