# frozen_string_literal: true
class TiptapService
# NOTE: node must be deep symbolized keys
def self.used_tags_and_libelle_for(node, tags = Set.new)
case node
in type: 'mention', attrs: { id:, label: }, **rest
tags << [id, label]
in { content:, **rest } if content.is_a?(Array)
content.each { used_tags_and_libelle_for(_1, tags) }
in type:, **rest
# noop
end
tags
end
def to_html(node, substitutions = {})
return '' if node.nil?
children(node[:content], substitutions, 0)
end
def to_texts_and_tags(node, substitutions = {})
return '' if node.nil?
children_texts_and_tags(node[:content], substitutions)
end
private
def initialize
@body_started = false
end
def children_texts_and_tags(content, substitutions)
content.map { node_to_texts_and_tags(_1, substitutions) }.join
end
def node_to_texts_and_tags(node, substitutions)
case node
in type: 'paragraph', content:
children_texts_and_tags(content, substitutions)
in type: 'paragraph' # empty paragraph
''
in type: 'text', text:
text.strip
in type: 'mention', attrs: { id:, label: }
if substitutions.present?
substitutions.fetch(id) { "--#{id}--" }
else
"#{label}"
end
end
end
def children(content, substitutions, level)
content.map { node_to_html(_1, substitutions, level) }.join
end
def node_to_html(node, substitutions, level)
if level == 0 && !@body_started && node[:type].in?(['paragraph', 'heading']) && node.key?(:content)
@body_started = true
body_start_mark = " class=\"body-start\""
end
case node
in type: 'header', content:
"
#{children(content, substitutions, level + 1)}
" in type: 'title', content:, **rest "