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,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Aside < Base
8
+ def to_coradoc(node, state = {})
9
+ content = treat_children_coradoc(node, state)
10
+ # Use AnnotationBlock with annotation_type: "sidebar" for aside elements
11
+ Coradoc::CoreModel::AnnotationBlock.new(
12
+ annotation_type: 'sidebar',
13
+ block_semantic_type: :sidebar,
14
+ children: content
15
+ )
16
+ end
17
+ end
18
+
19
+ register :aside, Aside.new
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Audio < Base
8
+ def to_coradoc(node, _state = {})
9
+ src = node['src']
10
+ id = node['id']
11
+ title = extract_title(node)
12
+ options(node)
13
+
14
+ # Use Block with custom attributes to store audio info
15
+ # CoreModel doesn't have a specific Audio type, so we use Block
16
+ # with element_attributes to store audio-specific data
17
+ Coradoc::CoreModel::Block.new(
18
+ element_type: 'audio',
19
+ block_semantic_type: :audio,
20
+ content: src,
21
+ title: title,
22
+ id: id,
23
+ element_attributes: {
24
+ autoplay: node['autoplay'],
25
+ loop: node['loop'],
26
+ controls: node['controls']
27
+ }.compact
28
+ )
29
+ end
30
+
31
+ def extract_title(node)
32
+ title = node.at('./track') || node.at('.//source')
33
+ return '' if title.nil?
34
+
35
+ title['label'] || title['srclang'] || ''
36
+ end
37
+
38
+ def options(node)
39
+ autoplay = node['autoplay']
40
+ loop_attr = node['loop']
41
+ controls = node['controls']
42
+ [autoplay, loop_attr, controls].compact
43
+ end
44
+ end
45
+
46
+ register :audio, Audio.new
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Base
8
+ # Default implementation to convert a given Nokogiri node
9
+ # to a CoreModel type.
10
+ # Can be overriden by subclasses.
11
+ def convert(node, state = {})
12
+ to_coradoc(node, state)
13
+ end
14
+
15
+ # NOTE: treat_children won't run plugin hooks
16
+ def treat_children(node, state)
17
+ node.children.map do |child|
18
+ treat(child, state)
19
+ end
20
+ end
21
+
22
+ def treat(node, state)
23
+ Converters.process(node, state)
24
+ end
25
+
26
+ def treat_children_coradoc(node, state)
27
+ results = node.children.map do |child|
28
+ treat_coradoc(child, state)
29
+ end.flatten
30
+
31
+ results.reject do |x|
32
+ x.nil? || (x.is_a?(String) && x.strip.empty?)
33
+ end
34
+ end
35
+
36
+ def treat_coradoc(node, state)
37
+ Converters.process_coradoc(node, state)
38
+ end
39
+
40
+ def extract_title(node)
41
+ node['title'].to_s
42
+ end
43
+
44
+ def node_has_ancestor?(node, name)
45
+ case name
46
+ when String
47
+ node.ancestors.map(&:name).include?(name)
48
+ when Array
49
+ (node.ancestors.map(&:name) & name).any?
50
+ end
51
+ end
52
+
53
+ def textnode_before_end_with?(node, str)
54
+ return nil unless [String, Regexp].include?(str.class)
55
+ return nil if str.is_a?(String) && str.empty?
56
+
57
+ str = /#{Regexp.escape(str)}/ if str.is_a?(String)
58
+ str = /(?:#{str})\z/
59
+
60
+ node2 = node.at_xpath('preceding-sibling::node()[1]')
61
+ node2.is_a?(Nokogiri::XML::Text) && node2.text.match?(str)
62
+ end
63
+
64
+ def textnode_after_start_with?(node, str)
65
+ return nil unless [String, Regexp].include?(str.class)
66
+ return nil if str.is_a?(String) && str.empty?
67
+
68
+ str = /#{Regexp.escape(str)}/ if str.is_a?(String)
69
+ str = /\A(?:#{str})/
70
+
71
+ node2 = node.at_xpath('following-sibling::node()[1]')
72
+ node2.is_a?(Nokogiri::XML::Text) && node2.text.match?(str)
73
+ end
74
+
75
+ def extract_leading_trailing_whitespace(node)
76
+ node.text =~ /^(\s+)/
77
+ leading_whitespace = ::Regexp.last_match(1)
78
+ unless leading_whitespace.nil?
79
+ first_text = node.at_xpath('./text()[1]')
80
+ first_text&.replace(first_text.text.lstrip)
81
+ leading_whitespace = ' '
82
+ end
83
+ node.text =~ /(\s+)$/
84
+ trailing_whitespace = ::Regexp.last_match(1)
85
+ unless trailing_whitespace.nil?
86
+ last_text = node.at_xpath('./text()[last()]')
87
+ last_text&.replace(last_text.text.rstrip)
88
+ trailing_whitespace = ' '
89
+ end
90
+ [leading_whitespace, trailing_whitespace]
91
+ end
92
+
93
+ def unconstrained_before?(node)
94
+ before = node.at_xpath('preceding::node()[1]')
95
+
96
+ before &&
97
+ !before.text.strip.empty? &&
98
+ before.text[-1]&.match?(/\w/)
99
+ end
100
+
101
+ def unconstrained_after?(node)
102
+ after = node.at_xpath('following::node()[1]')
103
+
104
+ after && !after.text.strip.empty? &&
105
+ after.text[0]&.match?(/\w|,|;|"|\.\?!/)
106
+ end
107
+
108
+ # Helper to escape text content
109
+ def escape_text(text)
110
+ text.to_s.gsub(/[<>&]/, '<' => '&lt;', '>' => '&gt;', '&' => '&amp;')
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Blockquote < Base
8
+ def to_coradoc(node, state = {})
9
+ id = node['id']
10
+ cite = node['cite']
11
+ content = treat_children_coradoc(node, state)
12
+
13
+ Coradoc::CoreModel::QuoteBlock.new(
14
+ content: content,
15
+ id: id,
16
+ attribution: cite
17
+ )
18
+ end
19
+ end
20
+
21
+ register :blockquote, Blockquote.new
22
+ end
23
+ end
24
+ end
25
+ 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 Br < Base
8
+ def to_coradoc(_node, _state = {})
9
+ Coradoc::CoreModel::InlineElement.new(
10
+ format_type: 'line_break'
11
+ )
12
+ end
13
+ end
14
+
15
+ register :br, Br.new
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Bypass < Base
8
+ def to_coradoc(node, state = {})
9
+ treat_children_coradoc(node, state)
10
+ end
11
+ end
12
+
13
+ register :document, Bypass.new
14
+ register :html, Bypass.new
15
+ register :body, Bypass.new
16
+ register :span, Bypass.new
17
+ register :thead, Bypass.new
18
+ register :tbody, Bypass.new
19
+ register :tfoot, Bypass.new
20
+ register :abbr, Bypass.new
21
+ register :acronym, Bypass.new
22
+ register :address, Bypass.new
23
+ register :applet, Bypass.new
24
+ register :map, Bypass.new
25
+ register :area, Bypass.new
26
+ register :bdi, Bypass.new
27
+ register :bdo, Bypass.new
28
+ register :big, Bypass.new
29
+ register :button, Bypass.new
30
+ register :canvas, Bypass.new
31
+ register :data, Bypass.new
32
+ register :datalist, Bypass.new
33
+ register :del, Bypass.new
34
+ register :ins, Bypass.new
35
+ register :dfn, Bypass.new
36
+ register :dialog, Bypass.new
37
+ register :embed, Bypass.new
38
+ register :fieldset, Bypass.new
39
+ register :font, Bypass.new
40
+ register :footer, Bypass.new
41
+ register :form, Bypass.new
42
+ register :frame, Bypass.new
43
+ register :frameset, Bypass.new
44
+ register :header, Bypass.new
45
+ register :iframe, Bypass.new
46
+ register :input, Bypass.new
47
+ register :label, Bypass.new
48
+ register :legend, Bypass.new
49
+ register :main, Bypass.new
50
+ register :menu, Bypass.new
51
+ register :menulist, Bypass.new
52
+ register :meter, Bypass.new
53
+ register :nav, Bypass.new
54
+ register :noframes, Bypass.new
55
+ register :noscript, Bypass.new
56
+ register :object, Bypass.new
57
+ register :optgroup, Bypass.new
58
+ register :option, Bypass.new
59
+ register :output, Bypass.new
60
+ register :param, Bypass.new
61
+ register :picture, Bypass.new
62
+ register :progress, Bypass.new
63
+ register :ruby, Bypass.new
64
+ register :rt, Bypass.new
65
+ register :rp, Bypass.new
66
+ register :s, Bypass.new
67
+ register :select, Bypass.new
68
+ register :small, Bypass.new
69
+ register :span, Bypass.new
70
+ register :strike, Bypass.new
71
+ register :details, Bypass.new
72
+ register :section, Bypass.new
73
+ register :summary, Bypass.new
74
+ register :svg, Bypass.new
75
+ register :template, Bypass.new
76
+ register :textarea, Bypass.new
77
+ register :track, Bypass.new
78
+ register :u, Bypass.new
79
+ register :wbr, Bypass.new
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Code < Markup
8
+ def coradoc_format_type
9
+ 'monospace'
10
+ end
11
+
12
+ def markup_ancestor_tag_names
13
+ %w[code tt kbd samp var]
14
+ end
15
+ end
16
+
17
+ register :code, Code.new
18
+ register :tt, Code.new
19
+ register :kbd, Code.new
20
+ register :samp, Code.new
21
+ register :var, Code.new
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Div < Base
8
+ def to_coradoc(node, state = {})
9
+ id = node['id']
10
+ contents = treat_children_coradoc(node, state)
11
+
12
+ Coradoc::CoreModel::OpenBlock.new(
13
+ content: contents,
14
+ id: id
15
+ )
16
+ end
17
+ end
18
+
19
+ register :div, Div.new
20
+ register :article, Div.new
21
+ register :center, Div.new
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Dl < Base
8
+ def to_coradoc(node, state = {})
9
+ items = process_dl(node, state)
10
+
11
+ # Convert items to CoreModel::ListItem objects
12
+ # For definition lists, term goes in content, definition goes in children
13
+ list_items = items.map do |item|
14
+ term_text = extract_text_from_content(item[:name])
15
+ Coradoc::CoreModel::ListItem.new(
16
+ content: term_text,
17
+ children: item[:value]
18
+ )
19
+ end
20
+
21
+ # Use CoreModel::ListBlock with marker_type "definition"
22
+ Coradoc::CoreModel::ListBlock.new(
23
+ marker_type: 'definition',
24
+ items: list_items
25
+ )
26
+ end
27
+
28
+ def process_dl(node, state = {})
29
+ groups = []
30
+ current = { name: [], value: [] }
31
+
32
+ seen_dd = false
33
+ child = node.at_xpath('*[1]')
34
+ grandchild = nil
35
+ until child.nil?
36
+ if child.name == 'div'
37
+ grandchild = child.at_xpath('*[1]')
38
+ until grandchild.nil?
39
+ groups, current, seen_dd = process_dt_or_dd(
40
+ groups,
41
+ current,
42
+ seen_dd,
43
+ grandchild,
44
+ state
45
+ )
46
+ grandchild = grandchild.at_xpath('following-sibling::*[1]')
47
+ end
48
+ elsif %w[dt dd].include?(child.name)
49
+ groups, current, seen_dd = process_dt_or_dd(
50
+ groups,
51
+ current,
52
+ seen_dd,
53
+ child,
54
+ state
55
+ )
56
+ end
57
+ child = child.at_xpath('following-sibling::*[1]')
58
+ groups << current if current[:name].any? && current[:value].any?
59
+ end
60
+ groups
61
+ end
62
+
63
+ def process_dt_or_dd(groups, current, seen_dd, subnode, state = {})
64
+ if subnode.name == 'dt'
65
+ if seen_dd
66
+ # groups << current
67
+ current = { name: [], value: [] }
68
+ seen_dd = false
69
+ end
70
+ current[:name] += treat_children_coradoc(subnode, state)
71
+ elsif subnode.name == 'dd'
72
+ current[:value] += treat_children_coradoc(subnode, state)
73
+ seen_dd = true
74
+ end
75
+ [groups, current, seen_dd]
76
+ end
77
+
78
+ # Extract text from content array
79
+ def extract_text_from_content(content)
80
+ return content if content.is_a?(String)
81
+ return '' if content.nil?
82
+
83
+ content.map do |item|
84
+ case item
85
+ when String
86
+ item
87
+ when Coradoc::CoreModel::InlineElement
88
+ item.content.to_s
89
+ when Coradoc::CoreModel::Base
90
+ if item.content
91
+ item.content.to_s
92
+ else
93
+ ''
94
+ end
95
+ else
96
+ item.to_s
97
+ end
98
+ end.join
99
+ end
100
+ end
101
+
102
+ register :dl, Dl.new
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Drop < Base
8
+ def to_coradoc(node, state = {})
9
+ convert(node, state)
10
+ end
11
+
12
+ def convert(_node, _state = {})
13
+ ''
14
+ end
15
+ end
16
+
17
+ register :caption, Drop.new
18
+ register :figcaption, Drop.new
19
+ register :title, Drop.new
20
+ register :link, Drop.new
21
+ register :style, Drop.new
22
+ register :meta, Drop.new
23
+ register :script, Drop.new
24
+ register :comment, Drop.new
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Em < Markup
8
+ def coradoc_format_type
9
+ 'italic'
10
+ end
11
+
12
+ def markup_ancestor_tag_names
13
+ %w[em i cite]
14
+ end
15
+ end
16
+
17
+ register :em, Em.new
18
+ register :i, Em.new
19
+ register :cite, Em.new
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Figure < Base
8
+ def to_coradoc(node, state = {})
9
+ id = node['id']
10
+ title_content = extract_title(node)
11
+ content = treat_children_coradoc(node, state)
12
+
13
+ # Use CoreModel::ExampleBlock for example/figure
14
+ Coradoc::CoreModel::ExampleBlock.new(
15
+ title: extract_text_from_content(title_content),
16
+ children: content,
17
+ id: id
18
+ )
19
+ end
20
+
21
+ def extract_title(node)
22
+ title = node.at('./figcaption')
23
+ return '' if title.nil?
24
+
25
+ treat_children_coradoc(title, {})
26
+ end
27
+
28
+ # Extract text from content array
29
+ def extract_text_from_content(content)
30
+ return content if content.is_a?(String)
31
+ return '' if content.nil?
32
+
33
+ content.map do |item|
34
+ case item
35
+ when String
36
+ item
37
+ when Coradoc::CoreModel::InlineElement
38
+ item.content.to_s
39
+ when Coradoc::CoreModel::Base
40
+ if item.content
41
+ item.content.to_s
42
+ elsif item.title
43
+ item.title.to_s
44
+ else
45
+ ''
46
+ end
47
+ else
48
+ item.to_s
49
+ end
50
+ end.join
51
+ end
52
+ end
53
+
54
+ register :figure, Figure.new
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class H < Base
8
+ def to_coradoc(node, state = {})
9
+ id = node['id']
10
+ internal_anchor = treat_children_anchors(node, state)
11
+
12
+ # Check if it has id attribute
13
+ if id.to_s.empty? && internal_anchor.size.positive?
14
+ first_model = internal_anchor.first
15
+ # InlineElement (anchor) has a target attribute
16
+ id = first_model.target if first_model.is_a?(Coradoc::CoreModel::InlineElement) && first_model.target
17
+ end
18
+
19
+ level_int = node.name[/\d/].to_i
20
+ content = treat_children_no_anchors(node, state)
21
+
22
+ Coradoc::CoreModel::StructuralElement.new(
23
+ element_type: 'section',
24
+ title: extract_title_text(content),
25
+ level: level_int,
26
+ id: id,
27
+ children: []
28
+ )
29
+ end
30
+
31
+ def treat_children_no_anchors(node, state)
32
+ node.children.reject { |a| a.name == 'a' }
33
+ .map do |child|
34
+ treat_coradoc(child, state)
35
+ end.flatten.compact
36
+ end
37
+
38
+ def treat_children_anchors(node, state)
39
+ node.children.select { |a| a.name == 'a' }
40
+ .map do |child|
41
+ treat_coradoc(child, state)
42
+ end.flatten.compact
43
+ end
44
+
45
+ private
46
+
47
+ def extract_title_text(content)
48
+ return '' if content.nil? || content.empty?
49
+
50
+ # Extract text from content
51
+ if content.is_a?(Array)
52
+ content.map do |c|
53
+ if c.is_a?(Coradoc::CoreModel::InlineElement)
54
+ c.content.to_s
55
+ else
56
+ c.to_s
57
+ end
58
+ end.join.strip
59
+ elsif content.is_a?(Coradoc::CoreModel::InlineElement)
60
+ content.content.to_s
61
+ else
62
+ content.to_s
63
+ end
64
+ end
65
+ end
66
+
67
+ register :h1, H.new
68
+ register :h2, H.new
69
+ register :h3, H.new
70
+ register :h4, H.new
71
+ register :h5, H.new
72
+ register :h6, H.new
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coradoc
4
+ module Input
5
+ module Html
6
+ module Converters
7
+ class Head < Base
8
+ def to_coradoc(node, _state = {})
9
+ title = extract_title(node)
10
+ # Use StructuralElement with element_type "document" for document header
11
+ Coradoc::CoreModel::StructuralElement.new(
12
+ element_type: 'document',
13
+ title: title,
14
+ level: 0
15
+ )
16
+ end
17
+
18
+ def extract_title(node)
19
+ title = node.at('./title')
20
+ return '(???)' if title.nil?
21
+
22
+ title.text
23
+ end
24
+ end
25
+
26
+ register :head, Head.new
27
+ end
28
+ end
29
+ end
30
+ end