diff --git a/app/controllers/administrateurs/attestation_template_v2s_controller.rb b/app/controllers/administrateurs/attestation_template_v2s_controller.rb index 276fabbeb..d432f6b58 100644 --- a/app/controllers/administrateurs/attestation_template_v2s_controller.rb +++ b/app/controllers/administrateurs/attestation_template_v2s_controller.rb @@ -4,7 +4,7 @@ module Administrateurs def show 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| format.html do diff --git a/app/services/tiptap_service.rb b/app/services/tiptap_service.rb index d1a2930bc..0f50ecc3d 100644 --- a/app/services/tiptap_service.rb +++ b/app/services/tiptap_service.rb @@ -1,76 +1,83 @@ class TiptapService - class << self - def to_html(node, tags) - return '' if node.nil? + def to_html(node, tags) + return '' if node.nil? - children(node[:content], tags) + children(node[:content], tags, 0) + end + + private + + def initialize + @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 - private - - def children(content, tags) - content.map { node_to_html(_1, tags) }.join - end - - def node_to_html(node, tags) - case node - in type: 'header', content: - "
#{children(content, tags)}
" - in type: 'footer', content:, **rest - "#{children(content, tags)}" - in type: 'headerColumn', content:, **rest - "#{children(content, tags)}" - in type: 'paragraph', content:, **rest - "#{children(content, tags)}

" - in type: 'title', content:, **rest - "#{children(content, tags)}" - in type: 'heading', attrs: { level:, **attrs }, content: - "#{children(content, tags)}" - in type: 'bulletList', content: - "
    #{children(content, tags)}
" - in type: 'orderedList', content: - "
    #{children(content, tags)}
" - in type: 'listItem', content: - "
  • #{children(content, tags)}
  • " - in type: 'text', text:, **rest - if rest[:marks].present? - apply_marks(text, rest[:marks]) - else - text - end - in type: 'mention', attrs: { id: }, **rest - if rest[:marks].present? - apply_marks(tags[id], rest[:marks]) - else - tags[id] - end - in { type: type } if ["paragraph", "title", "heading"].include?(type) && !node.key?(:content) - # noop - end - end - - def text_align(attrs) - if attrs.present? && attrs[:textAlign].present? - " style=\"text-align: #{attrs[:textAlign]}\"" + case node + in type: 'header', content: + "
    #{children(content, tags, level + 1)}
    " + in type: 'footer', content:, **rest + "#{children(content, tags, level + 1)}" + in type: 'headerColumn', content:, **rest + "#{children(content, tags, level + 1)}" + in type: 'paragraph', content:, **rest + "#{children(content, tags, level + 1)}

    " + in type: 'title', content:, **rest + "#{children(content, tags, level + 1)}" + in type: 'heading', attrs: { level: hlevel, **attrs }, content: + "#{children(content, tags, level + 1)}" + in type: 'bulletList', content: + "
      #{children(content, tags, level + 1)}
    " + in type: 'orderedList', content: + "
      #{children(content, tags, level + 1)}
    " + in type: 'listItem', content: + "
  • #{children(content, tags, level + 1)}
  • " + in type: 'text', text:, **rest + if rest[:marks].present? + apply_marks(text, rest[:marks]) else - "" + text end + in type: 'mention', attrs: { id: }, **rest + if rest[:marks].present? + apply_marks(tags[id], rest[:marks]) + else + tags[id] + end + in { type: type } if ["paragraph", "title", "heading"].include?(type) && !node.key?(:content) + # noop end + end - def apply_marks(text, marks) - marks.reduce(text) do |text, mark| - case mark - in type: 'bold' - "#{text}" - in type: 'italic' - "#{text}" - in type: 'underline' - "#{text}" - in type: 'strike' - "#{text}" - in type: 'highlight' - "#{text}" - end + def text_align(attrs) + if attrs.present? && attrs[:textAlign].present? + " style=\"text-align: #{attrs[:textAlign]}\"" + else + "" + end + end + + def apply_marks(text, marks) + marks.reduce(text) do |text, mark| + case mark + in type: 'bold' + "#{text}" + in type: 'italic' + "#{text}" + in type: 'underline' + "#{text}" + in type: 'strike' + "#{text}" + in type: 'highlight' + "#{text}" end end end diff --git a/spec/services/tiptap_service_spec.rb b/spec/services/tiptap_service_spec.rb index bb3c1587a..37216b664 100644 --- a/spec/services/tiptap_service_spec.rb +++ b/spec/services/tiptap_service_spec.rb @@ -25,18 +25,28 @@ RSpec.describe TiptapService do type: 'title' # remained empty in editor }, { - type: 'paragraph', - attrs: { textAlign: 'right' }, - content: [ - { - type: 'text', - text: 'Hello world!' - } - ] + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Heading 1' }] }, { - type: 'paragraph' - # no content, empty line + 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: 'paragraph', + attrs: { textAlign: 'right' }, + content: [{ type: 'text', text: 'First paragraph' }] }, { type: 'paragraph', @@ -63,23 +73,8 @@ RSpec.describe TiptapService do ] }, { - type: 'heading', - attrs: { level: 1 }, - 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: 'paragraph' + # no content, empty line }, { type: 'bulletList', @@ -157,13 +152,13 @@ RSpec.describe TiptapService do let(:tags) { { 'name' => 'Paul' } } let(:html) do [ - '
    Left
    Right
    ', + '
    Left
    Right
    ', '

    Title

    ', - '

    Hello world!

    ', - '

    Bonjour Paul !

    ', '

    Heading 1

    ', '

    Heading 2

    ', '

    Heading 3

    ', + '

    First paragraph

    ', + '

    Bonjour Paul !

    ', '
    • Item 1

    • Item 2

    ', '
    1. Item 1

    2. Item 2

    ', '' @@ -171,7 +166,7 @@ RSpec.describe TiptapService do end 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