feat(tiptap): detect first body paragraph for spacing, handle empty nodes
This commit is contained in:
parent
eaf4e24a55
commit
16cdff8425
3 changed files with 99 additions and 97 deletions
|
@ -4,7 +4,7 @@ module Administrateurs
|
||||||
|
|
||||||
def show
|
def show
|
||||||
json_body = @attestation_template.json_body&.deep_symbolize_keys
|
json_body = @attestation_template.json_body&.deep_symbolize_keys
|
||||||
@body = TiptapService.to_html(json_body, {})
|
@body = TiptapService.new.to_html(json_body, {})
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
|
|
|
@ -1,37 +1,45 @@
|
||||||
class TiptapService
|
class TiptapService
|
||||||
class << self
|
|
||||||
def to_html(node, tags)
|
def to_html(node, tags)
|
||||||
return '' if node.nil?
|
return '' if node.nil?
|
||||||
|
|
||||||
children(node[:content], tags)
|
children(node[:content], tags, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def children(content, tags)
|
def initialize
|
||||||
content.map { node_to_html(_1, tags) }.join
|
@body_started = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def children(content, tags, level)
|
||||||
|
content.map { node_to_html(_1, tags, level) }.join
|
||||||
|
end
|
||||||
|
|
||||||
|
def node_to_html(node, tags, level)
|
||||||
|
if level == 0 && !@body_started && node[:type] == 'paragraph' && node.key?(:content)
|
||||||
|
@body_started = true
|
||||||
|
body_start_mark = " class=\"body-start\""
|
||||||
end
|
end
|
||||||
|
|
||||||
def node_to_html(node, tags)
|
|
||||||
case node
|
case node
|
||||||
in type: 'header', content:
|
in type: 'header', content:
|
||||||
"<header>#{children(content, tags)}</header>"
|
"<header>#{children(content, tags, level + 1)}</header>"
|
||||||
in type: 'footer', content:, **rest
|
in type: 'footer', content:, **rest
|
||||||
"<footer#{text_align(rest[:attrs])}>#{children(content, tags)}</footer>"
|
"<footer#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</footer>"
|
||||||
in type: 'headerColumn', content:, **rest
|
in type: 'headerColumn', content:, **rest
|
||||||
"<div#{text_align(rest[:attrs])} class=\"column\">#{children(content, tags)}</div>"
|
"<div#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</div>"
|
||||||
in type: 'paragraph', content:, **rest
|
in type: 'paragraph', content:, **rest
|
||||||
"<p#{text_align(rest[:attrs])}>#{children(content, tags)}</p>"
|
"<p#{body_start_mark}#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</p>"
|
||||||
in type: 'title', content:, **rest
|
in type: 'title', content:, **rest
|
||||||
"<h1#{text_align(rest[:attrs])}>#{children(content, tags)}</h1>"
|
"<h1#{text_align(rest[:attrs])}>#{children(content, tags, level + 1)}</h1>"
|
||||||
in type: 'heading', attrs: { level:, **attrs }, content:
|
in type: 'heading', attrs: { level: hlevel, **attrs }, content:
|
||||||
"<h#{level}#{text_align(attrs)}>#{children(content, tags)}</h#{level}>"
|
"<h#{hlevel}#{text_align(attrs)}>#{children(content, tags, level + 1)}</h#{hlevel}>"
|
||||||
in type: 'bulletList', content:
|
in type: 'bulletList', content:
|
||||||
"<ul>#{children(content, tags)}</ul>"
|
"<ul>#{children(content, tags, level + 1)}</ul>"
|
||||||
in type: 'orderedList', content:
|
in type: 'orderedList', content:
|
||||||
"<ol>#{children(content, tags)}</ol>"
|
"<ol>#{children(content, tags, level + 1)}</ol>"
|
||||||
in type: 'listItem', content:
|
in type: 'listItem', content:
|
||||||
"<li>#{children(content, tags)}</li>"
|
"<li>#{children(content, tags, level + 1)}</li>"
|
||||||
in type: 'text', text:, **rest
|
in type: 'text', text:, **rest
|
||||||
if rest[:marks].present?
|
if rest[:marks].present?
|
||||||
apply_marks(text, rest[:marks])
|
apply_marks(text, rest[:marks])
|
||||||
|
@ -73,5 +81,4 @@ class TiptapService
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,18 +25,28 @@ RSpec.describe TiptapService do
|
||||||
type: 'title' # remained empty in editor
|
type: 'title' # remained empty in editor
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'paragraph',
|
type: 'heading',
|
||||||
attrs: { textAlign: 'right' },
|
attrs: { level: 1 },
|
||||||
content: [
|
content: [{ type: 'text', text: 'Heading 1' }]
|
||||||
{
|
|
||||||
type: 'text',
|
|
||||||
text: 'Hello world!'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'paragraph'
|
type: 'heading',
|
||||||
# no content, empty line
|
attrs: { level: 2, textAlign: 'center' },
|
||||||
|
content: [{ type: 'text', text: 'Heading 2' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'heading',
|
||||||
|
attrs: { level: 3 },
|
||||||
|
content: [{ type: 'text', text: 'Heading 3' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'heading',
|
||||||
|
attrs: { level: 3 } # remained empty in editor
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
attrs: { textAlign: 'right' },
|
||||||
|
content: [{ type: 'text', text: 'First paragraph' }]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
|
@ -63,23 +73,8 @@ RSpec.describe TiptapService do
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'heading',
|
type: 'paragraph'
|
||||||
attrs: { level: 1 },
|
# no content, empty line
|
||||||
content: [{ type: 'text', text: 'Heading 1' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'heading',
|
|
||||||
attrs: { level: 2, textAlign: 'center' },
|
|
||||||
content: [{ type: 'text', text: 'Heading 2' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'heading',
|
|
||||||
attrs: { level: 3 },
|
|
||||||
content: [{ type: 'text', text: 'Heading 3' }]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'heading',
|
|
||||||
attrs: { level: 3 } # remained empty in editor
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'bulletList',
|
type: 'bulletList',
|
||||||
|
@ -157,13 +152,13 @@ RSpec.describe TiptapService do
|
||||||
let(:tags) { { 'name' => 'Paul' } }
|
let(:tags) { { 'name' => 'Paul' } }
|
||||||
let(:html) do
|
let(:html) do
|
||||||
[
|
[
|
||||||
'<header><div class="column">Left</div><div class="column">Right</div></header>',
|
'<header><div>Left</div><div>Right</div></header>',
|
||||||
'<h1>Title</h1>',
|
'<h1>Title</h1>',
|
||||||
'<p style="text-align: right">Hello world!</p>',
|
|
||||||
'<p><s><em>Bonjour </em></s><u><strong>Paul</strong></u> <mark>!</mark></p>',
|
|
||||||
'<h1>Heading 1</h1>',
|
'<h1>Heading 1</h1>',
|
||||||
'<h2 style="text-align: center">Heading 2</h2>',
|
'<h2 style="text-align: center">Heading 2</h2>',
|
||||||
'<h3>Heading 3</h3>',
|
'<h3>Heading 3</h3>',
|
||||||
|
'<p class="body-start" style="text-align: right">First paragraph</p>',
|
||||||
|
'<p><s><em>Bonjour </em></s><u><strong>Paul</strong></u> <mark>!</mark></p>',
|
||||||
'<ul><li><p>Item 1</p></li><li><p>Item 2</p></li></ul>',
|
'<ul><li><p>Item 1</p></li><li><p>Item 2</p></li></ul>',
|
||||||
'<ol><li><p>Item 1</p></li><li><p>Item 2</p></li></ol>',
|
'<ol><li><p>Item 1</p></li><li><p>Item 2</p></li></ol>',
|
||||||
'<footer>Footer</footer>'
|
'<footer>Footer</footer>'
|
||||||
|
@ -171,7 +166,7 @@ RSpec.describe TiptapService do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns html' do
|
it 'returns html' do
|
||||||
expect(described_class.to_html(json, tags)).to eq(html)
|
expect(described_class.new.to_html(json, tags)).to eq(html)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue