Skip to content

Commit 0b1f83d

Browse files
swansonMatt Swanson
andauthored
Better ActionText plain text output for nested lists (rails#37976)
* Improve plaintext output for nested lists * Update plain_text_conversion_test.rb * Add additional test cases * Refactor a bit * Add changelog entry * Rearrange methods Co-authored-by: Matt Swanson <[email protected]>
1 parent dedefdd commit 0b1f83d

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

actiontext/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Fix an issue with how nested lists were displayed when converting to plain text
2+
3+
*Matt Swanson*
4+
15
* Allow passing in a custom `direct_upload_url` or `blob_url_template` to `rich_text_area_tag`.
26

37
*Lucas Mansur*

actiontext/lib/action_text/plain_text_conversion.rb

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,18 @@ def plain_text_for_block(node, index = 0)
3333
"#{remove_trailing_newlines(plain_text_for_node_children(node))}\n\n"
3434
end
3535

36-
%i[ h1 p ul ol ].each do |element|
36+
%i[ h1 p ].each do |element|
3737
alias_method :"plain_text_for_#{element}_node", :plain_text_for_block
3838
end
3939

40+
def plain_text_for_list(node, index)
41+
"#{break_if_nested_list(node, plain_text_for_block(node))}"
42+
end
43+
44+
%i[ ul ol ].each do |element|
45+
alias_method :"plain_text_for_#{element}_node", :plain_text_for_list
46+
end
47+
4048
def plain_text_for_br_node(node, index)
4149
"\n"
4250
end
@@ -61,7 +69,9 @@ def plain_text_for_blockquote_node(node, index)
6169
def plain_text_for_li_node(node, index)
6270
bullet = bullet_for_li_node(node, index)
6371
text = remove_trailing_newlines(plain_text_for_node_children(node))
64-
"#{bullet} #{text}\n"
72+
indentation = indentation_for_li_node(node)
73+
74+
"#{indentation}#{bullet} #{text}\n"
6575
end
6676

6777
def remove_trailing_newlines(text)
@@ -79,5 +89,24 @@ def bullet_for_li_node(node, index)
7989
def list_node_name_for_li_node(node)
8090
node.ancestors.lazy.map(&:name).grep(/^[uo]l$/).first
8191
end
92+
93+
def indentation_for_li_node(node)
94+
depth = list_node_depth_for_node(node)
95+
if depth > 1
96+
" " * (depth - 1)
97+
end
98+
end
99+
100+
def list_node_depth_for_node(node)
101+
node.ancestors.map(&:name).grep(/^[uo]l$/).count
102+
end
103+
104+
def break_if_nested_list(node, text)
105+
if list_node_depth_for_node(node) > 0
106+
"\n#{text}"
107+
else
108+
text
109+
end
110+
end
82111
end
83112
end

actiontext/test/unit/plain_text_conversion_test.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ class ActionText::PlainTextConversionTest < ActiveSupport::TestCase
5252
)
5353
end
5454

55+
test "basic nested <ul> tags are indented" do
56+
assert_converted_to(
57+
"• Item 1\n • Item 2",
58+
"<ul><li>Item 1<ul><li>Item 2</li></ul></li></ul>"
59+
)
60+
end
61+
62+
test "basic nested <ol> tags are indented" do
63+
assert_converted_to(
64+
"1. Item 1\n 1. Item 2",
65+
"<ol><li>Item 1<ol><li>Item 2</li></ol></li></ol>"
66+
)
67+
end
68+
69+
test "complex nested / mixed list tags are indented" do
70+
assert_converted_to(
71+
"• Item 0\n• Item 1\n • Item A\n 1. Item i\n 2. Item ii\n • Item B\n • Item i\n• Item 2",
72+
"<ul><li>Item 0</li><li>Item 1<ul><li>Item A<ol><li>Item i</li><li>Item ii</li></ol></li><li>Item B<ul><li>Item i</li></ul></li></ul></li><li>Item 2</li></ul>"
73+
)
74+
end
75+
5576
test "<br> tags are separated by one new line" do
5677
assert_converted_to(
5778
"Hello world!\none\ntwo\nthree",

0 commit comments

Comments
 (0)