coradoc 0.2.0 → 1.0.0

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/.docker/Dockerfile +1 -1
  3. data/.docker/docker-compose.yml +2 -2
  4. data/.editorconfig +15 -0
  5. data/CHANGELOG.md +4 -0
  6. data/README.md +4 -0
  7. data/Rakefile +10 -0
  8. data/coradoc.gemspec +11 -2
  9. data/exe/reverse_adoc +91 -0
  10. data/exe/w2a +72 -0
  11. data/lib/coradoc/document.rb +6 -6
  12. data/lib/coradoc/element/admonition.rb +8 -6
  13. data/lib/coradoc/element/attribute.rb +2 -2
  14. data/lib/coradoc/element/attribute_list.rb +94 -15
  15. data/lib/coradoc/element/audio.rb +14 -3
  16. data/lib/coradoc/element/author.rb +18 -14
  17. data/lib/coradoc/element/base.rb +69 -8
  18. data/lib/coradoc/element/block/core.rb +10 -6
  19. data/lib/coradoc/element/block/literal.rb +1 -1
  20. data/lib/coradoc/element/block/quote.rb +1 -1
  21. data/lib/coradoc/element/block/sourcecode.rb +2 -2
  22. data/lib/coradoc/element/break.rb +1 -1
  23. data/lib/coradoc/element/document_attributes.rb +6 -6
  24. data/lib/coradoc/element/header.rb +4 -2
  25. data/lib/coradoc/element/image/block_image.rb +13 -2
  26. data/lib/coradoc/element/image/core.rb +35 -5
  27. data/lib/coradoc/element/image/inline_image.rb +2 -2
  28. data/lib/coradoc/element/image.rb +0 -1
  29. data/lib/coradoc/element/inline/anchor.rb +4 -2
  30. data/lib/coradoc/element/inline/bold.rb +10 -4
  31. data/lib/coradoc/element/inline/cross_reference.rb +4 -2
  32. data/lib/coradoc/element/inline/hard_line_break.rb +1 -1
  33. data/lib/coradoc/element/inline/highlight.rb +12 -6
  34. data/lib/coradoc/element/inline/italic.rb +10 -4
  35. data/lib/coradoc/element/inline/link.rb +26 -10
  36. data/lib/coradoc/element/inline/monospace.rb +10 -4
  37. data/lib/coradoc/element/inline/quotation.rb +4 -1
  38. data/lib/coradoc/element/inline/subscript.rb +5 -2
  39. data/lib/coradoc/element/inline/superscript.rb +5 -2
  40. data/lib/coradoc/element/inline.rb +0 -1
  41. data/lib/coradoc/element/list/core.rb +10 -8
  42. data/lib/coradoc/element/list/definition.rb +19 -0
  43. data/lib/coradoc/element/list/ordered.rb +1 -1
  44. data/lib/coradoc/element/list/unordered.rb +1 -1
  45. data/lib/coradoc/element/list.rb +1 -1
  46. data/lib/coradoc/element/list_item.rb +9 -4
  47. data/lib/coradoc/element/list_item_definition.rb +32 -0
  48. data/lib/coradoc/element/paragraph.rb +5 -3
  49. data/lib/coradoc/element/revision.rb +20 -16
  50. data/lib/coradoc/element/section.rb +21 -4
  51. data/lib/coradoc/element/table.rb +36 -19
  52. data/lib/coradoc/element/text_element.rb +63 -17
  53. data/lib/coradoc/element/title.rb +27 -7
  54. data/lib/coradoc/element/video.rb +33 -6
  55. data/lib/coradoc/generator.rb +2 -2
  56. data/lib/coradoc/legacy_parser.rb +41 -41
  57. data/lib/coradoc/oscal.rb +2 -4
  58. data/lib/coradoc/parser/asciidoc/content.rb +15 -15
  59. data/lib/coradoc/parser/asciidoc/document_attributes.rb +1 -1
  60. data/lib/coradoc/parser/asciidoc/header.rb +6 -6
  61. data/lib/coradoc/parser/asciidoc/section.rb +1 -1
  62. data/lib/coradoc/reverse_adoc/LICENSE.txt +25 -0
  63. data/lib/coradoc/reverse_adoc/README.adoc +308 -0
  64. data/lib/coradoc/reverse_adoc/cleaner.rb +125 -0
  65. data/lib/coradoc/reverse_adoc/config.rb +73 -0
  66. data/lib/coradoc/reverse_adoc/converters/a.rb +47 -0
  67. data/lib/coradoc/reverse_adoc/converters/aside.rb +12 -0
  68. data/lib/coradoc/reverse_adoc/converters/audio.rb +25 -0
  69. data/lib/coradoc/reverse_adoc/converters/base.rb +104 -0
  70. data/lib/coradoc/reverse_adoc/converters/blockquote.rb +18 -0
  71. data/lib/coradoc/reverse_adoc/converters/br.rb +11 -0
  72. data/lib/coradoc/reverse_adoc/converters/bypass.rb +77 -0
  73. data/lib/coradoc/reverse_adoc/converters/code.rb +19 -0
  74. data/lib/coradoc/reverse_adoc/converters/div.rb +14 -0
  75. data/lib/coradoc/reverse_adoc/converters/dl.rb +55 -0
  76. data/lib/coradoc/reverse_adoc/converters/drop.rb +22 -0
  77. data/lib/coradoc/reverse_adoc/converters/em.rb +17 -0
  78. data/lib/coradoc/reverse_adoc/converters/figure.rb +21 -0
  79. data/lib/coradoc/reverse_adoc/converters/h.rb +38 -0
  80. data/lib/coradoc/reverse_adoc/converters/head.rb +19 -0
  81. data/lib/coradoc/reverse_adoc/converters/hr.rb +11 -0
  82. data/lib/coradoc/reverse_adoc/converters/ignore.rb +16 -0
  83. data/lib/coradoc/reverse_adoc/converters/img.rb +98 -0
  84. data/lib/coradoc/reverse_adoc/converters/li.rb +13 -0
  85. data/lib/coradoc/reverse_adoc/converters/mark.rb +15 -0
  86. data/lib/coradoc/reverse_adoc/converters/markup.rb +27 -0
  87. data/lib/coradoc/reverse_adoc/converters/math.rb +31 -0
  88. data/lib/coradoc/reverse_adoc/converters/ol.rb +60 -0
  89. data/lib/coradoc/reverse_adoc/converters/p.rb +19 -0
  90. data/lib/coradoc/reverse_adoc/converters/pass_through.rb +13 -0
  91. data/lib/coradoc/reverse_adoc/converters/pre.rb +51 -0
  92. data/lib/coradoc/reverse_adoc/converters/q.rb +12 -0
  93. data/lib/coradoc/reverse_adoc/converters/strong.rb +16 -0
  94. data/lib/coradoc/reverse_adoc/converters/sub.rb +18 -0
  95. data/lib/coradoc/reverse_adoc/converters/sup.rb +18 -0
  96. data/lib/coradoc/reverse_adoc/converters/table.rb +280 -0
  97. data/lib/coradoc/reverse_adoc/converters/td.rb +77 -0
  98. data/lib/coradoc/reverse_adoc/converters/text.rb +28 -0
  99. data/lib/coradoc/reverse_adoc/converters/th.rb +14 -0
  100. data/lib/coradoc/reverse_adoc/converters/tr.rb +18 -0
  101. data/lib/coradoc/reverse_adoc/converters/video.rb +25 -0
  102. data/lib/coradoc/reverse_adoc/converters.rb +53 -0
  103. data/lib/coradoc/reverse_adoc/errors.rb +10 -0
  104. data/lib/coradoc/reverse_adoc/html_converter.rb +150 -0
  105. data/lib/coradoc/reverse_adoc/plugin.rb +131 -0
  106. data/lib/coradoc/reverse_adoc/plugins/plateau.rb +174 -0
  107. data/lib/coradoc/reverse_adoc/postprocessor.rb +148 -0
  108. data/lib/coradoc/reverse_adoc.rb +30 -0
  109. data/lib/coradoc/transformer.rb +24 -14
  110. data/lib/coradoc/version.rb +1 -1
  111. data/lib/reverse_adoc.rb +20 -0
  112. metadata +184 -5
  113. data/lib/coradoc/element/inline/image.rb +0 -25
