coradoc-html 1.1.7

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.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/lib/coradoc/html/base.rb +157 -0
  4. data/lib/coradoc/html/config.rb +467 -0
  5. data/lib/coradoc/html/converter_base.rb +177 -0
  6. data/lib/coradoc/html/converters/admonition.rb +180 -0
  7. data/lib/coradoc/html/converters/attribute.rb +68 -0
  8. data/lib/coradoc/html/converters/attribute_reference.rb +60 -0
  9. data/lib/coradoc/html/converters/audio.rb +165 -0
  10. data/lib/coradoc/html/converters/base.rb +615 -0
  11. data/lib/coradoc/html/converters/bibliography.rb +82 -0
  12. data/lib/coradoc/html/converters/bibliography_entry.rb +108 -0
  13. data/lib/coradoc/html/converters/block_image.rb +72 -0
  14. data/lib/coradoc/html/converters/bold.rb +34 -0
  15. data/lib/coradoc/html/converters/break.rb +32 -0
  16. data/lib/coradoc/html/converters/comment_block.rb +42 -0
  17. data/lib/coradoc/html/converters/comment_line.rb +54 -0
  18. data/lib/coradoc/html/converters/cross_reference.rb +59 -0
  19. data/lib/coradoc/html/converters/document.rb +108 -0
  20. data/lib/coradoc/html/converters/example.rb +114 -0
  21. data/lib/coradoc/html/converters/highlight.rb +34 -0
  22. data/lib/coradoc/html/converters/include.rb +68 -0
  23. data/lib/coradoc/html/converters/inline_image.rb +41 -0
  24. data/lib/coradoc/html/converters/italic.rb +34 -0
  25. data/lib/coradoc/html/converters/line_break.rb +31 -0
  26. data/lib/coradoc/html/converters/link.rb +46 -0
  27. data/lib/coradoc/html/converters/list_item.rb +75 -0
  28. data/lib/coradoc/html/converters/listing.rb +99 -0
  29. data/lib/coradoc/html/converters/literal.rb +102 -0
  30. data/lib/coradoc/html/converters/monospace.rb +34 -0
  31. data/lib/coradoc/html/converters/open.rb +78 -0
  32. data/lib/coradoc/html/converters/ordered.rb +53 -0
  33. data/lib/coradoc/html/converters/paragraph.rb +46 -0
  34. data/lib/coradoc/html/converters/quote.rb +113 -0
  35. data/lib/coradoc/html/converters/reviewer_comment.rb +74 -0
  36. data/lib/coradoc/html/converters/reviewer_note.rb +134 -0
  37. data/lib/coradoc/html/converters/section.rb +90 -0
  38. data/lib/coradoc/html/converters/sidebar.rb +113 -0
  39. data/lib/coradoc/html/converters/source.rb +137 -0
  40. data/lib/coradoc/html/converters/source_code.rb +16 -0
  41. data/lib/coradoc/html/converters/span.rb +61 -0
  42. data/lib/coradoc/html/converters/strikethrough.rb +34 -0
  43. data/lib/coradoc/html/converters/subscript.rb +34 -0
  44. data/lib/coradoc/html/converters/superscript.rb +34 -0
  45. data/lib/coradoc/html/converters/table.rb +85 -0
  46. data/lib/coradoc/html/converters/table_cell.rb +203 -0
  47. data/lib/coradoc/html/converters/table_row.rb +45 -0
  48. data/lib/coradoc/html/converters/template_html_converter.rb +105 -0
  49. data/lib/coradoc/html/converters/term.rb +58 -0
  50. data/lib/coradoc/html/converters/text_element.rb +44 -0
  51. data/lib/coradoc/html/converters/underline.rb +34 -0
  52. data/lib/coradoc/html/converters/unordered.rb +47 -0
  53. data/lib/coradoc/html/converters/verse.rb +105 -0
  54. data/lib/coradoc/html/converters/video.rb +179 -0
  55. data/lib/coradoc/html/element_mapping.rb +210 -0
  56. data/lib/coradoc/html/entity.rb +137 -0
  57. data/lib/coradoc/html/input/cleaner.rb +163 -0
  58. data/lib/coradoc/html/input/config.rb +79 -0
  59. data/lib/coradoc/html/input/converters/a.rb +90 -0
  60. data/lib/coradoc/html/input/converters/aside.rb +23 -0
  61. data/lib/coradoc/html/input/converters/audio.rb +50 -0
  62. data/lib/coradoc/html/input/converters/base.rb +116 -0
  63. data/lib/coradoc/html/input/converters/blockquote.rb +25 -0
  64. data/lib/coradoc/html/input/converters/br.rb +19 -0
  65. data/lib/coradoc/html/input/converters/bypass.rb +83 -0
  66. data/lib/coradoc/html/input/converters/code.rb +25 -0
  67. data/lib/coradoc/html/input/converters/div.rb +25 -0
  68. data/lib/coradoc/html/input/converters/dl.rb +106 -0
  69. data/lib/coradoc/html/input/converters/drop.rb +28 -0
  70. data/lib/coradoc/html/input/converters/em.rb +23 -0
  71. data/lib/coradoc/html/input/converters/figure.rb +58 -0
  72. data/lib/coradoc/html/input/converters/h.rb +76 -0
  73. data/lib/coradoc/html/input/converters/head.rb +30 -0
  74. data/lib/coradoc/html/input/converters/hr.rb +20 -0
  75. data/lib/coradoc/html/input/converters/ignore.rb +22 -0
  76. data/lib/coradoc/html/input/converters/img.rb +110 -0
  77. data/lib/coradoc/html/input/converters/li.rb +35 -0
  78. data/lib/coradoc/html/input/converters/mark.rb +21 -0
  79. data/lib/coradoc/html/input/converters/markup.rb +107 -0
  80. data/lib/coradoc/html/input/converters/math.rb +46 -0
  81. data/lib/coradoc/html/input/converters/ol.rb +46 -0
  82. data/lib/coradoc/html/input/converters/p.rb +81 -0
  83. data/lib/coradoc/html/input/converters/pass_through.rb +19 -0
  84. data/lib/coradoc/html/input/converters/pre.rb +59 -0
  85. data/lib/coradoc/html/input/converters/q.rb +24 -0
  86. data/lib/coradoc/html/input/converters/strong.rb +22 -0
  87. data/lib/coradoc/html/input/converters/sub.rb +40 -0
  88. data/lib/coradoc/html/input/converters/sup.rb +40 -0
  89. data/lib/coradoc/html/input/converters/table.rb +64 -0
  90. data/lib/coradoc/html/input/converters/td.rb +70 -0
  91. data/lib/coradoc/html/input/converters/text.rb +67 -0
  92. data/lib/coradoc/html/input/converters/th.rb +20 -0
  93. data/lib/coradoc/html/input/converters/tr.rb +28 -0
  94. data/lib/coradoc/html/input/converters/video.rb +53 -0
  95. data/lib/coradoc/html/input/converters.rb +122 -0
  96. data/lib/coradoc/html/input/errors.rb +22 -0
  97. data/lib/coradoc/html/input/html_converter.rb +170 -0
  98. data/lib/coradoc/html/input/plugin.rb +169 -0
  99. data/lib/coradoc/html/input/plugins/plateau.rb +229 -0
  100. data/lib/coradoc/html/input/postprocessor.rb +31 -0
  101. data/lib/coradoc/html/input.rb +68 -0
  102. data/lib/coradoc/html/output.rb +95 -0
  103. data/lib/coradoc/html/renderer.rb +409 -0
  104. data/lib/coradoc/html/spa.rb +309 -0
  105. data/lib/coradoc/html/static.rb +293 -0
  106. data/lib/coradoc/html/template_config.rb +151 -0
  107. data/lib/coradoc/html/template_helpers.rb +58 -0
  108. data/lib/coradoc/html/template_locator.rb +114 -0
  109. data/lib/coradoc/html/theme/base.rb +231 -0
  110. data/lib/coradoc/html/theme/classic_renderer.rb +390 -0
  111. data/lib/coradoc/html/theme/modern/components/ui_components.rb +344 -0
  112. data/lib/coradoc/html/theme/modern/css_generator.rb +311 -0
  113. data/lib/coradoc/html/theme/modern/javascript_generator.rb +314 -0
  114. data/lib/coradoc/html/theme/modern/serializers/document_serializer.rb +382 -0
  115. data/lib/coradoc/html/theme/modern/tailwind_config_builder.rb +164 -0
  116. data/lib/coradoc/html/theme/modern/vue_template_generator.rb +374 -0
  117. data/lib/coradoc/html/theme/modern_renderer.rb +250 -0
  118. data/lib/coradoc/html/theme/registry.rb +153 -0
  119. data/lib/coradoc/html/theme.rb +13 -0
  120. data/lib/coradoc/html/transform/from_core_model.rb +32 -0
  121. data/lib/coradoc/html/transform/to_core_model.rb +39 -0
  122. data/lib/coradoc/html/version.rb +7 -0
  123. data/lib/coradoc/html.rb +255 -0
  124. metadata +264 -0
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Hr < Base
8
+ def to_coradoc(_node, _state = {})
9
+ Coradoc::CoreModel::Block.new(
10
+ element_type: 'thematic_break',
11
+ block_semantic_type: :horizontal_rule
12
+ )
13
+ end
14
+ end
15
+
16
+ register :hr, Hr.new
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Ignore < Base
8
+ def to_coradoc(node, state = {})
9
+ convert(node, state)
10
+ end
11
+
12
+ def convert(_node, _state = {})
13
+ '' # noop
14
+ end
15
+ end
16
+
17
+ register :colgroup, Ignore.new
18
+ register :col, Ignore.new
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'pathname'
5
+ require 'tempfile'
6
+ require 'base64'
7
+ require 'marcel'
8
+
9
+ module Coradoc
10
+ module Input
11
+ module Html
12
+ module Converters
13
+ class Img < Base
14
+ def image_number
15
+ format(
16
+ Coradoc::Html::Input.config.image_counter_pattern,
17
+ Coradoc::Html::Input.config.image_counter
18
+ )
19
+ end
20
+
21
+ def image_number_increment
22
+ Coradoc::Html::Input.config.image_counter += 1
23
+ end
24
+
25
+ def datauri2file(src)
26
+ return unless src
27
+
28
+ %r{^data:image/(?:[^;]+);base64,(?<imgdata>.+)$} =~ src
29
+
30
+ dest_dir = Pathname.new(Coradoc::Html::Input.config.destination).dirname
31
+ images_dir = dest_dir.join('images')
32
+ FileUtils.mkdir_p(images_dir)
33
+
34
+ ext, image_src_path, tempfile = determine_image_src_path(
35
+ src,
36
+ imgdata
37
+ )
38
+ image_dest_path = images_dir + "#{image_number}.#{ext}"
39
+
40
+ # puts "image_dest_path: #{image_dest_path.to_s}"
41
+ # puts "image_src_path: #{image_src_path.to_s}"
42
+
43
+ if File.exist?(image_src_path)
44
+ FileUtils.cp(image_src_path, image_dest_path)
45
+ else
46
+ @annotate_missing = image_src_path
47
+ Kernel.warn "Image #{image_src_path} does not exist"
48
+ end
49
+
50
+ image_number_increment
51
+
52
+ image_dest_path.relative_path_from(dest_dir)
53
+ ensure
54
+ tempfile&.close!
55
+ end
56
+
57
+ def determine_image_src_path(src, imgdata)
58
+ return copy_temp_file(imgdata) if imgdata
59
+
60
+ ext = File.extname(src).strip.downcase[1..]
61
+ [ext, Pathname.new(Coradoc::Html::Input.config.sourcedir).join(src)]
62
+ end
63
+
64
+ def copy_temp_file(imgdata)
65
+ f = Tempfile.open(['radoc', '.jpg'])
66
+ f.binmode
67
+ f.write(Base64.strict_decode64(imgdata))
68
+ f.rewind
69
+ ext = Marcel::MimeType.for(f).sub(%r{^[^/]+/}, '')
70
+ ext = 'svg' if ext == 'svg+xml'
71
+ [ext, f.path, f]
72
+ end
73
+
74
+ def to_coradoc(node, _state = {})
75
+ id = node['id']
76
+ alt = node['alt']
77
+ src = node['src']
78
+ width = node['width']
79
+ height = node['height']
80
+
81
+ # Convert width/height to integers if they are numeric strings
82
+ width = width.to_i if width&.match?(/\A\d+\z/)
83
+ height = height.to_i if height&.match?(/\A\d+\z/)
84
+
85
+ title = extract_title(node)
86
+
87
+ if Coradoc::Html::Input.config.external_images
88
+ # puts "external image conversion #{id}, #{src}"
89
+ src = datauri2file(src)
90
+ end
91
+
92
+ # Use CoreModel::Image
93
+ return unless src
94
+
95
+ Coradoc::CoreModel::Image.new(
96
+ src: src,
97
+ alt: alt,
98
+ caption: title,
99
+ width: width&.to_s,
100
+ height: height&.to_s,
101
+ id: id
102
+ )
103
+ end
104
+ end
105
+
106
+ register :img, Img
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Li < Base
8
+ def to_coradoc(node, state = {})
9
+ id = node['id']
10
+
11
+ # Check if all children are <p> tags
12
+ p_children = node.children.select { |child| child.name == 'p' }
13
+ non_empty_children = node.children.reject { |c| c.text? && c.text.strip.empty? }
14
+
15
+ content = if p_children.any? && p_children.size == non_empty_children.size && p_children.size == 1
16
+ # Single <p> tag - extract its content directly as inline content
17
+ treat_children_coradoc(p_children.first, state)
18
+ else
19
+ treat_children_coradoc(node, state)
20
+ end
21
+
22
+ # Use CoreModel::ListItem with children for mixed content
23
+ # content can be an array of inline elements or a single string
24
+ Coradoc::CoreModel::ListItem.new(
25
+ children: content,
26
+ id: id
27
+ )
28
+ end
29
+ end
30
+
31
+ register :li, Li.new
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Mark < Markup
8
+ def coradoc_format_type
9
+ 'highlight'
10
+ end
11
+
12
+ def markup_ancestor_tag_names
13
+ %w[mark]
14
+ end
15
+ end
16
+
17
+ register :mark, Mark.new
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Markup < Base
8
+ def to_coradoc(node, state = {})
9
+ u_before = unconstrained_before?(node)
10
+ u_after = unconstrained_after?(node)
11
+
12
+ leading_ws, trailing_ws =
13
+ extract_leading_trailing_whitespace(node)
14
+
15
+ # Wrap whitespace in InlineElement so it can be processed
16
+ leading_whitespace = if leading_ws
17
+ Coradoc::CoreModel::InlineElement.new(
18
+ format_type: 'text',
19
+ content: leading_ws
20
+ )
21
+ end
22
+ trailing_whitespace = if trailing_ws
23
+ Coradoc::CoreModel::InlineElement.new(
24
+ format_type: 'text',
25
+ content: trailing_ws
26
+ )
27
+ end
28
+
29
+ content = treat_children_coradoc(node, state)
30
+
31
+ if node_has_ancestor?(node, markup_ancestor_tag_names)
32
+ content
33
+ elsif node.children.empty?
34
+ # Return InlineElement wrapper for whitespace
35
+ if leading_ws
36
+ Coradoc::CoreModel::InlineElement.new(
37
+ format_type: 'text',
38
+ content: leading_ws
39
+ )
40
+ end
41
+ else
42
+ u = (u_before && leading_whitespace.nil?) ||
43
+ (u_after && trailing_whitespace.nil?)
44
+
45
+ # Separate text strings from InlineElements in content array
46
+ text_content, nested = extract_text_and_elements(content)
47
+
48
+ # Create CoreModel::InlineElement with the appropriate format type
49
+ inline_element = Coradoc::CoreModel::InlineElement.new(
50
+ format_type: coradoc_format_type,
51
+ content: text_content,
52
+ nested_elements: nested.empty? ? nil : nested,
53
+ metadata: { unconstrained: u }
54
+ )
55
+ result = [leading_whitespace, inline_element, trailing_whitespace].compact
56
+ result.length == 1 ? result.first : result
57
+ end
58
+ end
59
+
60
+ # Extract text content and InlineElements from mixed content array
61
+ def extract_text_and_elements(content)
62
+ return [content, []] unless content.is_a?(Array)
63
+
64
+ text_parts = []
65
+ elements = []
66
+
67
+ content.each do |item|
68
+ case item
69
+ when String
70
+ text_parts << item
71
+ when Coradoc::CoreModel::InlineElement
72
+ elements << item
73
+ when Coradoc::CoreModel::Base
74
+ # For other block types, convert to text
75
+ text_parts << extract_text_from_model(item)
76
+ else
77
+ text_parts << item.to_s
78
+ end
79
+ end
80
+
81
+ [text_parts.join, elements]
82
+ end
83
+
84
+ # Extract text from a CoreModel object
85
+ def extract_text_from_model(model)
86
+ return '' if model.nil?
87
+
88
+ if model.is_a?(Coradoc::CoreModel::Base) && model.content.is_a?(String)
89
+ model.content
90
+ elsif model.is_a?(Coradoc::CoreModel::StructuralElement) && model.children.is_a?(Array)
91
+ model.children.map { |c| extract_text_from_model(c) }.join
92
+ elsif model.is_a?(Coradoc::CoreModel::Base) && model.title.is_a?(String)
93
+ model.title
94
+ else
95
+ model.to_s
96
+ end
97
+ end
98
+
99
+ # Subclasses should override this to return the format type
100
+ def coradoc_format_type
101
+ 'text'
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Unless run with Coradoc::Input::HTML.config.mathml2asciimath,
4
+ # this is cheating: we're injecting MathML into Asciidoctor, but
5
+ # Asciidoctor only understands AsciiMath or LaTeX
6
+
7
+ module Coradoc
8
+ module Input
9
+ module Html
10
+ module Converters
11
+ class Math < Base
12
+ # FIXIT
13
+ def to_coradoc(node, state = {})
14
+ convert(node, state)
15
+ end
16
+
17
+ def convert(node, _state = {})
18
+ stem = node.to_s.tr("\n", ' ')
19
+ if Coradoc::Html::Input.config.mathml2asciimath
20
+ require 'plurimath'
21
+ stem = Plurimath::Math.parse(stem, :mathml).to_asciimath
22
+ end
23
+
24
+ unless stem.nil?
25
+ stem = stem.gsub('[', '\\[')
26
+ stem = stem.gsub(']', '\\]')
27
+ # Handle ((...)) patterns - iterate to avoid polynomial regex
28
+ loop do
29
+ new_stem = stem.gsub(/\(\(([^)]{1,100})\)\)/, '(\\1)')
30
+ break if new_stem == stem
31
+
32
+ stem = new_stem
33
+ end
34
+ end
35
+
36
+ # NOTE: MathML/LaTeX conversion to AsciiDoc stem format
37
+ # This converts HTML math elements to AsciiDoc's stem:[] macro format
38
+ ' stem:[' << stem << '] '
39
+ end
40
+ end
41
+
42
+ register :math, Math.new
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Ol < Base
8
+ def to_coradoc(node, state = {})
9
+ id = node['id']
10
+ ol_count = state.fetch(:ol_count, 0) + 1
11
+ items = treat_children_coradoc(
12
+ node,
13
+ state.merge(ol_count: ol_count)
14
+ )
15
+
16
+ marker_type = get_list_type(node, state)
17
+
18
+ Coradoc::CoreModel::ListBlock.new(
19
+ marker_type: marker_type,
20
+ items: items,
21
+ id: id,
22
+ start: node['start']&.to_i
23
+ )
24
+ end
25
+
26
+ def get_list_type(node, _state)
27
+ case node.name
28
+ when 'ol'
29
+ 'ordered'
30
+ when 'ul'
31
+ 'unordered'
32
+ when 'dir'
33
+ 'unordered'
34
+ else
35
+ 'unordered'
36
+ end
37
+ end
38
+ end
39
+
40
+ register :ol, Ol.new
41
+ register :ul, Ol.new
42
+ register :dir, Ol.new
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class P < Base
8
+ def to_coradoc(node, state = {})
9
+ id = node['id']
10
+ content = treat_children_coradoc(node, state)
11
+
12
+ # Strip full-width spaces from paragraph content
13
+ content = strip_fullwidth_spaces(content)
14
+
15
+ Coradoc::CoreModel::Block.new(
16
+ block_semantic_type: :paragraph,
17
+ element_type: 'paragraph',
18
+ children: content,
19
+ id: id
20
+ )
21
+ end
22
+
23
+ private
24
+
25
+ def strip_fullwidth_spaces(content)
26
+ return content unless content.is_a?(Array)
27
+
28
+ # Strip full-width spaces from all inline elements
29
+ content.each do |item|
30
+ if item.is_a?(Coradoc::CoreModel::InlineElement) && item.content.is_a?(String)
31
+ item.content = item.content.gsub(/\A +| +\z/, '')
32
+ elsif item.is_a?(String)
33
+ item.gsub(/\A +| +\z/, '')
34
+ end
35
+ end
36
+
37
+ # Strip leading space from first text element
38
+ first_text = content.find { |item| item.is_a?(Coradoc::CoreModel::InlineElement) || item.is_a?(String) }
39
+ if first_text.is_a?(Coradoc::CoreModel::InlineElement) && first_text.content.is_a?(String)
40
+ first_text.content = first_text.content.lstrip
41
+ elsif first_text.is_a?(String)
42
+ first_text.lstrip
43
+ end
44
+
45
+ # Strip trailing space from last text element
46
+ last_text = content.reverse.find do |item|
47
+ item.is_a?(Coradoc::CoreModel::InlineElement) || item.is_a?(String)
48
+ end
49
+ if last_text.is_a?(Coradoc::CoreModel::InlineElement) && last_text.content.is_a?(String)
50
+ last_text.content = last_text.content.rstrip
51
+ elsif last_text.is_a?(String)
52
+ last_text.rstrip
53
+ end
54
+
55
+ # Remove empty text elements after stripping
56
+ # But keep InlineElements that have nested_elements (e.g., bold with nested text)
57
+ content.reject do |item|
58
+ if item.is_a?(Coradoc::CoreModel::InlineElement)
59
+ item.content.to_s.empty? && !item_has_nested_content?(item)
60
+ elsif item.is_a?(String)
61
+ item.empty?
62
+ else
63
+ false
64
+ end
65
+ end
66
+ end
67
+
68
+ # Check if InlineElement has meaningful nested content
69
+ def item_has_nested_content?(item)
70
+ return false unless item.is_a?(Coradoc::CoreModel::InlineElement)
71
+ return false if item.nested_elements.nil? || item.nested_elements.empty?
72
+
73
+ true
74
+ end
75
+ end
76
+
77
+ register :p, P.new
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class PassThrough < Base
8
+ def to_coradoc(node, _state = {})
9
+ node.to_s
10
+ end
11
+
12
+ def convert(node, state = {})
13
+ to_coradoc(node, state)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Pre < Base
8
+ def to_coradoc(node, _state = {})
9
+ id = node['id']
10
+ lang = language(node)
11
+ content = extract_text_content(node)
12
+
13
+ if lang
14
+ Coradoc::CoreModel::SourceBlock.new(
15
+ element_type: 'source',
16
+ content: content,
17
+ id: id,
18
+ language: lang
19
+ )
20
+ else
21
+ Coradoc::CoreModel::LiteralBlock.new(
22
+ element_type: 'literal',
23
+ content: content,
24
+ id: id
25
+ )
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def extract_text_content(node)
32
+ # Get text content from pre node
33
+ node.text
34
+ end
35
+
36
+ def language(node)
37
+ lang = language_from_highlight_class(node)
38
+ lang || language_from_confluence_class(node)
39
+ end
40
+
41
+ def language_from_highlight_class(node)
42
+ node.parent['class'].to_s[/highlight-([a-zA-Z0-9]+)/, 1]
43
+ end
44
+
45
+ def language_from_confluence_class(node)
46
+ class_str = node['class'].to_s
47
+ return nil unless class_str.include?('brush:')
48
+
49
+ # Extract language from brush: language; pattern
50
+ match = class_str.match(/brush:\s*([^;]+);/)
51
+ match ? match[1].strip : nil
52
+ end
53
+ end
54
+
55
+ register :pre, Pre.new
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Q < Base
8
+ def to_coradoc(node, state = {})
9
+ content = treat_children_coradoc(node, state)
10
+ cite = node['cite']
11
+
12
+ Coradoc::CoreModel::InlineElement.new(
13
+ format_type: 'quotation',
14
+ content: content,
15
+ metadata: cite ? { cite: cite } : {}
16
+ )
17
+ end
18
+ end
19
+
20
+ register :q, Q.new
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Strong < Markup
8
+ def coradoc_format_type
9
+ 'bold'
10
+ end
11
+
12
+ def markup_ancestor_tag_names
13
+ %w[strong b]
14
+ end
15
+ end
16
+
17
+ register :strong, Strong.new
18
+ register :b, Strong.new
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Sub < Base
8
+ def to_coradoc(node, state = {})
9
+ leading_whitespace, trailing_whitespace = extract_leading_trailing_whitespace(node)
10
+
11
+ content = treat_children_coradoc(node, state)
12
+
13
+ # Check if content is empty
14
+ return nil if content_empty?(content)
15
+
16
+ # Create CoreModel::InlineElement with format_type "subscript"
17
+ e = Coradoc::CoreModel::InlineElement.new(
18
+ format_type: 'subscript',
19
+ content: content
20
+ )
21
+ result = [leading_whitespace, e, trailing_whitespace].compact
22
+ result.length == 1 ? result.first : result
23
+ end
24
+
25
+ private
26
+
27
+ def content_empty?(content)
28
+ return true if content.nil?
29
+ return content.strip.empty? if content.is_a?(String)
30
+ return content.empty? if content.is_a?(Array)
31
+
32
+ false
33
+ end
34
+ end
35
+
36
+ register :sub, Sub.new
37
+ end
38
+ end
39
+ end
40
+ end