@@ -0,0 +1,47 @@
1
+ require "coradoc"
2
+
3
+ module Coradoc::ReverseAdoc
4
+ module Converters
5
+ class A < Base
6
+ def to_coradoc(node, state = {})
7
+ name = treat_children(node, state)
8
+
9
+ href = node["href"]
10
+ title = extract_title(node)
11
+ id = node["id"] || node["name"]
12
+
13
+ id = id&.gsub(/\s/, "")&.gsub(/__+/, "_")
14
+ id = nil if id&.empty?
15
+
16
+ return "" if /^_Toc\d+$|^_GoBack$/.match?(id)
17
+
18
+ return Coradoc::Element::Inline::Anchor.new(id) if id
19
+
20
+ if href.to_s.start_with?("#")
21
+ href = href.sub(/^#/, "").gsub(/\s/, "").gsub(/__+/, "_")
22
+ return Coradoc::Element::Inline::CrossReference.new(href, name)
23
+ end
24
+
25
+ return name if href.to_s.empty?
26
+
27
+ ambigous_characters = /[\w.?&#=%;\[\u{ff}-\u{10ffff}]/
28
+ if name&.strip == href
29
+ name = ""
30
+ right_constrain = textnode_after_start_with?(node, ambigous_characters)
31
+ end
32
+
33
+ out = []
34
+ out << " " if textnode_before_end_with?(node, ambigous_characters)
35
+ out << Coradoc::Element::Inline::Link.new(
36
+ path: href,
37
+ name: name.strip,
38
+ title: title.strip,
39
+ right_constrain: right_constrain,
40
+ )
41
+ out
42
+ end
43
+ end
44
+
45
+ register :a, A.new
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Aside < Base
4
+ def to_coradoc(node, state = {})
5
+ content = treat_children(node, state)
6
+ Coradoc::Element::Block::Side.new(lines: content.lines)
7
+ end
8
+ end
9
+
10
+ register :aside, Aside.new
11
+ end
12
+ end
@@ -0,0 +1,25 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Audio < Base
4
+ def to_coradoc(node, _state = {})
5
+ src = node["src"]
6
+ id = node["id"]
7
+ title = extract_title(node)
8
+ attributes = Coradoc::Element::AttributeList.new
9
+ options = options(node)
10
+ attributes.add_named("options", options) if options.any?
11
+ Coradoc::Element::Audio.new(title, id: id, src: src,
12
+ attributes: attributes)
13
+ end
14
+
15
+ def options(node)
16
+ autoplay = node["autoplay"]
17
+ loop_attr = node["loop"]
18
+ controls = node["controls"]
19
+ [autoplay, loop_attr, controls].compact
20
+ end
21
+ end
22
+
23
+ register :audio, Audio.new
24
+ end
25
+ end
@@ -0,0 +1,104 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Base
4
+ # Default implementation to convert a given Nokogiri node
5
+ # to an AsciiDoc script.
6
+ # Can be overriden by subclasses.
7
+ def convert(node, state = {})
8
+ Coradoc::Generator.gen_adoc(to_coradoc(node, state))
9
+ end
10
+
11
+ # Note: treat_children won't run plugin hooks
12
+ def treat_children(node, state)
13
+ node.children.inject("") do |memo, child|
14
+ memo << treat(child, state)
15
+ end
16
+ end
17
+
18
+ def treat(node, state)
19
+ Converters.process(node, state)
20
+ end
21
+
22
+ def treat_children_coradoc(node, state)
23
+ node.children.inject([]) do |memo, child|
24
+ memo << treat_coradoc(child, state)
25
+ end.flatten.reject { |x| x == "" || x.nil? }
26
+ end
27
+
28
+ def treat_coradoc(node, state)
29
+ Converters.process_coradoc(node, state)
30
+ end
31
+
32
+ def extract_title(node)
33
+ title = Coradoc::Element::TextElement.escape_keychars(
34
+ node["title"].to_s,
35
+ )
36
+ title.empty? ? "" : %[ #{title}]
37
+ end
38
+
39
+ def node_has_ancestor?(node, name)
40
+ case name
41
+ when String
42
+ node.ancestors.map(&:name).include?(name)
43
+ when Array
44
+ (node.ancestors.map(&:name) & name).any?
45
+ end
46
+ end
47
+
48
+ def textnode_before_end_with?(node, str)
49
+ return nil unless [String, Regexp].include?(str.class)
50
+ return nil if str.is_a?(String) && str.empty?
51
+
52
+ str = /#{Regexp.escape(str)}/ if str.is_a?(String)
53
+ str = /(?:#{str})\z/
54
+
55
+ node2 = node.at_xpath("preceding-sibling::node()[1]")
56
+ node2.respond_to?(:text) && node2.text.match?(str)
57
+ end
58
+
59
+ def textnode_after_start_with?(node, str)
60
+ return nil unless [String, Regexp].include?(str.class)
61
+ return nil if str.is_a?(String) && str.empty?
62
+
63
+ str = /#{Regexp.escape(str)}/ if str.is_a?(String)
64
+ str = /\A(?:#{str})/
65
+
66
+ node2 = node.at_xpath("following-sibling::node()[1]")
67
+ node2.respond_to?(:text) && node2.text.match?(str)
68
+ end
69
+
70
+ def extract_leading_trailing_whitespace(node)
71
+ node.text =~ /^(\s+)/
72
+ leading_whitespace = $1
73
+ if !leading_whitespace.nil?
74
+ first_text = node.at_xpath("./text()[1]")
75
+ first_text.replace(first_text.text.lstrip)
76
+ leading_whitespace = " "
77
+ end
78
+ node.text =~ /(\s+)$/
79
+ trailing_whitespace = $1
80
+ if !trailing_whitespace.nil?
81
+ last_text = node.at_xpath("./text()[last()]")
82
+ last_text.replace(last_text.text.rstrip)
83
+ trailing_whitespace = " "
84
+ end
85
+ [leading_whitespace, trailing_whitespace]
86
+ end
87
+
88
+ def unconstrained_before?(node)
89
+ before = node.at_xpath("preceding::node()[1]")
90
+
91
+ before &&
92
+ !before.text.strip.empty? &&
93
+ before.text[-1]&.match?(/\w/)
94
+ end
95
+
96
+ def unconstrained_after?(node)
97
+ after = node.at_xpath("following::node()[1]")
98
+
99
+ after && !after.text.strip.empty? &&
100
+ after.text[0]&.match?(/\w|,|;|"|\.\?!/)
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,18 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Blockquote < Base
4
+ def to_coradoc(node, state = {})
5
+ node["id"]
6
+ cite = node["cite"]
7
+ attributes = Coradoc::Element::AttributeList.new
8
+ attributes.add_positional("quote", cite) if !cite.nil?
9
+ content = treat_children(node, state).strip
10
+ content = Coradoc::ReverseAdoc.cleaner.remove_newlines(content)
11
+ Coradoc::Element::Block::Quote.new(nil, lines: content,
12
+ attributes: attributes)
13
+ end
14
+ end
15
+
16
+ register :blockquote, Blockquote.new
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Br < Base
4
+ def to_coradoc(_node, _state = {})
5
+ Coradoc::Element::Inline::HardLineBreak.new
6
+ end
7
+ end
8
+
9
+ register :br, Br.new
10
+ end
11
+ end
@@ -0,0 +1,77 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Bypass < Base
4
+ def to_coradoc(node, state = {})
5
+ treat_children_coradoc(node, state)
6
+ end
7
+ end
8
+
9
+ register :document, Bypass.new
10
+ register :html, Bypass.new
11
+ register :body, Bypass.new
12
+ register :span, Bypass.new
13
+ register :thead, Bypass.new
14
+ register :tbody, Bypass.new
15
+ register :tfoot, Bypass.new
16
+ register :abbr, Bypass.new
17
+ register :acronym, Bypass.new
18
+ register :address, Bypass.new
19
+ register :applet, Bypass.new
20
+ register :map, Bypass.new
21
+ register :area, Bypass.new
22
+ register :bdi, Bypass.new
23
+ register :bdo, Bypass.new
24
+ register :big, Bypass.new
25
+ register :button, Bypass.new
26
+ register :canvas, Bypass.new
27
+ register :data, Bypass.new
28
+ register :datalist, Bypass.new
29
+ register :del, Bypass.new
30
+ register :ins, Bypass.new
31
+ register :dfn, Bypass.new
32
+ register :dialog, Bypass.new
33
+ register :embed, Bypass.new
34
+ register :fieldset, Bypass.new
35
+ register :font, Bypass.new
36
+ register :footer, Bypass.new
37
+ register :form, Bypass.new
38
+ register :frame, Bypass.new
39
+ register :frameset, Bypass.new
40
+ register :header, Bypass.new
41
+ register :iframe, Bypass.new
42
+ register :input, Bypass.new
43
+ register :label, Bypass.new
44
+ register :legend, Bypass.new
45
+ register :main, Bypass.new
46
+ register :menu, Bypass.new
47
+ register :menulist, Bypass.new
48
+ register :meter, Bypass.new
49
+ register :nav, Bypass.new
50
+ register :noframes, Bypass.new
51
+ register :noscript, Bypass.new
52
+ register :object, Bypass.new
53
+ register :optgroup, Bypass.new
54
+ register :option, Bypass.new
55
+ register :output, Bypass.new
56
+ register :param, Bypass.new
57
+ register :picture, Bypass.new
58
+ register :progress, Bypass.new
59
+ register :ruby, Bypass.new
60
+ register :rt, Bypass.new
61
+ register :rp, Bypass.new
62
+ register :s, Bypass.new
63
+ register :select, Bypass.new
64
+ register :small, Bypass.new
65
+ register :span, Bypass.new
66
+ register :strike, Bypass.new
67
+ register :details, Bypass.new
68
+ register :section, Bypass.new
69
+ register :summary, Bypass.new
70
+ register :svg, Bypass.new
71
+ register :template, Bypass.new
72
+ register :textarea, Bypass.new
73
+ register :track, Bypass.new
74
+ register :u, Bypass.new
75
+ register :wbr, Bypass.new
76
+ end
77
+ end
@@ -0,0 +1,19 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Code < Markup
4
+ def coradoc_class
5
+ Coradoc::Element::Inline::Monospace
6
+ end
7
+
8
+ def markup_ancestor_tag_names
9
+ %w[code tt kbd samp var]
10
+ end
11
+ end
12
+
13
+ register :code, Code.new
14
+ register :tt, Code.new
15
+ register :kbd, Code.new
16
+ register :samp, Code.new
17
+ register :var, Code.new
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Div < Base
4
+ def to_coradoc(node, state = {})
5
+ id = node["id"]
6
+ contents = treat_children_coradoc(node, state)
7
+ Coradoc::Element::Section.new(nil, id: id, contents: contents)
8
+ end
9
+ end
10
+
11
+ register :div, Div.new
12
+ register :article, Div.new
13
+ end
14
+ end
@@ -0,0 +1,55 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Dl < Base
4
+ def to_coradoc(node, state = {})
5
+ items = process_dl(node, state)
6
+ items2 = items.map do |item|
7
+ Coradoc::Element::ListItemDefinition.new(item[:name], item[:value])
8
+ end
9
+ Coradoc::Element::List::Definition.new(items2, delimiter: "::")
10
+ end
11
+
12
+ def process_dl(node, state = {})
13
+ groups = []
14
+ current = {name: [], value: []}
15
+
16
+ seen_dd = false
17
+ child = node.at_xpath("*[1]")
18
+ grandchild = nil
19
+ while !child.nil?
20
+ if child.name == "div"
21
+ grandchild = child.at_xpath("*[1]")
22
+ while !grandchild.nil?
23
+ groups, current, seen_dd = process_dt_or_dd(groups, current, seen_dd, grandchild, state)
24
+ grandchild = grandchild.at_xpath("following-sibling::*[1]")
25
+ end
26
+ elsif ["dt", "dd"].include?(child.name)
27
+ groups, current, seen_dd = process_dt_or_dd(groups, current, seen_dd, child, state)
28
+ end
29
+ child = child.at_xpath("following-sibling::*[1]")
30
+ if current[:name].any? && current[:value].any?
31
+ groups << current
32
+ end
33
+ end
34
+ groups
35
+ end
36
+
37
+ def process_dt_or_dd(groups, current, seen_dd, subnode, state = {})
38
+ if subnode.name == "dt"
39
+ if seen_dd
40
+ # groups << current
41
+ current = {name: [], value: []}
42
+ seen_dd = false
43
+ end
44
+ current[:name] += treat_children_coradoc(subnode, state)
45
+ elsif subnode.name == "dd"
46
+ current[:value] += treat_children_coradoc(subnode, state)
47
+ seen_dd = true
48
+ end
49
+ [groups, current, seen_dd]
50
+ end
51
+ end
52
+
53
+ register :dl, Dl.new
54
+ end
55
+ end
@@ -0,0 +1,22 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Drop < Base
4
+ def to_coradoc(node, state = {})
5
+ convert(node, state)
6
+ end
7
+
8
+ def convert(_node, _state = {})
9
+ ""
10
+ end
11
+ end
12
+
13
+ register :caption, Drop.new
14
+ register :figcaption, Drop.new
15
+ register :title, Drop.new
16
+ register :link, Drop.new
17
+ register :style, Drop.new
18
+ register :meta, Drop.new
19
+ register :script, Drop.new
20
+ register :comment, Drop.new
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Em < Markup
4
+ def coradoc_class
5
+ Coradoc::Element::Inline::Italic
6
+ end
7
+
8
+ def markup_ancestor_tag_names
9
+ %w[em i cite]
10
+ end
11
+ end
12
+
13
+ register :em, Em.new
14
+ register :i, Em.new
15
+ register :cite, Em.new
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Figure < Base
4
+ def to_coradoc(node, state = {})
5
+ id = node["id"]
6
+ title = extract_title(node)
7
+ content = treat_children_coradoc(node, state)
8
+ Coradoc::Element::Block::Example.new(title, lines: content, id: id)
9
+ end
10
+
11
+ def extract_title(node)
12
+ title = node.at("./figcaption")
13
+ return "" if title.nil?
14
+
15
+ treat_children_coradoc(title, {})
16
+ end
17
+ end
18
+
19
+ register :figure, Figure.new
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class H < Base
4
+ def to_coradoc(node, state = {})
5
+ id = node["id"]
6
+ internal_anchor = treat_children_anchors(node, state)
7
+
8
+ if id.to_s.empty? && internal_anchor.size.positive?
9
+ id = internal_anchor.first.id
10
+ end
11
+
12
+ level = node.name[/\d/].to_i
13
+ content = treat_children_no_anchors(node, state)
14
+
15
+ Coradoc::Element::Title.new(content, level, id: id)
16
+ end
17
+
18
+ def treat_children_no_anchors(node, state)
19
+ node.children.reject { |a| a.name == "a" }.inject([]) do |memo, child|
20
+ memo << treat_coradoc(child, state)
21
+ end
22
+ end
23
+
24
+ def treat_children_anchors(node, state)
25
+ node.children.select { |a| a.name == "a" }.inject([]) do |memo, child|
26
+ memo << treat_coradoc(child, state)
27
+ end
28
+ end
29
+ end
30
+
31
+ register :h1, H.new
32
+ register :h2, H.new
33
+ register :h3, H.new
34
+ register :h4, H.new
35
+ register :h5, H.new
36
+ register :h6, H.new
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Head < Base
4
+ def to_coradoc(node, _state = {})
5
+ title = extract_title(node)
6
+ Coradoc::Element::Header.new(title)
7
+ end
8
+
9
+ def extract_title(node)
10
+ title = node.at("./title")
11
+ return "(???)" if title.nil?
12
+
13
+ title.text
14
+ end
15
+ end
16
+
17
+ register :head, Head.new
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Hr < Base
4
+ def to_coradoc(_node, _state = {})
5
+ Coradoc::Element::Break::ThematicBreak.new
6
+ end
7
+ end
8
+
9
+ register :hr, Hr.new
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Ignore < Base
4
+ def to_coradoc(node, state = {})
5
+ convert(node, state)
6
+ end
7
+
8
+ def convert(_node, _state = {})
9
+ "" # noop
10
+ end
11
+ end
12
+
13
+ register :colgroup, Ignore.new
14
+ register :col, Ignore.new
15
+ end
16
+ end
@@ -0,0 +1,98 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "tempfile"
4
+ require "base64"
5
+ require "marcel"
6
+
7
+ module Coradoc::ReverseAdoc
8
+ module Converters
9
+ class Img < Base
10
+ def image_number
11
+ sprintf(
12
+ Coradoc::ReverseAdoc.config.image_counter_pattern,
13
+ Coradoc::ReverseAdoc.config.image_counter,
14
+ )
15
+ end
16
+
17
+ def image_number_increment
18
+ Coradoc::ReverseAdoc.config.image_counter += 1
19
+ end
20
+
21
+ def datauri2file(src)
22
+ return unless src
23
+
24
+ %r{^data:image/(?:[^;]+);base64,(?<imgdata>.+)$} =~ src
25
+
26
+ dest_dir = Pathname.new(Coradoc::ReverseAdoc.config.destination).dirname
27
+ images_dir = dest_dir.join("images")
28
+ FileUtils.mkdir_p(images_dir)
29
+
30
+ ext, image_src_path, tempfile = determine_image_src_path(src, imgdata)
31
+ image_dest_path = images_dir + "#{image_number}.#{ext}"
32
+
33
+ # puts "image_dest_path: #{image_dest_path.to_s}"
34
+ # puts "image_src_path: #{image_src_path.to_s}"
35
+
36
+ FileUtils.cp(image_src_path, image_dest_path)
37
+ image_number_increment
38
+
39
+ image_dest_path.relative_path_from(dest_dir)
40
+ ensure
41
+ tempfile&.close!
42
+ end
43
+
44
+ def determine_image_src_path(src, imgdata)
45
+ return copy_temp_file(imgdata) if imgdata
46
+
47
+ ext = File.extname(src).strip.downcase[1..-1]
48
+ [ext, Pathname.new(Coradoc::ReverseAdoc.config.sourcedir).join(src)]
49
+ end
50
+
51
+ def copy_temp_file(imgdata)
52
+ f = Tempfile.open(["radoc", ".jpg"])
53
+ f.binmode
54
+ f.write(Base64.strict_decode64(imgdata))
55
+ f.rewind
56
+ ext = Marcel::MimeType.for(f).sub(%r{^[^/]+/}, "")
57
+ ext = "svg" if ext == "svg+xml"
58
+ [ext, f.path, f]
59
+ end
60
+
61
+ def to_coradoc(node, _state = {})
62
+ id = node["id"]
63
+ alt = node["alt"]
64
+ src = node["src"]
65
+ width = node["width"]
66
+ height = node["height"]
67
+
68
+ width = width.to_i if width&.match?(/\A\d+\z/)
69
+ height = height.to_i if height&.match?(/\A\d+\z/)
70
+
71
+ title = extract_title(node)
72
+
73
+ if Coradoc::ReverseAdoc.config.external_images
74
+ # puts "external image conversion #{id}, #{src}"
75
+ src = datauri2file(src)
76
+ end
77
+
78
+ attributes = Coradoc::Element::AttributeList.new
79
+ # attributes.add_named("id", id) if id
80
+ if alt # && !alt.to_s.empty?
81
+ attributes.add_positional(alt)
82
+ elsif width || height
83
+ attributes.add_positional(nil)
84
+ end
85
+ attributes.add_named("title", title) if title && !title.empty?
86
+ attributes.add_positional(width) if width
87
+ attributes.add_positional(height) if height
88
+
89
+ if src
90
+ Coradoc::Element::Image::BlockImage.new(title, id, src,
91
+ attributes: attributes)
92
+ end
93
+ end
94
+ end
95
+
96
+ register :img, Img.new
97
+ end
98
+ end
@@ -0,0 +1,13 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Li < Base
4
+ def to_coradoc(node, state = {})
5
+ id = node["id"]
6
+ content = treat_children_coradoc(node, state)
7
+ Coradoc::Element::ListItem.new(content, id: id)
8
+ end
9
+ end
10
+
11
+ register :li, Li.new
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module Coradoc::ReverseAdoc
2
+ module Converters
3
+ class Mark < Markup
4
+ def coradoc_class
5
+ Coradoc::Element::Inline::Highlight
6
+ end
7
+
8
+ def markup_ancestor_tag_names
9
+ %w[mark]
10
+ end
11
+ end
12
+
13
+ register :mark, Mark.new
14
+ end
15
+ end